- glib
- pixman
- gnu-sed
+ update: true
# The channel name "irc.oftc.net#qemu" is encrypted against qemu/qemu
matrix:
include:
- env:
- - CONFIG="--disable-system"
+ - CONFIG="--disable-system --static"
# we split the system builds as it takes a while to build them all
F: target/s390x/ioinst.[ch]
F: target/s390x/machine.c
F: target/s390x/sigp.c
+F: target/s390x/cpu_features*.[ch]
+F: target/s390x/cpu_models.[ch]
F: hw/intc/s390_flic.c
F: hw/intc/s390_flic_kvm.c
F: include/hw/s390x/s390_flic.h
F: include/hw/misc/imx6_*.h
F: include/hw/ssi/imx_spi.h
+SBSA-REF
+M: Radoslaw Biernacki <radoslaw.biernacki@linaro.org>
+M: Peter Maydell <peter.maydell@linaro.org>
+R: Leif Lindholm <leif.lindholm@linaro.org>
+L: qemu-arm@nongnu.org
+S: Maintained
+F: hw/arm/sbsa-ref.c
+
Sharp SL-5500 (Collie) PDA
M: Peter Maydell <peter.maydell@linaro.org>
L: qemu-arm@nongnu.org
M: Eduardo Habkost <ehabkost@redhat.com>
M: Marcel Apfelbaum <marcel.apfelbaum@gmail.com>
S: Supported
+F: hw/core/machine-qmp-cmds.c
F: hw/core/machine.c
F: hw/core/null-machine.c
+F: hw/core/numa.c
F: hw/cpu/cluster.c
+F: qapi/machine.json
+F: qapi/machine-target.json
+F: qom/cpu.c
F: include/hw/boards.h
F: include/hw/cpu/cluster.h
+F: include/qom/cpu.h
+F: include/sysemu/numa.h
T: git https://github.com/ehabkost/qemu.git machine-next
Xtensa Machines
S: Supported
F: scripts/coverity-model.c
-CPU
-S: Supported
-F: qom/cpu.c
-F: include/qom/cpu.h
-
Device Tree
M: Alistair Francis <alistair.francis@wdc.com>
R: David Gibson <david@gibson.dropbear.id.au>
Dump
S: Supported
M: Marc-André Lureau <marcandre.lureau@redhat.com>
-F: dump.c
+F: dump/
F: hw/misc/vmcoreinfo.c
F: include/hw/misc/vmcoreinfo.h
+F: include/qemu/win_dump_defs
F: include/sysemu/dump-arch.h
F: include/sysemu/dump.h
+F: qapi/dump.json
F: scripts/dump-guest-memory.py
F: stubs/dump.c
S: Maintained
F: net/
F: include/net/
+F: qemu-bridge-helper.c
T: git https://github.com/jasowang/qemu.git net
F: qapi/net.json
S: Maintained
F: net/netmap.c
-NUMA
-M: Eduardo Habkost <ehabkost@redhat.com>
-S: Maintained
-F: numa.c
-F: include/sysemu/numa.h
-T: git https://github.com/ehabkost/qemu.git machine-next
-
Host Memory Backends
M: Eduardo Habkost <ehabkost@redhat.com>
M: Igor Mammedov <imammedo@redhat.com>
T: git https://github.com/mdroth/qemu.git qga
QOM
-M: Andreas Färber <afaerber@suse.de>
+M: Paolo Bonzini <pbonzini@redhat.com>
+R: Daniel P. Berrange <berrange@redhat.com>
+R: Eduardo Habkost <ehabkost@redhat.com>
S: Supported
-T: git https://github.com/afaerber/qemu-cpu.git qom-next
+F: docs/qdev-device-use.txt
+F: hw/core/qdev*
+F: include/hw/qdev*
+F: include/monitor/qdev.h
F: include/qom/
X: include/qom/cpu.h
+F: qapi/qom.json
+F: qapi/qdev.json
+F: qdev-monitor.c
F: qom/
X: qom/cpu.c
F: tests/check-qom-interface.c
F: tests/check-qom-proplist.c
+F: tests/test-qdev-global-props.c
QMP
M: Markus Armbruster <armbru@redhat.com>
UNCHECKED_GOALS := %clean TAGS cscope ctags dist \
html info pdf txt \
help check-help print-% \
- docker docker-% vm-test vm-build-%
+ docker docker-% vm-help vm-test vm-build-%
print-%:
@echo '$*=$($*)'
config-host.mak: $(SRC_PATH)/configure $(SRC_PATH)/pc-bios $(SRC_PATH)/VERSION
@echo $@ is out-of-date, running configure
- @# TODO: The next lines include code which supports a smooth
- @# transition from old configurations without config.status.
- @# This code can be removed after QEMU 1.7.
- @if test -x config.status; then \
- ./config.status; \
- else \
- sed -n "/.*Configured with/s/[^:]*: //p" $@ | sh; \
- fi
+ @./config.status
else
config-host.mak:
ifneq ($(filter-out $(UNCHECKED_GOALS),$(MAKECMDGOALS)),$(if $(MAKECMDGOALS),,fail))
qemu-options.def: $(SRC_PATH)/qemu-options.hx $(SRC_PATH)/scripts/hxtool
$(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -h < $< > $@,"GEN","$@")
-SUBDIR_RULES=$(patsubst %,subdir-%, $(TARGET_DIRS))
-SOFTMMU_SUBDIR_RULES=$(filter %-softmmu,$(SUBDIR_RULES))
+TARGET_DIRS_RULES := $(foreach t, all clean install, $(addsuffix /$(t), $(TARGET_DIRS)))
-$(SOFTMMU_SUBDIR_RULES): $(authz-obj-y)
-$(SOFTMMU_SUBDIR_RULES): $(block-obj-y)
-$(SOFTMMU_SUBDIR_RULES): $(chardev-obj-y)
-$(SOFTMMU_SUBDIR_RULES): $(crypto-obj-y)
-$(SOFTMMU_SUBDIR_RULES): $(io-obj-y)
-$(SOFTMMU_SUBDIR_RULES): config-all-devices.mak
-$(SOFTMMU_SUBDIR_RULES): $(edk2-decompressed)
+SOFTMMU_ALL_RULES=$(filter %-softmmu/all, $(TARGET_DIRS_RULES))
+$(SOFTMMU_ALL_RULES): $(authz-obj-y)
+$(SOFTMMU_ALL_RULES): $(block-obj-y)
+$(SOFTMMU_ALL_RULES): $(chardev-obj-y)
+$(SOFTMMU_ALL_RULES): $(crypto-obj-y)
+$(SOFTMMU_ALL_RULES): $(io-obj-y)
+$(SOFTMMU_ALL_RULES): config-all-devices.mak
+$(SOFTMMU_ALL_RULES): $(edk2-decompressed)
-subdir-%:
- $(call quiet-command,$(MAKE) $(SUBDIR_MAKEFLAGS) -C $* V="$(V)" TARGET_DIR="$*/" all,)
+.PHONY: $(TARGET_DIRS_RULES)
+# The $(TARGET_DIRS_RULES) are of the form SUBDIR/GOAL, so that
+# $(dir $@) yields the sub-directory, and $(notdir $@) yields the sub-goal
+$(TARGET_DIRS_RULES):
+ $(call quiet-command,$(MAKE) $(SUBDIR_MAKEFLAGS) -C $(dir $@) V="$(V)" TARGET_DIR="$(dir $@)" $(notdir $@),)
DTC_MAKE_ARGS=-I$(SRC_PATH)/dtc VPATH=$(SRC_PATH)/dtc -C dtc V="$(V)" LIBFDT_srcdir=$(SRC_PATH)/dtc/libfdt
DTC_CFLAGS=$(CFLAGS) $(QEMU_CFLAGS)
DTC_CPPFLAGS=-I$(BUILD_DIR)/dtc -I$(SRC_PATH)/dtc -I$(SRC_PATH)/dtc/libfdt
-subdir-dtc: .git-submodule-status dtc/libfdt dtc/tests
+.PHONY: dtc/all
+dtc/all: .git-submodule-status dtc/libfdt dtc/tests
$(call quiet-command,$(MAKE) $(DTC_MAKE_ARGS) CPPFLAGS="$(DTC_CPPFLAGS)" CFLAGS="$(DTC_CFLAGS)" LDFLAGS="$(LDFLAGS)" ARFLAGS="$(ARFLAGS)" CC="$(CC)" AR="$(AR)" LD="$(LD)" $(SUBDIR_MAKEFLAGS) libfdt/libfdt.a,)
dtc/%: .git-submodule-status
CAP_CFLAGS += -DCAPSTONE_HAS_POWERPC
CAP_CFLAGS += -DCAPSTONE_HAS_X86
-subdir-capstone: .git-submodule-status
+.PHONY: capstone/all
+capstone/all: .git-submodule-status
$(call quiet-command,$(MAKE) -C $(SRC_PATH)/capstone CAPSTONE_SHARED=no BUILDDIR="$(BUILD_DIR)/capstone" CC="$(CC)" AR="$(AR)" LD="$(LD)" RANLIB="$(RANLIB)" CFLAGS="$(CAP_CFLAGS)" $(SUBDIR_MAKEFLAGS) $(BUILD_DIR)/capstone/$(LIBCAPSTONE))
-subdir-slirp: .git-submodule-status
+.PHONY: slirp/all
+slirp/all: .git-submodule-status
$(call quiet-command,$(MAKE) -C $(SRC_PATH)/slirp BUILD_DIR="$(BUILD_DIR)/slirp" CC="$(CC)" AR="$(AR)" LD="$(LD)" RANLIB="$(RANLIB)" CFLAGS="$(QEMU_CFLAGS) $(CFLAGS)" LDFLAGS="$(LDFLAGS)")
-$(SUBDIR_RULES): libqemuutil.a $(common-obj-y) \
+# Compatibility gunk to keep make working across the rename of targets
+# for recursion, to be removed some time after 4.1.
+subdir-dtc: dtc/all
+subdir-capstone: capstone/all
+subdir-slirp: slirp/all
+
+$(filter %/all, $(TARGET_DIRS_RULES)): libqemuutil.a $(common-obj-y) \
$(qom-obj-y) $(crypto-user-obj-$(CONFIG_USER_ONLY))
-ROMSUBDIR_RULES=$(patsubst %,romsubdir-%, $(ROMS))
+ROM_DIRS = $(addprefix pc-bios/, $(ROMS))
+ROM_DIRS_RULES=$(foreach t, all clean, $(addsuffix /$(t), $(ROM_DIRS)))
# Only keep -O and -g cflags
-romsubdir-%:
- $(call quiet-command,$(MAKE) $(SUBDIR_MAKEFLAGS) -C pc-bios/$* V="$(V)" TARGET_DIR="$*/" CFLAGS="$(filter -O% -g%,$(CFLAGS))",)
-
-ALL_SUBDIRS=$(TARGET_DIRS) $(patsubst %,pc-bios/%, $(ROMS))
+.PHONY: $(ROM_DIRS_RULES)
+$(ROM_DIRS_RULES):
+ $(call quiet-command,$(MAKE) $(SUBDIR_MAKEFLAGS) -C $(dir $@) V="$(V)" TARGET_DIR="$(dir $@)" CFLAGS="$(filter -O% -g%,$(CFLAGS))" $(notdir $@),)
-recurse-all: $(SUBDIR_RULES) $(ROMSUBDIR_RULES)
+recurse-all: $(addsuffix /all, $(TARGET_DIRS) $(ROM_DIRS))
+recurse-clean: $(addsuffix /clean, $(TARGET_DIRS) $(ROM_DIRS))
+recurse-install: $(addsuffix /install, $(TARGET_DIRS))
$(BUILD_DIR)/version.o: $(SRC_PATH)/version.rc config-host.h
$(call quiet-command,$(WINDRES) -I$(BUILD_DIR) -o $@ $<,"RC","version.o")
"CLEAN", "coverage files")
endif
-clean:
+clean: recurse-clean
# avoid old build problems by removing potentially incorrect old files
rm -f config.mak op-i386.h opc-i386.h gen-op-i386.h op-arm.h opc-arm.h gen-op-arm.h
rm -f qemu-options.def
rm -f $(foreach f,$(generated-files-y),$(f) $(f)-timestamp)
rm -f qapi-gen-timestamp
rm -rf qga/qapi-generated
- for d in $(ALL_SUBDIRS); do \
- if test -d $$d; then $(MAKE) -C $$d $@ || exit 1; fi; \
- rm -f $$d/qemu-options.def; \
- done
rm -f config-all-devices.mak
VERSION ?= $(shell cat VERSION)
ifdef INSTALL_BLOBS
BLOBS=bios.bin bios-256k.bin sgabios.bin vgabios.bin vgabios-cirrus.bin \
vgabios-stdvga.bin vgabios-vmware.bin vgabios-qxl.bin vgabios-virtio.bin \
-vgabios-ramfb.bin vgabios-bochs-display.bin \
+vgabios-ramfb.bin vgabios-bochs-display.bin vgabios-ati.bin \
ppc_rom.bin openbios-sparc32 openbios-sparc64 openbios-ppc QEMU,tcx.bin QEMU,cgthree.bin \
pxe-e1000.rom pxe-eepro100.rom pxe-ne2k_pci.rom \
pxe-pcnet.rom pxe-rtl8139.rom pxe-virtio.rom \
ICON_SIZES=16x16 24x24 32x32 48x48 64x64 128x128 256x256 512x512
install: all $(if $(BUILD_DOCS),install-doc) install-datadir install-localstatedir \
- $(if $(INSTALL_BLOBS),$(edk2-decompressed))
+ $(if $(INSTALL_BLOBS),$(edk2-decompressed)) \
+ recurse-install
ifneq ($(TOOLS),)
$(call install-prog,$(subst qemu-ga,qemu-ga$(EXESUF),$(TOOLS)),$(DESTDIR)$(bindir))
endif
done
endif
for s in $(ICON_SIZES); do \
- mkdir -p "$(DESTDIR)/$(qemu_icondir)/hicolor/$${s}/apps"; \
+ mkdir -p "$(DESTDIR)$(qemu_icondir)/hicolor/$${s}/apps"; \
$(INSTALL_DATA) $(SRC_PATH)/ui/icons/qemu_$${s}.png \
- "$(DESTDIR)/$(qemu_icondir)/hicolor/$${s}/apps/qemu.png"; \
+ "$(DESTDIR)$(qemu_icondir)/hicolor/$${s}/apps/qemu.png"; \
done; \
- mkdir -p "$(DESTDIR)/$(qemu_icondir)/hicolor/32x32/apps"; \
+ mkdir -p "$(DESTDIR)$(qemu_icondir)/hicolor/32x32/apps"; \
$(INSTALL_DATA) $(SRC_PATH)/ui/icons/qemu_32x32.bmp \
- "$(DESTDIR)/$(qemu_icondir)/hicolor/32x32/apps/qemu.bmp"; \
- mkdir -p "$(DESTDIR)/$(qemu_icondir)/hicolor/scalable/apps"; \
+ "$(DESTDIR)$(qemu_icondir)/hicolor/32x32/apps/qemu.bmp"; \
+ mkdir -p "$(DESTDIR)$(qemu_icondir)/hicolor/scalable/apps"; \
$(INSTALL_DATA) $(SRC_PATH)/ui/icons/qemu.svg \
- "$(DESTDIR)/$(qemu_icondir)/hicolor/scalable/apps/qemu.svg"
- mkdir -p "$(DESTDIR)/$(qemu_desktopdir)"
+ "$(DESTDIR)$(qemu_icondir)/hicolor/scalable/apps/qemu.svg"
+ mkdir -p "$(DESTDIR)$(qemu_desktopdir)"
$(INSTALL_DATA) $(SRC_PATH)/ui/qemu.desktop \
- "$(DESTDIR)/$(qemu_desktopdir)/qemu.desktop"
+ "$(DESTDIR)$(qemu_desktopdir)/qemu.desktop"
ifdef CONFIG_GTK
$(MAKE) -C po $@
endif
$(INSTALL_DATA) $(SRC_PATH)/pc-bios/keymaps/$$x "$(DESTDIR)$(qemu_datadir)/keymaps"; \
done
$(INSTALL_DATA) $(BUILD_DIR)/trace-events-all "$(DESTDIR)$(qemu_datadir)/trace-events-all"
- for d in $(TARGET_DIRS); do \
- $(MAKE) $(SUBDIR_MAKEFLAGS) TARGET_DIR=$$d/ -C $$d $@ || exit 1 ; \
- done
.PHONY: ctags
ctags:
@$(if $(TARGET_DIRS), \
echo 'Architecture specific targets:'; \
$(foreach t, $(TARGET_DIRS), \
- printf " %-30s - Build for %s\\n" $(patsubst %,subdir-%,$(t)) $(t);) \
+ printf " %-30s - Build for %s\\n" $(t)/all $(t);) \
echo '')
@echo 'Cleaning targets:'
@echo ' clean - Remove most generated files but keep the config'
@echo 'Test targets:'
@echo ' check - Run all tests (check-help for details)'
@echo ' docker - Help about targets running tests inside Docker containers'
- @echo ' vm-test - Help about targets running tests inside VM'
+ @echo ' vm-help - Help about targets running tests inside VM'
@echo ''
@echo 'Documentation targets:'
@echo ' html info pdf txt'
ifeq ($(CONFIG_SOFTMMU),y)
common-obj-y = blockdev.o blockdev-nbd.o block/
common-obj-y += bootdevice.o iothread.o
+common-obj-y += dump/
common-obj-y += job-qmp.o
common-obj-y += monitor/
common-obj-y += net/
# qapi
common-obj-y += qapi/
-common-obj-y += monitor/
endif
#######################################################################
#########################################################
# System emulator target
ifdef CONFIG_SOFTMMU
-obj-y += arch_init.o cpus.o gdbstub.o balloon.o ioport.o numa.o
+obj-y += arch_init.o cpus.o gdbstub.o balloon.o ioport.o
obj-y += qtest.o
+obj-y += dump/
obj-y += hw/
obj-y += monitor/
obj-y += qapi/
obj-y += memory.o
obj-y += memory_mapping.o
-obj-y += dump.o
-obj-$(TARGET_X86_64) += win_dump.o
obj-y += migration/ram.o
LIBS := $(libs_softmmu) $(LIBS)
ss.rate = as->freq;
ba.fragsize = pa_usec_to_bytes(ppdo->latency, &ss);
- ba.maxlength = -1;
+ ba.maxlength = pa_usec_to_bytes(ppdo->latency * 2, &ss);
ba.minreq = -1;
ba.prebuf = -1;
break;
}
/* Copy if allocated above the base */
- ret = bdrv_is_allocated_above(blk_bs(s->top), blk_bs(s->base),
+ ret = bdrv_is_allocated_above(blk_bs(s->top), blk_bs(s->base), false,
offset, COMMIT_BUFFER_SIZE, &n);
copy = (ret == 1);
trace_commit_one_iteration(s, offset, n, ret);
/*
* Given an image chain: ... -> [BASE] -> [INTER1] -> [INTER2] -> [TOP]
*
- * Return true if (a prefix of) the given range is allocated in any image
- * between BASE and TOP (inclusive). BASE can be NULL to check if the given
- * offset is allocated in any image of the chain. Return false otherwise,
- * or negative errno on failure.
+ * Return 1 if (a prefix of) the given range is allocated in any image
+ * between BASE and TOP (BASE is only included if include_base is set).
+ * BASE can be NULL to check if the given offset is allocated in any
+ * image of the chain. Return 0 otherwise, or negative errno on
+ * failure.
*
* 'pnum' is set to the number of bytes (including and immediately
* following the specified offset) that are known to be in the same
*/
int bdrv_is_allocated_above(BlockDriverState *top,
BlockDriverState *base,
- int64_t offset, int64_t bytes, int64_t *pnum)
+ bool include_base, int64_t offset,
+ int64_t bytes, int64_t *pnum)
{
BlockDriverState *intermediate;
int ret;
int64_t n = bytes;
+ assert(base || !include_base);
+
intermediate = top;
- while (intermediate && intermediate != base) {
+ while (include_base || intermediate != base) {
int64_t pnum_inter;
int64_t size_inter;
+ assert(intermediate);
ret = bdrv_is_allocated(intermediate, offset, bytes, &pnum_inter);
if (ret < 0) {
return ret;
n = pnum_inter;
}
+ if (intermediate == base) {
+ break;
+ }
+
intermediate = backing_bs(intermediate);
}
return 0;
}
- ret = bdrv_is_allocated_above(bs, base, offset, bytes, &count);
+ ret = bdrv_is_allocated_above(bs, base, false, offset, bytes, &count);
if (ret < 0) {
return ret;
}
{
int64_t nr;
return !bytes ||
- (!bdrv_is_allocated_above(bs, NULL, offset, bytes, &nr) && nr == bytes);
+ (!bdrv_is_allocated_above(bs, NULL, false, offset, bytes, &nr) &&
+ nr == bytes);
}
static bool is_zero_cow(BlockDriverState *bs, QCowL2Meta *m)
rbd_image_t image;
char *image_name;
char *snap;
+ uint64_t image_size;
} BDRVRBDState;
static int qemu_rbd_connect(rados_t *cluster, rados_ioctx_t *io_ctx,
goto failed_open;
}
+ r = rbd_get_size(s->image, &s->image_size);
+ if (r < 0) {
+ error_setg_errno(errp, -r, "error getting image size from %s",
+ s->image_name);
+ rbd_close(s->image);
+ goto failed_open;
+ }
+
/* If we are using an rbd snapshot, we must be r/o, otherwise
* leave as-is */
if (s->snap != NULL) {
rados_shutdown(s->cluster);
}
+/* Resize the RBD image and update the 'image_size' with the current size */
+static int qemu_rbd_resize(BlockDriverState *bs, uint64_t size)
+{
+ BDRVRBDState *s = bs->opaque;
+ int r;
+
+ r = rbd_resize(s->image, size);
+ if (r < 0) {
+ return r;
+ }
+
+ s->image_size = size;
+
+ return 0;
+}
+
static const AIOCBInfo rbd_aiocb_info = {
.aiocb_size = sizeof(RBDAIOCB),
};
}
switch (cmd) {
- case RBD_AIO_WRITE:
+ case RBD_AIO_WRITE: {
+ /*
+ * RBD APIs don't allow us to write more than actual size, so in order
+ * to support growing images, we resize the image before write
+ * operations that exceed the current size.
+ */
+ if (off + size > s->image_size) {
+ r = qemu_rbd_resize(bs, off + size);
+ if (r < 0) {
+ goto failed_completion;
+ }
+ }
#ifdef LIBRBD_SUPPORTS_IOVEC
r = rbd_aio_writev(s->image, qiov->iov, qiov->niov, off, c);
#else
r = rbd_aio_write(s->image, off, size, rcb->buf, c);
#endif
break;
+ }
case RBD_AIO_READ:
#ifdef LIBRBD_SUPPORTS_IOVEC
r = rbd_aio_readv(s->image, qiov->iov, qiov->niov, off, c);
PreallocMode prealloc,
Error **errp)
{
- BDRVRBDState *s = bs->opaque;
int r;
if (prealloc != PREALLOC_MODE_OFF) {
return -ENOTSUP;
}
- r = rbd_resize(s->image, offset);
+ r = qemu_rbd_resize(bs, offset);
if (r < 0) {
error_setg_errno(errp, -r, "Failed to resize file");
return r;
while (remaining_sectors > 0) {
int64_t count;
- ret = bdrv_is_allocated_above(top->bs, base->bs,
+ ret = bdrv_is_allocated_above(top->bs, base->bs, false,
sector_num * BDRV_SECTOR_SIZE,
remaining_sectors * BDRV_SECTOR_SIZE,
&count);
typedef struct StreamBlockJob {
BlockJob common;
- BlockDriverState *base;
+ BlockDriverState *bottom;
BlockdevOnError on_error;
char *backing_file_str;
bool bs_read_only;
if (s->chain_frozen) {
BlockJob *bjob = &s->common;
- bdrv_unfreeze_backing_chain(blk_bs(bjob->blk), s->base);
+ bdrv_unfreeze_backing_chain(blk_bs(bjob->blk), s->bottom);
}
}
StreamBlockJob *s = container_of(job, StreamBlockJob, common.job);
BlockJob *bjob = &s->common;
BlockDriverState *bs = blk_bs(bjob->blk);
- BlockDriverState *base = s->base;
+ BlockDriverState *base = backing_bs(s->bottom);
Error *local_err = NULL;
int ret = 0;
- bdrv_unfreeze_backing_chain(bs, base);
+ bdrv_unfreeze_backing_chain(bs, s->bottom);
s->chain_frozen = false;
if (bs->backing) {
StreamBlockJob *s = container_of(job, StreamBlockJob, common.job);
BlockBackend *blk = s->common.blk;
BlockDriverState *bs = blk_bs(blk);
- BlockDriverState *base = s->base;
+ bool enable_cor = !backing_bs(s->bottom);
int64_t len;
int64_t offset = 0;
uint64_t delay_ns = 0;
int64_t n = 0; /* bytes */
void *buf;
- if (!bs->backing) {
- goto out;
+ if (bs == s->bottom) {
+ /* Nothing to stream */
+ return 0;
}
len = bdrv_getlength(bs);
if (len < 0) {
- ret = len;
- goto out;
+ return len;
}
job_progress_set_remaining(&s->common.job, len);
* backing chain since the copy-on-read operation does not take base into
* account.
*/
- if (!base) {
+ if (enable_cor) {
bdrv_enable_copy_on_read(bs);
}
} else if (ret >= 0) {
/* Copy if allocated in the intermediate images. Limit to the
* known-unallocated area [offset, offset+n*BDRV_SECTOR_SIZE). */
- ret = bdrv_is_allocated_above(backing_bs(bs), base,
+ ret = bdrv_is_allocated_above(backing_bs(bs), s->bottom, true,
offset, n, &n);
-
/* Finish early if end of backing file has been reached */
if (ret == 0 && n == 0) {
n = len - offset;
}
}
- if (!base) {
+ if (enable_cor) {
bdrv_disable_copy_on_read(bs);
}
- /* Do not remove the backing file if an error was there but ignored. */
- ret = error;
-
qemu_vfree(buf);
-out:
- /* Modify backing chain and close BDSes in main loop */
- return ret;
+ /* Do not remove the backing file if an error was there but ignored. */
+ return error;
}
static const BlockJobDriver stream_job_driver = {
StreamBlockJob *s;
BlockDriverState *iter;
bool bs_read_only;
+ int basic_flags = BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE_UNCHANGED;
+ BlockDriverState *bottom = bdrv_find_overlay(bs, base);
- if (bdrv_freeze_backing_chain(bs, base, errp) < 0) {
+ if (bdrv_freeze_backing_chain(bs, bottom, errp) < 0) {
return;
}
* already have our own plans. Also don't allow resize as the image size is
* queried only at the job start and then cached. */
s = block_job_create(job_id, &stream_job_driver, NULL, bs,
- BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE_UNCHANGED |
- BLK_PERM_GRAPH_MOD,
- BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE_UNCHANGED |
- BLK_PERM_WRITE,
+ basic_flags | BLK_PERM_GRAPH_MOD,
+ basic_flags | BLK_PERM_WRITE,
speed, creation_flags, NULL, NULL, errp);
if (!s) {
goto fail;
/* Block all intermediate nodes between bs and base, because they will
* disappear from the chain after this operation. The streaming job reads
- * every block only once, assuming that it doesn't change, so block writes
- * and resizes. */
+ * every block only once, assuming that it doesn't change, so forbid writes
+ * and resizes. Reassign the base node pointer because the backing BS of the
+ * bottom node might change after the call to bdrv_reopen_set_read_only()
+ * due to parallel block jobs running.
+ */
+ base = backing_bs(bottom);
for (iter = backing_bs(bs); iter && iter != base; iter = backing_bs(iter)) {
block_job_add_bdrv(&s->common, "intermediate node", iter, 0,
- BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE_UNCHANGED,
- &error_abort);
+ basic_flags, &error_abort);
}
- s->base = base;
+ s->bottom = bottom;
s->backing_file_str = g_strdup(backing_file_str);
s->bs_read_only = bs_read_only;
s->chain_frozen = true;
echo "us upstream at qemu-devel@nongnu.org."
fi
+# Note that if the Python conditional here evaluates True we will exit
+# with status 1 which is a shell 'false' value.
+if ! $python -c 'import sys; sys.exit(sys.version_info < (3,0))'; then
+ echo
+ echo "warning: Python 2 support is deprecated" >&2
+ echo "warning: Python 3 will be required for building future versions of QEMU" >&2
+fi
+
config_host_mak="config-host.mak"
echo "# Automatically generated by configure - do not modify" >config-all-disas.mak
echo "SLIRP_LIBS=$slirp_libs" >> $config_host_mak
fi
if [ "$slirp" = "git" -o "$slirp" = "internal" ]; then
- echo "config-host.h: subdir-slirp" >> $config_host_mak
+ echo "config-host.h: slirp/all" >> $config_host_mak
fi
if test "$vde" = "yes" ; then
echo "CONFIG_VDE=y" >> $config_host_mak
fi
if [ "$fdt" = "git" ]; then
- echo "config-host.h: subdir-dtc" >> $config_host_mak
+ echo "config-host.h: dtc/all" >> $config_host_mak
fi
if [ "$capstone" = "git" -o "$capstone" = "internal" ]; then
- echo "config-host.h: subdir-capstone" >> $config_host_mak
+ echo "config-host.h: capstone/all" >> $config_host_mak
fi
if test -n "$LIBCAPSTONE"; then
echo "LIBCAPSTONE=$LIBCAPSTONE" >> $config_host_mak
}
}
-void
-vug_init(VugDev *dev, int socket,
+bool
+vug_init(VugDev *dev, uint16_t max_queues, int socket,
vu_panic_cb panic, const VuDevIface *iface)
{
g_assert(dev);
g_assert(iface);
- vu_init(&dev->parent, socket, panic, set_watch, remove_watch, iface);
+ if (!vu_init(&dev->parent, max_queues, socket, panic, set_watch,
+ remove_watch, iface)) {
+ return false;
+ }
+
dev->fdmap = g_hash_table_new_full(NULL, NULL, NULL,
(GDestroyNotify) g_source_destroy);
dev->src = vug_source_new(dev, socket, G_IO_IN, vug_watch, NULL);
+
+ return true;
}
void
GSource *src;
} VugDev;
-void vug_init(VugDev *dev, int socket,
+bool vug_init(VugDev *dev, uint16_t max_queues, int socket,
vu_panic_cb panic, const VuDevIface *iface);
void vug_deinit(VugDev *dev);
}
}
+/* Set reply payload.u64 and clear request flags and fd_num */
+static void vmsg_set_reply_u64(VhostUserMsg *vmsg, uint64_t val)
+{
+ vmsg->flags = 0; /* defaults will be set by vu_send_reply() */
+ vmsg->size = sizeof(vmsg->payload.u64);
+ vmsg->payload.u64 = val;
+ vmsg->fd_num = 0;
+}
+
/* A test to see if we have userfault available */
static bool
have_userfault(void)
static void
vu_set_enable_all_rings(VuDev *dev, bool enabled)
{
- int i;
+ uint16_t i;
- for (i = 0; i < VHOST_MAX_NR_VIRTQUEUE; i++) {
+ for (i = 0; i < dev->max_queues; i++) {
dev->vq[i].enable = enabled;
}
}
{
int index = vmsg->payload.u64 & VHOST_USER_VRING_IDX_MASK;
- if (index >= VHOST_MAX_NR_VIRTQUEUE) {
+ if (index >= dev->max_queues) {
vmsg_close_fds(vmsg);
vu_panic(dev, "Invalid queue index: %u", index);
return false;
static bool
vu_get_protocol_features_exec(VuDev *dev, VhostUserMsg *vmsg)
{
- uint64_t features = 1ULL << VHOST_USER_PROTOCOL_F_LOG_SHMFD |
+ uint64_t features = 1ULL << VHOST_USER_PROTOCOL_F_MQ |
+ 1ULL << VHOST_USER_PROTOCOL_F_LOG_SHMFD |
1ULL << VHOST_USER_PROTOCOL_F_SLAVE_REQ |
1ULL << VHOST_USER_PROTOCOL_F_HOST_NOTIFIER |
1ULL << VHOST_USER_PROTOCOL_F_SLAVE_SEND_FD;
features |= dev->iface->get_protocol_features(dev);
}
- vmsg->payload.u64 = features;
- vmsg->size = sizeof(vmsg->payload.u64);
- vmsg->fd_num = 0;
-
+ vmsg_set_reply_u64(vmsg, features);
return true;
}
static bool
vu_get_queue_num_exec(VuDev *dev, VhostUserMsg *vmsg)
{
- DPRINT("Function %s() not implemented yet.\n", __func__);
- return false;
+ vmsg_set_reply_u64(vmsg, dev->max_queues);
+ return true;
}
static bool
DPRINT("State.index: %d\n", index);
DPRINT("State.enable: %d\n", enable);
- if (index >= VHOST_MAX_NR_VIRTQUEUE) {
+ if (index >= dev->max_queues) {
vu_panic(dev, "Invalid vring_enable index: %u", index);
return false;
}
static bool
vu_set_postcopy_listen(VuDev *dev, VhostUserMsg *vmsg)
{
- vmsg->payload.u64 = -1;
- vmsg->size = sizeof(vmsg->payload.u64);
-
if (dev->nregions) {
vu_panic(dev, "Regions already registered at postcopy-listen");
+ vmsg_set_reply_u64(vmsg, -1);
return true;
}
dev->postcopy_listening = true;
- vmsg->flags = VHOST_USER_VERSION | VHOST_USER_REPLY_MASK;
- vmsg->payload.u64 = 0; /* Success */
+ vmsg_set_reply_u64(vmsg, 0);
return true;
}
DPRINT("%s: Done close\n", __func__);
}
- vmsg->fd_num = 0;
- vmsg->payload.u64 = 0;
- vmsg->size = sizeof(vmsg->payload.u64);
- vmsg->flags = VHOST_USER_VERSION | VHOST_USER_REPLY_MASK;
+ vmsg_set_reply_u64(vmsg, 0);
DPRINT("%s: exit\n", __func__);
return true;
}
}
dev->nregions = 0;
- for (i = 0; i < VHOST_MAX_NR_VIRTQUEUE; i++) {
+ for (i = 0; i < dev->max_queues; i++) {
VuVirtq *vq = &dev->vq[i];
if (vq->call_fd != -1) {
if (dev->sock != -1) {
close(dev->sock);
}
+
+ free(dev->vq);
+ dev->vq = NULL;
}
-void
+bool
vu_init(VuDev *dev,
+ uint16_t max_queues,
int socket,
vu_panic_cb panic,
vu_set_watch_cb set_watch,
vu_remove_watch_cb remove_watch,
const VuDevIface *iface)
{
- int i;
+ uint16_t i;
+ assert(max_queues > 0);
assert(socket >= 0);
assert(set_watch);
assert(remove_watch);
dev->iface = iface;
dev->log_call_fd = -1;
dev->slave_fd = -1;
- for (i = 0; i < VHOST_MAX_NR_VIRTQUEUE; i++) {
+ dev->max_queues = max_queues;
+
+ dev->vq = malloc(max_queues * sizeof(dev->vq[0]));
+ if (!dev->vq) {
+ DPRINT("%s: failed to malloc virtqueues\n", __func__);
+ return false;
+ }
+
+ for (i = 0; i < max_queues; i++) {
dev->vq[i] = (VuVirtq) {
.call_fd = -1, .kick_fd = -1, .err_fd = -1,
.notification = true,
};
}
+
+ return true;
}
VuVirtq *
vu_get_queue(VuDev *dev, int qidx)
{
- assert(qidx < VHOST_MAX_NR_VIRTQUEUE);
+ assert(qidx < dev->max_queues);
return &dev->vq[qidx];
}
#define VHOST_USER_F_PROTOCOL_FEATURES 30
#define VHOST_LOG_PAGE 4096
-#define VHOST_MAX_NR_VIRTQUEUE 8
#define VIRTQUEUE_MAX_SIZE 1024
#define VHOST_MEMORY_MAX_NREGIONS 8
int sock;
uint32_t nregions;
VuDevRegion regions[VHOST_MEMORY_MAX_NREGIONS];
- VuVirtq vq[VHOST_MAX_NR_VIRTQUEUE];
+ VuVirtq *vq;
VuDevInflightInfo inflight_info;
int log_call_fd;
int slave_fd;
uint64_t features;
uint64_t protocol_features;
bool broken;
+ uint16_t max_queues;
/* @set_watch: add or update the given fd to the watch set,
* call cb when condition is met */
/**
* vu_init:
* @dev: a VuDev context
+ * @max_queues: maximum number of virtqueues
* @socket: the socket connected to vhost-user master
* @panic: a panic callback
* @set_watch: a set_watch callback
* @iface: a VuDevIface structure with vhost-user device callbacks
*
* Intializes a VuDev vhost-user context.
+ *
+ * Returns: true on success, false on failure.
**/
-void vu_init(VuDev *dev,
+bool vu_init(VuDev *dev,
+ uint16_t max_queues,
int socket,
vu_panic_cb panic,
vu_set_watch_cb set_watch,
#include <sys/ioctl.h>
#endif
+enum {
+ VHOST_USER_BLK_MAX_QUEUES = 8,
+};
+
struct virtio_blk_inhdr {
unsigned char status;
};
VuVirtq *vq;
int ret;
- if ((idx < 0) || (idx >= VHOST_MAX_NR_VIRTQUEUE)) {
- fprintf(stderr, "VQ Index out of range: %d\n", idx);
- vub_panic_cb(vu_dev, NULL);
- return;
- }
-
gdev = container_of(vu_dev, VugDev, parent);
vdev_blk = container_of(gdev, VubDev, parent);
assert(vdev_blk);
vdev_blk->enable_ro = true;
}
- vug_init(&vdev_blk->parent, csock, vub_panic_cb, &vub_iface);
+ if (!vug_init(&vdev_blk->parent, VHOST_USER_BLK_MAX_QUEUES, csock,
+ vub_panic_cb, &vub_iface)) {
+ fprintf(stderr, "Failed to initialized libvhost-user-glib\n");
+ goto err;
+ }
g_main_loop_run(vdev_blk->loop);
#include "virgl.h"
#include "vugbm.h"
+enum {
+ VHOST_USER_GPU_MAX_QUEUES = 2,
+};
+
struct virtio_gpu_simple_resource {
uint32_t resource_id;
uint32_t width;
exit(EXIT_FAILURE);
}
- vug_init(&g.dev, fd, vg_panic, &vuiface);
+ if (!vug_init(&g.dev, VHOST_USER_GPU_MAX_QUEUES, fd, vg_panic, &vuiface)) {
+ g_printerr("Failed to initialize libvhost-user-glib.\n");
+ exit(EXIT_FAILURE);
+ }
loop = g_main_loop_new(NULL, FALSE);
g_main_loop_run(loop);
#include "standard-headers/linux/virtio_input.h"
#include "qapi/error.h"
+enum {
+ VHOST_USER_INPUT_MAX_QUEUES = 2,
+};
+
typedef struct virtio_input_event virtio_input_event;
typedef struct virtio_input_config virtio_input_config;
g_printerr("Invalid vhost-user socket.\n");
exit(EXIT_FAILURE);
}
- vug_init(&vi.dev, fd, vi_panic, &vuiface);
+
+ if (!vug_init(&vi.dev, VHOST_USER_INPUT_MAX_QUEUES, fd, vi_panic,
+ &vuiface)) {
+ g_printerr("Failed to initialize libvhost-user-glib.\n");
+ exit(EXIT_FAILURE);
+ }
loop = g_main_loop_new(NULL, FALSE);
g_main_loop_run(loop);
#define VUS_ISCSI_INITIATOR "iqn.2016-11.com.nutanix:vhost-user-scsi"
+enum {
+ VHOST_USER_SCSI_MAX_QUEUES = 8,
+};
+
typedef struct VusIscsiLun {
struct iscsi_context *iscsi_ctx;
int iscsi_lun;
gdev = container_of(vu_dev, VugDev, parent);
vdev_scsi = container_of(gdev, VusDev, parent);
- if (idx < 0 || idx >= VHOST_MAX_NR_VIRTQUEUE) {
- g_warning("VQ Index out of range: %d", idx);
- vus_panic_cb(vu_dev, NULL);
- return;
- }
vq = vu_get_queue(vu_dev, idx);
if (!vq) {
assert(vu_dev);
- if (idx < 0 || idx >= VHOST_MAX_NR_VIRTQUEUE) {
- g_warning("VQ Index out of range: %d", idx);
- vus_panic_cb(vu_dev, NULL);
- return;
- }
-
vq = vu_get_queue(vu_dev, idx);
if (idx == 0 || idx == 1) {
goto err;
}
- vug_init(&vdev_scsi->parent, csock, vus_panic_cb, &vus_iface);
+ if (!vug_init(&vdev_scsi->parent, VHOST_USER_SCSI_MAX_QUEUES, csock,
+ vus_panic_cb, &vus_iface)) {
+ g_printerr("Failed to initialize libvhost-user-glib\n");
+ goto err;
+ }
g_main_loop_run(vdev_scsi->loop);
#include "qemu/osdep.h"
#include "qemu-common.h"
#include "qemu/config-file.h"
-#include "cpu.h"
#include "monitor/monitor.h"
#include "qapi/error.h"
#include "qapi/qapi-commands-misc.h"
#include "qapi/qmp/qerror.h"
#include "qemu/error-report.h"
#include "qemu/qemu-print.h"
-#include "sysemu/sysemu.h"
#include "sysemu/tcg.h"
#include "sysemu/block-backend.h"
#include "exec/gdbstub.h"
#include "tcg.h"
#include "hw/nmi.h"
#include "sysemu/replay.h"
-#include "hw/boards.h"
#ifdef CONFIG_LINUX
#endif
}
-CpuInfoList *qmp_query_cpus(Error **errp)
-{
- MachineState *ms = MACHINE(qdev_get_machine());
- MachineClass *mc = MACHINE_GET_CLASS(ms);
- CpuInfoList *head = NULL, *cur_item = NULL;
- CPUState *cpu;
-
- CPU_FOREACH(cpu) {
- CpuInfoList *info;
-#if defined(TARGET_I386)
- X86CPU *x86_cpu = X86_CPU(cpu);
- CPUX86State *env = &x86_cpu->env;
-#elif defined(TARGET_PPC)
- PowerPCCPU *ppc_cpu = POWERPC_CPU(cpu);
- CPUPPCState *env = &ppc_cpu->env;
-#elif defined(TARGET_SPARC)
- SPARCCPU *sparc_cpu = SPARC_CPU(cpu);
- CPUSPARCState *env = &sparc_cpu->env;
-#elif defined(TARGET_RISCV)
- RISCVCPU *riscv_cpu = RISCV_CPU(cpu);
- CPURISCVState *env = &riscv_cpu->env;
-#elif defined(TARGET_MIPS)
- MIPSCPU *mips_cpu = MIPS_CPU(cpu);
- CPUMIPSState *env = &mips_cpu->env;
-#elif defined(TARGET_TRICORE)
- TriCoreCPU *tricore_cpu = TRICORE_CPU(cpu);
- CPUTriCoreState *env = &tricore_cpu->env;
-#elif defined(TARGET_S390X)
- S390CPU *s390_cpu = S390_CPU(cpu);
- CPUS390XState *env = &s390_cpu->env;
-#endif
-
- cpu_synchronize_state(cpu);
-
- info = g_malloc0(sizeof(*info));
- info->value = g_malloc0(sizeof(*info->value));
- info->value->CPU = cpu->cpu_index;
- info->value->current = (cpu == first_cpu);
- info->value->halted = cpu->halted;
- info->value->qom_path = object_get_canonical_path(OBJECT(cpu));
- info->value->thread_id = cpu->thread_id;
-#if defined(TARGET_I386)
- info->value->arch = CPU_INFO_ARCH_X86;
- info->value->u.x86.pc = env->eip + env->segs[R_CS].base;
-#elif defined(TARGET_PPC)
- info->value->arch = CPU_INFO_ARCH_PPC;
- info->value->u.ppc.nip = env->nip;
-#elif defined(TARGET_SPARC)
- info->value->arch = CPU_INFO_ARCH_SPARC;
- info->value->u.q_sparc.pc = env->pc;
- info->value->u.q_sparc.npc = env->npc;
-#elif defined(TARGET_MIPS)
- info->value->arch = CPU_INFO_ARCH_MIPS;
- info->value->u.q_mips.PC = env->active_tc.PC;
-#elif defined(TARGET_TRICORE)
- info->value->arch = CPU_INFO_ARCH_TRICORE;
- info->value->u.tricore.PC = env->PC;
-#elif defined(TARGET_S390X)
- info->value->arch = CPU_INFO_ARCH_S390;
- info->value->u.s390.cpu_state = env->cpu_state;
-#elif defined(TARGET_RISCV)
- info->value->arch = CPU_INFO_ARCH_RISCV;
- info->value->u.riscv.pc = env->pc;
-#else
- info->value->arch = CPU_INFO_ARCH_OTHER;
-#endif
- info->value->has_props = !!mc->cpu_index_to_instance_props;
- if (info->value->has_props) {
- CpuInstanceProperties *props;
- props = g_malloc0(sizeof(*props));
- *props = mc->cpu_index_to_instance_props(ms, cpu->cpu_index);
- info->value->props = props;
- }
-
- /* XXX: waiting for the qapi to support GSList */
- if (!cur_item) {
- head = cur_item = info;
- } else {
- cur_item->next = info;
- cur_item = info;
- }
- }
-
- return head;
-}
-
-static CpuInfoArch sysemu_target_to_cpuinfo_arch(SysEmuTarget target)
-{
- /*
- * The @SysEmuTarget -> @CpuInfoArch mapping below is based on the
- * TARGET_ARCH -> TARGET_BASE_ARCH mapping in the "configure" script.
- */
- switch (target) {
- case SYS_EMU_TARGET_I386:
- case SYS_EMU_TARGET_X86_64:
- return CPU_INFO_ARCH_X86;
-
- case SYS_EMU_TARGET_PPC:
- case SYS_EMU_TARGET_PPC64:
- return CPU_INFO_ARCH_PPC;
-
- case SYS_EMU_TARGET_SPARC:
- case SYS_EMU_TARGET_SPARC64:
- return CPU_INFO_ARCH_SPARC;
-
- case SYS_EMU_TARGET_MIPS:
- case SYS_EMU_TARGET_MIPSEL:
- case SYS_EMU_TARGET_MIPS64:
- case SYS_EMU_TARGET_MIPS64EL:
- return CPU_INFO_ARCH_MIPS;
-
- case SYS_EMU_TARGET_TRICORE:
- return CPU_INFO_ARCH_TRICORE;
-
- case SYS_EMU_TARGET_S390X:
- return CPU_INFO_ARCH_S390;
-
- case SYS_EMU_TARGET_RISCV32:
- case SYS_EMU_TARGET_RISCV64:
- return CPU_INFO_ARCH_RISCV;
-
- default:
- return CPU_INFO_ARCH_OTHER;
- }
-}
-
-static void cpustate_to_cpuinfo_s390(CpuInfoS390 *info, const CPUState *cpu)
-{
-#ifdef TARGET_S390X
- S390CPU *s390_cpu = S390_CPU(cpu);
- CPUS390XState *env = &s390_cpu->env;
-
- info->cpu_state = env->cpu_state;
-#else
- abort();
-#endif
-}
-
-/*
- * fast means: we NEVER interrupt vCPU threads to retrieve
- * information from KVM.
- */
-CpuInfoFastList *qmp_query_cpus_fast(Error **errp)
-{
- MachineState *ms = MACHINE(qdev_get_machine());
- MachineClass *mc = MACHINE_GET_CLASS(ms);
- CpuInfoFastList *head = NULL, *cur_item = NULL;
- SysEmuTarget target = qapi_enum_parse(&SysEmuTarget_lookup, TARGET_NAME,
- -1, &error_abort);
- CPUState *cpu;
-
- CPU_FOREACH(cpu) {
- CpuInfoFastList *info = g_malloc0(sizeof(*info));
- info->value = g_malloc0(sizeof(*info->value));
-
- info->value->cpu_index = cpu->cpu_index;
- info->value->qom_path = object_get_canonical_path(OBJECT(cpu));
- info->value->thread_id = cpu->thread_id;
-
- info->value->has_props = !!mc->cpu_index_to_instance_props;
- if (info->value->has_props) {
- CpuInstanceProperties *props;
- props = g_malloc0(sizeof(*props));
- *props = mc->cpu_index_to_instance_props(ms, cpu->cpu_index);
- info->value->props = props;
- }
-
- info->value->arch = sysemu_target_to_cpuinfo_arch(target);
- info->value->target = target;
- if (target == SYS_EMU_TARGET_S390X) {
- cpustate_to_cpuinfo_s390(&info->value->u.s390x, cpu);
- }
-
- if (!cur_item) {
- head = cur_item = info;
- } else {
- cur_item->next = info;
- cur_item = info;
- }
- }
-
- return head;
-}
-
void qmp_memsave(int64_t addr, int64_t size, const char *filename,
bool has_cpu, int64_t cpu_index, Error **errp)
{
CONFIG_XLNX_ZYNQMP_ARM=y
CONFIG_XLNX_VERSAL=y
+CONFIG_SBSA_REF=y
# Common mips*-softmmu CONFIG defines
+# CONFIG_SEMIHOSTING is always required on this architecture
+CONFIG_SEMIHOSTING=y
+
CONFIG_ISA_BUS=y
CONFIG_PCI=y
CONFIG_PCI_DEVICES=y
-CONFIG_ESP=y
CONFIG_VGA_ISA=y
CONFIG_VGA_ISA_MM=y
CONFIG_VGA_CIRRUS=y
CONFIG_PIIX4=y
CONFIG_IDE_ISA=y
CONFIG_IDE_PIIX=y
-CONFIG_NE2000_ISA=y
-CONFIG_MIPSNET=y
CONFIG_PFLASH_CFI01=y
CONFIG_I8259=y
CONFIG_MC146818RTC=y
CONFIG_MIPS_ITU=y
CONFIG_R4K=y
CONFIG_MALTA=y
-CONFIG_SEMIHOSTING=y
CONFIG_PCNET_PCI=y
CONFIG_MIPSSIM=y
CONFIG_ACPI_SMBUS=y
# Default configuration for mips64-softmmu
include mips-softmmu-common.mak
-CONFIG_RC4030=y
-CONFIG_DP8393X=y
-CONFIG_DS1225Y=y
CONFIG_JAZZ=y
-CONFIG_G364FB=y
-CONFIG_JAZZ_LED=y
include mips-softmmu-common.mak
CONFIG_IDE_VIA=y
-CONFIG_RC4030=y
-CONFIG_DP8393X=y
-CONFIG_DS1225Y=y
CONFIG_FULONG=y
CONFIG_ATI_VGA=y
CONFIG_RTL8139_PCI=y
CONFIG_JAZZ=y
-CONFIG_G364FB=y
-CONFIG_JAZZ_LED=y
CONFIG_VT82C686=y
CONFIG_AHCI=y
CONFIG_MIPS_BOSTON=y
const rvc_constraint *constraints;
} rv_comp_data;
+enum {
+ rvcd_imm_nz = 0x1
+};
+
typedef struct {
const char * const name;
const rv_codec codec;
const char * const format;
const rv_comp_data *pseudo;
- const int decomp_rv32;
- const int decomp_rv64;
- const int decomp_rv128;
+ const short decomp_rv32;
+ const short decomp_rv64;
+ const short decomp_rv128;
+ const short decomp_data;
} rv_opcode_data;
/* register names */
static const rvc_constraint rvcc_rdinstret[] = { rvc_rs1_eq_x0, rvc_csr_eq_0xc02, rvc_end };
static const rvc_constraint rvcc_rdcycleh[] = { rvc_rs1_eq_x0, rvc_csr_eq_0xc80, rvc_end };
static const rvc_constraint rvcc_rdtimeh[] = { rvc_rs1_eq_x0, rvc_csr_eq_0xc81, rvc_end };
-static const rvc_constraint rvcc_rdinstreth[] = { rvc_rs1_eq_x0, rvc_csr_eq_0xc80, rvc_end };
+static const rvc_constraint rvcc_rdinstreth[] = { rvc_rs1_eq_x0,
+ rvc_csr_eq_0xc82, rvc_end };
static const rvc_constraint rvcc_frcsr[] = { rvc_rs1_eq_x0, rvc_csr_eq_0x003, rvc_end };
static const rvc_constraint rvcc_frrm[] = { rvc_rs1_eq_x0, rvc_csr_eq_0x002, rvc_end };
static const rvc_constraint rvcc_frflags[] = { rvc_rs1_eq_x0, rvc_csr_eq_0x001, rvc_end };
{ "fcvt.q.lu", rv_codec_r_m, rv_fmt_rm_frd_rs1, NULL, 0, 0, 0 },
{ "fmv.x.q", rv_codec_r, rv_fmt_rd_frs1, NULL, 0, 0, 0 },
{ "fmv.q.x", rv_codec_r, rv_fmt_frd_rs1, NULL, 0, 0, 0 },
- { "c.addi4spn", rv_codec_ciw_4spn, rv_fmt_rd_rs1_imm, NULL, rv_op_addi, rv_op_addi, rv_op_addi },
+ { "c.addi4spn", rv_codec_ciw_4spn, rv_fmt_rd_rs1_imm, NULL, rv_op_addi,
+ rv_op_addi, rv_op_addi, rvcd_imm_nz },
{ "c.fld", rv_codec_cl_ld, rv_fmt_frd_offset_rs1, NULL, rv_op_fld, rv_op_fld, 0 },
{ "c.lw", rv_codec_cl_lw, rv_fmt_rd_offset_rs1, NULL, rv_op_lw, rv_op_lw, rv_op_lw },
{ "c.flw", rv_codec_cl_lw, rv_fmt_frd_offset_rs1, NULL, rv_op_flw, 0, 0 },
{ "c.sw", rv_codec_cs_sw, rv_fmt_rs2_offset_rs1, NULL, rv_op_sw, rv_op_sw, rv_op_sw },
{ "c.fsw", rv_codec_cs_sw, rv_fmt_frs2_offset_rs1, NULL, rv_op_fsw, 0, 0 },
{ "c.nop", rv_codec_ci_none, rv_fmt_none, NULL, rv_op_addi, rv_op_addi, rv_op_addi },
- { "c.addi", rv_codec_ci, rv_fmt_rd_rs1_imm, NULL, rv_op_addi, rv_op_addi, rv_op_addi },
+ { "c.addi", rv_codec_ci, rv_fmt_rd_rs1_imm, NULL, rv_op_addi, rv_op_addi,
+ rv_op_addi, rvcd_imm_nz },
{ "c.jal", rv_codec_cj_jal, rv_fmt_rd_offset, NULL, rv_op_jal, 0, 0 },
{ "c.li", rv_codec_ci_li, rv_fmt_rd_rs1_imm, NULL, rv_op_addi, rv_op_addi, rv_op_addi },
- { "c.addi16sp", rv_codec_ci_16sp, rv_fmt_rd_rs1_imm, NULL, rv_op_addi, rv_op_addi, rv_op_addi },
- { "c.lui", rv_codec_ci_lui, rv_fmt_rd_imm, NULL, rv_op_lui, rv_op_lui, rv_op_lui },
- { "c.srli", rv_codec_cb_sh6, rv_fmt_rd_rs1_imm, NULL, rv_op_srli, rv_op_srli, rv_op_srli },
- { "c.srai", rv_codec_cb_sh6, rv_fmt_rd_rs1_imm, NULL, rv_op_srai, rv_op_srai, rv_op_srai },
- { "c.andi", rv_codec_cb_imm, rv_fmt_rd_rs1_imm, NULL, rv_op_andi, rv_op_andi, rv_op_andi },
+ { "c.addi16sp", rv_codec_ci_16sp, rv_fmt_rd_rs1_imm, NULL, rv_op_addi,
+ rv_op_addi, rv_op_addi, rvcd_imm_nz },
+ { "c.lui", rv_codec_ci_lui, rv_fmt_rd_imm, NULL, rv_op_lui, rv_op_lui,
+ rv_op_lui, rvcd_imm_nz },
+ { "c.srli", rv_codec_cb_sh6, rv_fmt_rd_rs1_imm, NULL, rv_op_srli,
+ rv_op_srli, rv_op_srli, rvcd_imm_nz },
+ { "c.srai", rv_codec_cb_sh6, rv_fmt_rd_rs1_imm, NULL, rv_op_srai,
+ rv_op_srai, rv_op_srai, rvcd_imm_nz },
+ { "c.andi", rv_codec_cb_imm, rv_fmt_rd_rs1_imm, NULL, rv_op_andi,
+ rv_op_andi, rv_op_andi },
{ "c.sub", rv_codec_cs, rv_fmt_rd_rs1_rs2, NULL, rv_op_sub, rv_op_sub, rv_op_sub },
{ "c.xor", rv_codec_cs, rv_fmt_rd_rs1_rs2, NULL, rv_op_xor, rv_op_xor, rv_op_xor },
{ "c.or", rv_codec_cs, rv_fmt_rd_rs1_rs2, NULL, rv_op_or, rv_op_or, rv_op_or },
{ "c.j", rv_codec_cj, rv_fmt_rd_offset, NULL, rv_op_jal, rv_op_jal, rv_op_jal },
{ "c.beqz", rv_codec_cb, rv_fmt_rs1_rs2_offset, NULL, rv_op_beq, rv_op_beq, rv_op_beq },
{ "c.bnez", rv_codec_cb, rv_fmt_rs1_rs2_offset, NULL, rv_op_bne, rv_op_bne, rv_op_bne },
- { "c.slli", rv_codec_ci_sh6, rv_fmt_rd_rs1_imm, NULL, rv_op_slli, rv_op_slli, rv_op_slli },
+ { "c.slli", rv_codec_ci_sh6, rv_fmt_rd_rs1_imm, NULL, rv_op_slli,
+ rv_op_slli, rv_op_slli, rvcd_imm_nz },
{ "c.fldsp", rv_codec_ci_ldsp, rv_fmt_frd_offset_rs1, NULL, rv_op_fld, rv_op_fld, rv_op_fld },
{ "c.lwsp", rv_codec_ci_lwsp, rv_fmt_rd_offset_rs1, NULL, rv_op_lw, rv_op_lw, rv_op_lw },
{ "c.flwsp", rv_codec_ci_lwsp, rv_fmt_frd_offset_rs1, NULL, rv_op_flw, 0, 0 },
{
int decomp_op = opcode_data[dec->op].decomp_rv32;
if (decomp_op != rv_op_illegal) {
- dec->op = decomp_op;
- dec->codec = opcode_data[decomp_op].codec;
+ if ((opcode_data[dec->op].decomp_data & rvcd_imm_nz)
+ && dec->imm == 0) {
+ dec->op = rv_op_illegal;
+ } else {
+ dec->op = decomp_op;
+ dec->codec = opcode_data[decomp_op].codec;
+ }
}
}
{
int decomp_op = opcode_data[dec->op].decomp_rv64;
if (decomp_op != rv_op_illegal) {
- dec->op = decomp_op;
- dec->codec = opcode_data[decomp_op].codec;
+ if ((opcode_data[dec->op].decomp_data & rvcd_imm_nz)
+ && dec->imm == 0) {
+ dec->op = rv_op_illegal;
+ } else {
+ dec->op = decomp_op;
+ dec->codec = opcode_data[decomp_op].codec;
+ }
}
}
{
int decomp_op = opcode_data[dec->op].decomp_rv128;
if (decomp_op != rv_op_illegal) {
- dec->op = decomp_op;
- dec->codec = opcode_data[decomp_op].codec;
+ if ((opcode_data[dec->op].decomp_data & rvcd_imm_nz)
+ && dec->imm == 0) {
+ dec->op = rv_op_illegal;
+ } else {
+ dec->op = decomp_op;
+ dec->codec = opcode_data[decomp_op].codec;
+ }
}
}
This test suite contains scripts that bootstrap various guest images that have
necessary packages to build QEMU. The basic usage is documented in ``Makefile``
-help which is displayed with ``make vm-test``.
+help which is displayed with ``make vm-help``.
Quickstart
----------
-Run ``make vm-test`` to list available make targets. Invoke a specific make
+Run ``make vm-help`` to list available make targets. Invoke a specific make
command to run build test in an image. For example, ``make vm-build-freebsd``
will build the source tree in the FreeBSD image. The command can be executed
from either the source tree or the build dir; if the former, ``./configure`` is
Multiple queue support
----------------------
-Multiple queue is treated as a protocol extension, hence the slave has
-to implement protocol features first. The multiple queues feature is
-supported only when the protocol feature ``VHOST_USER_PROTOCOL_F_MQ``
-(bit 0) is set.
+Multiple queue support allows the slave to advertise the maximum number of
+queues. This is treated as a protocol extension, hence the slave has to
+implement protocol features first. The multiple queues feature is supported
+only when the protocol feature ``VHOST_USER_PROTOCOL_F_MQ`` (bit 0) is set.
-The max number of queue pairs the slave supports can be queried with
-message ``VHOST_USER_GET_QUEUE_NUM``. Master should stop when the
-number of requested queues is bigger than that.
+The max number of queues the slave supports can be queried with message
+``VHOST_USER_GET_QUEUE_NUM``. Master should stop when the number of requested
+queues is bigger than that.
As all queues share one connection, the master uses a unique index for each
-queue in the sent message to identify a specified queue. One queue pair
-is enabled initially. More queues are enabled dynamically, by sending
-message ``VHOST_USER_SET_VRING_ENABLE``.
+queue in the sent message to identify a specified queue.
+
+The master enables queues by sending message ``VHOST_USER_SET_VRING_ENABLE``.
+vhost-user-net has historically automatically enabled the first queue pair.
Migration
---------
---------------
QEMU advertises the supported interrupt modes in the device tree
-property "ibm,arch-vec-5-platform-support" in byte 23 and the OS
-Selection for XIVE is indicated in the "ibm,architecture-vec-5"
+property ``ibm,arch-vec-5-platform-support`` in byte 23 and the OS
+Selection for XIVE is indicated in the ``ibm,architecture-vec-5``
property byte 23.
The interrupt modes supported by the machine depend on the CPU type
(POWER9 is required for XIVE) but also on the machine property
``ic-mode`` which can be set on the command line. It can take the
-following values: ``xics``, ``xive``, ``dual`` and currently ``xics``
-is the default but it may change in the future.
+following values: ``xics``, ``xive``, and ``dual`` which is the
+default mode. ``dual`` means that both modes XICS **and** XIVE are
+supported and if the guest OS supports XIVE, this mode will be
+selected.
The choosen interrupt mode is activated after a reconfiguration done
in a machine reset.
+KVM negotiation
+---------------
+
+When the guest starts under KVM, the capabilities of the host kernel
+and QEMU are also negotiated. Depending on the version of the host
+kernel, KVM will advertise the XIVE capability to QEMU or not.
+
+Nevertheless, the available interrupt modes in the machine should not
+depend on the XIVE KVM capability of the host. On older kernels
+without XIVE KVM support, QEMU will use the emulated XIVE device as a
+fallback and on newer kernels (>=5.2), the KVM XIVE device.
+
+As a final refinement, the user can also switch the use of the KVM
+device with the machine option ``kernel_irqchip``.
+
+
+XIVE support in KVM
+~~~~~~~~~~~~~~~~~~~
+
+For guest OSes supporting XIVE, the resulting interrupt modes on host
+kernels with XIVE KVM support are the following:
+
+============== ============= ============= ================
+ic-mode kernel_irqchip
+-------------- ----------------------------------------------
+/ allowed off on
+ (default)
+============== ============= ============= ================
+dual (default) XIVE KVM XIVE emul. XIVE KVM
+xive XIVE KVM XIVE emul. XIVE KVM
+xics XICS KVM XICS emul. XICS KVM
+============== ============= ============= ================
+
+For legacy guest OSes without XIVE support, the resulting interrupt
+modes are the following:
+
+============== ============= ============= ================
+ic-mode kernel_irqchip
+-------------- ----------------------------------------------
+/ allowed off on
+ (default)
+============== ============= ============= ================
+dual (default) XICS KVM XICS emul. XICS KVM
+xive QEMU error(3) QEMU error(3) QEMU error(3)
+xics XICS KVM XICS emul. XICS KVM
+============== ============= ============= ================
+
+(3) QEMU fails at CAS with ``Guest requested unavailable interrupt
+ mode (XICS), either don't set the ic-mode machine property or try
+ ic-mode=xics or ic-mode=dual``
+
+
+No XIVE support in KVM
+~~~~~~~~~~~~~~~~~~~~~~
+
+For guest OSes supporting XIVE, the resulting interrupt modes on host
+kernels without XIVE KVM support are the following:
+
+============== ============= ============= ================
+ic-mode kernel_irqchip
+-------------- ----------------------------------------------
+/ allowed off on
+ (default)
+============== ============= ============= ================
+dual (default) XIVE emul.(1) XIVE emul. QEMU error (2)
+xive XIVE emul.(1) XIVE emul. QEMU error (2)
+xics XICS KVM XICS emul. XICS KVM
+============== ============= ============= ================
+
+
+(1) QEMU warns with ``warning: kernel_irqchip requested but unavailable:
+ IRQ_XIVE capability must be present for KVM``
+(2) QEMU fails with ``kernel_irqchip requested but unavailable:
+ IRQ_XIVE capability must be present for KVM``
+
+
+For legacy guest OSes without XIVE support, the resulting interrupt
+modes are the following:
+
+============== ============= ============= ================
+ic-mode kernel_irqchip
+-------------- ----------------------------------------------
+/ allowed off on
+ (default)
+============== ============= ============= ================
+dual (default) QEMU error(4) XICS emul. QEMU error(4)
+xive QEMU error(3) QEMU error(3) QEMU error(3)
+xics XICS KVM XICS emul. XICS KVM
+============== ============= ============= ================
+
+(3) QEMU fails at CAS with ``Guest requested unavailable interrupt
+ mode (XICS), either don't set the ic-mode machine property or try
+ ic-mode=xics or ic-mode=dual``
+(4) QEMU/KVM incompatibility due to device destruction in reset. QEMU fails
+ with ``KVM is too old to support ic-mode=dual,kernel-irqchip=on``
+
+
XIVE Device tree properties
---------------------------
- ``0x0000 .. 0x0FFF`` 4K CPU IPIs (only used under XIVE)
- ``0x1000 .. 0x1000`` 1 EPOW
- ``0x1001 .. 0x1001`` 1 HOTPLUG
+- ``0x1002 .. 0x10FF`` unused
- ``0x1100 .. 0x11FF`` 256 VIO devices
-- ``0x1200 .. 0x127F`` 32 PHBs devices
+- ``0x1200 .. 0x127F`` 32x4 LSIs for PHB devices
- ``0x1280 .. 0x12FF`` unused
-- ``0x1300 .. 0x1FFF`` PHB MSIs
+- ``0x1300 .. 0x1FFF`` PHB MSIs (dynamically allocated)
Monitoring XIVE
---------------
processing layer of external interrupts:
- Interrupt Virtualization Source Engine (IVSE), or Source Controller
- (SC). These are found in PCI PHBs, in the PSI host bridge
- controller, but also inside the main controller for the core IPIs
- and other sub-chips (NX, CAP, NPU) of the chip/processor. They are
- configured to feed the IVRE with events.
+ (SC). These are found in PCI PHBs, in the Processor Service
+ Interface (PSI) host bridge Controller, but also inside the main
+ controller for the core IPIs and other sub-chips (NX, CAP, NPU) of
+ the chip/processor. They are configured to feed the IVRE with
+ events.
- Interrupt Virtualization Routing Engine (IVRE) or Virtualization
Controller (VC). It handles event coalescing and perform interrupt
routing by matching an event source number with an Event
+++ /dev/null
-/*
- * QEMU dump
- *
- * Copyright Fujitsu, Corp. 2011, 2012
- *
- * Authors:
- * Wen Congyang <wency@cn.fujitsu.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.
- *
- */
-
-#include "qemu/osdep.h"
-#include "qemu-common.h"
-#include "qemu/cutils.h"
-#include "elf.h"
-#include "cpu.h"
-#include "exec/hwaddr.h"
-#include "monitor/monitor.h"
-#include "sysemu/kvm.h"
-#include "sysemu/dump.h"
-#include "sysemu/sysemu.h"
-#include "sysemu/memory_mapping.h"
-#include "sysemu/cpus.h"
-#include "qapi/error.h"
-#include "qapi/qapi-commands-misc.h"
-#include "qapi/qapi-events-misc.h"
-#include "qapi/qmp/qerror.h"
-#include "qemu/error-report.h"
-#include "hw/misc/vmcoreinfo.h"
-
-#ifdef TARGET_X86_64
-#include "win_dump.h"
-#endif
-
-#include <zlib.h>
-#ifdef CONFIG_LZO
-#include <lzo/lzo1x.h>
-#endif
-#ifdef CONFIG_SNAPPY
-#include <snappy-c.h>
-#endif
-#ifndef ELF_MACHINE_UNAME
-#define ELF_MACHINE_UNAME "Unknown"
-#endif
-
-#define MAX_GUEST_NOTE_SIZE (1 << 20) /* 1MB should be enough */
-
-#define ELF_NOTE_SIZE(hdr_size, name_size, desc_size) \
- ((DIV_ROUND_UP((hdr_size), 4) + \
- DIV_ROUND_UP((name_size), 4) + \
- DIV_ROUND_UP((desc_size), 4)) * 4)
-
-uint16_t cpu_to_dump16(DumpState *s, uint16_t val)
-{
- if (s->dump_info.d_endian == ELFDATA2LSB) {
- val = cpu_to_le16(val);
- } else {
- val = cpu_to_be16(val);
- }
-
- return val;
-}
-
-uint32_t cpu_to_dump32(DumpState *s, uint32_t val)
-{
- if (s->dump_info.d_endian == ELFDATA2LSB) {
- val = cpu_to_le32(val);
- } else {
- val = cpu_to_be32(val);
- }
-
- return val;
-}
-
-uint64_t cpu_to_dump64(DumpState *s, uint64_t val)
-{
- if (s->dump_info.d_endian == ELFDATA2LSB) {
- val = cpu_to_le64(val);
- } else {
- val = cpu_to_be64(val);
- }
-
- return val;
-}
-
-static int dump_cleanup(DumpState *s)
-{
- guest_phys_blocks_free(&s->guest_phys_blocks);
- memory_mapping_list_free(&s->list);
- close(s->fd);
- g_free(s->guest_note);
- s->guest_note = NULL;
- if (s->resume) {
- if (s->detached) {
- qemu_mutex_lock_iothread();
- }
- vm_start();
- if (s->detached) {
- qemu_mutex_unlock_iothread();
- }
- }
-
- return 0;
-}
-
-static int fd_write_vmcore(const void *buf, size_t size, void *opaque)
-{
- DumpState *s = opaque;
- size_t written_size;
-
- written_size = qemu_write_full(s->fd, buf, size);
- if (written_size != size) {
- return -errno;
- }
-
- return 0;
-}
-
-static void write_elf64_header(DumpState *s, Error **errp)
-{
- Elf64_Ehdr elf_header;
- int ret;
-
- memset(&elf_header, 0, sizeof(Elf64_Ehdr));
- memcpy(&elf_header, ELFMAG, SELFMAG);
- elf_header.e_ident[EI_CLASS] = ELFCLASS64;
- elf_header.e_ident[EI_DATA] = s->dump_info.d_endian;
- elf_header.e_ident[EI_VERSION] = EV_CURRENT;
- elf_header.e_type = cpu_to_dump16(s, ET_CORE);
- elf_header.e_machine = cpu_to_dump16(s, s->dump_info.d_machine);
- elf_header.e_version = cpu_to_dump32(s, EV_CURRENT);
- elf_header.e_ehsize = cpu_to_dump16(s, sizeof(elf_header));
- elf_header.e_phoff = cpu_to_dump64(s, sizeof(Elf64_Ehdr));
- elf_header.e_phentsize = cpu_to_dump16(s, sizeof(Elf64_Phdr));
- elf_header.e_phnum = cpu_to_dump16(s, s->phdr_num);
- if (s->have_section) {
- uint64_t shoff = sizeof(Elf64_Ehdr) + sizeof(Elf64_Phdr) * s->sh_info;
-
- elf_header.e_shoff = cpu_to_dump64(s, shoff);
- elf_header.e_shentsize = cpu_to_dump16(s, sizeof(Elf64_Shdr));
- elf_header.e_shnum = cpu_to_dump16(s, 1);
- }
-
- ret = fd_write_vmcore(&elf_header, sizeof(elf_header), s);
- if (ret < 0) {
- error_setg_errno(errp, -ret, "dump: failed to write elf header");
- }
-}
-
-static void write_elf32_header(DumpState *s, Error **errp)
-{
- Elf32_Ehdr elf_header;
- int ret;
-
- memset(&elf_header, 0, sizeof(Elf32_Ehdr));
- memcpy(&elf_header, ELFMAG, SELFMAG);
- elf_header.e_ident[EI_CLASS] = ELFCLASS32;
- elf_header.e_ident[EI_DATA] = s->dump_info.d_endian;
- elf_header.e_ident[EI_VERSION] = EV_CURRENT;
- elf_header.e_type = cpu_to_dump16(s, ET_CORE);
- elf_header.e_machine = cpu_to_dump16(s, s->dump_info.d_machine);
- elf_header.e_version = cpu_to_dump32(s, EV_CURRENT);
- elf_header.e_ehsize = cpu_to_dump16(s, sizeof(elf_header));
- elf_header.e_phoff = cpu_to_dump32(s, sizeof(Elf32_Ehdr));
- elf_header.e_phentsize = cpu_to_dump16(s, sizeof(Elf32_Phdr));
- elf_header.e_phnum = cpu_to_dump16(s, s->phdr_num);
- if (s->have_section) {
- uint32_t shoff = sizeof(Elf32_Ehdr) + sizeof(Elf32_Phdr) * s->sh_info;
-
- elf_header.e_shoff = cpu_to_dump32(s, shoff);
- elf_header.e_shentsize = cpu_to_dump16(s, sizeof(Elf32_Shdr));
- elf_header.e_shnum = cpu_to_dump16(s, 1);
- }
-
- ret = fd_write_vmcore(&elf_header, sizeof(elf_header), s);
- if (ret < 0) {
- error_setg_errno(errp, -ret, "dump: failed to write elf header");
- }
-}
-
-static void write_elf64_load(DumpState *s, MemoryMapping *memory_mapping,
- int phdr_index, hwaddr offset,
- hwaddr filesz, Error **errp)
-{
- Elf64_Phdr phdr;
- int ret;
-
- memset(&phdr, 0, sizeof(Elf64_Phdr));
- phdr.p_type = cpu_to_dump32(s, PT_LOAD);
- phdr.p_offset = cpu_to_dump64(s, offset);
- phdr.p_paddr = cpu_to_dump64(s, memory_mapping->phys_addr);
- phdr.p_filesz = cpu_to_dump64(s, filesz);
- phdr.p_memsz = cpu_to_dump64(s, memory_mapping->length);
- phdr.p_vaddr = cpu_to_dump64(s, memory_mapping->virt_addr) ?: phdr.p_paddr;
-
- assert(memory_mapping->length >= filesz);
-
- ret = fd_write_vmcore(&phdr, sizeof(Elf64_Phdr), s);
- if (ret < 0) {
- error_setg_errno(errp, -ret,
- "dump: failed to write program header table");
- }
-}
-
-static void write_elf32_load(DumpState *s, MemoryMapping *memory_mapping,
- int phdr_index, hwaddr offset,
- hwaddr filesz, Error **errp)
-{
- Elf32_Phdr phdr;
- int ret;
-
- memset(&phdr, 0, sizeof(Elf32_Phdr));
- phdr.p_type = cpu_to_dump32(s, PT_LOAD);
- phdr.p_offset = cpu_to_dump32(s, offset);
- phdr.p_paddr = cpu_to_dump32(s, memory_mapping->phys_addr);
- phdr.p_filesz = cpu_to_dump32(s, filesz);
- phdr.p_memsz = cpu_to_dump32(s, memory_mapping->length);
- phdr.p_vaddr =
- cpu_to_dump32(s, memory_mapping->virt_addr) ?: phdr.p_paddr;
-
- assert(memory_mapping->length >= filesz);
-
- ret = fd_write_vmcore(&phdr, sizeof(Elf32_Phdr), s);
- if (ret < 0) {
- error_setg_errno(errp, -ret,
- "dump: failed to write program header table");
- }
-}
-
-static void write_elf64_note(DumpState *s, Error **errp)
-{
- Elf64_Phdr phdr;
- hwaddr begin = s->memory_offset - s->note_size;
- int ret;
-
- memset(&phdr, 0, sizeof(Elf64_Phdr));
- phdr.p_type = cpu_to_dump32(s, PT_NOTE);
- phdr.p_offset = cpu_to_dump64(s, begin);
- phdr.p_paddr = 0;
- phdr.p_filesz = cpu_to_dump64(s, s->note_size);
- phdr.p_memsz = cpu_to_dump64(s, s->note_size);
- phdr.p_vaddr = 0;
-
- ret = fd_write_vmcore(&phdr, sizeof(Elf64_Phdr), s);
- if (ret < 0) {
- error_setg_errno(errp, -ret,
- "dump: failed to write program header table");
- }
-}
-
-static inline int cpu_index(CPUState *cpu)
-{
- return cpu->cpu_index + 1;
-}
-
-static void write_guest_note(WriteCoreDumpFunction f, DumpState *s,
- Error **errp)
-{
- int ret;
-
- if (s->guest_note) {
- ret = f(s->guest_note, s->guest_note_size, s);
- if (ret < 0) {
- error_setg(errp, "dump: failed to write guest note");
- }
- }
-}
-
-static void write_elf64_notes(WriteCoreDumpFunction f, DumpState *s,
- Error **errp)
-{
- CPUState *cpu;
- int ret;
- int id;
-
- CPU_FOREACH(cpu) {
- id = cpu_index(cpu);
- ret = cpu_write_elf64_note(f, cpu, id, s);
- if (ret < 0) {
- error_setg(errp, "dump: failed to write elf notes");
- return;
- }
- }
-
- CPU_FOREACH(cpu) {
- ret = cpu_write_elf64_qemunote(f, cpu, s);
- if (ret < 0) {
- error_setg(errp, "dump: failed to write CPU status");
- return;
- }
- }
-
- write_guest_note(f, s, errp);
-}
-
-static void write_elf32_note(DumpState *s, Error **errp)
-{
- hwaddr begin = s->memory_offset - s->note_size;
- Elf32_Phdr phdr;
- int ret;
-
- memset(&phdr, 0, sizeof(Elf32_Phdr));
- phdr.p_type = cpu_to_dump32(s, PT_NOTE);
- phdr.p_offset = cpu_to_dump32(s, begin);
- phdr.p_paddr = 0;
- phdr.p_filesz = cpu_to_dump32(s, s->note_size);
- phdr.p_memsz = cpu_to_dump32(s, s->note_size);
- phdr.p_vaddr = 0;
-
- ret = fd_write_vmcore(&phdr, sizeof(Elf32_Phdr), s);
- if (ret < 0) {
- error_setg_errno(errp, -ret,
- "dump: failed to write program header table");
- }
-}
-
-static void write_elf32_notes(WriteCoreDumpFunction f, DumpState *s,
- Error **errp)
-{
- CPUState *cpu;
- int ret;
- int id;
-
- CPU_FOREACH(cpu) {
- id = cpu_index(cpu);
- ret = cpu_write_elf32_note(f, cpu, id, s);
- if (ret < 0) {
- error_setg(errp, "dump: failed to write elf notes");
- return;
- }
- }
-
- CPU_FOREACH(cpu) {
- ret = cpu_write_elf32_qemunote(f, cpu, s);
- if (ret < 0) {
- error_setg(errp, "dump: failed to write CPU status");
- return;
- }
- }
-
- write_guest_note(f, s, errp);
-}
-
-static void write_elf_section(DumpState *s, int type, Error **errp)
-{
- Elf32_Shdr shdr32;
- Elf64_Shdr shdr64;
- int shdr_size;
- void *shdr;
- int ret;
-
- if (type == 0) {
- shdr_size = sizeof(Elf32_Shdr);
- memset(&shdr32, 0, shdr_size);
- shdr32.sh_info = cpu_to_dump32(s, s->sh_info);
- shdr = &shdr32;
- } else {
- shdr_size = sizeof(Elf64_Shdr);
- memset(&shdr64, 0, shdr_size);
- shdr64.sh_info = cpu_to_dump32(s, s->sh_info);
- shdr = &shdr64;
- }
-
- ret = fd_write_vmcore(&shdr, shdr_size, s);
- if (ret < 0) {
- error_setg_errno(errp, -ret,
- "dump: failed to write section header table");
- }
-}
-
-static void write_data(DumpState *s, void *buf, int length, Error **errp)
-{
- int ret;
-
- ret = fd_write_vmcore(buf, length, s);
- if (ret < 0) {
- error_setg_errno(errp, -ret, "dump: failed to save memory");
- } else {
- s->written_size += length;
- }
-}
-
-/* write the memory to vmcore. 1 page per I/O. */
-static void write_memory(DumpState *s, GuestPhysBlock *block, ram_addr_t start,
- int64_t size, Error **errp)
-{
- int64_t i;
- Error *local_err = NULL;
-
- for (i = 0; i < size / s->dump_info.page_size; i++) {
- write_data(s, block->host_addr + start + i * s->dump_info.page_size,
- s->dump_info.page_size, &local_err);
- if (local_err) {
- error_propagate(errp, local_err);
- return;
- }
- }
-
- if ((size % s->dump_info.page_size) != 0) {
- write_data(s, block->host_addr + start + i * s->dump_info.page_size,
- size % s->dump_info.page_size, &local_err);
- if (local_err) {
- error_propagate(errp, local_err);
- return;
- }
- }
-}
-
-/* get the memory's offset and size in the vmcore */
-static void get_offset_range(hwaddr phys_addr,
- ram_addr_t mapping_length,
- DumpState *s,
- hwaddr *p_offset,
- hwaddr *p_filesz)
-{
- GuestPhysBlock *block;
- hwaddr offset = s->memory_offset;
- int64_t size_in_block, start;
-
- /* When the memory is not stored into vmcore, offset will be -1 */
- *p_offset = -1;
- *p_filesz = 0;
-
- if (s->has_filter) {
- if (phys_addr < s->begin || phys_addr >= s->begin + s->length) {
- return;
- }
- }
-
- QTAILQ_FOREACH(block, &s->guest_phys_blocks.head, next) {
- if (s->has_filter) {
- if (block->target_start >= s->begin + s->length ||
- block->target_end <= s->begin) {
- /* This block is out of the range */
- continue;
- }
-
- if (s->begin <= block->target_start) {
- start = block->target_start;
- } else {
- start = s->begin;
- }
-
- size_in_block = block->target_end - start;
- if (s->begin + s->length < block->target_end) {
- size_in_block -= block->target_end - (s->begin + s->length);
- }
- } else {
- start = block->target_start;
- size_in_block = block->target_end - block->target_start;
- }
-
- if (phys_addr >= start && phys_addr < start + size_in_block) {
- *p_offset = phys_addr - start + offset;
-
- /* The offset range mapped from the vmcore file must not spill over
- * the GuestPhysBlock, clamp it. The rest of the mapping will be
- * zero-filled in memory at load time; see
- * <http://refspecs.linuxbase.org/elf/gabi4+/ch5.pheader.html>.
- */
- *p_filesz = phys_addr + mapping_length <= start + size_in_block ?
- mapping_length :
- size_in_block - (phys_addr - start);
- return;
- }
-
- offset += size_in_block;
- }
-}
-
-static void write_elf_loads(DumpState *s, Error **errp)
-{
- hwaddr offset, filesz;
- MemoryMapping *memory_mapping;
- uint32_t phdr_index = 1;
- uint32_t max_index;
- Error *local_err = NULL;
-
- if (s->have_section) {
- max_index = s->sh_info;
- } else {
- max_index = s->phdr_num;
- }
-
- QTAILQ_FOREACH(memory_mapping, &s->list.head, next) {
- get_offset_range(memory_mapping->phys_addr,
- memory_mapping->length,
- s, &offset, &filesz);
- if (s->dump_info.d_class == ELFCLASS64) {
- write_elf64_load(s, memory_mapping, phdr_index++, offset,
- filesz, &local_err);
- } else {
- write_elf32_load(s, memory_mapping, phdr_index++, offset,
- filesz, &local_err);
- }
-
- if (local_err) {
- error_propagate(errp, local_err);
- return;
- }
-
- if (phdr_index >= max_index) {
- break;
- }
- }
-}
-
-/* write elf header, PT_NOTE and elf note to vmcore. */
-static void dump_begin(DumpState *s, Error **errp)
-{
- Error *local_err = NULL;
-
- /*
- * the vmcore's format is:
- * --------------
- * | elf header |
- * --------------
- * | PT_NOTE |
- * --------------
- * | PT_LOAD |
- * --------------
- * | ...... |
- * --------------
- * | PT_LOAD |
- * --------------
- * | sec_hdr |
- * --------------
- * | elf note |
- * --------------
- * | memory |
- * --------------
- *
- * we only know where the memory is saved after we write elf note into
- * vmcore.
- */
-
- /* write elf header to vmcore */
- if (s->dump_info.d_class == ELFCLASS64) {
- write_elf64_header(s, &local_err);
- } else {
- write_elf32_header(s, &local_err);
- }
- if (local_err) {
- error_propagate(errp, local_err);
- return;
- }
-
- if (s->dump_info.d_class == ELFCLASS64) {
- /* write PT_NOTE to vmcore */
- write_elf64_note(s, &local_err);
- if (local_err) {
- error_propagate(errp, local_err);
- return;
- }
-
- /* write all PT_LOAD to vmcore */
- write_elf_loads(s, &local_err);
- if (local_err) {
- error_propagate(errp, local_err);
- return;
- }
-
- /* write section to vmcore */
- if (s->have_section) {
- write_elf_section(s, 1, &local_err);
- if (local_err) {
- error_propagate(errp, local_err);
- return;
- }
- }
-
- /* write notes to vmcore */
- write_elf64_notes(fd_write_vmcore, s, &local_err);
- if (local_err) {
- error_propagate(errp, local_err);
- return;
- }
- } else {
- /* write PT_NOTE to vmcore */
- write_elf32_note(s, &local_err);
- if (local_err) {
- error_propagate(errp, local_err);
- return;
- }
-
- /* write all PT_LOAD to vmcore */
- write_elf_loads(s, &local_err);
- if (local_err) {
- error_propagate(errp, local_err);
- return;
- }
-
- /* write section to vmcore */
- if (s->have_section) {
- write_elf_section(s, 0, &local_err);
- if (local_err) {
- error_propagate(errp, local_err);
- return;
- }
- }
-
- /* write notes to vmcore */
- write_elf32_notes(fd_write_vmcore, s, &local_err);
- if (local_err) {
- error_propagate(errp, local_err);
- return;
- }
- }
-}
-
-static int get_next_block(DumpState *s, GuestPhysBlock *block)
-{
- while (1) {
- block = QTAILQ_NEXT(block, next);
- if (!block) {
- /* no more block */
- return 1;
- }
-
- s->start = 0;
- s->next_block = block;
- if (s->has_filter) {
- if (block->target_start >= s->begin + s->length ||
- block->target_end <= s->begin) {
- /* This block is out of the range */
- continue;
- }
-
- if (s->begin > block->target_start) {
- s->start = s->begin - block->target_start;
- }
- }
-
- return 0;
- }
-}
-
-/* write all memory to vmcore */
-static void dump_iterate(DumpState *s, Error **errp)
-{
- GuestPhysBlock *block;
- int64_t size;
- Error *local_err = NULL;
-
- do {
- block = s->next_block;
-
- size = block->target_end - block->target_start;
- if (s->has_filter) {
- size -= s->start;
- if (s->begin + s->length < block->target_end) {
- size -= block->target_end - (s->begin + s->length);
- }
- }
- write_memory(s, block, s->start, size, &local_err);
- if (local_err) {
- error_propagate(errp, local_err);
- return;
- }
-
- } while (!get_next_block(s, block));
-}
-
-static void create_vmcore(DumpState *s, Error **errp)
-{
- Error *local_err = NULL;
-
- dump_begin(s, &local_err);
- if (local_err) {
- error_propagate(errp, local_err);
- return;
- }
-
- dump_iterate(s, errp);
-}
-
-static int write_start_flat_header(int fd)
-{
- MakedumpfileHeader *mh;
- int ret = 0;
-
- QEMU_BUILD_BUG_ON(sizeof *mh > MAX_SIZE_MDF_HEADER);
- mh = g_malloc0(MAX_SIZE_MDF_HEADER);
-
- memcpy(mh->signature, MAKEDUMPFILE_SIGNATURE,
- MIN(sizeof mh->signature, sizeof MAKEDUMPFILE_SIGNATURE));
-
- mh->type = cpu_to_be64(TYPE_FLAT_HEADER);
- mh->version = cpu_to_be64(VERSION_FLAT_HEADER);
-
- size_t written_size;
- written_size = qemu_write_full(fd, mh, MAX_SIZE_MDF_HEADER);
- if (written_size != MAX_SIZE_MDF_HEADER) {
- ret = -1;
- }
-
- g_free(mh);
- return ret;
-}
-
-static int write_end_flat_header(int fd)
-{
- MakedumpfileDataHeader mdh;
-
- mdh.offset = END_FLAG_FLAT_HEADER;
- mdh.buf_size = END_FLAG_FLAT_HEADER;
-
- size_t written_size;
- written_size = qemu_write_full(fd, &mdh, sizeof(mdh));
- if (written_size != sizeof(mdh)) {
- return -1;
- }
-
- return 0;
-}
-
-static int write_buffer(int fd, off_t offset, const void *buf, size_t size)
-{
- size_t written_size;
- MakedumpfileDataHeader mdh;
-
- mdh.offset = cpu_to_be64(offset);
- mdh.buf_size = cpu_to_be64(size);
-
- written_size = qemu_write_full(fd, &mdh, sizeof(mdh));
- if (written_size != sizeof(mdh)) {
- return -1;
- }
-
- written_size = qemu_write_full(fd, buf, size);
- if (written_size != size) {
- return -1;
- }
-
- return 0;
-}
-
-static int buf_write_note(const void *buf, size_t size, void *opaque)
-{
- DumpState *s = opaque;
-
- /* note_buf is not enough */
- if (s->note_buf_offset + size > s->note_size) {
- return -1;
- }
-
- memcpy(s->note_buf + s->note_buf_offset, buf, size);
-
- s->note_buf_offset += size;
-
- return 0;
-}
-
-/*
- * This function retrieves various sizes from an elf header.
- *
- * @note has to be a valid ELF note. The return sizes are unmodified
- * (not padded or rounded up to be multiple of 4).
- */
-static void get_note_sizes(DumpState *s, const void *note,
- uint64_t *note_head_size,
- uint64_t *name_size,
- uint64_t *desc_size)
-{
- uint64_t note_head_sz;
- uint64_t name_sz;
- uint64_t desc_sz;
-
- if (s->dump_info.d_class == ELFCLASS64) {
- const Elf64_Nhdr *hdr = note;
- note_head_sz = sizeof(Elf64_Nhdr);
- name_sz = tswap64(hdr->n_namesz);
- desc_sz = tswap64(hdr->n_descsz);
- } else {
- const Elf32_Nhdr *hdr = note;
- note_head_sz = sizeof(Elf32_Nhdr);
- name_sz = tswap32(hdr->n_namesz);
- desc_sz = tswap32(hdr->n_descsz);
- }
-
- if (note_head_size) {
- *note_head_size = note_head_sz;
- }
- if (name_size) {
- *name_size = name_sz;
- }
- if (desc_size) {
- *desc_size = desc_sz;
- }
-}
-
-static bool note_name_equal(DumpState *s,
- const uint8_t *note, const char *name)
-{
- int len = strlen(name) + 1;
- uint64_t head_size, name_size;
-
- get_note_sizes(s, note, &head_size, &name_size, NULL);
- head_size = ROUND_UP(head_size, 4);
-
- return name_size == len && memcmp(note + head_size, name, len) == 0;
-}
-
-/* write common header, sub header and elf note to vmcore */
-static void create_header32(DumpState *s, Error **errp)
-{
- DiskDumpHeader32 *dh = NULL;
- KdumpSubHeader32 *kh = NULL;
- size_t size;
- uint32_t block_size;
- uint32_t sub_hdr_size;
- uint32_t bitmap_blocks;
- uint32_t status = 0;
- uint64_t offset_note;
- Error *local_err = NULL;
-
- /* write common header, the version of kdump-compressed format is 6th */
- size = sizeof(DiskDumpHeader32);
- dh = g_malloc0(size);
-
- memcpy(dh->signature, KDUMP_SIGNATURE, SIG_LEN);
- dh->header_version = cpu_to_dump32(s, 6);
- block_size = s->dump_info.page_size;
- dh->block_size = cpu_to_dump32(s, block_size);
- sub_hdr_size = sizeof(struct KdumpSubHeader32) + s->note_size;
- sub_hdr_size = DIV_ROUND_UP(sub_hdr_size, block_size);
- dh->sub_hdr_size = cpu_to_dump32(s, sub_hdr_size);
- /* dh->max_mapnr may be truncated, full 64bit is in kh.max_mapnr_64 */
- dh->max_mapnr = cpu_to_dump32(s, MIN(s->max_mapnr, UINT_MAX));
- dh->nr_cpus = cpu_to_dump32(s, s->nr_cpus);
- bitmap_blocks = DIV_ROUND_UP(s->len_dump_bitmap, block_size) * 2;
- dh->bitmap_blocks = cpu_to_dump32(s, bitmap_blocks);
- strncpy(dh->utsname.machine, ELF_MACHINE_UNAME, sizeof(dh->utsname.machine));
-
- if (s->flag_compress & DUMP_DH_COMPRESSED_ZLIB) {
- status |= DUMP_DH_COMPRESSED_ZLIB;
- }
-#ifdef CONFIG_LZO
- if (s->flag_compress & DUMP_DH_COMPRESSED_LZO) {
- status |= DUMP_DH_COMPRESSED_LZO;
- }
-#endif
-#ifdef CONFIG_SNAPPY
- if (s->flag_compress & DUMP_DH_COMPRESSED_SNAPPY) {
- status |= DUMP_DH_COMPRESSED_SNAPPY;
- }
-#endif
- dh->status = cpu_to_dump32(s, status);
-
- if (write_buffer(s->fd, 0, dh, size) < 0) {
- error_setg(errp, "dump: failed to write disk dump header");
- goto out;
- }
-
- /* write sub header */
- size = sizeof(KdumpSubHeader32);
- kh = g_malloc0(size);
-
- /* 64bit max_mapnr_64 */
- kh->max_mapnr_64 = cpu_to_dump64(s, s->max_mapnr);
- kh->phys_base = cpu_to_dump32(s, s->dump_info.phys_base);
- kh->dump_level = cpu_to_dump32(s, DUMP_LEVEL);
-
- offset_note = DISKDUMP_HEADER_BLOCKS * block_size + size;
- if (s->guest_note &&
- note_name_equal(s, s->guest_note, "VMCOREINFO")) {
- uint64_t hsize, name_size, size_vmcoreinfo_desc, offset_vmcoreinfo;
-
- get_note_sizes(s, s->guest_note,
- &hsize, &name_size, &size_vmcoreinfo_desc);
- offset_vmcoreinfo = offset_note + s->note_size - s->guest_note_size +
- (DIV_ROUND_UP(hsize, 4) + DIV_ROUND_UP(name_size, 4)) * 4;
- kh->offset_vmcoreinfo = cpu_to_dump64(s, offset_vmcoreinfo);
- kh->size_vmcoreinfo = cpu_to_dump32(s, size_vmcoreinfo_desc);
- }
-
- kh->offset_note = cpu_to_dump64(s, offset_note);
- kh->note_size = cpu_to_dump32(s, s->note_size);
-
- if (write_buffer(s->fd, DISKDUMP_HEADER_BLOCKS *
- block_size, kh, size) < 0) {
- error_setg(errp, "dump: failed to write kdump sub header");
- goto out;
- }
-
- /* write note */
- s->note_buf = g_malloc0(s->note_size);
- s->note_buf_offset = 0;
-
- /* use s->note_buf to store notes temporarily */
- write_elf32_notes(buf_write_note, s, &local_err);
- if (local_err) {
- error_propagate(errp, local_err);
- goto out;
- }
- if (write_buffer(s->fd, offset_note, s->note_buf,
- s->note_size) < 0) {
- error_setg(errp, "dump: failed to write notes");
- goto out;
- }
-
- /* get offset of dump_bitmap */
- s->offset_dump_bitmap = (DISKDUMP_HEADER_BLOCKS + sub_hdr_size) *
- block_size;
-
- /* get offset of page */
- s->offset_page = (DISKDUMP_HEADER_BLOCKS + sub_hdr_size + bitmap_blocks) *
- block_size;
-
-out:
- g_free(dh);
- g_free(kh);
- g_free(s->note_buf);
-}
-
-/* write common header, sub header and elf note to vmcore */
-static void create_header64(DumpState *s, Error **errp)
-{
- DiskDumpHeader64 *dh = NULL;
- KdumpSubHeader64 *kh = NULL;
- size_t size;
- uint32_t block_size;
- uint32_t sub_hdr_size;
- uint32_t bitmap_blocks;
- uint32_t status = 0;
- uint64_t offset_note;
- Error *local_err = NULL;
-
- /* write common header, the version of kdump-compressed format is 6th */
- size = sizeof(DiskDumpHeader64);
- dh = g_malloc0(size);
-
- memcpy(dh->signature, KDUMP_SIGNATURE, SIG_LEN);
- dh->header_version = cpu_to_dump32(s, 6);
- block_size = s->dump_info.page_size;
- dh->block_size = cpu_to_dump32(s, block_size);
- sub_hdr_size = sizeof(struct KdumpSubHeader64) + s->note_size;
- sub_hdr_size = DIV_ROUND_UP(sub_hdr_size, block_size);
- dh->sub_hdr_size = cpu_to_dump32(s, sub_hdr_size);
- /* dh->max_mapnr may be truncated, full 64bit is in kh.max_mapnr_64 */
- dh->max_mapnr = cpu_to_dump32(s, MIN(s->max_mapnr, UINT_MAX));
- dh->nr_cpus = cpu_to_dump32(s, s->nr_cpus);
- bitmap_blocks = DIV_ROUND_UP(s->len_dump_bitmap, block_size) * 2;
- dh->bitmap_blocks = cpu_to_dump32(s, bitmap_blocks);
- strncpy(dh->utsname.machine, ELF_MACHINE_UNAME, sizeof(dh->utsname.machine));
-
- if (s->flag_compress & DUMP_DH_COMPRESSED_ZLIB) {
- status |= DUMP_DH_COMPRESSED_ZLIB;
- }
-#ifdef CONFIG_LZO
- if (s->flag_compress & DUMP_DH_COMPRESSED_LZO) {
- status |= DUMP_DH_COMPRESSED_LZO;
- }
-#endif
-#ifdef CONFIG_SNAPPY
- if (s->flag_compress & DUMP_DH_COMPRESSED_SNAPPY) {
- status |= DUMP_DH_COMPRESSED_SNAPPY;
- }
-#endif
- dh->status = cpu_to_dump32(s, status);
-
- if (write_buffer(s->fd, 0, dh, size) < 0) {
- error_setg(errp, "dump: failed to write disk dump header");
- goto out;
- }
-
- /* write sub header */
- size = sizeof(KdumpSubHeader64);
- kh = g_malloc0(size);
-
- /* 64bit max_mapnr_64 */
- kh->max_mapnr_64 = cpu_to_dump64(s, s->max_mapnr);
- kh->phys_base = cpu_to_dump64(s, s->dump_info.phys_base);
- kh->dump_level = cpu_to_dump32(s, DUMP_LEVEL);
-
- offset_note = DISKDUMP_HEADER_BLOCKS * block_size + size;
- if (s->guest_note &&
- note_name_equal(s, s->guest_note, "VMCOREINFO")) {
- uint64_t hsize, name_size, size_vmcoreinfo_desc, offset_vmcoreinfo;
-
- get_note_sizes(s, s->guest_note,
- &hsize, &name_size, &size_vmcoreinfo_desc);
- offset_vmcoreinfo = offset_note + s->note_size - s->guest_note_size +
- (DIV_ROUND_UP(hsize, 4) + DIV_ROUND_UP(name_size, 4)) * 4;
- kh->offset_vmcoreinfo = cpu_to_dump64(s, offset_vmcoreinfo);
- kh->size_vmcoreinfo = cpu_to_dump64(s, size_vmcoreinfo_desc);
- }
-
- kh->offset_note = cpu_to_dump64(s, offset_note);
- kh->note_size = cpu_to_dump64(s, s->note_size);
-
- if (write_buffer(s->fd, DISKDUMP_HEADER_BLOCKS *
- block_size, kh, size) < 0) {
- error_setg(errp, "dump: failed to write kdump sub header");
- goto out;
- }
-
- /* write note */
- s->note_buf = g_malloc0(s->note_size);
- s->note_buf_offset = 0;
-
- /* use s->note_buf to store notes temporarily */
- write_elf64_notes(buf_write_note, s, &local_err);
- if (local_err) {
- error_propagate(errp, local_err);
- goto out;
- }
-
- if (write_buffer(s->fd, offset_note, s->note_buf,
- s->note_size) < 0) {
- error_setg(errp, "dump: failed to write notes");
- goto out;
- }
-
- /* get offset of dump_bitmap */
- s->offset_dump_bitmap = (DISKDUMP_HEADER_BLOCKS + sub_hdr_size) *
- block_size;
-
- /* get offset of page */
- s->offset_page = (DISKDUMP_HEADER_BLOCKS + sub_hdr_size + bitmap_blocks) *
- block_size;
-
-out:
- g_free(dh);
- g_free(kh);
- g_free(s->note_buf);
-}
-
-static void write_dump_header(DumpState *s, Error **errp)
-{
- Error *local_err = NULL;
-
- if (s->dump_info.d_class == ELFCLASS32) {
- create_header32(s, &local_err);
- } else {
- create_header64(s, &local_err);
- }
- error_propagate(errp, local_err);
-}
-
-static size_t dump_bitmap_get_bufsize(DumpState *s)
-{
- return s->dump_info.page_size;
-}
-
-/*
- * set dump_bitmap sequencely. the bit before last_pfn is not allowed to be
- * rewritten, so if need to set the first bit, set last_pfn and pfn to 0.
- * set_dump_bitmap will always leave the recently set bit un-sync. And setting
- * (last bit + sizeof(buf) * 8) to 0 will do flushing the content in buf into
- * vmcore, ie. synchronizing un-sync bit into vmcore.
- */
-static int set_dump_bitmap(uint64_t last_pfn, uint64_t pfn, bool value,
- uint8_t *buf, DumpState *s)
-{
- off_t old_offset, new_offset;
- off_t offset_bitmap1, offset_bitmap2;
- uint32_t byte, bit;
- size_t bitmap_bufsize = dump_bitmap_get_bufsize(s);
- size_t bits_per_buf = bitmap_bufsize * CHAR_BIT;
-
- /* should not set the previous place */
- assert(last_pfn <= pfn);
-
- /*
- * if the bit needed to be set is not cached in buf, flush the data in buf
- * to vmcore firstly.
- * making new_offset be bigger than old_offset can also sync remained data
- * into vmcore.
- */
- old_offset = bitmap_bufsize * (last_pfn / bits_per_buf);
- new_offset = bitmap_bufsize * (pfn / bits_per_buf);
-
- while (old_offset < new_offset) {
- /* calculate the offset and write dump_bitmap */
- offset_bitmap1 = s->offset_dump_bitmap + old_offset;
- if (write_buffer(s->fd, offset_bitmap1, buf,
- bitmap_bufsize) < 0) {
- return -1;
- }
-
- /* dump level 1 is chosen, so 1st and 2nd bitmap are same */
- offset_bitmap2 = s->offset_dump_bitmap + s->len_dump_bitmap +
- old_offset;
- if (write_buffer(s->fd, offset_bitmap2, buf,
- bitmap_bufsize) < 0) {
- return -1;
- }
-
- memset(buf, 0, bitmap_bufsize);
- old_offset += bitmap_bufsize;
- }
-
- /* get the exact place of the bit in the buf, and set it */
- byte = (pfn % bits_per_buf) / CHAR_BIT;
- bit = (pfn % bits_per_buf) % CHAR_BIT;
- if (value) {
- buf[byte] |= 1u << bit;
- } else {
- buf[byte] &= ~(1u << bit);
- }
-
- return 0;
-}
-
-static uint64_t dump_paddr_to_pfn(DumpState *s, uint64_t addr)
-{
- int target_page_shift = ctz32(s->dump_info.page_size);
-
- return (addr >> target_page_shift) - ARCH_PFN_OFFSET;
-}
-
-static uint64_t dump_pfn_to_paddr(DumpState *s, uint64_t pfn)
-{
- int target_page_shift = ctz32(s->dump_info.page_size);
-
- return (pfn + ARCH_PFN_OFFSET) << target_page_shift;
-}
-
-/*
- * exam every page and return the page frame number and the address of the page.
- * bufptr can be NULL. note: the blocks here is supposed to reflect guest-phys
- * blocks, so block->target_start and block->target_end should be interal
- * multiples of the target page size.
- */
-static bool get_next_page(GuestPhysBlock **blockptr, uint64_t *pfnptr,
- uint8_t **bufptr, DumpState *s)
-{
- GuestPhysBlock *block = *blockptr;
- hwaddr addr, target_page_mask = ~((hwaddr)s->dump_info.page_size - 1);
- uint8_t *buf;
-
- /* block == NULL means the start of the iteration */
- if (!block) {
- block = QTAILQ_FIRST(&s->guest_phys_blocks.head);
- *blockptr = block;
- assert((block->target_start & ~target_page_mask) == 0);
- assert((block->target_end & ~target_page_mask) == 0);
- *pfnptr = dump_paddr_to_pfn(s, block->target_start);
- if (bufptr) {
- *bufptr = block->host_addr;
- }
- return true;
- }
-
- *pfnptr = *pfnptr + 1;
- addr = dump_pfn_to_paddr(s, *pfnptr);
-
- if ((addr >= block->target_start) &&
- (addr + s->dump_info.page_size <= block->target_end)) {
- buf = block->host_addr + (addr - block->target_start);
- } else {
- /* the next page is in the next block */
- block = QTAILQ_NEXT(block, next);
- *blockptr = block;
- if (!block) {
- return false;
- }
- assert((block->target_start & ~target_page_mask) == 0);
- assert((block->target_end & ~target_page_mask) == 0);
- *pfnptr = dump_paddr_to_pfn(s, block->target_start);
- buf = block->host_addr;
- }
-
- if (bufptr) {
- *bufptr = buf;
- }
-
- return true;
-}
-
-static void write_dump_bitmap(DumpState *s, Error **errp)
-{
- int ret = 0;
- uint64_t last_pfn, pfn;
- void *dump_bitmap_buf;
- size_t num_dumpable;
- GuestPhysBlock *block_iter = NULL;
- size_t bitmap_bufsize = dump_bitmap_get_bufsize(s);
- size_t bits_per_buf = bitmap_bufsize * CHAR_BIT;
-
- /* dump_bitmap_buf is used to store dump_bitmap temporarily */
- dump_bitmap_buf = g_malloc0(bitmap_bufsize);
-
- num_dumpable = 0;
- last_pfn = 0;
-
- /*
- * exam memory page by page, and set the bit in dump_bitmap corresponded
- * to the existing page.
- */
- while (get_next_page(&block_iter, &pfn, NULL, s)) {
- ret = set_dump_bitmap(last_pfn, pfn, true, dump_bitmap_buf, s);
- if (ret < 0) {
- error_setg(errp, "dump: failed to set dump_bitmap");
- goto out;
- }
-
- last_pfn = pfn;
- num_dumpable++;
- }
-
- /*
- * set_dump_bitmap will always leave the recently set bit un-sync. Here we
- * set the remaining bits from last_pfn to the end of the bitmap buffer to
- * 0. With those set, the un-sync bit will be synchronized into the vmcore.
- */
- if (num_dumpable > 0) {
- ret = set_dump_bitmap(last_pfn, last_pfn + bits_per_buf, false,
- dump_bitmap_buf, s);
- if (ret < 0) {
- error_setg(errp, "dump: failed to sync dump_bitmap");
- goto out;
- }
- }
-
- /* number of dumpable pages that will be dumped later */
- s->num_dumpable = num_dumpable;
-
-out:
- g_free(dump_bitmap_buf);
-}
-
-static void prepare_data_cache(DataCache *data_cache, DumpState *s,
- off_t offset)
-{
- data_cache->fd = s->fd;
- data_cache->data_size = 0;
- data_cache->buf_size = 4 * dump_bitmap_get_bufsize(s);
- data_cache->buf = g_malloc0(data_cache->buf_size);
- data_cache->offset = offset;
-}
-
-static int write_cache(DataCache *dc, const void *buf, size_t size,
- bool flag_sync)
-{
- /*
- * dc->buf_size should not be less than size, otherwise dc will never be
- * enough
- */
- assert(size <= dc->buf_size);
-
- /*
- * if flag_sync is set, synchronize data in dc->buf into vmcore.
- * otherwise check if the space is enough for caching data in buf, if not,
- * write the data in dc->buf to dc->fd and reset dc->buf
- */
- if ((!flag_sync && dc->data_size + size > dc->buf_size) ||
- (flag_sync && dc->data_size > 0)) {
- if (write_buffer(dc->fd, dc->offset, dc->buf, dc->data_size) < 0) {
- return -1;
- }
-
- dc->offset += dc->data_size;
- dc->data_size = 0;
- }
-
- if (!flag_sync) {
- memcpy(dc->buf + dc->data_size, buf, size);
- dc->data_size += size;
- }
-
- return 0;
-}
-
-static void free_data_cache(DataCache *data_cache)
-{
- g_free(data_cache->buf);
-}
-
-static size_t get_len_buf_out(size_t page_size, uint32_t flag_compress)
-{
- switch (flag_compress) {
- case DUMP_DH_COMPRESSED_ZLIB:
- return compressBound(page_size);
-
- case DUMP_DH_COMPRESSED_LZO:
- /*
- * LZO will expand incompressible data by a little amount. Please check
- * the following URL to see the expansion calculation:
- * http://www.oberhumer.com/opensource/lzo/lzofaq.php
- */
- return page_size + page_size / 16 + 64 + 3;
-
-#ifdef CONFIG_SNAPPY
- case DUMP_DH_COMPRESSED_SNAPPY:
- return snappy_max_compressed_length(page_size);
-#endif
- }
- return 0;
-}
-
-/*
- * check if the page is all 0
- */
-static inline bool is_zero_page(const uint8_t *buf, size_t page_size)
-{
- return buffer_is_zero(buf, page_size);
-}
-
-static void write_dump_pages(DumpState *s, Error **errp)
-{
- int ret = 0;
- DataCache page_desc, page_data;
- size_t len_buf_out, size_out;
-#ifdef CONFIG_LZO
- lzo_bytep wrkmem = NULL;
-#endif
- uint8_t *buf_out = NULL;
- off_t offset_desc, offset_data;
- PageDescriptor pd, pd_zero;
- uint8_t *buf;
- GuestPhysBlock *block_iter = NULL;
- uint64_t pfn_iter;
-
- /* get offset of page_desc and page_data in dump file */
- offset_desc = s->offset_page;
- offset_data = offset_desc + sizeof(PageDescriptor) * s->num_dumpable;
-
- prepare_data_cache(&page_desc, s, offset_desc);
- prepare_data_cache(&page_data, s, offset_data);
-
- /* prepare buffer to store compressed data */
- len_buf_out = get_len_buf_out(s->dump_info.page_size, s->flag_compress);
- assert(len_buf_out != 0);
-
-#ifdef CONFIG_LZO
- wrkmem = g_malloc(LZO1X_1_MEM_COMPRESS);
-#endif
-
- buf_out = g_malloc(len_buf_out);
-
- /*
- * init zero page's page_desc and page_data, because every zero page
- * uses the same page_data
- */
- pd_zero.size = cpu_to_dump32(s, s->dump_info.page_size);
- pd_zero.flags = cpu_to_dump32(s, 0);
- pd_zero.offset = cpu_to_dump64(s, offset_data);
- pd_zero.page_flags = cpu_to_dump64(s, 0);
- buf = g_malloc0(s->dump_info.page_size);
- ret = write_cache(&page_data, buf, s->dump_info.page_size, false);
- g_free(buf);
- if (ret < 0) {
- error_setg(errp, "dump: failed to write page data (zero page)");
- goto out;
- }
-
- offset_data += s->dump_info.page_size;
-
- /*
- * dump memory to vmcore page by page. zero page will all be resided in the
- * first page of page section
- */
- while (get_next_page(&block_iter, &pfn_iter, &buf, s)) {
- /* check zero page */
- if (is_zero_page(buf, s->dump_info.page_size)) {
- ret = write_cache(&page_desc, &pd_zero, sizeof(PageDescriptor),
- false);
- if (ret < 0) {
- error_setg(errp, "dump: failed to write page desc");
- goto out;
- }
- } else {
- /*
- * not zero page, then:
- * 1. compress the page
- * 2. write the compressed page into the cache of page_data
- * 3. get page desc of the compressed page and write it into the
- * cache of page_desc
- *
- * only one compression format will be used here, for
- * s->flag_compress is set. But when compression fails to work,
- * we fall back to save in plaintext.
- */
- size_out = len_buf_out;
- if ((s->flag_compress & DUMP_DH_COMPRESSED_ZLIB) &&
- (compress2(buf_out, (uLongf *)&size_out, buf,
- s->dump_info.page_size, Z_BEST_SPEED) == Z_OK) &&
- (size_out < s->dump_info.page_size)) {
- pd.flags = cpu_to_dump32(s, DUMP_DH_COMPRESSED_ZLIB);
- pd.size = cpu_to_dump32(s, size_out);
-
- ret = write_cache(&page_data, buf_out, size_out, false);
- if (ret < 0) {
- error_setg(errp, "dump: failed to write page data");
- goto out;
- }
-#ifdef CONFIG_LZO
- } else if ((s->flag_compress & DUMP_DH_COMPRESSED_LZO) &&
- (lzo1x_1_compress(buf, s->dump_info.page_size, buf_out,
- (lzo_uint *)&size_out, wrkmem) == LZO_E_OK) &&
- (size_out < s->dump_info.page_size)) {
- pd.flags = cpu_to_dump32(s, DUMP_DH_COMPRESSED_LZO);
- pd.size = cpu_to_dump32(s, size_out);
-
- ret = write_cache(&page_data, buf_out, size_out, false);
- if (ret < 0) {
- error_setg(errp, "dump: failed to write page data");
- goto out;
- }
-#endif
-#ifdef CONFIG_SNAPPY
- } else if ((s->flag_compress & DUMP_DH_COMPRESSED_SNAPPY) &&
- (snappy_compress((char *)buf, s->dump_info.page_size,
- (char *)buf_out, &size_out) == SNAPPY_OK) &&
- (size_out < s->dump_info.page_size)) {
- pd.flags = cpu_to_dump32(s, DUMP_DH_COMPRESSED_SNAPPY);
- pd.size = cpu_to_dump32(s, size_out);
-
- ret = write_cache(&page_data, buf_out, size_out, false);
- if (ret < 0) {
- error_setg(errp, "dump: failed to write page data");
- goto out;
- }
-#endif
- } else {
- /*
- * fall back to save in plaintext, size_out should be
- * assigned the target's page size
- */
- pd.flags = cpu_to_dump32(s, 0);
- size_out = s->dump_info.page_size;
- pd.size = cpu_to_dump32(s, size_out);
-
- ret = write_cache(&page_data, buf,
- s->dump_info.page_size, false);
- if (ret < 0) {
- error_setg(errp, "dump: failed to write page data");
- goto out;
- }
- }
-
- /* get and write page desc here */
- pd.page_flags = cpu_to_dump64(s, 0);
- pd.offset = cpu_to_dump64(s, offset_data);
- offset_data += size_out;
-
- ret = write_cache(&page_desc, &pd, sizeof(PageDescriptor), false);
- if (ret < 0) {
- error_setg(errp, "dump: failed to write page desc");
- goto out;
- }
- }
- s->written_size += s->dump_info.page_size;
- }
-
- ret = write_cache(&page_desc, NULL, 0, true);
- if (ret < 0) {
- error_setg(errp, "dump: failed to sync cache for page_desc");
- goto out;
- }
- ret = write_cache(&page_data, NULL, 0, true);
- if (ret < 0) {
- error_setg(errp, "dump: failed to sync cache for page_data");
- goto out;
- }
-
-out:
- free_data_cache(&page_desc);
- free_data_cache(&page_data);
-
-#ifdef CONFIG_LZO
- g_free(wrkmem);
-#endif
-
- g_free(buf_out);
-}
-
-static void create_kdump_vmcore(DumpState *s, Error **errp)
-{
- int ret;
- Error *local_err = NULL;
-
- /*
- * the kdump-compressed format is:
- * File offset
- * +------------------------------------------+ 0x0
- * | main header (struct disk_dump_header) |
- * |------------------------------------------+ block 1
- * | sub header (struct kdump_sub_header) |
- * |------------------------------------------+ block 2
- * | 1st-dump_bitmap |
- * |------------------------------------------+ block 2 + X blocks
- * | 2nd-dump_bitmap | (aligned by block)
- * |------------------------------------------+ block 2 + 2 * X blocks
- * | page desc for pfn 0 (struct page_desc) | (aligned by block)
- * | page desc for pfn 1 (struct page_desc) |
- * | : |
- * |------------------------------------------| (not aligned by block)
- * | page data (pfn 0) |
- * | page data (pfn 1) |
- * | : |
- * +------------------------------------------+
- */
-
- ret = write_start_flat_header(s->fd);
- if (ret < 0) {
- error_setg(errp, "dump: failed to write start flat header");
- return;
- }
-
- write_dump_header(s, &local_err);
- if (local_err) {
- error_propagate(errp, local_err);
- return;
- }
-
- write_dump_bitmap(s, &local_err);
- if (local_err) {
- error_propagate(errp, local_err);
- return;
- }
-
- write_dump_pages(s, &local_err);
- if (local_err) {
- error_propagate(errp, local_err);
- return;
- }
-
- ret = write_end_flat_header(s->fd);
- if (ret < 0) {
- error_setg(errp, "dump: failed to write end flat header");
- return;
- }
-}
-
-static ram_addr_t get_start_block(DumpState *s)
-{
- GuestPhysBlock *block;
-
- if (!s->has_filter) {
- s->next_block = QTAILQ_FIRST(&s->guest_phys_blocks.head);
- return 0;
- }
-
- QTAILQ_FOREACH(block, &s->guest_phys_blocks.head, next) {
- if (block->target_start >= s->begin + s->length ||
- block->target_end <= s->begin) {
- /* This block is out of the range */
- continue;
- }
-
- s->next_block = block;
- if (s->begin > block->target_start) {
- s->start = s->begin - block->target_start;
- } else {
- s->start = 0;
- }
- return s->start;
- }
-
- return -1;
-}
-
-static void get_max_mapnr(DumpState *s)
-{
- GuestPhysBlock *last_block;
-
- last_block = QTAILQ_LAST(&s->guest_phys_blocks.head);
- s->max_mapnr = dump_paddr_to_pfn(s, last_block->target_end);
-}
-
-static DumpState dump_state_global = { .status = DUMP_STATUS_NONE };
-
-static void dump_state_prepare(DumpState *s)
-{
- /* zero the struct, setting status to active */
- *s = (DumpState) { .status = DUMP_STATUS_ACTIVE };
-}
-
-bool dump_in_progress(void)
-{
- DumpState *state = &dump_state_global;
- return (atomic_read(&state->status) == DUMP_STATUS_ACTIVE);
-}
-
-/* calculate total size of memory to be dumped (taking filter into
- * acoount.) */
-static int64_t dump_calculate_size(DumpState *s)
-{
- GuestPhysBlock *block;
- int64_t size = 0, total = 0, left = 0, right = 0;
-
- QTAILQ_FOREACH(block, &s->guest_phys_blocks.head, next) {
- if (s->has_filter) {
- /* calculate the overlapped region. */
- left = MAX(s->begin, block->target_start);
- right = MIN(s->begin + s->length, block->target_end);
- size = right - left;
- size = size > 0 ? size : 0;
- } else {
- /* count the whole region in */
- size = (block->target_end - block->target_start);
- }
- total += size;
- }
-
- return total;
-}
-
-static void vmcoreinfo_update_phys_base(DumpState *s)
-{
- uint64_t size, note_head_size, name_size, phys_base;
- char **lines;
- uint8_t *vmci;
- size_t i;
-
- if (!note_name_equal(s, s->guest_note, "VMCOREINFO")) {
- return;
- }
-
- get_note_sizes(s, s->guest_note, ¬e_head_size, &name_size, &size);
- note_head_size = ROUND_UP(note_head_size, 4);
-
- vmci = s->guest_note + note_head_size + ROUND_UP(name_size, 4);
- *(vmci + size) = '\0';
-
- lines = g_strsplit((char *)vmci, "\n", -1);
- for (i = 0; lines[i]; i++) {
- const char *prefix = NULL;
-
- if (s->dump_info.d_machine == EM_X86_64) {
- prefix = "NUMBER(phys_base)=";
- } else if (s->dump_info.d_machine == EM_AARCH64) {
- prefix = "NUMBER(PHYS_OFFSET)=";
- }
-
- if (prefix && g_str_has_prefix(lines[i], prefix)) {
- if (qemu_strtou64(lines[i] + strlen(prefix), NULL, 16,
- &phys_base) < 0) {
- warn_report("Failed to read %s", prefix);
- } else {
- s->dump_info.phys_base = phys_base;
- }
- break;
- }
- }
-
- g_strfreev(lines);
-}
-
-static void dump_init(DumpState *s, int fd, bool has_format,
- DumpGuestMemoryFormat format, bool paging, bool has_filter,
- int64_t begin, int64_t length, Error **errp)
-{
- VMCoreInfoState *vmci = vmcoreinfo_find();
- CPUState *cpu;
- int nr_cpus;
- Error *err = NULL;
- int ret;
-
- s->has_format = has_format;
- s->format = format;
- s->written_size = 0;
-
- /* kdump-compressed is conflict with paging and filter */
- if (has_format && format != DUMP_GUEST_MEMORY_FORMAT_ELF) {
- assert(!paging && !has_filter);
- }
-
- if (runstate_is_running()) {
- vm_stop(RUN_STATE_SAVE_VM);
- s->resume = true;
- } else {
- s->resume = false;
- }
-
- /* If we use KVM, we should synchronize the registers before we get dump
- * info or physmap info.
- */
- cpu_synchronize_all_states();
- nr_cpus = 0;
- CPU_FOREACH(cpu) {
- nr_cpus++;
- }
-
- s->fd = fd;
- s->has_filter = has_filter;
- s->begin = begin;
- s->length = length;
-
- memory_mapping_list_init(&s->list);
-
- guest_phys_blocks_init(&s->guest_phys_blocks);
- guest_phys_blocks_append(&s->guest_phys_blocks);
- s->total_size = dump_calculate_size(s);
-#ifdef DEBUG_DUMP_GUEST_MEMORY
- fprintf(stderr, "DUMP: total memory to dump: %lu\n", s->total_size);
-#endif
-
- /* it does not make sense to dump non-existent memory */
- if (!s->total_size) {
- error_setg(errp, "dump: no guest memory to dump");
- goto cleanup;
- }
-
- s->start = get_start_block(s);
- if (s->start == -1) {
- error_setg(errp, QERR_INVALID_PARAMETER, "begin");
- goto cleanup;
- }
-
- /* get dump info: endian, class and architecture.
- * If the target architecture is not supported, cpu_get_dump_info() will
- * return -1.
- */
- ret = cpu_get_dump_info(&s->dump_info, &s->guest_phys_blocks);
- if (ret < 0) {
- error_setg(errp, QERR_UNSUPPORTED);
- goto cleanup;
- }
-
- if (!s->dump_info.page_size) {
- s->dump_info.page_size = TARGET_PAGE_SIZE;
- }
-
- s->note_size = cpu_get_note_size(s->dump_info.d_class,
- s->dump_info.d_machine, nr_cpus);
- if (s->note_size < 0) {
- error_setg(errp, QERR_UNSUPPORTED);
- goto cleanup;
- }
-
- /*
- * The goal of this block is to (a) update the previously guessed
- * phys_base, (b) copy the guest note out of the guest.
- * Failure to do so is not fatal for dumping.
- */
- if (vmci) {
- uint64_t addr, note_head_size, name_size, desc_size;
- uint32_t size;
- uint16_t format;
-
- note_head_size = s->dump_info.d_class == ELFCLASS32 ?
- sizeof(Elf32_Nhdr) : sizeof(Elf64_Nhdr);
-
- format = le16_to_cpu(vmci->vmcoreinfo.guest_format);
- size = le32_to_cpu(vmci->vmcoreinfo.size);
- addr = le64_to_cpu(vmci->vmcoreinfo.paddr);
- if (!vmci->has_vmcoreinfo) {
- warn_report("guest note is not present");
- } else if (size < note_head_size || size > MAX_GUEST_NOTE_SIZE) {
- warn_report("guest note size is invalid: %" PRIu32, size);
- } else if (format != FW_CFG_VMCOREINFO_FORMAT_ELF) {
- warn_report("guest note format is unsupported: %" PRIu16, format);
- } else {
- s->guest_note = g_malloc(size + 1); /* +1 for adding \0 */
- cpu_physical_memory_read(addr, s->guest_note, size);
-
- get_note_sizes(s, s->guest_note, NULL, &name_size, &desc_size);
- s->guest_note_size = ELF_NOTE_SIZE(note_head_size, name_size,
- desc_size);
- if (name_size > MAX_GUEST_NOTE_SIZE ||
- desc_size > MAX_GUEST_NOTE_SIZE ||
- s->guest_note_size > size) {
- warn_report("Invalid guest note header");
- g_free(s->guest_note);
- s->guest_note = NULL;
- } else {
- vmcoreinfo_update_phys_base(s);
- s->note_size += s->guest_note_size;
- }
- }
- }
-
- /* get memory mapping */
- if (paging) {
- qemu_get_guest_memory_mapping(&s->list, &s->guest_phys_blocks, &err);
- if (err != NULL) {
- error_propagate(errp, err);
- goto cleanup;
- }
- } else {
- qemu_get_guest_simple_memory_mapping(&s->list, &s->guest_phys_blocks);
- }
-
- s->nr_cpus = nr_cpus;
-
- get_max_mapnr(s);
-
- uint64_t tmp;
- tmp = DIV_ROUND_UP(DIV_ROUND_UP(s->max_mapnr, CHAR_BIT),
- s->dump_info.page_size);
- s->len_dump_bitmap = tmp * s->dump_info.page_size;
-
- /* init for kdump-compressed format */
- if (has_format && format != DUMP_GUEST_MEMORY_FORMAT_ELF) {
- switch (format) {
- case DUMP_GUEST_MEMORY_FORMAT_KDUMP_ZLIB:
- s->flag_compress = DUMP_DH_COMPRESSED_ZLIB;
- break;
-
- case DUMP_GUEST_MEMORY_FORMAT_KDUMP_LZO:
-#ifdef CONFIG_LZO
- if (lzo_init() != LZO_E_OK) {
- error_setg(errp, "failed to initialize the LZO library");
- goto cleanup;
- }
-#endif
- s->flag_compress = DUMP_DH_COMPRESSED_LZO;
- break;
-
- case DUMP_GUEST_MEMORY_FORMAT_KDUMP_SNAPPY:
- s->flag_compress = DUMP_DH_COMPRESSED_SNAPPY;
- break;
-
- default:
- s->flag_compress = 0;
- }
-
- return;
- }
-
- if (s->has_filter) {
- memory_mapping_filter(&s->list, s->begin, s->length);
- }
-
- /*
- * calculate phdr_num
- *
- * the type of ehdr->e_phnum is uint16_t, so we should avoid overflow
- */
- s->phdr_num = 1; /* PT_NOTE */
- if (s->list.num < UINT16_MAX - 2) {
- s->phdr_num += s->list.num;
- s->have_section = false;
- } else {
- s->have_section = true;
- s->phdr_num = PN_XNUM;
- s->sh_info = 1; /* PT_NOTE */
-
- /* the type of shdr->sh_info is uint32_t, so we should avoid overflow */
- if (s->list.num <= UINT32_MAX - 1) {
- s->sh_info += s->list.num;
- } else {
- s->sh_info = UINT32_MAX;
- }
- }
-
- if (s->dump_info.d_class == ELFCLASS64) {
- if (s->have_section) {
- s->memory_offset = sizeof(Elf64_Ehdr) +
- sizeof(Elf64_Phdr) * s->sh_info +
- sizeof(Elf64_Shdr) + s->note_size;
- } else {
- s->memory_offset = sizeof(Elf64_Ehdr) +
- sizeof(Elf64_Phdr) * s->phdr_num + s->note_size;
- }
- } else {
- if (s->have_section) {
- s->memory_offset = sizeof(Elf32_Ehdr) +
- sizeof(Elf32_Phdr) * s->sh_info +
- sizeof(Elf32_Shdr) + s->note_size;
- } else {
- s->memory_offset = sizeof(Elf32_Ehdr) +
- sizeof(Elf32_Phdr) * s->phdr_num + s->note_size;
- }
- }
-
- return;
-
-cleanup:
- dump_cleanup(s);
-}
-
-/* this operation might be time consuming. */
-static void dump_process(DumpState *s, Error **errp)
-{
- Error *local_err = NULL;
- DumpQueryResult *result = NULL;
-
- if (s->has_format && s->format == DUMP_GUEST_MEMORY_FORMAT_WIN_DMP) {
-#ifdef TARGET_X86_64
- create_win_dump(s, &local_err);
-#endif
- } else if (s->has_format && s->format != DUMP_GUEST_MEMORY_FORMAT_ELF) {
- create_kdump_vmcore(s, &local_err);
- } else {
- create_vmcore(s, &local_err);
- }
-
- /* make sure status is written after written_size updates */
- smp_wmb();
- atomic_set(&s->status,
- (local_err ? DUMP_STATUS_FAILED : DUMP_STATUS_COMPLETED));
-
- /* send DUMP_COMPLETED message (unconditionally) */
- result = qmp_query_dump(NULL);
- /* should never fail */
- assert(result);
- qapi_event_send_dump_completed(result, !!local_err, (local_err ? \
- error_get_pretty(local_err) : NULL));
- qapi_free_DumpQueryResult(result);
-
- error_propagate(errp, local_err);
- dump_cleanup(s);
-}
-
-static void *dump_thread(void *data)
-{
- DumpState *s = (DumpState *)data;
- dump_process(s, NULL);
- return NULL;
-}
-
-DumpQueryResult *qmp_query_dump(Error **errp)
-{
- DumpQueryResult *result = g_new(DumpQueryResult, 1);
- DumpState *state = &dump_state_global;
- result->status = atomic_read(&state->status);
- /* make sure we are reading status and written_size in order */
- smp_rmb();
- result->completed = state->written_size;
- result->total = state->total_size;
- return result;
-}
-
-void qmp_dump_guest_memory(bool paging, const char *file,
- bool has_detach, bool detach,
- bool has_begin, int64_t begin, bool has_length,
- int64_t length, bool has_format,
- DumpGuestMemoryFormat format, Error **errp)
-{
- const char *p;
- int fd = -1;
- DumpState *s;
- Error *local_err = NULL;
- bool detach_p = false;
-
- if (runstate_check(RUN_STATE_INMIGRATE)) {
- error_setg(errp, "Dump not allowed during incoming migration.");
- return;
- }
-
- /* if there is a dump in background, we should wait until the dump
- * finished */
- if (dump_in_progress()) {
- error_setg(errp, "There is a dump in process, please wait.");
- return;
- }
-
- /*
- * kdump-compressed format need the whole memory dumped, so paging or
- * filter is not supported here.
- */
- if ((has_format && format != DUMP_GUEST_MEMORY_FORMAT_ELF) &&
- (paging || has_begin || has_length)) {
- error_setg(errp, "kdump-compressed format doesn't support paging or "
- "filter");
- return;
- }
- if (has_begin && !has_length) {
- error_setg(errp, QERR_MISSING_PARAMETER, "length");
- return;
- }
- if (!has_begin && has_length) {
- error_setg(errp, QERR_MISSING_PARAMETER, "begin");
- return;
- }
- if (has_detach) {
- detach_p = detach;
- }
-
- /* check whether lzo/snappy is supported */
-#ifndef CONFIG_LZO
- if (has_format && format == DUMP_GUEST_MEMORY_FORMAT_KDUMP_LZO) {
- error_setg(errp, "kdump-lzo is not available now");
- return;
- }
-#endif
-
-#ifndef CONFIG_SNAPPY
- if (has_format && format == DUMP_GUEST_MEMORY_FORMAT_KDUMP_SNAPPY) {
- error_setg(errp, "kdump-snappy is not available now");
- return;
- }
-#endif
-
-#ifndef TARGET_X86_64
- if (has_format && format == DUMP_GUEST_MEMORY_FORMAT_WIN_DMP) {
- error_setg(errp, "Windows dump is only available for x86-64");
- return;
- }
-#endif
-
-#if !defined(WIN32)
- if (strstart(file, "fd:", &p)) {
- fd = monitor_get_fd(cur_mon, p, errp);
- if (fd == -1) {
- return;
- }
- }
-#endif
-
- if (strstart(file, "file:", &p)) {
- fd = qemu_open(p, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, S_IRUSR);
- if (fd < 0) {
- error_setg_file_open(errp, errno, p);
- return;
- }
- }
-
- if (fd == -1) {
- error_setg(errp, QERR_INVALID_PARAMETER, "protocol");
- return;
- }
-
- s = &dump_state_global;
- dump_state_prepare(s);
-
- dump_init(s, fd, has_format, format, paging, has_begin,
- begin, length, &local_err);
- if (local_err) {
- error_propagate(errp, local_err);
- atomic_set(&s->status, DUMP_STATUS_FAILED);
- return;
- }
-
- if (detach_p) {
- /* detached dump */
- s->detached = true;
- qemu_thread_create(&s->dump_thread, "dump_thread", dump_thread,
- s, QEMU_THREAD_DETACHED);
- } else {
- /* sync dump */
- dump_process(s, errp);
- }
-}
-
-DumpGuestMemoryCapability *qmp_query_dump_guest_memory_capability(Error **errp)
-{
- DumpGuestMemoryFormatList *item;
- DumpGuestMemoryCapability *cap =
- g_malloc0(sizeof(DumpGuestMemoryCapability));
-
- /* elf is always available */
- item = g_malloc0(sizeof(DumpGuestMemoryFormatList));
- cap->formats = item;
- item->value = DUMP_GUEST_MEMORY_FORMAT_ELF;
-
- /* kdump-zlib is always available */
- item->next = g_malloc0(sizeof(DumpGuestMemoryFormatList));
- item = item->next;
- item->value = DUMP_GUEST_MEMORY_FORMAT_KDUMP_ZLIB;
-
- /* add new item if kdump-lzo is available */
-#ifdef CONFIG_LZO
- item->next = g_malloc0(sizeof(DumpGuestMemoryFormatList));
- item = item->next;
- item->value = DUMP_GUEST_MEMORY_FORMAT_KDUMP_LZO;
-#endif
-
- /* add new item if kdump-snappy is available */
-#ifdef CONFIG_SNAPPY
- item->next = g_malloc0(sizeof(DumpGuestMemoryFormatList));
- item = item->next;
- item->value = DUMP_GUEST_MEMORY_FORMAT_KDUMP_SNAPPY;
-#endif
-
- /* Windows dump is available only if target is x86_64 */
-#ifdef TARGET_X86_64
- item->next = g_malloc0(sizeof(DumpGuestMemoryFormatList));
- item = item->next;
- item->value = DUMP_GUEST_MEMORY_FORMAT_WIN_DMP;
-#endif
-
- return cap;
-}
--- /dev/null
+obj-y += dump.o
+common-obj-y += dump-hmp-cmds.o
+obj-$(TARGET_X86_64) += win_dump.o
--- /dev/null
+/*
+ * Human Monitor Interface commands
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include "qemu/osdep.h"
+#include "monitor/hmp.h"
+#include "monitor/monitor.h"
+#include "qapi/error.h"
+#include "qapi/qapi-commands-dump.h"
+#include "qapi/qmp/qdict.h"
+
+void hmp_dump_guest_memory(Monitor *mon, const QDict *qdict)
+{
+ Error *err = NULL;
+ bool win_dmp = qdict_get_try_bool(qdict, "windmp", false);
+ bool paging = qdict_get_try_bool(qdict, "paging", false);
+ bool zlib = qdict_get_try_bool(qdict, "zlib", false);
+ bool lzo = qdict_get_try_bool(qdict, "lzo", false);
+ bool snappy = qdict_get_try_bool(qdict, "snappy", false);
+ const char *file = qdict_get_str(qdict, "filename");
+ bool has_begin = qdict_haskey(qdict, "begin");
+ bool has_length = qdict_haskey(qdict, "length");
+ bool has_detach = qdict_haskey(qdict, "detach");
+ int64_t begin = 0;
+ int64_t length = 0;
+ bool detach = false;
+ enum DumpGuestMemoryFormat dump_format = DUMP_GUEST_MEMORY_FORMAT_ELF;
+ char *prot;
+
+ if (zlib + lzo + snappy + win_dmp > 1) {
+ error_setg(&err, "only one of '-z|-l|-s|-w' can be set");
+ hmp_handle_error(mon, &err);
+ return;
+ }
+
+ if (win_dmp) {
+ dump_format = DUMP_GUEST_MEMORY_FORMAT_WIN_DMP;
+ }
+
+ if (zlib) {
+ dump_format = DUMP_GUEST_MEMORY_FORMAT_KDUMP_ZLIB;
+ }
+
+ if (lzo) {
+ dump_format = DUMP_GUEST_MEMORY_FORMAT_KDUMP_LZO;
+ }
+
+ if (snappy) {
+ dump_format = DUMP_GUEST_MEMORY_FORMAT_KDUMP_SNAPPY;
+ }
+
+ if (has_begin) {
+ begin = qdict_get_int(qdict, "begin");
+ }
+ if (has_length) {
+ length = qdict_get_int(qdict, "length");
+ }
+ if (has_detach) {
+ detach = qdict_get_bool(qdict, "detach");
+ }
+
+ prot = g_strconcat("file:", file, NULL);
+
+ qmp_dump_guest_memory(paging, prot, true, detach, has_begin, begin,
+ has_length, length, true, dump_format, &err);
+ hmp_handle_error(mon, &err);
+ g_free(prot);
+}
+
+void hmp_info_dump(Monitor *mon, const QDict *qdict)
+{
+ DumpQueryResult *result = qmp_query_dump(NULL);
+
+ assert(result && result->status < DUMP_STATUS__MAX);
+ monitor_printf(mon, "Status: %s\n", DumpStatus_str(result->status));
+
+ if (result->status == DUMP_STATUS_ACTIVE) {
+ float percent = 0;
+ assert(result->total != 0);
+ percent = 100.0 * result->completed / result->total;
+ monitor_printf(mon, "Finished: %.2f %%\n", percent);
+ }
+
+ qapi_free_DumpQueryResult(result);
+}
--- /dev/null
+/*
+ * QEMU dump
+ *
+ * Copyright Fujitsu, Corp. 2011, 2012
+ *
+ * Authors:
+ * Wen Congyang <wency@cn.fujitsu.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.
+ *
+ */
+
+#include "qemu/osdep.h"
+#include "qemu-common.h"
+#include "qemu/cutils.h"
+#include "elf.h"
+#include "cpu.h"
+#include "exec/hwaddr.h"
+#include "monitor/monitor.h"
+#include "sysemu/kvm.h"
+#include "sysemu/dump.h"
+#include "sysemu/sysemu.h"
+#include "sysemu/memory_mapping.h"
+#include "sysemu/cpus.h"
+#include "qapi/error.h"
+#include "qapi/qapi-commands-dump.h"
+#include "qapi/qapi-events-dump.h"
+#include "qapi/qmp/qerror.h"
+#include "qemu/error-report.h"
+#include "hw/misc/vmcoreinfo.h"
+
+#ifdef TARGET_X86_64
+#include "win_dump.h"
+#endif
+
+#include <zlib.h>
+#ifdef CONFIG_LZO
+#include <lzo/lzo1x.h>
+#endif
+#ifdef CONFIG_SNAPPY
+#include <snappy-c.h>
+#endif
+#ifndef ELF_MACHINE_UNAME
+#define ELF_MACHINE_UNAME "Unknown"
+#endif
+
+#define MAX_GUEST_NOTE_SIZE (1 << 20) /* 1MB should be enough */
+
+#define ELF_NOTE_SIZE(hdr_size, name_size, desc_size) \
+ ((DIV_ROUND_UP((hdr_size), 4) + \
+ DIV_ROUND_UP((name_size), 4) + \
+ DIV_ROUND_UP((desc_size), 4)) * 4)
+
+uint16_t cpu_to_dump16(DumpState *s, uint16_t val)
+{
+ if (s->dump_info.d_endian == ELFDATA2LSB) {
+ val = cpu_to_le16(val);
+ } else {
+ val = cpu_to_be16(val);
+ }
+
+ return val;
+}
+
+uint32_t cpu_to_dump32(DumpState *s, uint32_t val)
+{
+ if (s->dump_info.d_endian == ELFDATA2LSB) {
+ val = cpu_to_le32(val);
+ } else {
+ val = cpu_to_be32(val);
+ }
+
+ return val;
+}
+
+uint64_t cpu_to_dump64(DumpState *s, uint64_t val)
+{
+ if (s->dump_info.d_endian == ELFDATA2LSB) {
+ val = cpu_to_le64(val);
+ } else {
+ val = cpu_to_be64(val);
+ }
+
+ return val;
+}
+
+static int dump_cleanup(DumpState *s)
+{
+ guest_phys_blocks_free(&s->guest_phys_blocks);
+ memory_mapping_list_free(&s->list);
+ close(s->fd);
+ g_free(s->guest_note);
+ s->guest_note = NULL;
+ if (s->resume) {
+ if (s->detached) {
+ qemu_mutex_lock_iothread();
+ }
+ vm_start();
+ if (s->detached) {
+ qemu_mutex_unlock_iothread();
+ }
+ }
+
+ return 0;
+}
+
+static int fd_write_vmcore(const void *buf, size_t size, void *opaque)
+{
+ DumpState *s = opaque;
+ size_t written_size;
+
+ written_size = qemu_write_full(s->fd, buf, size);
+ if (written_size != size) {
+ return -errno;
+ }
+
+ return 0;
+}
+
+static void write_elf64_header(DumpState *s, Error **errp)
+{
+ Elf64_Ehdr elf_header;
+ int ret;
+
+ memset(&elf_header, 0, sizeof(Elf64_Ehdr));
+ memcpy(&elf_header, ELFMAG, SELFMAG);
+ elf_header.e_ident[EI_CLASS] = ELFCLASS64;
+ elf_header.e_ident[EI_DATA] = s->dump_info.d_endian;
+ elf_header.e_ident[EI_VERSION] = EV_CURRENT;
+ elf_header.e_type = cpu_to_dump16(s, ET_CORE);
+ elf_header.e_machine = cpu_to_dump16(s, s->dump_info.d_machine);
+ elf_header.e_version = cpu_to_dump32(s, EV_CURRENT);
+ elf_header.e_ehsize = cpu_to_dump16(s, sizeof(elf_header));
+ elf_header.e_phoff = cpu_to_dump64(s, sizeof(Elf64_Ehdr));
+ elf_header.e_phentsize = cpu_to_dump16(s, sizeof(Elf64_Phdr));
+ elf_header.e_phnum = cpu_to_dump16(s, s->phdr_num);
+ if (s->have_section) {
+ uint64_t shoff = sizeof(Elf64_Ehdr) + sizeof(Elf64_Phdr) * s->sh_info;
+
+ elf_header.e_shoff = cpu_to_dump64(s, shoff);
+ elf_header.e_shentsize = cpu_to_dump16(s, sizeof(Elf64_Shdr));
+ elf_header.e_shnum = cpu_to_dump16(s, 1);
+ }
+
+ ret = fd_write_vmcore(&elf_header, sizeof(elf_header), s);
+ if (ret < 0) {
+ error_setg_errno(errp, -ret, "dump: failed to write elf header");
+ }
+}
+
+static void write_elf32_header(DumpState *s, Error **errp)
+{
+ Elf32_Ehdr elf_header;
+ int ret;
+
+ memset(&elf_header, 0, sizeof(Elf32_Ehdr));
+ memcpy(&elf_header, ELFMAG, SELFMAG);
+ elf_header.e_ident[EI_CLASS] = ELFCLASS32;
+ elf_header.e_ident[EI_DATA] = s->dump_info.d_endian;
+ elf_header.e_ident[EI_VERSION] = EV_CURRENT;
+ elf_header.e_type = cpu_to_dump16(s, ET_CORE);
+ elf_header.e_machine = cpu_to_dump16(s, s->dump_info.d_machine);
+ elf_header.e_version = cpu_to_dump32(s, EV_CURRENT);
+ elf_header.e_ehsize = cpu_to_dump16(s, sizeof(elf_header));
+ elf_header.e_phoff = cpu_to_dump32(s, sizeof(Elf32_Ehdr));
+ elf_header.e_phentsize = cpu_to_dump16(s, sizeof(Elf32_Phdr));
+ elf_header.e_phnum = cpu_to_dump16(s, s->phdr_num);
+ if (s->have_section) {
+ uint32_t shoff = sizeof(Elf32_Ehdr) + sizeof(Elf32_Phdr) * s->sh_info;
+
+ elf_header.e_shoff = cpu_to_dump32(s, shoff);
+ elf_header.e_shentsize = cpu_to_dump16(s, sizeof(Elf32_Shdr));
+ elf_header.e_shnum = cpu_to_dump16(s, 1);
+ }
+
+ ret = fd_write_vmcore(&elf_header, sizeof(elf_header), s);
+ if (ret < 0) {
+ error_setg_errno(errp, -ret, "dump: failed to write elf header");
+ }
+}
+
+static void write_elf64_load(DumpState *s, MemoryMapping *memory_mapping,
+ int phdr_index, hwaddr offset,
+ hwaddr filesz, Error **errp)
+{
+ Elf64_Phdr phdr;
+ int ret;
+
+ memset(&phdr, 0, sizeof(Elf64_Phdr));
+ phdr.p_type = cpu_to_dump32(s, PT_LOAD);
+ phdr.p_offset = cpu_to_dump64(s, offset);
+ phdr.p_paddr = cpu_to_dump64(s, memory_mapping->phys_addr);
+ phdr.p_filesz = cpu_to_dump64(s, filesz);
+ phdr.p_memsz = cpu_to_dump64(s, memory_mapping->length);
+ phdr.p_vaddr = cpu_to_dump64(s, memory_mapping->virt_addr) ?: phdr.p_paddr;
+
+ assert(memory_mapping->length >= filesz);
+
+ ret = fd_write_vmcore(&phdr, sizeof(Elf64_Phdr), s);
+ if (ret < 0) {
+ error_setg_errno(errp, -ret,
+ "dump: failed to write program header table");
+ }
+}
+
+static void write_elf32_load(DumpState *s, MemoryMapping *memory_mapping,
+ int phdr_index, hwaddr offset,
+ hwaddr filesz, Error **errp)
+{
+ Elf32_Phdr phdr;
+ int ret;
+
+ memset(&phdr, 0, sizeof(Elf32_Phdr));
+ phdr.p_type = cpu_to_dump32(s, PT_LOAD);
+ phdr.p_offset = cpu_to_dump32(s, offset);
+ phdr.p_paddr = cpu_to_dump32(s, memory_mapping->phys_addr);
+ phdr.p_filesz = cpu_to_dump32(s, filesz);
+ phdr.p_memsz = cpu_to_dump32(s, memory_mapping->length);
+ phdr.p_vaddr =
+ cpu_to_dump32(s, memory_mapping->virt_addr) ?: phdr.p_paddr;
+
+ assert(memory_mapping->length >= filesz);
+
+ ret = fd_write_vmcore(&phdr, sizeof(Elf32_Phdr), s);
+ if (ret < 0) {
+ error_setg_errno(errp, -ret,
+ "dump: failed to write program header table");
+ }
+}
+
+static void write_elf64_note(DumpState *s, Error **errp)
+{
+ Elf64_Phdr phdr;
+ hwaddr begin = s->memory_offset - s->note_size;
+ int ret;
+
+ memset(&phdr, 0, sizeof(Elf64_Phdr));
+ phdr.p_type = cpu_to_dump32(s, PT_NOTE);
+ phdr.p_offset = cpu_to_dump64(s, begin);
+ phdr.p_paddr = 0;
+ phdr.p_filesz = cpu_to_dump64(s, s->note_size);
+ phdr.p_memsz = cpu_to_dump64(s, s->note_size);
+ phdr.p_vaddr = 0;
+
+ ret = fd_write_vmcore(&phdr, sizeof(Elf64_Phdr), s);
+ if (ret < 0) {
+ error_setg_errno(errp, -ret,
+ "dump: failed to write program header table");
+ }
+}
+
+static inline int cpu_index(CPUState *cpu)
+{
+ return cpu->cpu_index + 1;
+}
+
+static void write_guest_note(WriteCoreDumpFunction f, DumpState *s,
+ Error **errp)
+{
+ int ret;
+
+ if (s->guest_note) {
+ ret = f(s->guest_note, s->guest_note_size, s);
+ if (ret < 0) {
+ error_setg(errp, "dump: failed to write guest note");
+ }
+ }
+}
+
+static void write_elf64_notes(WriteCoreDumpFunction f, DumpState *s,
+ Error **errp)
+{
+ CPUState *cpu;
+ int ret;
+ int id;
+
+ CPU_FOREACH(cpu) {
+ id = cpu_index(cpu);
+ ret = cpu_write_elf64_note(f, cpu, id, s);
+ if (ret < 0) {
+ error_setg(errp, "dump: failed to write elf notes");
+ return;
+ }
+ }
+
+ CPU_FOREACH(cpu) {
+ ret = cpu_write_elf64_qemunote(f, cpu, s);
+ if (ret < 0) {
+ error_setg(errp, "dump: failed to write CPU status");
+ return;
+ }
+ }
+
+ write_guest_note(f, s, errp);
+}
+
+static void write_elf32_note(DumpState *s, Error **errp)
+{
+ hwaddr begin = s->memory_offset - s->note_size;
+ Elf32_Phdr phdr;
+ int ret;
+
+ memset(&phdr, 0, sizeof(Elf32_Phdr));
+ phdr.p_type = cpu_to_dump32(s, PT_NOTE);
+ phdr.p_offset = cpu_to_dump32(s, begin);
+ phdr.p_paddr = 0;
+ phdr.p_filesz = cpu_to_dump32(s, s->note_size);
+ phdr.p_memsz = cpu_to_dump32(s, s->note_size);
+ phdr.p_vaddr = 0;
+
+ ret = fd_write_vmcore(&phdr, sizeof(Elf32_Phdr), s);
+ if (ret < 0) {
+ error_setg_errno(errp, -ret,
+ "dump: failed to write program header table");
+ }
+}
+
+static void write_elf32_notes(WriteCoreDumpFunction f, DumpState *s,
+ Error **errp)
+{
+ CPUState *cpu;
+ int ret;
+ int id;
+
+ CPU_FOREACH(cpu) {
+ id = cpu_index(cpu);
+ ret = cpu_write_elf32_note(f, cpu, id, s);
+ if (ret < 0) {
+ error_setg(errp, "dump: failed to write elf notes");
+ return;
+ }
+ }
+
+ CPU_FOREACH(cpu) {
+ ret = cpu_write_elf32_qemunote(f, cpu, s);
+ if (ret < 0) {
+ error_setg(errp, "dump: failed to write CPU status");
+ return;
+ }
+ }
+
+ write_guest_note(f, s, errp);
+}
+
+static void write_elf_section(DumpState *s, int type, Error **errp)
+{
+ Elf32_Shdr shdr32;
+ Elf64_Shdr shdr64;
+ int shdr_size;
+ void *shdr;
+ int ret;
+
+ if (type == 0) {
+ shdr_size = sizeof(Elf32_Shdr);
+ memset(&shdr32, 0, shdr_size);
+ shdr32.sh_info = cpu_to_dump32(s, s->sh_info);
+ shdr = &shdr32;
+ } else {
+ shdr_size = sizeof(Elf64_Shdr);
+ memset(&shdr64, 0, shdr_size);
+ shdr64.sh_info = cpu_to_dump32(s, s->sh_info);
+ shdr = &shdr64;
+ }
+
+ ret = fd_write_vmcore(&shdr, shdr_size, s);
+ if (ret < 0) {
+ error_setg_errno(errp, -ret,
+ "dump: failed to write section header table");
+ }
+}
+
+static void write_data(DumpState *s, void *buf, int length, Error **errp)
+{
+ int ret;
+
+ ret = fd_write_vmcore(buf, length, s);
+ if (ret < 0) {
+ error_setg_errno(errp, -ret, "dump: failed to save memory");
+ } else {
+ s->written_size += length;
+ }
+}
+
+/* write the memory to vmcore. 1 page per I/O. */
+static void write_memory(DumpState *s, GuestPhysBlock *block, ram_addr_t start,
+ int64_t size, Error **errp)
+{
+ int64_t i;
+ Error *local_err = NULL;
+
+ for (i = 0; i < size / s->dump_info.page_size; i++) {
+ write_data(s, block->host_addr + start + i * s->dump_info.page_size,
+ s->dump_info.page_size, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ return;
+ }
+ }
+
+ if ((size % s->dump_info.page_size) != 0) {
+ write_data(s, block->host_addr + start + i * s->dump_info.page_size,
+ size % s->dump_info.page_size, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ return;
+ }
+ }
+}
+
+/* get the memory's offset and size in the vmcore */
+static void get_offset_range(hwaddr phys_addr,
+ ram_addr_t mapping_length,
+ DumpState *s,
+ hwaddr *p_offset,
+ hwaddr *p_filesz)
+{
+ GuestPhysBlock *block;
+ hwaddr offset = s->memory_offset;
+ int64_t size_in_block, start;
+
+ /* When the memory is not stored into vmcore, offset will be -1 */
+ *p_offset = -1;
+ *p_filesz = 0;
+
+ if (s->has_filter) {
+ if (phys_addr < s->begin || phys_addr >= s->begin + s->length) {
+ return;
+ }
+ }
+
+ QTAILQ_FOREACH(block, &s->guest_phys_blocks.head, next) {
+ if (s->has_filter) {
+ if (block->target_start >= s->begin + s->length ||
+ block->target_end <= s->begin) {
+ /* This block is out of the range */
+ continue;
+ }
+
+ if (s->begin <= block->target_start) {
+ start = block->target_start;
+ } else {
+ start = s->begin;
+ }
+
+ size_in_block = block->target_end - start;
+ if (s->begin + s->length < block->target_end) {
+ size_in_block -= block->target_end - (s->begin + s->length);
+ }
+ } else {
+ start = block->target_start;
+ size_in_block = block->target_end - block->target_start;
+ }
+
+ if (phys_addr >= start && phys_addr < start + size_in_block) {
+ *p_offset = phys_addr - start + offset;
+
+ /* The offset range mapped from the vmcore file must not spill over
+ * the GuestPhysBlock, clamp it. The rest of the mapping will be
+ * zero-filled in memory at load time; see
+ * <http://refspecs.linuxbase.org/elf/gabi4+/ch5.pheader.html>.
+ */
+ *p_filesz = phys_addr + mapping_length <= start + size_in_block ?
+ mapping_length :
+ size_in_block - (phys_addr - start);
+ return;
+ }
+
+ offset += size_in_block;
+ }
+}
+
+static void write_elf_loads(DumpState *s, Error **errp)
+{
+ hwaddr offset, filesz;
+ MemoryMapping *memory_mapping;
+ uint32_t phdr_index = 1;
+ uint32_t max_index;
+ Error *local_err = NULL;
+
+ if (s->have_section) {
+ max_index = s->sh_info;
+ } else {
+ max_index = s->phdr_num;
+ }
+
+ QTAILQ_FOREACH(memory_mapping, &s->list.head, next) {
+ get_offset_range(memory_mapping->phys_addr,
+ memory_mapping->length,
+ s, &offset, &filesz);
+ if (s->dump_info.d_class == ELFCLASS64) {
+ write_elf64_load(s, memory_mapping, phdr_index++, offset,
+ filesz, &local_err);
+ } else {
+ write_elf32_load(s, memory_mapping, phdr_index++, offset,
+ filesz, &local_err);
+ }
+
+ if (local_err) {
+ error_propagate(errp, local_err);
+ return;
+ }
+
+ if (phdr_index >= max_index) {
+ break;
+ }
+ }
+}
+
+/* write elf header, PT_NOTE and elf note to vmcore. */
+static void dump_begin(DumpState *s, Error **errp)
+{
+ Error *local_err = NULL;
+
+ /*
+ * the vmcore's format is:
+ * --------------
+ * | elf header |
+ * --------------
+ * | PT_NOTE |
+ * --------------
+ * | PT_LOAD |
+ * --------------
+ * | ...... |
+ * --------------
+ * | PT_LOAD |
+ * --------------
+ * | sec_hdr |
+ * --------------
+ * | elf note |
+ * --------------
+ * | memory |
+ * --------------
+ *
+ * we only know where the memory is saved after we write elf note into
+ * vmcore.
+ */
+
+ /* write elf header to vmcore */
+ if (s->dump_info.d_class == ELFCLASS64) {
+ write_elf64_header(s, &local_err);
+ } else {
+ write_elf32_header(s, &local_err);
+ }
+ if (local_err) {
+ error_propagate(errp, local_err);
+ return;
+ }
+
+ if (s->dump_info.d_class == ELFCLASS64) {
+ /* write PT_NOTE to vmcore */
+ write_elf64_note(s, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ return;
+ }
+
+ /* write all PT_LOAD to vmcore */
+ write_elf_loads(s, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ return;
+ }
+
+ /* write section to vmcore */
+ if (s->have_section) {
+ write_elf_section(s, 1, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ return;
+ }
+ }
+
+ /* write notes to vmcore */
+ write_elf64_notes(fd_write_vmcore, s, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ return;
+ }
+ } else {
+ /* write PT_NOTE to vmcore */
+ write_elf32_note(s, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ return;
+ }
+
+ /* write all PT_LOAD to vmcore */
+ write_elf_loads(s, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ return;
+ }
+
+ /* write section to vmcore */
+ if (s->have_section) {
+ write_elf_section(s, 0, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ return;
+ }
+ }
+
+ /* write notes to vmcore */
+ write_elf32_notes(fd_write_vmcore, s, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ return;
+ }
+ }
+}
+
+static int get_next_block(DumpState *s, GuestPhysBlock *block)
+{
+ while (1) {
+ block = QTAILQ_NEXT(block, next);
+ if (!block) {
+ /* no more block */
+ return 1;
+ }
+
+ s->start = 0;
+ s->next_block = block;
+ if (s->has_filter) {
+ if (block->target_start >= s->begin + s->length ||
+ block->target_end <= s->begin) {
+ /* This block is out of the range */
+ continue;
+ }
+
+ if (s->begin > block->target_start) {
+ s->start = s->begin - block->target_start;
+ }
+ }
+
+ return 0;
+ }
+}
+
+/* write all memory to vmcore */
+static void dump_iterate(DumpState *s, Error **errp)
+{
+ GuestPhysBlock *block;
+ int64_t size;
+ Error *local_err = NULL;
+
+ do {
+ block = s->next_block;
+
+ size = block->target_end - block->target_start;
+ if (s->has_filter) {
+ size -= s->start;
+ if (s->begin + s->length < block->target_end) {
+ size -= block->target_end - (s->begin + s->length);
+ }
+ }
+ write_memory(s, block, s->start, size, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ return;
+ }
+
+ } while (!get_next_block(s, block));
+}
+
+static void create_vmcore(DumpState *s, Error **errp)
+{
+ Error *local_err = NULL;
+
+ dump_begin(s, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ return;
+ }
+
+ dump_iterate(s, errp);
+}
+
+static int write_start_flat_header(int fd)
+{
+ MakedumpfileHeader *mh;
+ int ret = 0;
+
+ QEMU_BUILD_BUG_ON(sizeof *mh > MAX_SIZE_MDF_HEADER);
+ mh = g_malloc0(MAX_SIZE_MDF_HEADER);
+
+ memcpy(mh->signature, MAKEDUMPFILE_SIGNATURE,
+ MIN(sizeof mh->signature, sizeof MAKEDUMPFILE_SIGNATURE));
+
+ mh->type = cpu_to_be64(TYPE_FLAT_HEADER);
+ mh->version = cpu_to_be64(VERSION_FLAT_HEADER);
+
+ size_t written_size;
+ written_size = qemu_write_full(fd, mh, MAX_SIZE_MDF_HEADER);
+ if (written_size != MAX_SIZE_MDF_HEADER) {
+ ret = -1;
+ }
+
+ g_free(mh);
+ return ret;
+}
+
+static int write_end_flat_header(int fd)
+{
+ MakedumpfileDataHeader mdh;
+
+ mdh.offset = END_FLAG_FLAT_HEADER;
+ mdh.buf_size = END_FLAG_FLAT_HEADER;
+
+ size_t written_size;
+ written_size = qemu_write_full(fd, &mdh, sizeof(mdh));
+ if (written_size != sizeof(mdh)) {
+ return -1;
+ }
+
+ return 0;
+}
+
+static int write_buffer(int fd, off_t offset, const void *buf, size_t size)
+{
+ size_t written_size;
+ MakedumpfileDataHeader mdh;
+
+ mdh.offset = cpu_to_be64(offset);
+ mdh.buf_size = cpu_to_be64(size);
+
+ written_size = qemu_write_full(fd, &mdh, sizeof(mdh));
+ if (written_size != sizeof(mdh)) {
+ return -1;
+ }
+
+ written_size = qemu_write_full(fd, buf, size);
+ if (written_size != size) {
+ return -1;
+ }
+
+ return 0;
+}
+
+static int buf_write_note(const void *buf, size_t size, void *opaque)
+{
+ DumpState *s = opaque;
+
+ /* note_buf is not enough */
+ if (s->note_buf_offset + size > s->note_size) {
+ return -1;
+ }
+
+ memcpy(s->note_buf + s->note_buf_offset, buf, size);
+
+ s->note_buf_offset += size;
+
+ return 0;
+}
+
+/*
+ * This function retrieves various sizes from an elf header.
+ *
+ * @note has to be a valid ELF note. The return sizes are unmodified
+ * (not padded or rounded up to be multiple of 4).
+ */
+static void get_note_sizes(DumpState *s, const void *note,
+ uint64_t *note_head_size,
+ uint64_t *name_size,
+ uint64_t *desc_size)
+{
+ uint64_t note_head_sz;
+ uint64_t name_sz;
+ uint64_t desc_sz;
+
+ if (s->dump_info.d_class == ELFCLASS64) {
+ const Elf64_Nhdr *hdr = note;
+ note_head_sz = sizeof(Elf64_Nhdr);
+ name_sz = tswap64(hdr->n_namesz);
+ desc_sz = tswap64(hdr->n_descsz);
+ } else {
+ const Elf32_Nhdr *hdr = note;
+ note_head_sz = sizeof(Elf32_Nhdr);
+ name_sz = tswap32(hdr->n_namesz);
+ desc_sz = tswap32(hdr->n_descsz);
+ }
+
+ if (note_head_size) {
+ *note_head_size = note_head_sz;
+ }
+ if (name_size) {
+ *name_size = name_sz;
+ }
+ if (desc_size) {
+ *desc_size = desc_sz;
+ }
+}
+
+static bool note_name_equal(DumpState *s,
+ const uint8_t *note, const char *name)
+{
+ int len = strlen(name) + 1;
+ uint64_t head_size, name_size;
+
+ get_note_sizes(s, note, &head_size, &name_size, NULL);
+ head_size = ROUND_UP(head_size, 4);
+
+ return name_size == len && memcmp(note + head_size, name, len) == 0;
+}
+
+/* write common header, sub header and elf note to vmcore */
+static void create_header32(DumpState *s, Error **errp)
+{
+ DiskDumpHeader32 *dh = NULL;
+ KdumpSubHeader32 *kh = NULL;
+ size_t size;
+ uint32_t block_size;
+ uint32_t sub_hdr_size;
+ uint32_t bitmap_blocks;
+ uint32_t status = 0;
+ uint64_t offset_note;
+ Error *local_err = NULL;
+
+ /* write common header, the version of kdump-compressed format is 6th */
+ size = sizeof(DiskDumpHeader32);
+ dh = g_malloc0(size);
+
+ memcpy(dh->signature, KDUMP_SIGNATURE, SIG_LEN);
+ dh->header_version = cpu_to_dump32(s, 6);
+ block_size = s->dump_info.page_size;
+ dh->block_size = cpu_to_dump32(s, block_size);
+ sub_hdr_size = sizeof(struct KdumpSubHeader32) + s->note_size;
+ sub_hdr_size = DIV_ROUND_UP(sub_hdr_size, block_size);
+ dh->sub_hdr_size = cpu_to_dump32(s, sub_hdr_size);
+ /* dh->max_mapnr may be truncated, full 64bit is in kh.max_mapnr_64 */
+ dh->max_mapnr = cpu_to_dump32(s, MIN(s->max_mapnr, UINT_MAX));
+ dh->nr_cpus = cpu_to_dump32(s, s->nr_cpus);
+ bitmap_blocks = DIV_ROUND_UP(s->len_dump_bitmap, block_size) * 2;
+ dh->bitmap_blocks = cpu_to_dump32(s, bitmap_blocks);
+ strncpy(dh->utsname.machine, ELF_MACHINE_UNAME, sizeof(dh->utsname.machine));
+
+ if (s->flag_compress & DUMP_DH_COMPRESSED_ZLIB) {
+ status |= DUMP_DH_COMPRESSED_ZLIB;
+ }
+#ifdef CONFIG_LZO
+ if (s->flag_compress & DUMP_DH_COMPRESSED_LZO) {
+ status |= DUMP_DH_COMPRESSED_LZO;
+ }
+#endif
+#ifdef CONFIG_SNAPPY
+ if (s->flag_compress & DUMP_DH_COMPRESSED_SNAPPY) {
+ status |= DUMP_DH_COMPRESSED_SNAPPY;
+ }
+#endif
+ dh->status = cpu_to_dump32(s, status);
+
+ if (write_buffer(s->fd, 0, dh, size) < 0) {
+ error_setg(errp, "dump: failed to write disk dump header");
+ goto out;
+ }
+
+ /* write sub header */
+ size = sizeof(KdumpSubHeader32);
+ kh = g_malloc0(size);
+
+ /* 64bit max_mapnr_64 */
+ kh->max_mapnr_64 = cpu_to_dump64(s, s->max_mapnr);
+ kh->phys_base = cpu_to_dump32(s, s->dump_info.phys_base);
+ kh->dump_level = cpu_to_dump32(s, DUMP_LEVEL);
+
+ offset_note = DISKDUMP_HEADER_BLOCKS * block_size + size;
+ if (s->guest_note &&
+ note_name_equal(s, s->guest_note, "VMCOREINFO")) {
+ uint64_t hsize, name_size, size_vmcoreinfo_desc, offset_vmcoreinfo;
+
+ get_note_sizes(s, s->guest_note,
+ &hsize, &name_size, &size_vmcoreinfo_desc);
+ offset_vmcoreinfo = offset_note + s->note_size - s->guest_note_size +
+ (DIV_ROUND_UP(hsize, 4) + DIV_ROUND_UP(name_size, 4)) * 4;
+ kh->offset_vmcoreinfo = cpu_to_dump64(s, offset_vmcoreinfo);
+ kh->size_vmcoreinfo = cpu_to_dump32(s, size_vmcoreinfo_desc);
+ }
+
+ kh->offset_note = cpu_to_dump64(s, offset_note);
+ kh->note_size = cpu_to_dump32(s, s->note_size);
+
+ if (write_buffer(s->fd, DISKDUMP_HEADER_BLOCKS *
+ block_size, kh, size) < 0) {
+ error_setg(errp, "dump: failed to write kdump sub header");
+ goto out;
+ }
+
+ /* write note */
+ s->note_buf = g_malloc0(s->note_size);
+ s->note_buf_offset = 0;
+
+ /* use s->note_buf to store notes temporarily */
+ write_elf32_notes(buf_write_note, s, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ goto out;
+ }
+ if (write_buffer(s->fd, offset_note, s->note_buf,
+ s->note_size) < 0) {
+ error_setg(errp, "dump: failed to write notes");
+ goto out;
+ }
+
+ /* get offset of dump_bitmap */
+ s->offset_dump_bitmap = (DISKDUMP_HEADER_BLOCKS + sub_hdr_size) *
+ block_size;
+
+ /* get offset of page */
+ s->offset_page = (DISKDUMP_HEADER_BLOCKS + sub_hdr_size + bitmap_blocks) *
+ block_size;
+
+out:
+ g_free(dh);
+ g_free(kh);
+ g_free(s->note_buf);
+}
+
+/* write common header, sub header and elf note to vmcore */
+static void create_header64(DumpState *s, Error **errp)
+{
+ DiskDumpHeader64 *dh = NULL;
+ KdumpSubHeader64 *kh = NULL;
+ size_t size;
+ uint32_t block_size;
+ uint32_t sub_hdr_size;
+ uint32_t bitmap_blocks;
+ uint32_t status = 0;
+ uint64_t offset_note;
+ Error *local_err = NULL;
+
+ /* write common header, the version of kdump-compressed format is 6th */
+ size = sizeof(DiskDumpHeader64);
+ dh = g_malloc0(size);
+
+ memcpy(dh->signature, KDUMP_SIGNATURE, SIG_LEN);
+ dh->header_version = cpu_to_dump32(s, 6);
+ block_size = s->dump_info.page_size;
+ dh->block_size = cpu_to_dump32(s, block_size);
+ sub_hdr_size = sizeof(struct KdumpSubHeader64) + s->note_size;
+ sub_hdr_size = DIV_ROUND_UP(sub_hdr_size, block_size);
+ dh->sub_hdr_size = cpu_to_dump32(s, sub_hdr_size);
+ /* dh->max_mapnr may be truncated, full 64bit is in kh.max_mapnr_64 */
+ dh->max_mapnr = cpu_to_dump32(s, MIN(s->max_mapnr, UINT_MAX));
+ dh->nr_cpus = cpu_to_dump32(s, s->nr_cpus);
+ bitmap_blocks = DIV_ROUND_UP(s->len_dump_bitmap, block_size) * 2;
+ dh->bitmap_blocks = cpu_to_dump32(s, bitmap_blocks);
+ strncpy(dh->utsname.machine, ELF_MACHINE_UNAME, sizeof(dh->utsname.machine));
+
+ if (s->flag_compress & DUMP_DH_COMPRESSED_ZLIB) {
+ status |= DUMP_DH_COMPRESSED_ZLIB;
+ }
+#ifdef CONFIG_LZO
+ if (s->flag_compress & DUMP_DH_COMPRESSED_LZO) {
+ status |= DUMP_DH_COMPRESSED_LZO;
+ }
+#endif
+#ifdef CONFIG_SNAPPY
+ if (s->flag_compress & DUMP_DH_COMPRESSED_SNAPPY) {
+ status |= DUMP_DH_COMPRESSED_SNAPPY;
+ }
+#endif
+ dh->status = cpu_to_dump32(s, status);
+
+ if (write_buffer(s->fd, 0, dh, size) < 0) {
+ error_setg(errp, "dump: failed to write disk dump header");
+ goto out;
+ }
+
+ /* write sub header */
+ size = sizeof(KdumpSubHeader64);
+ kh = g_malloc0(size);
+
+ /* 64bit max_mapnr_64 */
+ kh->max_mapnr_64 = cpu_to_dump64(s, s->max_mapnr);
+ kh->phys_base = cpu_to_dump64(s, s->dump_info.phys_base);
+ kh->dump_level = cpu_to_dump32(s, DUMP_LEVEL);
+
+ offset_note = DISKDUMP_HEADER_BLOCKS * block_size + size;
+ if (s->guest_note &&
+ note_name_equal(s, s->guest_note, "VMCOREINFO")) {
+ uint64_t hsize, name_size, size_vmcoreinfo_desc, offset_vmcoreinfo;
+
+ get_note_sizes(s, s->guest_note,
+ &hsize, &name_size, &size_vmcoreinfo_desc);
+ offset_vmcoreinfo = offset_note + s->note_size - s->guest_note_size +
+ (DIV_ROUND_UP(hsize, 4) + DIV_ROUND_UP(name_size, 4)) * 4;
+ kh->offset_vmcoreinfo = cpu_to_dump64(s, offset_vmcoreinfo);
+ kh->size_vmcoreinfo = cpu_to_dump64(s, size_vmcoreinfo_desc);
+ }
+
+ kh->offset_note = cpu_to_dump64(s, offset_note);
+ kh->note_size = cpu_to_dump64(s, s->note_size);
+
+ if (write_buffer(s->fd, DISKDUMP_HEADER_BLOCKS *
+ block_size, kh, size) < 0) {
+ error_setg(errp, "dump: failed to write kdump sub header");
+ goto out;
+ }
+
+ /* write note */
+ s->note_buf = g_malloc0(s->note_size);
+ s->note_buf_offset = 0;
+
+ /* use s->note_buf to store notes temporarily */
+ write_elf64_notes(buf_write_note, s, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ goto out;
+ }
+
+ if (write_buffer(s->fd, offset_note, s->note_buf,
+ s->note_size) < 0) {
+ error_setg(errp, "dump: failed to write notes");
+ goto out;
+ }
+
+ /* get offset of dump_bitmap */
+ s->offset_dump_bitmap = (DISKDUMP_HEADER_BLOCKS + sub_hdr_size) *
+ block_size;
+
+ /* get offset of page */
+ s->offset_page = (DISKDUMP_HEADER_BLOCKS + sub_hdr_size + bitmap_blocks) *
+ block_size;
+
+out:
+ g_free(dh);
+ g_free(kh);
+ g_free(s->note_buf);
+}
+
+static void write_dump_header(DumpState *s, Error **errp)
+{
+ Error *local_err = NULL;
+
+ if (s->dump_info.d_class == ELFCLASS32) {
+ create_header32(s, &local_err);
+ } else {
+ create_header64(s, &local_err);
+ }
+ error_propagate(errp, local_err);
+}
+
+static size_t dump_bitmap_get_bufsize(DumpState *s)
+{
+ return s->dump_info.page_size;
+}
+
+/*
+ * set dump_bitmap sequencely. the bit before last_pfn is not allowed to be
+ * rewritten, so if need to set the first bit, set last_pfn and pfn to 0.
+ * set_dump_bitmap will always leave the recently set bit un-sync. And setting
+ * (last bit + sizeof(buf) * 8) to 0 will do flushing the content in buf into
+ * vmcore, ie. synchronizing un-sync bit into vmcore.
+ */
+static int set_dump_bitmap(uint64_t last_pfn, uint64_t pfn, bool value,
+ uint8_t *buf, DumpState *s)
+{
+ off_t old_offset, new_offset;
+ off_t offset_bitmap1, offset_bitmap2;
+ uint32_t byte, bit;
+ size_t bitmap_bufsize = dump_bitmap_get_bufsize(s);
+ size_t bits_per_buf = bitmap_bufsize * CHAR_BIT;
+
+ /* should not set the previous place */
+ assert(last_pfn <= pfn);
+
+ /*
+ * if the bit needed to be set is not cached in buf, flush the data in buf
+ * to vmcore firstly.
+ * making new_offset be bigger than old_offset can also sync remained data
+ * into vmcore.
+ */
+ old_offset = bitmap_bufsize * (last_pfn / bits_per_buf);
+ new_offset = bitmap_bufsize * (pfn / bits_per_buf);
+
+ while (old_offset < new_offset) {
+ /* calculate the offset and write dump_bitmap */
+ offset_bitmap1 = s->offset_dump_bitmap + old_offset;
+ if (write_buffer(s->fd, offset_bitmap1, buf,
+ bitmap_bufsize) < 0) {
+ return -1;
+ }
+
+ /* dump level 1 is chosen, so 1st and 2nd bitmap are same */
+ offset_bitmap2 = s->offset_dump_bitmap + s->len_dump_bitmap +
+ old_offset;
+ if (write_buffer(s->fd, offset_bitmap2, buf,
+ bitmap_bufsize) < 0) {
+ return -1;
+ }
+
+ memset(buf, 0, bitmap_bufsize);
+ old_offset += bitmap_bufsize;
+ }
+
+ /* get the exact place of the bit in the buf, and set it */
+ byte = (pfn % bits_per_buf) / CHAR_BIT;
+ bit = (pfn % bits_per_buf) % CHAR_BIT;
+ if (value) {
+ buf[byte] |= 1u << bit;
+ } else {
+ buf[byte] &= ~(1u << bit);
+ }
+
+ return 0;
+}
+
+static uint64_t dump_paddr_to_pfn(DumpState *s, uint64_t addr)
+{
+ int target_page_shift = ctz32(s->dump_info.page_size);
+
+ return (addr >> target_page_shift) - ARCH_PFN_OFFSET;
+}
+
+static uint64_t dump_pfn_to_paddr(DumpState *s, uint64_t pfn)
+{
+ int target_page_shift = ctz32(s->dump_info.page_size);
+
+ return (pfn + ARCH_PFN_OFFSET) << target_page_shift;
+}
+
+/*
+ * exam every page and return the page frame number and the address of the page.
+ * bufptr can be NULL. note: the blocks here is supposed to reflect guest-phys
+ * blocks, so block->target_start and block->target_end should be interal
+ * multiples of the target page size.
+ */
+static bool get_next_page(GuestPhysBlock **blockptr, uint64_t *pfnptr,
+ uint8_t **bufptr, DumpState *s)
+{
+ GuestPhysBlock *block = *blockptr;
+ hwaddr addr, target_page_mask = ~((hwaddr)s->dump_info.page_size - 1);
+ uint8_t *buf;
+
+ /* block == NULL means the start of the iteration */
+ if (!block) {
+ block = QTAILQ_FIRST(&s->guest_phys_blocks.head);
+ *blockptr = block;
+ assert((block->target_start & ~target_page_mask) == 0);
+ assert((block->target_end & ~target_page_mask) == 0);
+ *pfnptr = dump_paddr_to_pfn(s, block->target_start);
+ if (bufptr) {
+ *bufptr = block->host_addr;
+ }
+ return true;
+ }
+
+ *pfnptr = *pfnptr + 1;
+ addr = dump_pfn_to_paddr(s, *pfnptr);
+
+ if ((addr >= block->target_start) &&
+ (addr + s->dump_info.page_size <= block->target_end)) {
+ buf = block->host_addr + (addr - block->target_start);
+ } else {
+ /* the next page is in the next block */
+ block = QTAILQ_NEXT(block, next);
+ *blockptr = block;
+ if (!block) {
+ return false;
+ }
+ assert((block->target_start & ~target_page_mask) == 0);
+ assert((block->target_end & ~target_page_mask) == 0);
+ *pfnptr = dump_paddr_to_pfn(s, block->target_start);
+ buf = block->host_addr;
+ }
+
+ if (bufptr) {
+ *bufptr = buf;
+ }
+
+ return true;
+}
+
+static void write_dump_bitmap(DumpState *s, Error **errp)
+{
+ int ret = 0;
+ uint64_t last_pfn, pfn;
+ void *dump_bitmap_buf;
+ size_t num_dumpable;
+ GuestPhysBlock *block_iter = NULL;
+ size_t bitmap_bufsize = dump_bitmap_get_bufsize(s);
+ size_t bits_per_buf = bitmap_bufsize * CHAR_BIT;
+
+ /* dump_bitmap_buf is used to store dump_bitmap temporarily */
+ dump_bitmap_buf = g_malloc0(bitmap_bufsize);
+
+ num_dumpable = 0;
+ last_pfn = 0;
+
+ /*
+ * exam memory page by page, and set the bit in dump_bitmap corresponded
+ * to the existing page.
+ */
+ while (get_next_page(&block_iter, &pfn, NULL, s)) {
+ ret = set_dump_bitmap(last_pfn, pfn, true, dump_bitmap_buf, s);
+ if (ret < 0) {
+ error_setg(errp, "dump: failed to set dump_bitmap");
+ goto out;
+ }
+
+ last_pfn = pfn;
+ num_dumpable++;
+ }
+
+ /*
+ * set_dump_bitmap will always leave the recently set bit un-sync. Here we
+ * set the remaining bits from last_pfn to the end of the bitmap buffer to
+ * 0. With those set, the un-sync bit will be synchronized into the vmcore.
+ */
+ if (num_dumpable > 0) {
+ ret = set_dump_bitmap(last_pfn, last_pfn + bits_per_buf, false,
+ dump_bitmap_buf, s);
+ if (ret < 0) {
+ error_setg(errp, "dump: failed to sync dump_bitmap");
+ goto out;
+ }
+ }
+
+ /* number of dumpable pages that will be dumped later */
+ s->num_dumpable = num_dumpable;
+
+out:
+ g_free(dump_bitmap_buf);
+}
+
+static void prepare_data_cache(DataCache *data_cache, DumpState *s,
+ off_t offset)
+{
+ data_cache->fd = s->fd;
+ data_cache->data_size = 0;
+ data_cache->buf_size = 4 * dump_bitmap_get_bufsize(s);
+ data_cache->buf = g_malloc0(data_cache->buf_size);
+ data_cache->offset = offset;
+}
+
+static int write_cache(DataCache *dc, const void *buf, size_t size,
+ bool flag_sync)
+{
+ /*
+ * dc->buf_size should not be less than size, otherwise dc will never be
+ * enough
+ */
+ assert(size <= dc->buf_size);
+
+ /*
+ * if flag_sync is set, synchronize data in dc->buf into vmcore.
+ * otherwise check if the space is enough for caching data in buf, if not,
+ * write the data in dc->buf to dc->fd and reset dc->buf
+ */
+ if ((!flag_sync && dc->data_size + size > dc->buf_size) ||
+ (flag_sync && dc->data_size > 0)) {
+ if (write_buffer(dc->fd, dc->offset, dc->buf, dc->data_size) < 0) {
+ return -1;
+ }
+
+ dc->offset += dc->data_size;
+ dc->data_size = 0;
+ }
+
+ if (!flag_sync) {
+ memcpy(dc->buf + dc->data_size, buf, size);
+ dc->data_size += size;
+ }
+
+ return 0;
+}
+
+static void free_data_cache(DataCache *data_cache)
+{
+ g_free(data_cache->buf);
+}
+
+static size_t get_len_buf_out(size_t page_size, uint32_t flag_compress)
+{
+ switch (flag_compress) {
+ case DUMP_DH_COMPRESSED_ZLIB:
+ return compressBound(page_size);
+
+ case DUMP_DH_COMPRESSED_LZO:
+ /*
+ * LZO will expand incompressible data by a little amount. Please check
+ * the following URL to see the expansion calculation:
+ * http://www.oberhumer.com/opensource/lzo/lzofaq.php
+ */
+ return page_size + page_size / 16 + 64 + 3;
+
+#ifdef CONFIG_SNAPPY
+ case DUMP_DH_COMPRESSED_SNAPPY:
+ return snappy_max_compressed_length(page_size);
+#endif
+ }
+ return 0;
+}
+
+/*
+ * check if the page is all 0
+ */
+static inline bool is_zero_page(const uint8_t *buf, size_t page_size)
+{
+ return buffer_is_zero(buf, page_size);
+}
+
+static void write_dump_pages(DumpState *s, Error **errp)
+{
+ int ret = 0;
+ DataCache page_desc, page_data;
+ size_t len_buf_out, size_out;
+#ifdef CONFIG_LZO
+ lzo_bytep wrkmem = NULL;
+#endif
+ uint8_t *buf_out = NULL;
+ off_t offset_desc, offset_data;
+ PageDescriptor pd, pd_zero;
+ uint8_t *buf;
+ GuestPhysBlock *block_iter = NULL;
+ uint64_t pfn_iter;
+
+ /* get offset of page_desc and page_data in dump file */
+ offset_desc = s->offset_page;
+ offset_data = offset_desc + sizeof(PageDescriptor) * s->num_dumpable;
+
+ prepare_data_cache(&page_desc, s, offset_desc);
+ prepare_data_cache(&page_data, s, offset_data);
+
+ /* prepare buffer to store compressed data */
+ len_buf_out = get_len_buf_out(s->dump_info.page_size, s->flag_compress);
+ assert(len_buf_out != 0);
+
+#ifdef CONFIG_LZO
+ wrkmem = g_malloc(LZO1X_1_MEM_COMPRESS);
+#endif
+
+ buf_out = g_malloc(len_buf_out);
+
+ /*
+ * init zero page's page_desc and page_data, because every zero page
+ * uses the same page_data
+ */
+ pd_zero.size = cpu_to_dump32(s, s->dump_info.page_size);
+ pd_zero.flags = cpu_to_dump32(s, 0);
+ pd_zero.offset = cpu_to_dump64(s, offset_data);
+ pd_zero.page_flags = cpu_to_dump64(s, 0);
+ buf = g_malloc0(s->dump_info.page_size);
+ ret = write_cache(&page_data, buf, s->dump_info.page_size, false);
+ g_free(buf);
+ if (ret < 0) {
+ error_setg(errp, "dump: failed to write page data (zero page)");
+ goto out;
+ }
+
+ offset_data += s->dump_info.page_size;
+
+ /*
+ * dump memory to vmcore page by page. zero page will all be resided in the
+ * first page of page section
+ */
+ while (get_next_page(&block_iter, &pfn_iter, &buf, s)) {
+ /* check zero page */
+ if (is_zero_page(buf, s->dump_info.page_size)) {
+ ret = write_cache(&page_desc, &pd_zero, sizeof(PageDescriptor),
+ false);
+ if (ret < 0) {
+ error_setg(errp, "dump: failed to write page desc");
+ goto out;
+ }
+ } else {
+ /*
+ * not zero page, then:
+ * 1. compress the page
+ * 2. write the compressed page into the cache of page_data
+ * 3. get page desc of the compressed page and write it into the
+ * cache of page_desc
+ *
+ * only one compression format will be used here, for
+ * s->flag_compress is set. But when compression fails to work,
+ * we fall back to save in plaintext.
+ */
+ size_out = len_buf_out;
+ if ((s->flag_compress & DUMP_DH_COMPRESSED_ZLIB) &&
+ (compress2(buf_out, (uLongf *)&size_out, buf,
+ s->dump_info.page_size, Z_BEST_SPEED) == Z_OK) &&
+ (size_out < s->dump_info.page_size)) {
+ pd.flags = cpu_to_dump32(s, DUMP_DH_COMPRESSED_ZLIB);
+ pd.size = cpu_to_dump32(s, size_out);
+
+ ret = write_cache(&page_data, buf_out, size_out, false);
+ if (ret < 0) {
+ error_setg(errp, "dump: failed to write page data");
+ goto out;
+ }
+#ifdef CONFIG_LZO
+ } else if ((s->flag_compress & DUMP_DH_COMPRESSED_LZO) &&
+ (lzo1x_1_compress(buf, s->dump_info.page_size, buf_out,
+ (lzo_uint *)&size_out, wrkmem) == LZO_E_OK) &&
+ (size_out < s->dump_info.page_size)) {
+ pd.flags = cpu_to_dump32(s, DUMP_DH_COMPRESSED_LZO);
+ pd.size = cpu_to_dump32(s, size_out);
+
+ ret = write_cache(&page_data, buf_out, size_out, false);
+ if (ret < 0) {
+ error_setg(errp, "dump: failed to write page data");
+ goto out;
+ }
+#endif
+#ifdef CONFIG_SNAPPY
+ } else if ((s->flag_compress & DUMP_DH_COMPRESSED_SNAPPY) &&
+ (snappy_compress((char *)buf, s->dump_info.page_size,
+ (char *)buf_out, &size_out) == SNAPPY_OK) &&
+ (size_out < s->dump_info.page_size)) {
+ pd.flags = cpu_to_dump32(s, DUMP_DH_COMPRESSED_SNAPPY);
+ pd.size = cpu_to_dump32(s, size_out);
+
+ ret = write_cache(&page_data, buf_out, size_out, false);
+ if (ret < 0) {
+ error_setg(errp, "dump: failed to write page data");
+ goto out;
+ }
+#endif
+ } else {
+ /*
+ * fall back to save in plaintext, size_out should be
+ * assigned the target's page size
+ */
+ pd.flags = cpu_to_dump32(s, 0);
+ size_out = s->dump_info.page_size;
+ pd.size = cpu_to_dump32(s, size_out);
+
+ ret = write_cache(&page_data, buf,
+ s->dump_info.page_size, false);
+ if (ret < 0) {
+ error_setg(errp, "dump: failed to write page data");
+ goto out;
+ }
+ }
+
+ /* get and write page desc here */
+ pd.page_flags = cpu_to_dump64(s, 0);
+ pd.offset = cpu_to_dump64(s, offset_data);
+ offset_data += size_out;
+
+ ret = write_cache(&page_desc, &pd, sizeof(PageDescriptor), false);
+ if (ret < 0) {
+ error_setg(errp, "dump: failed to write page desc");
+ goto out;
+ }
+ }
+ s->written_size += s->dump_info.page_size;
+ }
+
+ ret = write_cache(&page_desc, NULL, 0, true);
+ if (ret < 0) {
+ error_setg(errp, "dump: failed to sync cache for page_desc");
+ goto out;
+ }
+ ret = write_cache(&page_data, NULL, 0, true);
+ if (ret < 0) {
+ error_setg(errp, "dump: failed to sync cache for page_data");
+ goto out;
+ }
+
+out:
+ free_data_cache(&page_desc);
+ free_data_cache(&page_data);
+
+#ifdef CONFIG_LZO
+ g_free(wrkmem);
+#endif
+
+ g_free(buf_out);
+}
+
+static void create_kdump_vmcore(DumpState *s, Error **errp)
+{
+ int ret;
+ Error *local_err = NULL;
+
+ /*
+ * the kdump-compressed format is:
+ * File offset
+ * +------------------------------------------+ 0x0
+ * | main header (struct disk_dump_header) |
+ * |------------------------------------------+ block 1
+ * | sub header (struct kdump_sub_header) |
+ * |------------------------------------------+ block 2
+ * | 1st-dump_bitmap |
+ * |------------------------------------------+ block 2 + X blocks
+ * | 2nd-dump_bitmap | (aligned by block)
+ * |------------------------------------------+ block 2 + 2 * X blocks
+ * | page desc for pfn 0 (struct page_desc) | (aligned by block)
+ * | page desc for pfn 1 (struct page_desc) |
+ * | : |
+ * |------------------------------------------| (not aligned by block)
+ * | page data (pfn 0) |
+ * | page data (pfn 1) |
+ * | : |
+ * +------------------------------------------+
+ */
+
+ ret = write_start_flat_header(s->fd);
+ if (ret < 0) {
+ error_setg(errp, "dump: failed to write start flat header");
+ return;
+ }
+
+ write_dump_header(s, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ return;
+ }
+
+ write_dump_bitmap(s, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ return;
+ }
+
+ write_dump_pages(s, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ return;
+ }
+
+ ret = write_end_flat_header(s->fd);
+ if (ret < 0) {
+ error_setg(errp, "dump: failed to write end flat header");
+ return;
+ }
+}
+
+static ram_addr_t get_start_block(DumpState *s)
+{
+ GuestPhysBlock *block;
+
+ if (!s->has_filter) {
+ s->next_block = QTAILQ_FIRST(&s->guest_phys_blocks.head);
+ return 0;
+ }
+
+ QTAILQ_FOREACH(block, &s->guest_phys_blocks.head, next) {
+ if (block->target_start >= s->begin + s->length ||
+ block->target_end <= s->begin) {
+ /* This block is out of the range */
+ continue;
+ }
+
+ s->next_block = block;
+ if (s->begin > block->target_start) {
+ s->start = s->begin - block->target_start;
+ } else {
+ s->start = 0;
+ }
+ return s->start;
+ }
+
+ return -1;
+}
+
+static void get_max_mapnr(DumpState *s)
+{
+ GuestPhysBlock *last_block;
+
+ last_block = QTAILQ_LAST(&s->guest_phys_blocks.head);
+ s->max_mapnr = dump_paddr_to_pfn(s, last_block->target_end);
+}
+
+static DumpState dump_state_global = { .status = DUMP_STATUS_NONE };
+
+static void dump_state_prepare(DumpState *s)
+{
+ /* zero the struct, setting status to active */
+ *s = (DumpState) { .status = DUMP_STATUS_ACTIVE };
+}
+
+bool dump_in_progress(void)
+{
+ DumpState *state = &dump_state_global;
+ return (atomic_read(&state->status) == DUMP_STATUS_ACTIVE);
+}
+
+/* calculate total size of memory to be dumped (taking filter into
+ * acoount.) */
+static int64_t dump_calculate_size(DumpState *s)
+{
+ GuestPhysBlock *block;
+ int64_t size = 0, total = 0, left = 0, right = 0;
+
+ QTAILQ_FOREACH(block, &s->guest_phys_blocks.head, next) {
+ if (s->has_filter) {
+ /* calculate the overlapped region. */
+ left = MAX(s->begin, block->target_start);
+ right = MIN(s->begin + s->length, block->target_end);
+ size = right - left;
+ size = size > 0 ? size : 0;
+ } else {
+ /* count the whole region in */
+ size = (block->target_end - block->target_start);
+ }
+ total += size;
+ }
+
+ return total;
+}
+
+static void vmcoreinfo_update_phys_base(DumpState *s)
+{
+ uint64_t size, note_head_size, name_size, phys_base;
+ char **lines;
+ uint8_t *vmci;
+ size_t i;
+
+ if (!note_name_equal(s, s->guest_note, "VMCOREINFO")) {
+ return;
+ }
+
+ get_note_sizes(s, s->guest_note, ¬e_head_size, &name_size, &size);
+ note_head_size = ROUND_UP(note_head_size, 4);
+
+ vmci = s->guest_note + note_head_size + ROUND_UP(name_size, 4);
+ *(vmci + size) = '\0';
+
+ lines = g_strsplit((char *)vmci, "\n", -1);
+ for (i = 0; lines[i]; i++) {
+ const char *prefix = NULL;
+
+ if (s->dump_info.d_machine == EM_X86_64) {
+ prefix = "NUMBER(phys_base)=";
+ } else if (s->dump_info.d_machine == EM_AARCH64) {
+ prefix = "NUMBER(PHYS_OFFSET)=";
+ }
+
+ if (prefix && g_str_has_prefix(lines[i], prefix)) {
+ if (qemu_strtou64(lines[i] + strlen(prefix), NULL, 16,
+ &phys_base) < 0) {
+ warn_report("Failed to read %s", prefix);
+ } else {
+ s->dump_info.phys_base = phys_base;
+ }
+ break;
+ }
+ }
+
+ g_strfreev(lines);
+}
+
+static void dump_init(DumpState *s, int fd, bool has_format,
+ DumpGuestMemoryFormat format, bool paging, bool has_filter,
+ int64_t begin, int64_t length, Error **errp)
+{
+ VMCoreInfoState *vmci = vmcoreinfo_find();
+ CPUState *cpu;
+ int nr_cpus;
+ Error *err = NULL;
+ int ret;
+
+ s->has_format = has_format;
+ s->format = format;
+ s->written_size = 0;
+
+ /* kdump-compressed is conflict with paging and filter */
+ if (has_format && format != DUMP_GUEST_MEMORY_FORMAT_ELF) {
+ assert(!paging && !has_filter);
+ }
+
+ if (runstate_is_running()) {
+ vm_stop(RUN_STATE_SAVE_VM);
+ s->resume = true;
+ } else {
+ s->resume = false;
+ }
+
+ /* If we use KVM, we should synchronize the registers before we get dump
+ * info or physmap info.
+ */
+ cpu_synchronize_all_states();
+ nr_cpus = 0;
+ CPU_FOREACH(cpu) {
+ nr_cpus++;
+ }
+
+ s->fd = fd;
+ s->has_filter = has_filter;
+ s->begin = begin;
+ s->length = length;
+
+ memory_mapping_list_init(&s->list);
+
+ guest_phys_blocks_init(&s->guest_phys_blocks);
+ guest_phys_blocks_append(&s->guest_phys_blocks);
+ s->total_size = dump_calculate_size(s);
+#ifdef DEBUG_DUMP_GUEST_MEMORY
+ fprintf(stderr, "DUMP: total memory to dump: %lu\n", s->total_size);
+#endif
+
+ /* it does not make sense to dump non-existent memory */
+ if (!s->total_size) {
+ error_setg(errp, "dump: no guest memory to dump");
+ goto cleanup;
+ }
+
+ s->start = get_start_block(s);
+ if (s->start == -1) {
+ error_setg(errp, QERR_INVALID_PARAMETER, "begin");
+ goto cleanup;
+ }
+
+ /* get dump info: endian, class and architecture.
+ * If the target architecture is not supported, cpu_get_dump_info() will
+ * return -1.
+ */
+ ret = cpu_get_dump_info(&s->dump_info, &s->guest_phys_blocks);
+ if (ret < 0) {
+ error_setg(errp, QERR_UNSUPPORTED);
+ goto cleanup;
+ }
+
+ if (!s->dump_info.page_size) {
+ s->dump_info.page_size = TARGET_PAGE_SIZE;
+ }
+
+ s->note_size = cpu_get_note_size(s->dump_info.d_class,
+ s->dump_info.d_machine, nr_cpus);
+ if (s->note_size < 0) {
+ error_setg(errp, QERR_UNSUPPORTED);
+ goto cleanup;
+ }
+
+ /*
+ * The goal of this block is to (a) update the previously guessed
+ * phys_base, (b) copy the guest note out of the guest.
+ * Failure to do so is not fatal for dumping.
+ */
+ if (vmci) {
+ uint64_t addr, note_head_size, name_size, desc_size;
+ uint32_t size;
+ uint16_t format;
+
+ note_head_size = s->dump_info.d_class == ELFCLASS32 ?
+ sizeof(Elf32_Nhdr) : sizeof(Elf64_Nhdr);
+
+ format = le16_to_cpu(vmci->vmcoreinfo.guest_format);
+ size = le32_to_cpu(vmci->vmcoreinfo.size);
+ addr = le64_to_cpu(vmci->vmcoreinfo.paddr);
+ if (!vmci->has_vmcoreinfo) {
+ warn_report("guest note is not present");
+ } else if (size < note_head_size || size > MAX_GUEST_NOTE_SIZE) {
+ warn_report("guest note size is invalid: %" PRIu32, size);
+ } else if (format != FW_CFG_VMCOREINFO_FORMAT_ELF) {
+ warn_report("guest note format is unsupported: %" PRIu16, format);
+ } else {
+ s->guest_note = g_malloc(size + 1); /* +1 for adding \0 */
+ cpu_physical_memory_read(addr, s->guest_note, size);
+
+ get_note_sizes(s, s->guest_note, NULL, &name_size, &desc_size);
+ s->guest_note_size = ELF_NOTE_SIZE(note_head_size, name_size,
+ desc_size);
+ if (name_size > MAX_GUEST_NOTE_SIZE ||
+ desc_size > MAX_GUEST_NOTE_SIZE ||
+ s->guest_note_size > size) {
+ warn_report("Invalid guest note header");
+ g_free(s->guest_note);
+ s->guest_note = NULL;
+ } else {
+ vmcoreinfo_update_phys_base(s);
+ s->note_size += s->guest_note_size;
+ }
+ }
+ }
+
+ /* get memory mapping */
+ if (paging) {
+ qemu_get_guest_memory_mapping(&s->list, &s->guest_phys_blocks, &err);
+ if (err != NULL) {
+ error_propagate(errp, err);
+ goto cleanup;
+ }
+ } else {
+ qemu_get_guest_simple_memory_mapping(&s->list, &s->guest_phys_blocks);
+ }
+
+ s->nr_cpus = nr_cpus;
+
+ get_max_mapnr(s);
+
+ uint64_t tmp;
+ tmp = DIV_ROUND_UP(DIV_ROUND_UP(s->max_mapnr, CHAR_BIT),
+ s->dump_info.page_size);
+ s->len_dump_bitmap = tmp * s->dump_info.page_size;
+
+ /* init for kdump-compressed format */
+ if (has_format && format != DUMP_GUEST_MEMORY_FORMAT_ELF) {
+ switch (format) {
+ case DUMP_GUEST_MEMORY_FORMAT_KDUMP_ZLIB:
+ s->flag_compress = DUMP_DH_COMPRESSED_ZLIB;
+ break;
+
+ case DUMP_GUEST_MEMORY_FORMAT_KDUMP_LZO:
+#ifdef CONFIG_LZO
+ if (lzo_init() != LZO_E_OK) {
+ error_setg(errp, "failed to initialize the LZO library");
+ goto cleanup;
+ }
+#endif
+ s->flag_compress = DUMP_DH_COMPRESSED_LZO;
+ break;
+
+ case DUMP_GUEST_MEMORY_FORMAT_KDUMP_SNAPPY:
+ s->flag_compress = DUMP_DH_COMPRESSED_SNAPPY;
+ break;
+
+ default:
+ s->flag_compress = 0;
+ }
+
+ return;
+ }
+
+ if (s->has_filter) {
+ memory_mapping_filter(&s->list, s->begin, s->length);
+ }
+
+ /*
+ * calculate phdr_num
+ *
+ * the type of ehdr->e_phnum is uint16_t, so we should avoid overflow
+ */
+ s->phdr_num = 1; /* PT_NOTE */
+ if (s->list.num < UINT16_MAX - 2) {
+ s->phdr_num += s->list.num;
+ s->have_section = false;
+ } else {
+ s->have_section = true;
+ s->phdr_num = PN_XNUM;
+ s->sh_info = 1; /* PT_NOTE */
+
+ /* the type of shdr->sh_info is uint32_t, so we should avoid overflow */
+ if (s->list.num <= UINT32_MAX - 1) {
+ s->sh_info += s->list.num;
+ } else {
+ s->sh_info = UINT32_MAX;
+ }
+ }
+
+ if (s->dump_info.d_class == ELFCLASS64) {
+ if (s->have_section) {
+ s->memory_offset = sizeof(Elf64_Ehdr) +
+ sizeof(Elf64_Phdr) * s->sh_info +
+ sizeof(Elf64_Shdr) + s->note_size;
+ } else {
+ s->memory_offset = sizeof(Elf64_Ehdr) +
+ sizeof(Elf64_Phdr) * s->phdr_num + s->note_size;
+ }
+ } else {
+ if (s->have_section) {
+ s->memory_offset = sizeof(Elf32_Ehdr) +
+ sizeof(Elf32_Phdr) * s->sh_info +
+ sizeof(Elf32_Shdr) + s->note_size;
+ } else {
+ s->memory_offset = sizeof(Elf32_Ehdr) +
+ sizeof(Elf32_Phdr) * s->phdr_num + s->note_size;
+ }
+ }
+
+ return;
+
+cleanup:
+ dump_cleanup(s);
+}
+
+/* this operation might be time consuming. */
+static void dump_process(DumpState *s, Error **errp)
+{
+ Error *local_err = NULL;
+ DumpQueryResult *result = NULL;
+
+ if (s->has_format && s->format == DUMP_GUEST_MEMORY_FORMAT_WIN_DMP) {
+#ifdef TARGET_X86_64
+ create_win_dump(s, &local_err);
+#endif
+ } else if (s->has_format && s->format != DUMP_GUEST_MEMORY_FORMAT_ELF) {
+ create_kdump_vmcore(s, &local_err);
+ } else {
+ create_vmcore(s, &local_err);
+ }
+
+ /* make sure status is written after written_size updates */
+ smp_wmb();
+ atomic_set(&s->status,
+ (local_err ? DUMP_STATUS_FAILED : DUMP_STATUS_COMPLETED));
+
+ /* send DUMP_COMPLETED message (unconditionally) */
+ result = qmp_query_dump(NULL);
+ /* should never fail */
+ assert(result);
+ qapi_event_send_dump_completed(result, !!local_err, (local_err ? \
+ error_get_pretty(local_err) : NULL));
+ qapi_free_DumpQueryResult(result);
+
+ error_propagate(errp, local_err);
+ dump_cleanup(s);
+}
+
+static void *dump_thread(void *data)
+{
+ DumpState *s = (DumpState *)data;
+ dump_process(s, NULL);
+ return NULL;
+}
+
+DumpQueryResult *qmp_query_dump(Error **errp)
+{
+ DumpQueryResult *result = g_new(DumpQueryResult, 1);
+ DumpState *state = &dump_state_global;
+ result->status = atomic_read(&state->status);
+ /* make sure we are reading status and written_size in order */
+ smp_rmb();
+ result->completed = state->written_size;
+ result->total = state->total_size;
+ return result;
+}
+
+void qmp_dump_guest_memory(bool paging, const char *file,
+ bool has_detach, bool detach,
+ bool has_begin, int64_t begin, bool has_length,
+ int64_t length, bool has_format,
+ DumpGuestMemoryFormat format, Error **errp)
+{
+ const char *p;
+ int fd = -1;
+ DumpState *s;
+ Error *local_err = NULL;
+ bool detach_p = false;
+
+ if (runstate_check(RUN_STATE_INMIGRATE)) {
+ error_setg(errp, "Dump not allowed during incoming migration.");
+ return;
+ }
+
+ /* if there is a dump in background, we should wait until the dump
+ * finished */
+ if (dump_in_progress()) {
+ error_setg(errp, "There is a dump in process, please wait.");
+ return;
+ }
+
+ /*
+ * kdump-compressed format need the whole memory dumped, so paging or
+ * filter is not supported here.
+ */
+ if ((has_format && format != DUMP_GUEST_MEMORY_FORMAT_ELF) &&
+ (paging || has_begin || has_length)) {
+ error_setg(errp, "kdump-compressed format doesn't support paging or "
+ "filter");
+ return;
+ }
+ if (has_begin && !has_length) {
+ error_setg(errp, QERR_MISSING_PARAMETER, "length");
+ return;
+ }
+ if (!has_begin && has_length) {
+ error_setg(errp, QERR_MISSING_PARAMETER, "begin");
+ return;
+ }
+ if (has_detach) {
+ detach_p = detach;
+ }
+
+ /* check whether lzo/snappy is supported */
+#ifndef CONFIG_LZO
+ if (has_format && format == DUMP_GUEST_MEMORY_FORMAT_KDUMP_LZO) {
+ error_setg(errp, "kdump-lzo is not available now");
+ return;
+ }
+#endif
+
+#ifndef CONFIG_SNAPPY
+ if (has_format && format == DUMP_GUEST_MEMORY_FORMAT_KDUMP_SNAPPY) {
+ error_setg(errp, "kdump-snappy is not available now");
+ return;
+ }
+#endif
+
+#ifndef TARGET_X86_64
+ if (has_format && format == DUMP_GUEST_MEMORY_FORMAT_WIN_DMP) {
+ error_setg(errp, "Windows dump is only available for x86-64");
+ return;
+ }
+#endif
+
+#if !defined(WIN32)
+ if (strstart(file, "fd:", &p)) {
+ fd = monitor_get_fd(cur_mon, p, errp);
+ if (fd == -1) {
+ return;
+ }
+ }
+#endif
+
+ if (strstart(file, "file:", &p)) {
+ fd = qemu_open(p, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, S_IRUSR);
+ if (fd < 0) {
+ error_setg_file_open(errp, errno, p);
+ return;
+ }
+ }
+
+ if (fd == -1) {
+ error_setg(errp, QERR_INVALID_PARAMETER, "protocol");
+ return;
+ }
+
+ s = &dump_state_global;
+ dump_state_prepare(s);
+
+ dump_init(s, fd, has_format, format, paging, has_begin,
+ begin, length, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ atomic_set(&s->status, DUMP_STATUS_FAILED);
+ return;
+ }
+
+ if (detach_p) {
+ /* detached dump */
+ s->detached = true;
+ qemu_thread_create(&s->dump_thread, "dump_thread", dump_thread,
+ s, QEMU_THREAD_DETACHED);
+ } else {
+ /* sync dump */
+ dump_process(s, errp);
+ }
+}
+
+DumpGuestMemoryCapability *qmp_query_dump_guest_memory_capability(Error **errp)
+{
+ DumpGuestMemoryFormatList *item;
+ DumpGuestMemoryCapability *cap =
+ g_malloc0(sizeof(DumpGuestMemoryCapability));
+
+ /* elf is always available */
+ item = g_malloc0(sizeof(DumpGuestMemoryFormatList));
+ cap->formats = item;
+ item->value = DUMP_GUEST_MEMORY_FORMAT_ELF;
+
+ /* kdump-zlib is always available */
+ item->next = g_malloc0(sizeof(DumpGuestMemoryFormatList));
+ item = item->next;
+ item->value = DUMP_GUEST_MEMORY_FORMAT_KDUMP_ZLIB;
+
+ /* add new item if kdump-lzo is available */
+#ifdef CONFIG_LZO
+ item->next = g_malloc0(sizeof(DumpGuestMemoryFormatList));
+ item = item->next;
+ item->value = DUMP_GUEST_MEMORY_FORMAT_KDUMP_LZO;
+#endif
+
+ /* add new item if kdump-snappy is available */
+#ifdef CONFIG_SNAPPY
+ item->next = g_malloc0(sizeof(DumpGuestMemoryFormatList));
+ item = item->next;
+ item->value = DUMP_GUEST_MEMORY_FORMAT_KDUMP_SNAPPY;
+#endif
+
+ /* Windows dump is available only if target is x86_64 */
+#ifdef TARGET_X86_64
+ item->next = g_malloc0(sizeof(DumpGuestMemoryFormatList));
+ item = item->next;
+ item->value = DUMP_GUEST_MEMORY_FORMAT_WIN_DMP;
+#endif
+
+ return cap;
+}
--- /dev/null
+/*
+ * Windows crashdump
+ *
+ * Copyright (c) 2018 Virtuozzo International GmbH
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+
+#include "qemu/osdep.h"
+#include "qemu-common.h"
+#include "qemu/cutils.h"
+#include "elf.h"
+#include "cpu.h"
+#include "exec/hwaddr.h"
+#include "monitor/monitor.h"
+#include "sysemu/kvm.h"
+#include "sysemu/dump.h"
+#include "sysemu/sysemu.h"
+#include "sysemu/memory_mapping.h"
+#include "sysemu/cpus.h"
+#include "qapi/error.h"
+#include "qapi/qmp/qerror.h"
+#include "qemu/error-report.h"
+#include "hw/misc/vmcoreinfo.h"
+#include "win_dump.h"
+
+static size_t write_run(WinDumpPhyMemRun64 *run, int fd, Error **errp)
+{
+ void *buf;
+ uint64_t addr = run->BasePage << TARGET_PAGE_BITS;
+ uint64_t size = run->PageCount << TARGET_PAGE_BITS;
+ uint64_t len, l;
+ size_t total = 0;
+
+ while (size) {
+ len = size;
+
+ buf = cpu_physical_memory_map(addr, &len, false);
+ if (!buf) {
+ error_setg(errp, "win-dump: failed to map physical range"
+ " 0x%016" PRIx64 "-0x%016" PRIx64, addr, addr + size - 1);
+ return 0;
+ }
+
+ l = qemu_write_full(fd, buf, len);
+ cpu_physical_memory_unmap(buf, addr, false, len);
+ if (l != len) {
+ error_setg(errp, QERR_IO_ERROR);
+ return 0;
+ }
+
+ addr += l;
+ size -= l;
+ total += l;
+ }
+
+ return total;
+}
+
+static void write_runs(DumpState *s, WinDumpHeader64 *h, Error **errp)
+{
+ WinDumpPhyMemDesc64 *desc = &h->PhysicalMemoryBlock;
+ WinDumpPhyMemRun64 *run = desc->Run;
+ Error *local_err = NULL;
+ int i;
+
+ for (i = 0; i < desc->NumberOfRuns; i++) {
+ s->written_size += write_run(run + i, s->fd, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ return;
+ }
+ }
+}
+
+static void patch_mm_pfn_database(WinDumpHeader64 *h, Error **errp)
+{
+ if (cpu_memory_rw_debug(first_cpu,
+ h->KdDebuggerDataBlock + KDBG_MM_PFN_DATABASE_OFFSET64,
+ (uint8_t *)&h->PfnDatabase, sizeof(h->PfnDatabase), 0)) {
+ error_setg(errp, "win-dump: failed to read MmPfnDatabase");
+ return;
+ }
+}
+
+static void patch_bugcheck_data(WinDumpHeader64 *h, Error **errp)
+{
+ uint64_t KiBugcheckData;
+
+ if (cpu_memory_rw_debug(first_cpu,
+ h->KdDebuggerDataBlock + KDBG_KI_BUGCHECK_DATA_OFFSET64,
+ (uint8_t *)&KiBugcheckData, sizeof(KiBugcheckData), 0)) {
+ error_setg(errp, "win-dump: failed to read KiBugcheckData");
+ return;
+ }
+
+ if (cpu_memory_rw_debug(first_cpu,
+ KiBugcheckData,
+ h->BugcheckData, sizeof(h->BugcheckData), 0)) {
+ error_setg(errp, "win-dump: failed to read bugcheck data");
+ return;
+ }
+
+ /*
+ * If BugcheckCode wasn't saved, we consider guest OS as alive.
+ */
+
+ if (!h->BugcheckCode) {
+ h->BugcheckCode = LIVE_SYSTEM_DUMP;
+ }
+}
+
+/*
+ * This routine tries to correct mistakes in crashdump header.
+ */
+static void patch_header(WinDumpHeader64 *h)
+{
+ Error *local_err = NULL;
+
+ h->RequiredDumpSpace = sizeof(WinDumpHeader64) +
+ (h->PhysicalMemoryBlock.NumberOfPages << TARGET_PAGE_BITS);
+ h->PhysicalMemoryBlock.unused = 0;
+ h->unused1 = 0;
+
+ patch_mm_pfn_database(h, &local_err);
+ if (local_err) {
+ warn_report_err(local_err);
+ local_err = NULL;
+ }
+ patch_bugcheck_data(h, &local_err);
+ if (local_err) {
+ warn_report_err(local_err);
+ }
+}
+
+static void check_header(WinDumpHeader64 *h, Error **errp)
+{
+ const char Signature[] = "PAGE";
+ const char ValidDump[] = "DU64";
+
+ if (memcmp(h->Signature, Signature, sizeof(h->Signature))) {
+ error_setg(errp, "win-dump: invalid header, expected '%.4s',"
+ " got '%.4s'", Signature, h->Signature);
+ return;
+ }
+
+ if (memcmp(h->ValidDump, ValidDump, sizeof(h->ValidDump))) {
+ error_setg(errp, "win-dump: invalid header, expected '%.4s',"
+ " got '%.4s'", ValidDump, h->ValidDump);
+ return;
+ }
+}
+
+static void check_kdbg(WinDumpHeader64 *h, Error **errp)
+{
+ const char OwnerTag[] = "KDBG";
+ char read_OwnerTag[4];
+ uint64_t KdDebuggerDataBlock = h->KdDebuggerDataBlock;
+ bool try_fallback = true;
+
+try_again:
+ if (cpu_memory_rw_debug(first_cpu,
+ KdDebuggerDataBlock + KDBG_OWNER_TAG_OFFSET64,
+ (uint8_t *)&read_OwnerTag, sizeof(read_OwnerTag), 0)) {
+ error_setg(errp, "win-dump: failed to read OwnerTag");
+ return;
+ }
+
+ if (memcmp(read_OwnerTag, OwnerTag, sizeof(read_OwnerTag))) {
+ if (try_fallback) {
+ /*
+ * If attempt to use original KDBG failed
+ * (most likely because of its encryption),
+ * we try to use KDBG obtained by guest driver.
+ */
+
+ KdDebuggerDataBlock = h->BugcheckParameter1;
+ try_fallback = false;
+ goto try_again;
+ } else {
+ error_setg(errp, "win-dump: invalid KDBG OwnerTag,"
+ " expected '%.4s', got '%.4s'",
+ OwnerTag, read_OwnerTag);
+ return;
+ }
+ }
+
+ h->KdDebuggerDataBlock = KdDebuggerDataBlock;
+}
+
+struct saved_context {
+ WinContext ctx;
+ uint64_t addr;
+};
+
+static void patch_and_save_context(WinDumpHeader64 *h,
+ struct saved_context *saved_ctx,
+ Error **errp)
+{
+ uint64_t KiProcessorBlock;
+ uint16_t OffsetPrcbContext;
+ CPUState *cpu;
+ int i = 0;
+
+ if (cpu_memory_rw_debug(first_cpu,
+ h->KdDebuggerDataBlock + KDBG_KI_PROCESSOR_BLOCK_OFFSET64,
+ (uint8_t *)&KiProcessorBlock, sizeof(KiProcessorBlock), 0)) {
+ error_setg(errp, "win-dump: failed to read KiProcessorBlock");
+ return;
+ }
+
+ if (cpu_memory_rw_debug(first_cpu,
+ h->KdDebuggerDataBlock + KDBG_OFFSET_PRCB_CONTEXT_OFFSET64,
+ (uint8_t *)&OffsetPrcbContext, sizeof(OffsetPrcbContext), 0)) {
+ error_setg(errp, "win-dump: failed to read OffsetPrcbContext");
+ return;
+ }
+
+ CPU_FOREACH(cpu) {
+ X86CPU *x86_cpu = X86_CPU(cpu);
+ CPUX86State *env = &x86_cpu->env;
+ uint64_t Prcb;
+ uint64_t Context;
+ WinContext ctx;
+
+ if (cpu_memory_rw_debug(first_cpu,
+ KiProcessorBlock + i * sizeof(uint64_t),
+ (uint8_t *)&Prcb, sizeof(Prcb), 0)) {
+ error_setg(errp, "win-dump: failed to read"
+ " CPU #%d PRCB location", i);
+ return;
+ }
+
+ if (cpu_memory_rw_debug(first_cpu,
+ Prcb + OffsetPrcbContext,
+ (uint8_t *)&Context, sizeof(Context), 0)) {
+ error_setg(errp, "win-dump: failed to read"
+ " CPU #%d ContextFrame location", i);
+ return;
+ }
+
+ saved_ctx[i].addr = Context;
+
+ ctx = (WinContext){
+ .ContextFlags = WIN_CTX_ALL,
+ .MxCsr = env->mxcsr,
+
+ .SegEs = env->segs[0].selector,
+ .SegCs = env->segs[1].selector,
+ .SegSs = env->segs[2].selector,
+ .SegDs = env->segs[3].selector,
+ .SegFs = env->segs[4].selector,
+ .SegGs = env->segs[5].selector,
+ .EFlags = cpu_compute_eflags(env),
+
+ .Dr0 = env->dr[0],
+ .Dr1 = env->dr[1],
+ .Dr2 = env->dr[2],
+ .Dr3 = env->dr[3],
+ .Dr6 = env->dr[6],
+ .Dr7 = env->dr[7],
+
+ .Rax = env->regs[R_EAX],
+ .Rbx = env->regs[R_EBX],
+ .Rcx = env->regs[R_ECX],
+ .Rdx = env->regs[R_EDX],
+ .Rsp = env->regs[R_ESP],
+ .Rbp = env->regs[R_EBP],
+ .Rsi = env->regs[R_ESI],
+ .Rdi = env->regs[R_EDI],
+ .R8 = env->regs[8],
+ .R9 = env->regs[9],
+ .R10 = env->regs[10],
+ .R11 = env->regs[11],
+ .R12 = env->regs[12],
+ .R13 = env->regs[13],
+ .R14 = env->regs[14],
+ .R15 = env->regs[15],
+
+ .Rip = env->eip,
+ .FltSave = {
+ .MxCsr = env->mxcsr,
+ },
+ };
+
+ if (cpu_memory_rw_debug(first_cpu, Context,
+ (uint8_t *)&saved_ctx[i].ctx, sizeof(WinContext), 0)) {
+ error_setg(errp, "win-dump: failed to save CPU #%d context", i);
+ return;
+ }
+
+ if (cpu_memory_rw_debug(first_cpu, Context,
+ (uint8_t *)&ctx, sizeof(WinContext), 1)) {
+ error_setg(errp, "win-dump: failed to write CPU #%d context", i);
+ return;
+ }
+
+ i++;
+ }
+}
+
+static void restore_context(WinDumpHeader64 *h,
+ struct saved_context *saved_ctx)
+{
+ int i;
+ Error *err = NULL;
+
+ for (i = 0; i < h->NumberProcessors; i++) {
+ if (cpu_memory_rw_debug(first_cpu, saved_ctx[i].addr,
+ (uint8_t *)&saved_ctx[i].ctx, sizeof(WinContext), 1)) {
+ error_setg(&err, "win-dump: failed to restore CPU #%d context", i);
+ warn_report_err(err);
+ }
+ }
+}
+
+void create_win_dump(DumpState *s, Error **errp)
+{
+ WinDumpHeader64 *h = (WinDumpHeader64 *)(s->guest_note +
+ VMCOREINFO_ELF_NOTE_HDR_SIZE);
+ X86CPU *first_x86_cpu = X86_CPU(first_cpu);
+ uint64_t saved_cr3 = first_x86_cpu->env.cr[3];
+ struct saved_context *saved_ctx = NULL;
+ Error *local_err = NULL;
+
+ if (s->guest_note_size != sizeof(WinDumpHeader64) +
+ VMCOREINFO_ELF_NOTE_HDR_SIZE) {
+ error_setg(errp, "win-dump: invalid vmcoreinfo note size");
+ return;
+ }
+
+ check_header(h, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ return;
+ }
+
+ /*
+ * Further access to kernel structures by virtual addresses
+ * should be made from system context.
+ */
+
+ first_x86_cpu->env.cr[3] = h->DirectoryTableBase;
+
+ check_kdbg(h, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ goto out_cr3;
+ }
+
+ patch_header(h);
+
+ saved_ctx = g_new(struct saved_context, h->NumberProcessors);
+
+ /*
+ * Always patch context because there is no way
+ * to determine if the system-saved context is valid
+ */
+
+ patch_and_save_context(h, saved_ctx, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ goto out_free;
+ }
+
+ s->total_size = h->RequiredDumpSpace;
+
+ s->written_size = qemu_write_full(s->fd, h, sizeof(*h));
+ if (s->written_size != sizeof(*h)) {
+ error_setg(errp, QERR_IO_ERROR);
+ goto out_restore;
+ }
+
+ write_runs(s, h, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ goto out_restore;
+ }
+
+out_restore:
+ restore_context(h, saved_ctx);
+out_free:
+ g_free(saved_ctx);
+out_cr3:
+ first_x86_cpu->env.cr[3] = saved_cr3;
+
+ return;
+}
--- /dev/null
+/*
+ * Windows crashdump
+ *
+ * Copyright (c) 2018 Virtuozzo International GmbH
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+
+#ifndef WIN_DUMP_H
+#define WIN_DUMP_H
+
+#include "qemu/win_dump_defs.h"
+
+void create_win_dump(DumpState *s, Error **errp);
+
+#endif /* WIN_DUMP_H */
{
.name = "announce_self",
- .args_type = "",
- .params = "",
+ .args_type = "interfaces:s?,id:s?",
+ .params = "[interfaces] [id]",
.help = "Trigger GARP/RARP announcements",
.cmd = hmp_announce_self,
},
Trigger a round of GARP/RARP broadcasts; this is useful for explicitly updating the
network infrastructure after a reconfiguration or some forms of migration.
The timings of the round are set by the migration announce parameters.
+An optional comma separated @var{interfaces} list restricts the announce to the
+named set of interfaces. An optional @var{id} can be used to start a separate announce
+timer and to change the parameters of it later.
ETEXI
{
+++ /dev/null
-/*
- * Human Monitor Interface
- *
- * Copyright IBM, Corp. 2011
- *
- * Authors:
- * Anthony Liguori <aliguori@us.ibm.com>
- *
- * This work is licensed under the terms of the GNU GPL, version 2. See
- * the COPYING file in the top-level directory.
- *
- */
-
-#ifndef HMP_H
-#define HMP_H
-
-#include "qemu/readline.h"
-
-void hmp_info_name(Monitor *mon, const QDict *qdict);
-void hmp_info_version(Monitor *mon, const QDict *qdict);
-void hmp_info_kvm(Monitor *mon, const QDict *qdict);
-void hmp_info_status(Monitor *mon, const QDict *qdict);
-void hmp_info_uuid(Monitor *mon, const QDict *qdict);
-void hmp_info_chardev(Monitor *mon, const QDict *qdict);
-void hmp_info_mice(Monitor *mon, const QDict *qdict);
-void hmp_info_migrate(Monitor *mon, const QDict *qdict);
-void hmp_info_migrate_capabilities(Monitor *mon, const QDict *qdict);
-void hmp_info_migrate_parameters(Monitor *mon, const QDict *qdict);
-void hmp_info_migrate_cache_size(Monitor *mon, const QDict *qdict);
-void hmp_info_cpus(Monitor *mon, const QDict *qdict);
-void hmp_info_block(Monitor *mon, const QDict *qdict);
-void hmp_info_blockstats(Monitor *mon, const QDict *qdict);
-void hmp_info_vnc(Monitor *mon, const QDict *qdict);
-void hmp_info_spice(Monitor *mon, const QDict *qdict);
-void hmp_info_balloon(Monitor *mon, const QDict *qdict);
-void hmp_info_irq(Monitor *mon, const QDict *qdict);
-void hmp_info_pic(Monitor *mon, const QDict *qdict);
-void hmp_info_rdma(Monitor *mon, const QDict *qdict);
-void hmp_info_pci(Monitor *mon, const QDict *qdict);
-void hmp_info_block_jobs(Monitor *mon, const QDict *qdict);
-void hmp_info_tpm(Monitor *mon, const QDict *qdict);
-void hmp_info_iothreads(Monitor *mon, const QDict *qdict);
-void hmp_quit(Monitor *mon, const QDict *qdict);
-void hmp_stop(Monitor *mon, const QDict *qdict);
-void hmp_sync_profile(Monitor *mon, const QDict *qdict);
-void hmp_system_reset(Monitor *mon, const QDict *qdict);
-void hmp_system_powerdown(Monitor *mon, const QDict *qdict);
-void hmp_exit_preconfig(Monitor *mon, const QDict *qdict);
-void hmp_announce_self(Monitor *mon, const QDict *qdict);
-void hmp_cpu(Monitor *mon, const QDict *qdict);
-void hmp_memsave(Monitor *mon, const QDict *qdict);
-void hmp_pmemsave(Monitor *mon, const QDict *qdict);
-void hmp_ringbuf_write(Monitor *mon, const QDict *qdict);
-void hmp_ringbuf_read(Monitor *mon, const QDict *qdict);
-void hmp_cont(Monitor *mon, const QDict *qdict);
-void hmp_system_wakeup(Monitor *mon, const QDict *qdict);
-void hmp_nmi(Monitor *mon, const QDict *qdict);
-void hmp_set_link(Monitor *mon, const QDict *qdict);
-void hmp_block_passwd(Monitor *mon, const QDict *qdict);
-void hmp_balloon(Monitor *mon, const QDict *qdict);
-void hmp_block_resize(Monitor *mon, const QDict *qdict);
-void hmp_snapshot_blkdev(Monitor *mon, const QDict *qdict);
-void hmp_snapshot_blkdev_internal(Monitor *mon, const QDict *qdict);
-void hmp_snapshot_delete_blkdev_internal(Monitor *mon, const QDict *qdict);
-void hmp_drive_mirror(Monitor *mon, const QDict *qdict);
-void hmp_drive_backup(Monitor *mon, const QDict *qdict);
-void hmp_loadvm(Monitor *mon, const QDict *qdict);
-void hmp_savevm(Monitor *mon, const QDict *qdict);
-void hmp_delvm(Monitor *mon, const QDict *qdict);
-void hmp_info_snapshots(Monitor *mon, const QDict *qdict);
-void hmp_migrate_cancel(Monitor *mon, const QDict *qdict);
-void hmp_migrate_continue(Monitor *mon, const QDict *qdict);
-void hmp_migrate_incoming(Monitor *mon, const QDict *qdict);
-void hmp_migrate_recover(Monitor *mon, const QDict *qdict);
-void hmp_migrate_pause(Monitor *mon, const QDict *qdict);
-void hmp_migrate_set_downtime(Monitor *mon, const QDict *qdict);
-void hmp_migrate_set_speed(Monitor *mon, const QDict *qdict);
-void hmp_migrate_set_capability(Monitor *mon, const QDict *qdict);
-void hmp_migrate_set_parameter(Monitor *mon, const QDict *qdict);
-void hmp_migrate_set_cache_size(Monitor *mon, const QDict *qdict);
-void hmp_client_migrate_info(Monitor *mon, const QDict *qdict);
-void hmp_migrate_start_postcopy(Monitor *mon, const QDict *qdict);
-void hmp_x_colo_lost_heartbeat(Monitor *mon, const QDict *qdict);
-void hmp_set_password(Monitor *mon, const QDict *qdict);
-void hmp_expire_password(Monitor *mon, const QDict *qdict);
-void hmp_eject(Monitor *mon, const QDict *qdict);
-void hmp_change(Monitor *mon, const QDict *qdict);
-void hmp_block_set_io_throttle(Monitor *mon, const QDict *qdict);
-void hmp_block_stream(Monitor *mon, const QDict *qdict);
-void hmp_block_job_set_speed(Monitor *mon, const QDict *qdict);
-void hmp_block_job_cancel(Monitor *mon, const QDict *qdict);
-void hmp_block_job_pause(Monitor *mon, const QDict *qdict);
-void hmp_block_job_resume(Monitor *mon, const QDict *qdict);
-void hmp_block_job_complete(Monitor *mon, const QDict *qdict);
-void hmp_migrate(Monitor *mon, const QDict *qdict);
-void hmp_device_add(Monitor *mon, const QDict *qdict);
-void hmp_device_del(Monitor *mon, const QDict *qdict);
-void hmp_dump_guest_memory(Monitor *mon, const QDict *qdict);
-void hmp_netdev_add(Monitor *mon, const QDict *qdict);
-void hmp_netdev_del(Monitor *mon, const QDict *qdict);
-void hmp_getfd(Monitor *mon, const QDict *qdict);
-void hmp_closefd(Monitor *mon, const QDict *qdict);
-void hmp_sendkey(Monitor *mon, const QDict *qdict);
-void hmp_screendump(Monitor *mon, const QDict *qdict);
-void hmp_nbd_server_start(Monitor *mon, const QDict *qdict);
-void hmp_nbd_server_add(Monitor *mon, const QDict *qdict);
-void hmp_nbd_server_remove(Monitor *mon, const QDict *qdict);
-void hmp_nbd_server_stop(Monitor *mon, const QDict *qdict);
-void hmp_chardev_add(Monitor *mon, const QDict *qdict);
-void hmp_chardev_change(Monitor *mon, const QDict *qdict);
-void hmp_chardev_remove(Monitor *mon, const QDict *qdict);
-void hmp_chardev_send_break(Monitor *mon, const QDict *qdict);
-void hmp_qemu_io(Monitor *mon, const QDict *qdict);
-void hmp_cpu_add(Monitor *mon, const QDict *qdict);
-void hmp_object_add(Monitor *mon, const QDict *qdict);
-void hmp_object_del(Monitor *mon, const QDict *qdict);
-void hmp_info_memdev(Monitor *mon, const QDict *qdict);
-void hmp_info_memory_devices(Monitor *mon, const QDict *qdict);
-void hmp_qom_list(Monitor *mon, const QDict *qdict);
-void hmp_qom_set(Monitor *mon, const QDict *qdict);
-void object_add_completion(ReadLineState *rs, int nb_args, const char *str);
-void object_del_completion(ReadLineState *rs, int nb_args, const char *str);
-void device_add_completion(ReadLineState *rs, int nb_args, const char *str);
-void device_del_completion(ReadLineState *rs, int nb_args, const char *str);
-void sendkey_completion(ReadLineState *rs, int nb_args, const char *str);
-void chardev_remove_completion(ReadLineState *rs, int nb_args, const char *str);
-void chardev_add_completion(ReadLineState *rs, int nb_args, const char *str);
-void set_link_completion(ReadLineState *rs, int nb_args, const char *str);
-void netdev_add_completion(ReadLineState *rs, int nb_args, const char *str);
-void netdev_del_completion(ReadLineState *rs, int nb_args, const char *str);
-void ringbuf_write_completion(ReadLineState *rs, int nb_args, const char *str);
-void info_trace_events_completion(ReadLineState *rs, int nb_args, const char *str);
-void trace_event_completion(ReadLineState *rs, int nb_args, const char *str);
-void watchdog_action_completion(ReadLineState *rs, int nb_args,
- const char *str);
-void migrate_set_capability_completion(ReadLineState *rs, int nb_args,
- const char *str);
-void migrate_set_parameter_completion(ReadLineState *rs, int nb_args,
- const char *str);
-void delvm_completion(ReadLineState *rs, int nb_args, const char *str);
-void loadvm_completion(ReadLineState *rs, int nb_args, const char *str);
-void hmp_rocker(Monitor *mon, const QDict *qdict);
-void hmp_rocker_ports(Monitor *mon, const QDict *qdict);
-void hmp_rocker_of_dpa_flows(Monitor *mon, const QDict *qdict);
-void hmp_rocker_of_dpa_groups(Monitor *mon, const QDict *qdict);
-void hmp_info_dump(Monitor *mon, const QDict *qdict);
-void hmp_info_ramblock(Monitor *mon, const QDict *qdict);
-void hmp_hotpluggable_cpus(Monitor *mon, const QDict *qdict);
-void hmp_info_vm_generation_id(Monitor *mon, const QDict *qdict);
-void hmp_info_memory_size_summary(Monitor *mon, const QDict *qdict);
-void hmp_info_sev(Monitor *mon, const QDict *qdict);
-
-#endif
select DS1338 # I2C RTC+NVRAM
select USB_OHCI
+config SBSA_REF
+ bool
+ imply PCI_DEVICES
+ select AHCI
+ select ARM_SMMUV3
+ select GPIO_KEY
+ select PCI_EXPRESS
+ select PCI_EXPRESS_GENERIC_BRIDGE
+ select PFLASH_CFI01
+ select PL011 # UART
+ select PL031 # RTC
+ select PL061 # GPIO
+ select USB_EHCI_SYSBUS
+
config SABRELITE
bool
select FSL_IMX6
obj-$(CONFIG_TOSA) += tosa.o
obj-$(CONFIG_Z2) += z2.o
obj-$(CONFIG_REALVIEW) += realview.o
+obj-$(CONFIG_SBSA_REF) += sbsa-ref.o
obj-$(CONFIG_STELLARIS) += stellaris.o
obj-$(CONFIG_COLLIE) += collie.o
obj-$(CONFIG_VERSATILE) += versatilepb.o
#include "hw/misc/tmp105.h"
#include "qemu/log.h"
#include "sysemu/block-backend.h"
+#include "sysemu/sysemu.h"
#include "hw/loader.h"
#include "qemu/error-report.h"
#include "qemu/units.h"
static struct arm_boot_info aspeed_board_binfo = {
.board_id = -1, /* device-tree-only board */
- .nb_cpus = 1,
};
struct AspeedBoardState {
AspeedSoCState soc;
+ MemoryRegion ram_container;
MemoryRegion ram;
MemoryRegion max_ram;
};
SCU_AST2500_HW_STRAP_ACPI_ENABLE | \
SCU_HW_STRAP_SPI_MODE(SCU_HW_STRAP_SPI_MASTER))
+/* Swift hardware value: 0xF11AD206 */
+#define SWIFT_BMC_HW_STRAP1 ( \
+ AST2500_HW_STRAP1_DEFAULTS | \
+ SCU_AST2500_HW_STRAP_SPI_AUTOFETCH_ENABLE | \
+ SCU_AST2500_HW_STRAP_GPIO_STRAP_ENABLE | \
+ SCU_AST2500_HW_STRAP_UART_DEBUG | \
+ SCU_AST2500_HW_STRAP_DDR4_ENABLE | \
+ SCU_H_PLL_BYPASS_EN | \
+ SCU_AST2500_HW_STRAP_ACPI_ENABLE | \
+ SCU_HW_STRAP_SPI_MODE(SCU_HW_STRAP_SPI_MASTER))
+
/* Witherspoon hardware value: 0xF10AD216 (but use romulus definition) */
#define WITHERSPOON_BMC_HW_STRAP1 ROMULUS_BMC_HW_STRAP1
ram_addr_t max_ram_size;
bmc = g_new0(AspeedBoardState, 1);
+
+ memory_region_init(&bmc->ram_container, NULL, "aspeed-ram-container",
+ UINT32_MAX);
+
object_initialize_child(OBJECT(machine), "soc", &bmc->soc,
(sizeof(bmc->soc)), cfg->soc_name, &error_abort,
NULL);
&error_abort);
object_property_set_int(OBJECT(&bmc->soc), cfg->num_cs, "num-cs",
&error_abort);
+ object_property_set_int(OBJECT(&bmc->soc), smp_cpus, "num-cpus",
+ &error_abort);
if (machine->kernel_filename) {
/*
* When booting with a -kernel command line there is no u-boot
&error_abort);
memory_region_allocate_system_memory(&bmc->ram, NULL, "ram", ram_size);
- memory_region_add_subregion(get_system_memory(), sc->info->sdram_base,
- &bmc->ram);
- object_property_add_const_link(OBJECT(&bmc->soc), "ram", OBJECT(&bmc->ram),
- &error_abort);
+ memory_region_add_subregion(&bmc->ram_container, 0, &bmc->ram);
+ memory_region_add_subregion(get_system_memory(),
+ sc->info->memmap[ASPEED_SDRAM],
+ &bmc->ram_container);
max_ram_size = object_property_get_uint(OBJECT(&bmc->soc), "max-ram-size",
&error_abort);
memory_region_init_io(&bmc->max_ram, NULL, &max_ram_ops, NULL,
"max_ram", max_ram_size - ram_size);
- memory_region_add_subregion(get_system_memory(),
- sc->info->sdram_base + ram_size,
- &bmc->max_ram);
+ memory_region_add_subregion(&bmc->ram_container, ram_size, &bmc->max_ram);
aspeed_board_init_flashes(&bmc->soc.fmc, cfg->fmc_model, &error_abort);
aspeed_board_init_flashes(&bmc->soc.spi[0], cfg->spi_model, &error_abort);
aspeed_board_binfo.initrd_filename = machine->initrd_filename;
aspeed_board_binfo.kernel_cmdline = machine->kernel_cmdline;
aspeed_board_binfo.ram_size = ram_size;
- aspeed_board_binfo.loader_start = sc->info->sdram_base;
+ aspeed_board_binfo.loader_start = sc->info->memmap[ASPEED_SDRAM];
+ aspeed_board_binfo.nb_cpus = bmc->soc.num_cpus;
if (cfg->i2c_init) {
cfg->i2c_init(bmc);
i2c_create_slave(aspeed_i2c_get_bus(DEVICE(&soc->i2c), 11), "ds1338", 0x32);
}
+static void swift_bmc_i2c_init(AspeedBoardState *bmc)
+{
+ AspeedSoCState *soc = &bmc->soc;
+
+ i2c_create_slave(aspeed_i2c_get_bus(DEVICE(&soc->i2c), 3), "pca9552", 0x60);
+
+ /* The swift board expects a TMP275 but a TMP105 is compatible */
+ i2c_create_slave(aspeed_i2c_get_bus(DEVICE(&soc->i2c), 7), "tmp105", 0x48);
+ /* The swift board expects a pca9551 but a pca9552 is compatible */
+ i2c_create_slave(aspeed_i2c_get_bus(DEVICE(&soc->i2c), 7), "pca9552", 0x60);
+
+ /* The swift board expects an Epson RX8900 RTC but a ds1338 is compatible */
+ i2c_create_slave(aspeed_i2c_get_bus(DEVICE(&soc->i2c), 8), "ds1338", 0x32);
+ i2c_create_slave(aspeed_i2c_get_bus(DEVICE(&soc->i2c), 8), "pca9552", 0x60);
+
+ i2c_create_slave(aspeed_i2c_get_bus(DEVICE(&soc->i2c), 9), "tmp423", 0x4c);
+ /* The swift board expects a pca9539 but a pca9552 is compatible */
+ i2c_create_slave(aspeed_i2c_get_bus(DEVICE(&soc->i2c), 9), "pca9552", 0x74);
+
+ i2c_create_slave(aspeed_i2c_get_bus(DEVICE(&soc->i2c), 10), "tmp423", 0x4c);
+ /* The swift board expects a pca9539 but a pca9552 is compatible */
+ i2c_create_slave(aspeed_i2c_get_bus(DEVICE(&soc->i2c), 10), "pca9552",
+ 0x74);
+
+ /* The swift board expects a TMP275 but a TMP105 is compatible */
+ i2c_create_slave(aspeed_i2c_get_bus(DEVICE(&soc->i2c), 12), "tmp105", 0x48);
+ i2c_create_slave(aspeed_i2c_get_bus(DEVICE(&soc->i2c), 12), "tmp105", 0x4a);
+}
+
static void witherspoon_bmc_i2c_init(AspeedBoardState *bmc)
{
AspeedSoCState *soc = &bmc->soc;
mc->desc = board->desc;
mc->init = aspeed_machine_init;
- mc->max_cpus = 1;
+ mc->max_cpus = ASPEED_CPUS_NUM;
mc->no_sdcard = 1;
mc->no_floppy = 1;
mc->no_cdrom = 1;
.num_cs = 2,
.i2c_init = romulus_bmc_i2c_init,
.ram = 512 * MiB,
+ }, {
+ .name = MACHINE_TYPE_NAME("swift-bmc"),
+ .desc = "OpenPOWER Swift BMC (ARM1176)",
+ .soc_name = "ast2500-a1",
+ .hw_strap1 = SWIFT_BMC_HW_STRAP1,
+ .fmc_model = "mx66l1g45g",
+ .spi_model = "mx66l1g45g",
+ .num_cs = 2,
+ .i2c_init = swift_bmc_i2c_init,
+ .ram = 512 * MiB,
}, {
.name = MACHINE_TYPE_NAME("witherspoon-bmc"),
.desc = "OpenPOWER Witherspoon BMC (ARM1176)",
#include "hw/char/serial.h"
#include "qemu/log.h"
#include "qemu/module.h"
+#include "qemu/error-report.h"
#include "hw/i2c/aspeed_i2c.h"
#include "net/net.h"
-#define ASPEED_SOC_UART_5_BASE 0x00184000
#define ASPEED_SOC_IOMEM_SIZE 0x00200000
-#define ASPEED_SOC_IOMEM_BASE 0x1E600000
-#define ASPEED_SOC_FMC_BASE 0x1E620000
-#define ASPEED_SOC_SPI_BASE 0x1E630000
-#define ASPEED_SOC_SPI2_BASE 0x1E631000
-#define ASPEED_SOC_VIC_BASE 0x1E6C0000
-#define ASPEED_SOC_SDMC_BASE 0x1E6E0000
-#define ASPEED_SOC_SCU_BASE 0x1E6E2000
-#define ASPEED_SOC_SRAM_BASE 0x1E720000
-#define ASPEED_SOC_TIMER_BASE 0x1E782000
-#define ASPEED_SOC_WDT_BASE 0x1E785000
-#define ASPEED_SOC_I2C_BASE 0x1E78A000
-#define ASPEED_SOC_ETH1_BASE 0x1E660000
-#define ASPEED_SOC_ETH2_BASE 0x1E680000
-
-static const int uart_irqs[] = { 9, 32, 33, 34, 10 };
-static const int timer_irqs[] = { 16, 17, 18, 35, 36, 37, 38, 39, };
-
-#define AST2400_SDRAM_BASE 0x40000000
-#define AST2500_SDRAM_BASE 0x80000000
-
-static const hwaddr aspeed_soc_ast2400_spi_bases[] = { ASPEED_SOC_SPI_BASE };
-static const char *aspeed_soc_ast2400_typenames[] = { "aspeed.smc.spi" };
-static const hwaddr aspeed_soc_ast2500_spi_bases[] = { ASPEED_SOC_SPI_BASE,
- ASPEED_SOC_SPI2_BASE};
+static const hwaddr aspeed_soc_ast2400_memmap[] = {
+ [ASPEED_IOMEM] = 0x1E600000,
+ [ASPEED_FMC] = 0x1E620000,
+ [ASPEED_SPI1] = 0x1E630000,
+ [ASPEED_VIC] = 0x1E6C0000,
+ [ASPEED_SDMC] = 0x1E6E0000,
+ [ASPEED_SCU] = 0x1E6E2000,
+ [ASPEED_XDMA] = 0x1E6E7000,
+ [ASPEED_ADC] = 0x1E6E9000,
+ [ASPEED_SRAM] = 0x1E720000,
+ [ASPEED_GPIO] = 0x1E780000,
+ [ASPEED_RTC] = 0x1E781000,
+ [ASPEED_TIMER1] = 0x1E782000,
+ [ASPEED_WDT] = 0x1E785000,
+ [ASPEED_PWM] = 0x1E786000,
+ [ASPEED_LPC] = 0x1E789000,
+ [ASPEED_IBT] = 0x1E789140,
+ [ASPEED_I2C] = 0x1E78A000,
+ [ASPEED_ETH1] = 0x1E660000,
+ [ASPEED_ETH2] = 0x1E680000,
+ [ASPEED_UART1] = 0x1E783000,
+ [ASPEED_UART5] = 0x1E784000,
+ [ASPEED_VUART] = 0x1E787000,
+ [ASPEED_SDRAM] = 0x40000000,
+};
+
+static const hwaddr aspeed_soc_ast2500_memmap[] = {
+ [ASPEED_IOMEM] = 0x1E600000,
+ [ASPEED_FMC] = 0x1E620000,
+ [ASPEED_SPI1] = 0x1E630000,
+ [ASPEED_SPI2] = 0x1E631000,
+ [ASPEED_VIC] = 0x1E6C0000,
+ [ASPEED_SDMC] = 0x1E6E0000,
+ [ASPEED_SCU] = 0x1E6E2000,
+ [ASPEED_XDMA] = 0x1E6E7000,
+ [ASPEED_ADC] = 0x1E6E9000,
+ [ASPEED_SRAM] = 0x1E720000,
+ [ASPEED_GPIO] = 0x1E780000,
+ [ASPEED_RTC] = 0x1E781000,
+ [ASPEED_TIMER1] = 0x1E782000,
+ [ASPEED_WDT] = 0x1E785000,
+ [ASPEED_PWM] = 0x1E786000,
+ [ASPEED_LPC] = 0x1E789000,
+ [ASPEED_IBT] = 0x1E789140,
+ [ASPEED_I2C] = 0x1E78A000,
+ [ASPEED_ETH1] = 0x1E660000,
+ [ASPEED_ETH2] = 0x1E680000,
+ [ASPEED_UART1] = 0x1E783000,
+ [ASPEED_UART5] = 0x1E784000,
+ [ASPEED_VUART] = 0x1E787000,
+ [ASPEED_SDRAM] = 0x80000000,
+};
+
+static const int aspeed_soc_ast2400_irqmap[] = {
+ [ASPEED_UART1] = 9,
+ [ASPEED_UART2] = 32,
+ [ASPEED_UART3] = 33,
+ [ASPEED_UART4] = 34,
+ [ASPEED_UART5] = 10,
+ [ASPEED_VUART] = 8,
+ [ASPEED_FMC] = 19,
+ [ASPEED_SDMC] = 0,
+ [ASPEED_SCU] = 21,
+ [ASPEED_ADC] = 31,
+ [ASPEED_GPIO] = 20,
+ [ASPEED_RTC] = 22,
+ [ASPEED_TIMER1] = 16,
+ [ASPEED_TIMER2] = 17,
+ [ASPEED_TIMER3] = 18,
+ [ASPEED_TIMER4] = 35,
+ [ASPEED_TIMER5] = 36,
+ [ASPEED_TIMER6] = 37,
+ [ASPEED_TIMER7] = 38,
+ [ASPEED_TIMER8] = 39,
+ [ASPEED_WDT] = 27,
+ [ASPEED_PWM] = 28,
+ [ASPEED_LPC] = 8,
+ [ASPEED_IBT] = 8, /* LPC */
+ [ASPEED_I2C] = 12,
+ [ASPEED_ETH1] = 2,
+ [ASPEED_ETH2] = 3,
+ [ASPEED_XDMA] = 6,
+};
+
+#define aspeed_soc_ast2500_irqmap aspeed_soc_ast2400_irqmap
+
+static const char *aspeed_soc_ast2400_typenames[] = { "aspeed.smc.spi" };
static const char *aspeed_soc_ast2500_typenames[] = {
"aspeed.smc.ast2500-spi1", "aspeed.smc.ast2500-spi2" };
.name = "ast2400-a0",
.cpu_type = ARM_CPU_TYPE_NAME("arm926"),
.silicon_rev = AST2400_A0_SILICON_REV,
- .sdram_base = AST2400_SDRAM_BASE,
.sram_size = 0x8000,
.spis_num = 1,
- .spi_bases = aspeed_soc_ast2400_spi_bases,
.fmc_typename = "aspeed.smc.fmc",
.spi_typename = aspeed_soc_ast2400_typenames,
.wdts_num = 2,
+ .irqmap = aspeed_soc_ast2400_irqmap,
+ .memmap = aspeed_soc_ast2400_memmap,
+ .num_cpus = 1,
}, {
.name = "ast2400-a1",
.cpu_type = ARM_CPU_TYPE_NAME("arm926"),
.silicon_rev = AST2400_A1_SILICON_REV,
- .sdram_base = AST2400_SDRAM_BASE,
.sram_size = 0x8000,
.spis_num = 1,
- .spi_bases = aspeed_soc_ast2400_spi_bases,
.fmc_typename = "aspeed.smc.fmc",
.spi_typename = aspeed_soc_ast2400_typenames,
.wdts_num = 2,
+ .irqmap = aspeed_soc_ast2400_irqmap,
+ .memmap = aspeed_soc_ast2400_memmap,
+ .num_cpus = 1,
}, {
.name = "ast2400",
.cpu_type = ARM_CPU_TYPE_NAME("arm926"),
.silicon_rev = AST2400_A0_SILICON_REV,
- .sdram_base = AST2400_SDRAM_BASE,
.sram_size = 0x8000,
.spis_num = 1,
- .spi_bases = aspeed_soc_ast2400_spi_bases,
.fmc_typename = "aspeed.smc.fmc",
.spi_typename = aspeed_soc_ast2400_typenames,
.wdts_num = 2,
+ .irqmap = aspeed_soc_ast2400_irqmap,
+ .memmap = aspeed_soc_ast2400_memmap,
+ .num_cpus = 1,
}, {
.name = "ast2500-a1",
.cpu_type = ARM_CPU_TYPE_NAME("arm1176"),
.silicon_rev = AST2500_A1_SILICON_REV,
- .sdram_base = AST2500_SDRAM_BASE,
.sram_size = 0x9000,
.spis_num = 2,
- .spi_bases = aspeed_soc_ast2500_spi_bases,
.fmc_typename = "aspeed.smc.ast2500-fmc",
.spi_typename = aspeed_soc_ast2500_typenames,
.wdts_num = 3,
+ .irqmap = aspeed_soc_ast2500_irqmap,
+ .memmap = aspeed_soc_ast2500_memmap,
+ .num_cpus = 1,
},
};
+static qemu_irq aspeed_soc_get_irq(AspeedSoCState *s, int ctrl)
+{
+ AspeedSoCClass *sc = ASPEED_SOC_GET_CLASS(s);
+
+ return qdev_get_gpio_in(DEVICE(&s->vic), sc->info->irqmap[ctrl]);
+}
+
static void aspeed_soc_init(Object *obj)
{
AspeedSoCState *s = ASPEED_SOC(obj);
AspeedSoCClass *sc = ASPEED_SOC_GET_CLASS(s);
int i;
- object_initialize_child(obj, "cpu", OBJECT(&s->cpu), sizeof(s->cpu),
- sc->info->cpu_type, &error_abort, NULL);
+ for (i = 0; i < sc->info->num_cpus; i++) {
+ object_initialize_child(obj, "cpu[*]", OBJECT(&s->cpu[i]),
+ sizeof(s->cpu[i]), sc->info->cpu_type,
+ &error_abort, NULL);
+ }
sysbus_init_child_obj(obj, "scu", OBJECT(&s->scu), sizeof(s->scu),
TYPE_ASPEED_SCU);
sysbus_init_child_obj(obj, "vic", OBJECT(&s->vic), sizeof(s->vic),
TYPE_ASPEED_VIC);
+ sysbus_init_child_obj(obj, "rtc", OBJECT(&s->rtc), sizeof(s->rtc),
+ TYPE_ASPEED_RTC);
+
sysbus_init_child_obj(obj, "timerctrl", OBJECT(&s->timerctrl),
sizeof(s->timerctrl), TYPE_ASPEED_TIMER);
object_property_add_const_link(OBJECT(&s->timerctrl), "scu",
sizeof(s->wdt[i]), TYPE_ASPEED_WDT);
qdev_prop_set_uint32(DEVICE(&s->wdt[i]), "silicon-rev",
sc->info->silicon_rev);
+ object_property_add_const_link(OBJECT(&s->wdt[i]), "scu",
+ OBJECT(&s->scu), &error_abort);
}
- sysbus_init_child_obj(obj, "ftgmac100", OBJECT(&s->ftgmac100),
- sizeof(s->ftgmac100), TYPE_FTGMAC100);
+ for (i = 0; i < ASPEED_MACS_NUM; i++) {
+ sysbus_init_child_obj(obj, "ftgmac100[*]", OBJECT(&s->ftgmac100[i]),
+ sizeof(s->ftgmac100[i]), TYPE_FTGMAC100);
+ }
+
+ sysbus_init_child_obj(obj, "xdma", OBJECT(&s->xdma), sizeof(s->xdma),
+ TYPE_ASPEED_XDMA);
}
static void aspeed_soc_realize(DeviceState *dev, Error **errp)
Error *err = NULL, *local_err = NULL;
/* IO space */
- create_unimplemented_device("aspeed_soc.io",
- ASPEED_SOC_IOMEM_BASE, ASPEED_SOC_IOMEM_SIZE);
+ create_unimplemented_device("aspeed_soc.io", sc->info->memmap[ASPEED_IOMEM],
+ ASPEED_SOC_IOMEM_SIZE);
+
+ if (s->num_cpus > sc->info->num_cpus) {
+ warn_report("%s: invalid number of CPUs %d, using default %d",
+ sc->info->name, s->num_cpus, sc->info->num_cpus);
+ s->num_cpus = sc->info->num_cpus;
+ }
/* CPU */
- object_property_set_bool(OBJECT(&s->cpu), true, "realized", &err);
- if (err) {
- error_propagate(errp, err);
- return;
+ for (i = 0; i < s->num_cpus; i++) {
+ object_property_set_bool(OBJECT(&s->cpu[i]), true, "realized", &err);
+ if (err) {
+ error_propagate(errp, err);
+ return;
+ }
}
/* SRAM */
error_propagate(errp, err);
return;
}
- memory_region_add_subregion(get_system_memory(), ASPEED_SOC_SRAM_BASE,
- &s->sram);
+ memory_region_add_subregion(get_system_memory(),
+ sc->info->memmap[ASPEED_SRAM], &s->sram);
/* SCU */
object_property_set_bool(OBJECT(&s->scu), true, "realized", &err);
error_propagate(errp, err);
return;
}
- sysbus_mmio_map(SYS_BUS_DEVICE(&s->scu), 0, ASPEED_SOC_SCU_BASE);
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->scu), 0, sc->info->memmap[ASPEED_SCU]);
/* VIC */
object_property_set_bool(OBJECT(&s->vic), true, "realized", &err);
error_propagate(errp, err);
return;
}
- sysbus_mmio_map(SYS_BUS_DEVICE(&s->vic), 0, ASPEED_SOC_VIC_BASE);
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->vic), 0, sc->info->memmap[ASPEED_VIC]);
sysbus_connect_irq(SYS_BUS_DEVICE(&s->vic), 0,
qdev_get_gpio_in(DEVICE(&s->cpu), ARM_CPU_IRQ));
sysbus_connect_irq(SYS_BUS_DEVICE(&s->vic), 1,
qdev_get_gpio_in(DEVICE(&s->cpu), ARM_CPU_FIQ));
+ /* RTC */
+ object_property_set_bool(OBJECT(&s->rtc), true, "realized", &err);
+ if (err) {
+ error_propagate(errp, err);
+ return;
+ }
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->rtc), 0, sc->info->memmap[ASPEED_RTC]);
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->rtc), 0,
+ aspeed_soc_get_irq(s, ASPEED_RTC));
+
/* Timer */
object_property_set_bool(OBJECT(&s->timerctrl), true, "realized", &err);
if (err) {
error_propagate(errp, err);
return;
}
- sysbus_mmio_map(SYS_BUS_DEVICE(&s->timerctrl), 0, ASPEED_SOC_TIMER_BASE);
- for (i = 0; i < ARRAY_SIZE(timer_irqs); i++) {
- qemu_irq irq = qdev_get_gpio_in(DEVICE(&s->vic), timer_irqs[i]);
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->timerctrl), 0,
+ sc->info->memmap[ASPEED_TIMER1]);
+ for (i = 0; i < ASPEED_TIMER_NR_TIMERS; i++) {
+ qemu_irq irq = aspeed_soc_get_irq(s, ASPEED_TIMER1 + i);
sysbus_connect_irq(SYS_BUS_DEVICE(&s->timerctrl), i, irq);
}
/* UART - attach an 8250 to the IO space as our UART5 */
if (serial_hd(0)) {
- qemu_irq uart5 = qdev_get_gpio_in(DEVICE(&s->vic), uart_irqs[4]);
- serial_mm_init(get_system_memory(),
- ASPEED_SOC_IOMEM_BASE + ASPEED_SOC_UART_5_BASE, 2,
+ qemu_irq uart5 = aspeed_soc_get_irq(s, ASPEED_UART5);
+ serial_mm_init(get_system_memory(), sc->info->memmap[ASPEED_UART5], 2,
uart5, 38400, serial_hd(0), DEVICE_LITTLE_ENDIAN);
}
error_propagate(errp, err);
return;
}
- sysbus_mmio_map(SYS_BUS_DEVICE(&s->i2c), 0, ASPEED_SOC_I2C_BASE);
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->i2c), 0, sc->info->memmap[ASPEED_I2C]);
sysbus_connect_irq(SYS_BUS_DEVICE(&s->i2c), 0,
- qdev_get_gpio_in(DEVICE(&s->vic), 12));
+ aspeed_soc_get_irq(s, ASPEED_I2C));
/* FMC, The number of CS is set at the board level */
+ object_property_set_int(OBJECT(&s->fmc), sc->info->memmap[ASPEED_SDRAM],
+ "sdram-base", &err);
+ if (err) {
+ error_propagate(errp, err);
+ return;
+ }
object_property_set_bool(OBJECT(&s->fmc), true, "realized", &err);
if (err) {
error_propagate(errp, err);
return;
}
- sysbus_mmio_map(SYS_BUS_DEVICE(&s->fmc), 0, ASPEED_SOC_FMC_BASE);
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->fmc), 0, sc->info->memmap[ASPEED_FMC]);
sysbus_mmio_map(SYS_BUS_DEVICE(&s->fmc), 1,
s->fmc.ctrl->flash_window_base);
sysbus_connect_irq(SYS_BUS_DEVICE(&s->fmc), 0,
- qdev_get_gpio_in(DEVICE(&s->vic), 19));
+ aspeed_soc_get_irq(s, ASPEED_FMC));
/* SPI */
for (i = 0; i < sc->info->spis_num; i++) {
error_propagate(errp, err);
return;
}
- sysbus_mmio_map(SYS_BUS_DEVICE(&s->spi[i]), 0, sc->info->spi_bases[i]);
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->spi[i]), 0,
+ sc->info->memmap[ASPEED_SPI1 + i]);
sysbus_mmio_map(SYS_BUS_DEVICE(&s->spi[i]), 1,
s->spi[i].ctrl->flash_window_base);
}
error_propagate(errp, err);
return;
}
- sysbus_mmio_map(SYS_BUS_DEVICE(&s->sdmc), 0, ASPEED_SOC_SDMC_BASE);
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->sdmc), 0, sc->info->memmap[ASPEED_SDMC]);
/* Watch dog */
for (i = 0; i < sc->info->wdts_num; i++) {
return;
}
sysbus_mmio_map(SYS_BUS_DEVICE(&s->wdt[i]), 0,
- ASPEED_SOC_WDT_BASE + i * 0x20);
+ sc->info->memmap[ASPEED_WDT] + i * 0x20);
}
/* Net */
- qdev_set_nic_properties(DEVICE(&s->ftgmac100), &nd_table[0]);
- object_property_set_bool(OBJECT(&s->ftgmac100), true, "aspeed", &err);
- object_property_set_bool(OBJECT(&s->ftgmac100), true, "realized",
- &local_err);
- error_propagate(&err, local_err);
+ for (i = 0; i < nb_nics; i++) {
+ qdev_set_nic_properties(DEVICE(&s->ftgmac100[i]), &nd_table[i]);
+ object_property_set_bool(OBJECT(&s->ftgmac100[i]), true, "aspeed",
+ &err);
+ object_property_set_bool(OBJECT(&s->ftgmac100[i]), true, "realized",
+ &local_err);
+ error_propagate(&err, local_err);
+ if (err) {
+ error_propagate(errp, err);
+ return;
+ }
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->ftgmac100[i]), 0,
+ sc->info->memmap[ASPEED_ETH1 + i]);
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->ftgmac100[i]), 0,
+ aspeed_soc_get_irq(s, ASPEED_ETH1 + i));
+ }
+
+ /* XDMA */
+ object_property_set_bool(OBJECT(&s->xdma), true, "realized", &err);
if (err) {
error_propagate(errp, err);
return;
}
- sysbus_mmio_map(SYS_BUS_DEVICE(&s->ftgmac100), 0, ASPEED_SOC_ETH1_BASE);
- sysbus_connect_irq(SYS_BUS_DEVICE(&s->ftgmac100), 0,
- qdev_get_gpio_in(DEVICE(&s->vic), 2));
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->xdma), 0,
+ sc->info->memmap[ASPEED_XDMA]);
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->xdma), 0,
+ aspeed_soc_get_irq(s, ASPEED_XDMA));
}
+static Property aspeed_soc_properties[] = {
+ DEFINE_PROP_UINT32("num-cpus", AspeedSoCState, num_cpus, 0),
+ DEFINE_PROP_END_OF_LIST(),
+};
static void aspeed_soc_class_init(ObjectClass *oc, void *data)
{
dc->realize = aspeed_soc_realize;
/* Reason: Uses serial_hds and nd_table in realize() directly */
dc->user_creatable = false;
+ dc->props = aspeed_soc_properties;
}
static const TypeInfo aspeed_soc_type_info = {
info->initrd_filename);
exit(1);
}
- if (info->initrd_start + initrd_size > info->ram_size) {
+ if (info->initrd_start + initrd_size > ram_end) {
error_report("could not load initrd '%s': "
"too big to fit into RAM after the kernel",
info->initrd_filename);
+ exit(1);
}
} else {
initrd_size = 0;
*/
create_unimplemented_device("lcdif", FSL_IMX7_LCDIF_ADDR,
FSL_IMX7_LCDIF_SIZE);
+
+ /*
+ * DMA APBH
+ */
+ create_unimplemented_device("dma-apbh", FSL_IMX7_DMA_APBH_ADDR,
+ FSL_IMX7_DMA_APBH_SIZE);
+ /*
+ * PCIe PHY
+ */
+ create_unimplemented_device("pcie-phy", FSL_IMX7_PCIE_PHY_ADDR,
+ FSL_IMX7_PCIE_PHY_SIZE);
}
static void fsl_imx7_class_init(ObjectClass *oc, void *data)
if (strcmp(machine->cpu_type, mc->default_cpu_type) != 0) {
error_report("This board can only be used with CPU %s",
mc->default_cpu_type);
+ exit(1);
}
memory_region_init_ram(ddr, NULL, "ddr-ram", DDR_SIZE,
--- /dev/null
+/*
+ * ARM SBSA Reference Platform emulation
+ *
+ * Copyright (c) 2018 Linaro Limited
+ * Written by Hongbo Zhang <hongbo.zhang@linaro.org>
+ *
+ * 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/>.
+ */
+
+#include "qemu/osdep.h"
+#include "qemu-common.h"
+#include "qapi/error.h"
+#include "qemu/error-report.h"
+#include "qemu/units.h"
+#include "sysemu/device_tree.h"
+#include "sysemu/numa.h"
+#include "sysemu/sysemu.h"
+#include "exec/address-spaces.h"
+#include "exec/hwaddr.h"
+#include "kvm_arm.h"
+#include "hw/arm/boot.h"
+#include "hw/block/flash.h"
+#include "hw/boards.h"
+#include "hw/ide/internal.h"
+#include "hw/ide/ahci_internal.h"
+#include "hw/intc/arm_gicv3_common.h"
+#include "hw/loader.h"
+#include "hw/pci-host/gpex.h"
+#include "hw/usb.h"
+#include "net/net.h"
+
+#define RAMLIMIT_GB 8192
+#define RAMLIMIT_BYTES (RAMLIMIT_GB * GiB)
+
+#define NUM_IRQS 256
+#define NUM_SMMU_IRQS 4
+#define NUM_SATA_PORTS 6
+
+#define VIRTUAL_PMU_IRQ 7
+#define ARCH_GIC_MAINT_IRQ 9
+#define ARCH_TIMER_VIRT_IRQ 11
+#define ARCH_TIMER_S_EL1_IRQ 13
+#define ARCH_TIMER_NS_EL1_IRQ 14
+#define ARCH_TIMER_NS_EL2_IRQ 10
+
+enum {
+ SBSA_FLASH,
+ SBSA_MEM,
+ SBSA_CPUPERIPHS,
+ SBSA_GIC_DIST,
+ SBSA_GIC_REDIST,
+ SBSA_SMMU,
+ SBSA_UART,
+ SBSA_RTC,
+ SBSA_PCIE,
+ SBSA_PCIE_MMIO,
+ SBSA_PCIE_MMIO_HIGH,
+ SBSA_PCIE_PIO,
+ SBSA_PCIE_ECAM,
+ SBSA_GPIO,
+ SBSA_SECURE_UART,
+ SBSA_SECURE_UART_MM,
+ SBSA_SECURE_MEM,
+ SBSA_AHCI,
+ SBSA_EHCI,
+};
+
+typedef struct MemMapEntry {
+ hwaddr base;
+ hwaddr size;
+} MemMapEntry;
+
+typedef struct {
+ MachineState parent;
+ struct arm_boot_info bootinfo;
+ int smp_cpus;
+ void *fdt;
+ int fdt_size;
+ int psci_conduit;
+ PFlashCFI01 *flash[2];
+} SBSAMachineState;
+
+#define TYPE_SBSA_MACHINE MACHINE_TYPE_NAME("sbsa-ref")
+#define SBSA_MACHINE(obj) \
+ OBJECT_CHECK(SBSAMachineState, (obj), TYPE_SBSA_MACHINE)
+
+static const MemMapEntry sbsa_ref_memmap[] = {
+ /* 512M boot ROM */
+ [SBSA_FLASH] = { 0, 0x20000000 },
+ /* 512M secure memory */
+ [SBSA_SECURE_MEM] = { 0x20000000, 0x20000000 },
+ /* Space reserved for CPU peripheral devices */
+ [SBSA_CPUPERIPHS] = { 0x40000000, 0x00040000 },
+ [SBSA_GIC_DIST] = { 0x40060000, 0x00010000 },
+ [SBSA_GIC_REDIST] = { 0x40080000, 0x04000000 },
+ [SBSA_UART] = { 0x60000000, 0x00001000 },
+ [SBSA_RTC] = { 0x60010000, 0x00001000 },
+ [SBSA_GPIO] = { 0x60020000, 0x00001000 },
+ [SBSA_SECURE_UART] = { 0x60030000, 0x00001000 },
+ [SBSA_SECURE_UART_MM] = { 0x60040000, 0x00001000 },
+ [SBSA_SMMU] = { 0x60050000, 0x00020000 },
+ /* Space here reserved for more SMMUs */
+ [SBSA_AHCI] = { 0x60100000, 0x00010000 },
+ [SBSA_EHCI] = { 0x60110000, 0x00010000 },
+ /* Space here reserved for other devices */
+ [SBSA_PCIE_PIO] = { 0x7fff0000, 0x00010000 },
+ /* 32-bit address PCIE MMIO space */
+ [SBSA_PCIE_MMIO] = { 0x80000000, 0x70000000 },
+ /* 256M PCIE ECAM space */
+ [SBSA_PCIE_ECAM] = { 0xf0000000, 0x10000000 },
+ /* ~1TB PCIE MMIO space (4GB to 1024GB boundary) */
+ [SBSA_PCIE_MMIO_HIGH] = { 0x100000000ULL, 0xFF00000000ULL },
+ [SBSA_MEM] = { 0x10000000000ULL, RAMLIMIT_BYTES },
+};
+
+static const int sbsa_ref_irqmap[] = {
+ [SBSA_UART] = 1,
+ [SBSA_RTC] = 2,
+ [SBSA_PCIE] = 3, /* ... to 6 */
+ [SBSA_GPIO] = 7,
+ [SBSA_SECURE_UART] = 8,
+ [SBSA_SECURE_UART_MM] = 9,
+ [SBSA_AHCI] = 10,
+ [SBSA_EHCI] = 11,
+};
+
+/*
+ * Firmware on this machine only uses ACPI table to load OS, these limited
+ * device tree nodes are just to let firmware know the info which varies from
+ * command line parameters, so it is not necessary to be fully compatible
+ * with the kernel CPU and NUMA binding rules.
+ */
+static void create_fdt(SBSAMachineState *sms)
+{
+ void *fdt = create_device_tree(&sms->fdt_size);
+ const MachineState *ms = MACHINE(sms);
+ int cpu;
+
+ if (!fdt) {
+ error_report("create_device_tree() failed");
+ exit(1);
+ }
+
+ sms->fdt = fdt;
+
+ qemu_fdt_setprop_string(fdt, "/", "compatible", "linux,sbsa-ref");
+ qemu_fdt_setprop_cell(fdt, "/", "#address-cells", 0x2);
+ qemu_fdt_setprop_cell(fdt, "/", "#size-cells", 0x2);
+
+ if (have_numa_distance) {
+ int size = nb_numa_nodes * nb_numa_nodes * 3 * sizeof(uint32_t);
+ uint32_t *matrix = g_malloc0(size);
+ int idx, i, j;
+
+ for (i = 0; i < nb_numa_nodes; i++) {
+ for (j = 0; j < nb_numa_nodes; j++) {
+ idx = (i * nb_numa_nodes + j) * 3;
+ matrix[idx + 0] = cpu_to_be32(i);
+ matrix[idx + 1] = cpu_to_be32(j);
+ matrix[idx + 2] = cpu_to_be32(numa_info[i].distance[j]);
+ }
+ }
+
+ qemu_fdt_add_subnode(fdt, "/distance-map");
+ qemu_fdt_setprop(fdt, "/distance-map", "distance-matrix",
+ matrix, size);
+ g_free(matrix);
+ }
+
+ qemu_fdt_add_subnode(sms->fdt, "/cpus");
+
+ for (cpu = sms->smp_cpus - 1; cpu >= 0; cpu--) {
+ char *nodename = g_strdup_printf("/cpus/cpu@%d", cpu);
+ ARMCPU *armcpu = ARM_CPU(qemu_get_cpu(cpu));
+ CPUState *cs = CPU(armcpu);
+
+ qemu_fdt_add_subnode(sms->fdt, nodename);
+
+ if (ms->possible_cpus->cpus[cs->cpu_index].props.has_node_id) {
+ qemu_fdt_setprop_cell(sms->fdt, nodename, "numa-node-id",
+ ms->possible_cpus->cpus[cs->cpu_index].props.node_id);
+ }
+
+ g_free(nodename);
+ }
+}
+
+#define SBSA_FLASH_SECTOR_SIZE (256 * KiB)
+
+static PFlashCFI01 *sbsa_flash_create1(SBSAMachineState *sms,
+ const char *name,
+ const char *alias_prop_name)
+{
+ /*
+ * Create a single flash device. We use the same parameters as
+ * the flash devices on the Versatile Express board.
+ */
+ DeviceState *dev = qdev_create(NULL, TYPE_PFLASH_CFI01);
+
+ qdev_prop_set_uint64(dev, "sector-length", SBSA_FLASH_SECTOR_SIZE);
+ qdev_prop_set_uint8(dev, "width", 4);
+ qdev_prop_set_uint8(dev, "device-width", 2);
+ qdev_prop_set_bit(dev, "big-endian", false);
+ qdev_prop_set_uint16(dev, "id0", 0x89);
+ qdev_prop_set_uint16(dev, "id1", 0x18);
+ qdev_prop_set_uint16(dev, "id2", 0x00);
+ qdev_prop_set_uint16(dev, "id3", 0x00);
+ qdev_prop_set_string(dev, "name", name);
+ object_property_add_child(OBJECT(sms), name, OBJECT(dev),
+ &error_abort);
+ object_property_add_alias(OBJECT(sms), alias_prop_name,
+ OBJECT(dev), "drive", &error_abort);
+ return PFLASH_CFI01(dev);
+}
+
+static void sbsa_flash_create(SBSAMachineState *sms)
+{
+ sms->flash[0] = sbsa_flash_create1(sms, "sbsa.flash0", "pflash0");
+ sms->flash[1] = sbsa_flash_create1(sms, "sbsa.flash1", "pflash1");
+}
+
+static void sbsa_flash_map1(PFlashCFI01 *flash,
+ hwaddr base, hwaddr size,
+ MemoryRegion *sysmem)
+{
+ DeviceState *dev = DEVICE(flash);
+
+ assert(size % SBSA_FLASH_SECTOR_SIZE == 0);
+ assert(size / SBSA_FLASH_SECTOR_SIZE <= UINT32_MAX);
+ qdev_prop_set_uint32(dev, "num-blocks", size / SBSA_FLASH_SECTOR_SIZE);
+ qdev_init_nofail(dev);
+
+ memory_region_add_subregion(sysmem, base,
+ sysbus_mmio_get_region(SYS_BUS_DEVICE(dev),
+ 0));
+}
+
+static void sbsa_flash_map(SBSAMachineState *sms,
+ MemoryRegion *sysmem,
+ MemoryRegion *secure_sysmem)
+{
+ /*
+ * Map two flash devices to fill the SBSA_FLASH space in the memmap.
+ * sysmem is the system memory space. secure_sysmem is the secure view
+ * of the system, and the first flash device should be made visible only
+ * there. The second flash device is visible to both secure and nonsecure.
+ * If sysmem == secure_sysmem this means there is no separate Secure
+ * address space and both flash devices are generally visible.
+ */
+ hwaddr flashsize = sbsa_ref_memmap[SBSA_FLASH].size / 2;
+ hwaddr flashbase = sbsa_ref_memmap[SBSA_FLASH].base;
+
+ sbsa_flash_map1(sms->flash[0], flashbase, flashsize,
+ secure_sysmem);
+ sbsa_flash_map1(sms->flash[1], flashbase + flashsize, flashsize,
+ sysmem);
+}
+
+static bool sbsa_firmware_init(SBSAMachineState *sms,
+ MemoryRegion *sysmem,
+ MemoryRegion *secure_sysmem)
+{
+ int i;
+ BlockBackend *pflash_blk0;
+
+ /* Map legacy -drive if=pflash to machine properties */
+ for (i = 0; i < ARRAY_SIZE(sms->flash); i++) {
+ pflash_cfi01_legacy_drive(sms->flash[i],
+ drive_get(IF_PFLASH, 0, i));
+ }
+
+ sbsa_flash_map(sms, sysmem, secure_sysmem);
+
+ pflash_blk0 = pflash_cfi01_get_blk(sms->flash[0]);
+
+ if (bios_name) {
+ char *fname;
+ MemoryRegion *mr;
+ int image_size;
+
+ if (pflash_blk0) {
+ error_report("The contents of the first flash device may be "
+ "specified with -bios or with -drive if=pflash... "
+ "but you cannot use both options at once");
+ exit(1);
+ }
+
+ /* Fall back to -bios */
+
+ fname = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
+ if (!fname) {
+ error_report("Could not find ROM image '%s'", bios_name);
+ exit(1);
+ }
+ mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(sms->flash[0]), 0);
+ image_size = load_image_mr(fname, mr);
+ g_free(fname);
+ if (image_size < 0) {
+ error_report("Could not load ROM image '%s'", bios_name);
+ exit(1);
+ }
+ }
+
+ return pflash_blk0 || bios_name;
+}
+
+static void create_secure_ram(SBSAMachineState *sms,
+ MemoryRegion *secure_sysmem)
+{
+ MemoryRegion *secram = g_new(MemoryRegion, 1);
+ hwaddr base = sbsa_ref_memmap[SBSA_SECURE_MEM].base;
+ hwaddr size = sbsa_ref_memmap[SBSA_SECURE_MEM].size;
+
+ memory_region_init_ram(secram, NULL, "sbsa-ref.secure-ram", size,
+ &error_fatal);
+ memory_region_add_subregion(secure_sysmem, base, secram);
+}
+
+static void create_gic(SBSAMachineState *sms, qemu_irq *pic)
+{
+ DeviceState *gicdev;
+ SysBusDevice *gicbusdev;
+ const char *gictype;
+ uint32_t redist0_capacity, redist0_count;
+ int i;
+
+ gictype = gicv3_class_name();
+
+ gicdev = qdev_create(NULL, gictype);
+ qdev_prop_set_uint32(gicdev, "revision", 3);
+ qdev_prop_set_uint32(gicdev, "num-cpu", smp_cpus);
+ /*
+ * Note that the num-irq property counts both internal and external
+ * interrupts; there are always 32 of the former (mandated by GIC spec).
+ */
+ qdev_prop_set_uint32(gicdev, "num-irq", NUM_IRQS + 32);
+ qdev_prop_set_bit(gicdev, "has-security-extensions", true);
+
+ redist0_capacity =
+ sbsa_ref_memmap[SBSA_GIC_REDIST].size / GICV3_REDIST_SIZE;
+ redist0_count = MIN(smp_cpus, redist0_capacity);
+
+ qdev_prop_set_uint32(gicdev, "len-redist-region-count", 1);
+ qdev_prop_set_uint32(gicdev, "redist-region-count[0]", redist0_count);
+
+ qdev_init_nofail(gicdev);
+ gicbusdev = SYS_BUS_DEVICE(gicdev);
+ sysbus_mmio_map(gicbusdev, 0, sbsa_ref_memmap[SBSA_GIC_DIST].base);
+ sysbus_mmio_map(gicbusdev, 1, sbsa_ref_memmap[SBSA_GIC_REDIST].base);
+
+ /*
+ * Wire the outputs from each CPU's generic timer and the GICv3
+ * maintenance interrupt signal to the appropriate GIC PPI inputs,
+ * and the GIC's IRQ/FIQ/VIRQ/VFIQ interrupt outputs to the CPU's inputs.
+ */
+ for (i = 0; i < smp_cpus; i++) {
+ DeviceState *cpudev = DEVICE(qemu_get_cpu(i));
+ int ppibase = NUM_IRQS + i * GIC_INTERNAL + GIC_NR_SGIS;
+ int irq;
+ /*
+ * Mapping from the output timer irq lines from the CPU to the
+ * GIC PPI inputs used for this board.
+ */
+ const int timer_irq[] = {
+ [GTIMER_PHYS] = ARCH_TIMER_NS_EL1_IRQ,
+ [GTIMER_VIRT] = ARCH_TIMER_VIRT_IRQ,
+ [GTIMER_HYP] = ARCH_TIMER_NS_EL2_IRQ,
+ [GTIMER_SEC] = ARCH_TIMER_S_EL1_IRQ,
+ };
+
+ for (irq = 0; irq < ARRAY_SIZE(timer_irq); irq++) {
+ qdev_connect_gpio_out(cpudev, irq,
+ qdev_get_gpio_in(gicdev,
+ ppibase + timer_irq[irq]));
+ }
+
+ qdev_connect_gpio_out_named(cpudev, "gicv3-maintenance-interrupt", 0,
+ qdev_get_gpio_in(gicdev, ppibase
+ + ARCH_GIC_MAINT_IRQ));
+ qdev_connect_gpio_out_named(cpudev, "pmu-interrupt", 0,
+ qdev_get_gpio_in(gicdev, ppibase
+ + VIRTUAL_PMU_IRQ));
+
+ sysbus_connect_irq(gicbusdev, i, qdev_get_gpio_in(cpudev, ARM_CPU_IRQ));
+ sysbus_connect_irq(gicbusdev, i + smp_cpus,
+ qdev_get_gpio_in(cpudev, ARM_CPU_FIQ));
+ sysbus_connect_irq(gicbusdev, i + 2 * smp_cpus,
+ qdev_get_gpio_in(cpudev, ARM_CPU_VIRQ));
+ sysbus_connect_irq(gicbusdev, i + 3 * smp_cpus,
+ qdev_get_gpio_in(cpudev, ARM_CPU_VFIQ));
+ }
+
+ for (i = 0; i < NUM_IRQS; i++) {
+ pic[i] = qdev_get_gpio_in(gicdev, i);
+ }
+}
+
+static void create_uart(const SBSAMachineState *sms, qemu_irq *pic, int uart,
+ MemoryRegion *mem, Chardev *chr)
+{
+ hwaddr base = sbsa_ref_memmap[uart].base;
+ int irq = sbsa_ref_irqmap[uart];
+ DeviceState *dev = qdev_create(NULL, "pl011");
+ SysBusDevice *s = SYS_BUS_DEVICE(dev);
+
+ qdev_prop_set_chr(dev, "chardev", chr);
+ qdev_init_nofail(dev);
+ memory_region_add_subregion(mem, base,
+ sysbus_mmio_get_region(s, 0));
+ sysbus_connect_irq(s, 0, pic[irq]);
+}
+
+static void create_rtc(const SBSAMachineState *sms, qemu_irq *pic)
+{
+ hwaddr base = sbsa_ref_memmap[SBSA_RTC].base;
+ int irq = sbsa_ref_irqmap[SBSA_RTC];
+
+ sysbus_create_simple("pl031", base, pic[irq]);
+}
+
+static DeviceState *gpio_key_dev;
+static void sbsa_ref_powerdown_req(Notifier *n, void *opaque)
+{
+ /* use gpio Pin 3 for power button event */
+ qemu_set_irq(qdev_get_gpio_in(gpio_key_dev, 0), 1);
+}
+
+static Notifier sbsa_ref_powerdown_notifier = {
+ .notify = sbsa_ref_powerdown_req
+};
+
+static void create_gpio(const SBSAMachineState *sms, qemu_irq *pic)
+{
+ DeviceState *pl061_dev;
+ hwaddr base = sbsa_ref_memmap[SBSA_GPIO].base;
+ int irq = sbsa_ref_irqmap[SBSA_GPIO];
+
+ pl061_dev = sysbus_create_simple("pl061", base, pic[irq]);
+
+ gpio_key_dev = sysbus_create_simple("gpio-key", -1,
+ qdev_get_gpio_in(pl061_dev, 3));
+
+ /* connect powerdown request */
+ qemu_register_powerdown_notifier(&sbsa_ref_powerdown_notifier);
+}
+
+static void create_ahci(const SBSAMachineState *sms, qemu_irq *pic)
+{
+ hwaddr base = sbsa_ref_memmap[SBSA_AHCI].base;
+ int irq = sbsa_ref_irqmap[SBSA_AHCI];
+ DeviceState *dev;
+ DriveInfo *hd[NUM_SATA_PORTS];
+ SysbusAHCIState *sysahci;
+ AHCIState *ahci;
+ int i;
+
+ dev = qdev_create(NULL, "sysbus-ahci");
+ qdev_prop_set_uint32(dev, "num-ports", NUM_SATA_PORTS);
+ qdev_init_nofail(dev);
+ sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base);
+ sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, pic[irq]);
+
+ sysahci = SYSBUS_AHCI(dev);
+ ahci = &sysahci->ahci;
+ ide_drive_get(hd, ARRAY_SIZE(hd));
+ for (i = 0; i < ahci->ports; i++) {
+ if (hd[i] == NULL) {
+ continue;
+ }
+ ide_create_drive(&ahci->dev[i].port, 0, hd[i]);
+ }
+}
+
+static void create_ehci(const SBSAMachineState *sms, qemu_irq *pic)
+{
+ hwaddr base = sbsa_ref_memmap[SBSA_EHCI].base;
+ int irq = sbsa_ref_irqmap[SBSA_EHCI];
+
+ sysbus_create_simple("platform-ehci-usb", base, pic[irq]);
+}
+
+static void create_smmu(const SBSAMachineState *sms, qemu_irq *pic,
+ PCIBus *bus)
+{
+ hwaddr base = sbsa_ref_memmap[SBSA_SMMU].base;
+ int irq = sbsa_ref_irqmap[SBSA_SMMU];
+ DeviceState *dev;
+ int i;
+
+ dev = qdev_create(NULL, "arm-smmuv3");
+
+ object_property_set_link(OBJECT(dev), OBJECT(bus), "primary-bus",
+ &error_abort);
+ qdev_init_nofail(dev);
+ sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base);
+ for (i = 0; i < NUM_SMMU_IRQS; i++) {
+ sysbus_connect_irq(SYS_BUS_DEVICE(dev), i, pic[irq + i]);
+ }
+}
+
+static void create_pcie(SBSAMachineState *sms, qemu_irq *pic)
+{
+ hwaddr base_ecam = sbsa_ref_memmap[SBSA_PCIE_ECAM].base;
+ hwaddr size_ecam = sbsa_ref_memmap[SBSA_PCIE_ECAM].size;
+ hwaddr base_mmio = sbsa_ref_memmap[SBSA_PCIE_MMIO].base;
+ hwaddr size_mmio = sbsa_ref_memmap[SBSA_PCIE_MMIO].size;
+ hwaddr base_mmio_high = sbsa_ref_memmap[SBSA_PCIE_MMIO_HIGH].base;
+ hwaddr size_mmio_high = sbsa_ref_memmap[SBSA_PCIE_MMIO_HIGH].size;
+ hwaddr base_pio = sbsa_ref_memmap[SBSA_PCIE_PIO].base;
+ int irq = sbsa_ref_irqmap[SBSA_PCIE];
+ MemoryRegion *mmio_alias, *mmio_alias_high, *mmio_reg;
+ MemoryRegion *ecam_alias, *ecam_reg;
+ DeviceState *dev;
+ PCIHostState *pci;
+ int i;
+
+ dev = qdev_create(NULL, TYPE_GPEX_HOST);
+ qdev_init_nofail(dev);
+
+ /* Map ECAM space */
+ ecam_alias = g_new0(MemoryRegion, 1);
+ ecam_reg = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 0);
+ memory_region_init_alias(ecam_alias, OBJECT(dev), "pcie-ecam",
+ ecam_reg, 0, size_ecam);
+ memory_region_add_subregion(get_system_memory(), base_ecam, ecam_alias);
+
+ /* Map the MMIO space */
+ mmio_alias = g_new0(MemoryRegion, 1);
+ mmio_reg = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 1);
+ memory_region_init_alias(mmio_alias, OBJECT(dev), "pcie-mmio",
+ mmio_reg, base_mmio, size_mmio);
+ memory_region_add_subregion(get_system_memory(), base_mmio, mmio_alias);
+
+ /* Map the MMIO_HIGH space */
+ mmio_alias_high = g_new0(MemoryRegion, 1);
+ memory_region_init_alias(mmio_alias_high, OBJECT(dev), "pcie-mmio-high",
+ mmio_reg, base_mmio_high, size_mmio_high);
+ memory_region_add_subregion(get_system_memory(), base_mmio_high,
+ mmio_alias_high);
+
+ /* Map IO port space */
+ sysbus_mmio_map(SYS_BUS_DEVICE(dev), 2, base_pio);
+
+ for (i = 0; i < GPEX_NUM_IRQS; i++) {
+ sysbus_connect_irq(SYS_BUS_DEVICE(dev), i, pic[irq + i]);
+ gpex_set_irq_num(GPEX_HOST(dev), i, irq + i);
+ }
+
+ pci = PCI_HOST_BRIDGE(dev);
+ if (pci->bus) {
+ for (i = 0; i < nb_nics; i++) {
+ NICInfo *nd = &nd_table[i];
+
+ if (!nd->model) {
+ nd->model = g_strdup("e1000e");
+ }
+
+ pci_nic_init_nofail(nd, pci->bus, nd->model, NULL);
+ }
+ }
+
+ pci_create_simple(pci->bus, -1, "VGA");
+
+ create_smmu(sms, pic, pci->bus);
+}
+
+static void *sbsa_ref_dtb(const struct arm_boot_info *binfo, int *fdt_size)
+{
+ const SBSAMachineState *board = container_of(binfo, SBSAMachineState,
+ bootinfo);
+
+ *fdt_size = board->fdt_size;
+ return board->fdt;
+}
+
+static void sbsa_ref_init(MachineState *machine)
+{
+ SBSAMachineState *sms = SBSA_MACHINE(machine);
+ MachineClass *mc = MACHINE_GET_CLASS(machine);
+ MemoryRegion *sysmem = get_system_memory();
+ MemoryRegion *secure_sysmem = NULL;
+ MemoryRegion *ram = g_new(MemoryRegion, 1);
+ bool firmware_loaded;
+ const CPUArchIdList *possible_cpus;
+ int n, sbsa_max_cpus;
+ qemu_irq pic[NUM_IRQS];
+
+ if (strcmp(machine->cpu_type, ARM_CPU_TYPE_NAME("cortex-a57"))) {
+ error_report("sbsa-ref: CPU type other than the built-in "
+ "cortex-a57 not supported");
+ exit(1);
+ }
+
+ if (kvm_enabled()) {
+ error_report("sbsa-ref: KVM is not supported for this machine");
+ exit(1);
+ }
+
+ /*
+ * The Secure view of the world is the same as the NonSecure,
+ * but with a few extra devices. Create it as a container region
+ * containing the system memory at low priority; any secure-only
+ * devices go in at higher priority and take precedence.
+ */
+ secure_sysmem = g_new(MemoryRegion, 1);
+ memory_region_init(secure_sysmem, OBJECT(machine), "secure-memory",
+ UINT64_MAX);
+ memory_region_add_subregion_overlap(secure_sysmem, 0, sysmem, -1);
+
+ firmware_loaded = sbsa_firmware_init(sms, sysmem,
+ secure_sysmem ?: sysmem);
+
+ if (machine->kernel_filename && firmware_loaded) {
+ error_report("sbsa-ref: No fw_cfg device on this machine, "
+ "so -kernel option is not supported when firmware loaded, "
+ "please load OS from hard disk instead");
+ exit(1);
+ }
+
+ /*
+ * This machine has EL3 enabled, external firmware should supply PSCI
+ * implementation, so the QEMU's internal PSCI is disabled.
+ */
+ sms->psci_conduit = QEMU_PSCI_CONDUIT_DISABLED;
+
+ sbsa_max_cpus = sbsa_ref_memmap[SBSA_GIC_REDIST].size / GICV3_REDIST_SIZE;
+
+ if (max_cpus > sbsa_max_cpus) {
+ error_report("Number of SMP CPUs requested (%d) exceeds max CPUs "
+ "supported by machine 'sbsa-ref' (%d)",
+ max_cpus, sbsa_max_cpus);
+ exit(1);
+ }
+
+ sms->smp_cpus = smp_cpus;
+
+ if (machine->ram_size > sbsa_ref_memmap[SBSA_MEM].size) {
+ error_report("sbsa-ref: cannot model more than %dGB RAM", RAMLIMIT_GB);
+ exit(1);
+ }
+
+ possible_cpus = mc->possible_cpu_arch_ids(machine);
+ for (n = 0; n < possible_cpus->len; n++) {
+ Object *cpuobj;
+ CPUState *cs;
+
+ if (n >= smp_cpus) {
+ break;
+ }
+
+ cpuobj = object_new(possible_cpus->cpus[n].type);
+ object_property_set_int(cpuobj, possible_cpus->cpus[n].arch_id,
+ "mp-affinity", NULL);
+
+ cs = CPU(cpuobj);
+ cs->cpu_index = n;
+
+ numa_cpu_pre_plug(&possible_cpus->cpus[cs->cpu_index], DEVICE(cpuobj),
+ &error_fatal);
+
+ if (object_property_find(cpuobj, "reset-cbar", NULL)) {
+ object_property_set_int(cpuobj,
+ sbsa_ref_memmap[SBSA_CPUPERIPHS].base,
+ "reset-cbar", &error_abort);
+ }
+
+ object_property_set_link(cpuobj, OBJECT(sysmem), "memory",
+ &error_abort);
+
+ object_property_set_link(cpuobj, OBJECT(secure_sysmem),
+ "secure-memory", &error_abort);
+
+ object_property_set_bool(cpuobj, true, "realized", &error_fatal);
+ object_unref(cpuobj);
+ }
+
+ memory_region_allocate_system_memory(ram, NULL, "sbsa-ref.ram",
+ machine->ram_size);
+ memory_region_add_subregion(sysmem, sbsa_ref_memmap[SBSA_MEM].base, ram);
+
+ create_fdt(sms);
+
+ create_secure_ram(sms, secure_sysmem);
+
+ create_gic(sms, pic);
+
+ create_uart(sms, pic, SBSA_UART, sysmem, serial_hd(0));
+ create_uart(sms, pic, SBSA_SECURE_UART, secure_sysmem, serial_hd(1));
+ /* Second secure UART for RAS and MM from EL0 */
+ create_uart(sms, pic, SBSA_SECURE_UART_MM, secure_sysmem, serial_hd(2));
+
+ create_rtc(sms, pic);
+
+ create_gpio(sms, pic);
+
+ create_ahci(sms, pic);
+
+ create_ehci(sms, pic);
+
+ create_pcie(sms, pic);
+
+ sms->bootinfo.ram_size = machine->ram_size;
+ sms->bootinfo.kernel_filename = machine->kernel_filename;
+ sms->bootinfo.nb_cpus = smp_cpus;
+ sms->bootinfo.board_id = -1;
+ sms->bootinfo.loader_start = sbsa_ref_memmap[SBSA_MEM].base;
+ sms->bootinfo.get_dtb = sbsa_ref_dtb;
+ sms->bootinfo.firmware_loaded = firmware_loaded;
+ arm_load_kernel(ARM_CPU(first_cpu), &sms->bootinfo);
+}
+
+static uint64_t sbsa_ref_cpu_mp_affinity(SBSAMachineState *sms, int idx)
+{
+ uint8_t clustersz = ARM_DEFAULT_CPUS_PER_CLUSTER;
+ return arm_cpu_mp_affinity(idx, clustersz);
+}
+
+static const CPUArchIdList *sbsa_ref_possible_cpu_arch_ids(MachineState *ms)
+{
+ SBSAMachineState *sms = SBSA_MACHINE(ms);
+ int n;
+
+ if (ms->possible_cpus) {
+ assert(ms->possible_cpus->len == max_cpus);
+ return ms->possible_cpus;
+ }
+
+ ms->possible_cpus = g_malloc0(sizeof(CPUArchIdList) +
+ sizeof(CPUArchId) * max_cpus);
+ ms->possible_cpus->len = max_cpus;
+ for (n = 0; n < ms->possible_cpus->len; n++) {
+ ms->possible_cpus->cpus[n].type = ms->cpu_type;
+ ms->possible_cpus->cpus[n].arch_id =
+ sbsa_ref_cpu_mp_affinity(sms, n);
+ ms->possible_cpus->cpus[n].props.has_thread_id = true;
+ ms->possible_cpus->cpus[n].props.thread_id = n;
+ }
+ return ms->possible_cpus;
+}
+
+static CpuInstanceProperties
+sbsa_ref_cpu_index_to_props(MachineState *ms, unsigned cpu_index)
+{
+ MachineClass *mc = MACHINE_GET_CLASS(ms);
+ const CPUArchIdList *possible_cpus = mc->possible_cpu_arch_ids(ms);
+
+ assert(cpu_index < possible_cpus->len);
+ return possible_cpus->cpus[cpu_index].props;
+}
+
+static int64_t
+sbsa_ref_get_default_cpu_node_id(const MachineState *ms, int idx)
+{
+ return idx % nb_numa_nodes;
+}
+
+static void sbsa_ref_instance_init(Object *obj)
+{
+ SBSAMachineState *sms = SBSA_MACHINE(obj);
+
+ sbsa_flash_create(sms);
+}
+
+static void sbsa_ref_class_init(ObjectClass *oc, void *data)
+{
+ MachineClass *mc = MACHINE_CLASS(oc);
+
+ mc->init = sbsa_ref_init;
+ mc->desc = "QEMU 'SBSA Reference' ARM Virtual Machine";
+ mc->default_cpu_type = ARM_CPU_TYPE_NAME("cortex-a57");
+ mc->max_cpus = 512;
+ mc->pci_allow_0_address = true;
+ mc->minimum_page_bits = 12;
+ mc->block_default_type = IF_IDE;
+ mc->no_cdrom = 1;
+ mc->default_ram_size = 1 * GiB;
+ mc->default_cpus = 4;
+ mc->possible_cpu_arch_ids = sbsa_ref_possible_cpu_arch_ids;
+ mc->cpu_index_to_instance_props = sbsa_ref_cpu_index_to_props;
+ mc->get_default_cpu_node_id = sbsa_ref_get_default_cpu_node_id;
+}
+
+static const TypeInfo sbsa_ref_info = {
+ .name = TYPE_SBSA_MACHINE,
+ .parent = TYPE_MACHINE,
+ .instance_init = sbsa_ref_instance_init,
+ .class_init = sbsa_ref_class_init,
+ .instance_size = sizeof(SBSAMachineState),
+};
+
+static void sbsa_ref_machine_init(void)
+{
+ type_register_static(&sbsa_ref_info);
+}
+
+type_init(sbsa_ref_machine_init);
};
static const char *valid_cpus[] = {
+ ARM_CPU_TYPE_NAME("cortex-a7"),
ARM_CPU_TYPE_NAME("cortex-a15"),
ARM_CPU_TYPE_NAME("cortex-a53"),
ARM_CPU_TYPE_NAME("cortex-a57"),
switch (width) {
case 1:
ret = p[offset];
- trace_pflash_data_read8(offset, ret);
break;
case 2:
if (be) {
ret = p[offset];
ret |= p[offset + 1] << 8;
}
- trace_pflash_data_read16(offset, ret);
break;
case 4:
if (be) {
ret |= p[offset + 2] << 16;
ret |= p[offset + 3] << 24;
}
- trace_pflash_data_read32(offset, ret);
break;
default:
DPRINTF("BUG in %s\n", __func__);
abort();
}
+ trace_pflash_data_read(offset, width << 1, ret);
return ret;
}
uint32_t ret;
ret = -1;
- trace_pflash_read(offset, pfl->cmd, width, pfl->wcycle);
switch (pfl->cmd) {
default:
/* This should never happen : reset state & treat it as a read */
break;
}
+ trace_pflash_io_read(offset, width, width << 1, ret, pfl->cmd, pfl->wcycle);
+
return ret;
}
{
uint8_t *p = pfl->storage;
- trace_pflash_data_write(offset, value, width, pfl->counter);
+ trace_pflash_data_write(offset, width << 1, value, pfl->counter);
switch (width) {
case 1:
p[offset] = value;
cmd = value;
- trace_pflash_write(offset, value, width, pfl->wcycle);
+ trace_pflash_io_write(offset, width, width << 1, value, pfl->wcycle);
if (!pfl->wcycle) {
/* Set the device in I/O access mode */
memory_region_rom_device_set_romd(&pfl->mem, false);
* - CFI queries
*
* It does not support flash interleaving.
- * It does not implement boot blocs with reduced size
* It does not implement software data protection as found in many real chips
- * It does not implement erase suspend/resume commands
- * It does not implement multiple sectors erase
*/
#include "qemu/osdep.h"
#include "hw/block/block.h"
#include "hw/block/flash.h"
#include "qapi/error.h"
+#include "qemu/bitmap.h"
#include "qemu/timer.h"
#include "sysemu/block-backend.h"
#include "qemu/host-utils.h"
#include "hw/sysbus.h"
#include "trace.h"
-//#define PFLASH_DEBUG
-#ifdef PFLASH_DEBUG
+#define PFLASH_DEBUG false
#define DPRINTF(fmt, ...) \
do { \
- fprintf(stderr, "PFLASH: " fmt , ## __VA_ARGS__); \
+ if (PFLASH_DEBUG) { \
+ fprintf(stderr, "PFLASH: " fmt, ## __VA_ARGS__); \
+ } \
} while (0)
-#else
-#define DPRINTF(fmt, ...) do { } while (0)
-#endif
#define PFLASH_LAZY_ROMD_THRESHOLD 42
+/*
+ * The size of the cfi_table indirectly depends on this and the start of the
+ * PRI table directly depends on it. 4 is the maximum size (and also what
+ * seems common) without changing the PRT table address.
+ */
+#define PFLASH_MAX_ERASE_REGIONS 4
+
+/* Special write cycles for CFI queries. */
+enum {
+ WCYCLE_CFI = 7,
+ WCYCLE_AUTOSELECT_CFI = 8,
+};
+
struct PFlashCFI02 {
/*< private >*/
SysBusDevice parent_obj;
/*< public >*/
BlockBackend *blk;
- uint32_t sector_len;
- uint32_t nb_blocs;
+ uint32_t uniform_nb_blocs;
+ uint32_t uniform_sector_len;
+ uint32_t total_sectors;
+ uint32_t nb_blocs[PFLASH_MAX_ERASE_REGIONS];
+ uint32_t sector_len[PFLASH_MAX_ERASE_REGIONS];
uint32_t chip_len;
uint8_t mappings;
uint8_t width;
uint16_t ident3;
uint16_t unlock_addr0;
uint16_t unlock_addr1;
- uint8_t cfi_table[0x52];
+ uint8_t cfi_table[0x4d];
QEMUTimer timer;
/* The device replicates the flash memory across its memory space. Emulate
* that by having a container (.mem) filled with an array of aliases
MemoryRegion orig_mem;
int rom_mode;
int read_counter; /* used for lazy switch-back to rom mode */
+ int sectors_to_erase;
+ uint64_t erase_time_remaining;
+ unsigned long *sector_erase_map;
char *name;
void *storage;
};
+/*
+ * Toggle status bit DQ7.
+ */
+static inline void toggle_dq7(PFlashCFI02 *pfl)
+{
+ pfl->status ^= 0x80;
+}
+
+/*
+ * Set status bit DQ7 to bit 7 of value.
+ */
+static inline void set_dq7(PFlashCFI02 *pfl, uint8_t value)
+{
+ pfl->status &= 0x7F;
+ pfl->status |= value & 0x80;
+}
+
+/*
+ * Toggle status bit DQ6.
+ */
+static inline void toggle_dq6(PFlashCFI02 *pfl)
+{
+ pfl->status ^= 0x40;
+}
+
+/*
+ * Turn on DQ3.
+ */
+static inline void assert_dq3(PFlashCFI02 *pfl)
+{
+ pfl->status |= 0x08;
+}
+
+/*
+ * Turn off DQ3.
+ */
+static inline void reset_dq3(PFlashCFI02 *pfl)
+{
+ pfl->status &= ~0x08;
+}
+
+/*
+ * Toggle status bit DQ2.
+ */
+static inline void toggle_dq2(PFlashCFI02 *pfl)
+{
+ pfl->status ^= 0x04;
+}
+
/*
* Set up replicated mappings of the same region.
*/
pfl->rom_mode = rom_mode;
}
-static void pflash_timer (void *opaque)
+static size_t pflash_regions_count(PFlashCFI02 *pfl)
+{
+ return pfl->cfi_table[0x2c];
+}
+
+/*
+ * Returns the time it takes to erase the number of sectors scheduled for
+ * erasure based on CFI address 0x21 which is "Typical timeout per individual
+ * block erase 2^N ms."
+ */
+static uint64_t pflash_erase_time(PFlashCFI02 *pfl)
+{
+ /*
+ * If there are no sectors to erase (which can happen if all of the sectors
+ * to be erased are protected), then erase takes 100 us. Protected sectors
+ * aren't supported so this should never happen.
+ */
+ return ((1ULL << pfl->cfi_table[0x21]) * pfl->sectors_to_erase) * SCALE_US;
+}
+
+/*
+ * Returns true if the device is currently in erase suspend mode.
+ */
+static inline bool pflash_erase_suspend_mode(PFlashCFI02 *pfl)
+{
+ return pfl->erase_time_remaining > 0;
+}
+
+static void pflash_timer(void *opaque)
{
PFlashCFI02 *pfl = opaque;
trace_pflash_timer_expired(pfl->cmd);
+ if (pfl->cmd == 0x30) {
+ /*
+ * Sector erase. If DQ3 is 0 when the timer expires, then the 50
+ * us erase timeout has expired so we need to start the timer for the
+ * sector erase algorithm. Otherwise, the erase completed and we should
+ * go back to read array mode.
+ */
+ if ((pfl->status & 0x08) == 0) {
+ assert_dq3(pfl);
+ uint64_t timeout = pflash_erase_time(pfl);
+ timer_mod(&pfl->timer,
+ qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + timeout);
+ DPRINTF("%s: erase timeout fired; erasing %d sectors\n",
+ __func__, pfl->sectors_to_erase);
+ return;
+ }
+ DPRINTF("%s: sector erase complete\n", __func__);
+ bitmap_zero(pfl->sector_erase_map, pfl->total_sectors);
+ pfl->sectors_to_erase = 0;
+ reset_dq3(pfl);
+ }
+
/* Reset flash */
- pfl->status ^= 0x80;
+ toggle_dq7(pfl);
if (pfl->bypass) {
pfl->wcycle = 2;
} else {
pfl->cmd = 0;
}
-static uint32_t pflash_read(PFlashCFI02 *pfl, hwaddr offset,
- int width, int be)
+/*
+ * Read data from flash.
+ */
+static uint64_t pflash_data_read(PFlashCFI02 *pfl, hwaddr offset,
+ unsigned int width)
+{
+ uint8_t *p = (uint8_t *)pfl->storage + offset;
+ uint64_t ret = pfl->be ? ldn_be_p(p, width) : ldn_le_p(p, width);
+ trace_pflash_data_read(offset, width << 1, ret);
+ return ret;
+}
+
+typedef struct {
+ uint32_t len;
+ uint32_t num;
+} SectorInfo;
+
+/*
+ * offset should be a byte offset of the QEMU device and _not_ a device
+ * offset.
+ */
+static SectorInfo pflash_sector_info(PFlashCFI02 *pfl, hwaddr offset)
{
+ assert(offset < pfl->chip_len);
+ hwaddr addr = 0;
+ uint32_t sector_num = 0;
+ for (int i = 0; i < pflash_regions_count(pfl); ++i) {
+ uint64_t region_size = (uint64_t)pfl->nb_blocs[i] * pfl->sector_len[i];
+ if (addr <= offset && offset < addr + region_size) {
+ return (SectorInfo) {
+ .len = pfl->sector_len[i],
+ .num = sector_num + (offset - addr) / pfl->sector_len[i],
+ };
+ }
+ sector_num += pfl->nb_blocs[i];
+ addr += region_size;
+ }
+ abort();
+}
+
+/*
+ * Returns true if the offset refers to a flash sector that is currently being
+ * erased.
+ */
+static bool pflash_sector_is_erasing(PFlashCFI02 *pfl, hwaddr offset)
+{
+ long sector_num = pflash_sector_info(pfl, offset).num;
+ return test_bit(sector_num, pfl->sector_erase_map);
+}
+
+static uint64_t pflash_read(void *opaque, hwaddr offset, unsigned int width)
+{
+ PFlashCFI02 *pfl = opaque;
hwaddr boff;
- uint32_t ret;
- uint8_t *p;
+ uint64_t ret;
ret = -1;
- trace_pflash_read(offset, pfl->cmd, width, pfl->wcycle);
/* Lazy reset to ROMD mode after a certain amount of read accesses */
if (!pfl->rom_mode && pfl->wcycle == 0 &&
++pfl->read_counter > PFLASH_LAZY_ROMD_THRESHOLD) {
}
offset &= pfl->chip_len - 1;
boff = offset & 0xFF;
- if (pfl->width == 2)
+ if (pfl->width == 2) {
boff = boff >> 1;
- else if (pfl->width == 4)
- boff = boff >> 2;
+ }
switch (pfl->cmd) {
default:
/* This should never happen : reset state & treat it as a read*/
pfl->wcycle = 0;
pfl->cmd = 0;
/* fall through to the read code */
- case 0x80:
+ case 0x80: /* Erase (unlock) */
/* We accept reads during second unlock sequence... */
case 0x00:
- flash_read:
- /* Flash area read */
- p = pfl->storage;
- switch (width) {
- case 1:
- ret = p[offset];
- trace_pflash_data_read8(offset, ret);
- break;
- case 2:
- if (be) {
- ret = p[offset] << 8;
- ret |= p[offset + 1];
- } else {
- ret = p[offset];
- ret |= p[offset + 1] << 8;
- }
- trace_pflash_data_read16(offset, ret);
- break;
- case 4:
- if (be) {
- ret = p[offset] << 24;
- ret |= p[offset + 1] << 16;
- ret |= p[offset + 2] << 8;
- ret |= p[offset + 3];
- } else {
- ret = p[offset];
- ret |= p[offset + 1] << 8;
- ret |= p[offset + 2] << 16;
- ret |= p[offset + 3] << 24;
- }
- trace_pflash_data_read32(offset, ret);
+ if (pflash_erase_suspend_mode(pfl) &&
+ pflash_sector_is_erasing(pfl, offset)) {
+ /* Toggle bit 2, but not 6. */
+ toggle_dq2(pfl);
+ /* Status register read */
+ ret = pfl->status;
+ DPRINTF("%s: status %" PRIx64 "\n", __func__, ret);
break;
}
+ /* Flash area read */
+ ret = pflash_data_read(pfl, offset, width);
break;
- case 0x90:
- /* flash ID read */
+ case 0x90: /* flash ID read */
switch (boff) {
case 0x00:
case 0x01:
case 0x0E:
case 0x0F:
ret = boff & 0x01 ? pfl->ident3 : pfl->ident2;
- if (ret == (uint8_t)-1) {
- goto flash_read;
+ if (ret != (uint8_t)-1) {
+ break;
}
- break;
+ /* Fall through to data read. */
default:
- goto flash_read;
+ ret = pflash_data_read(pfl, offset, width);
}
- DPRINTF("%s: ID " TARGET_FMT_plx " %x\n", __func__, boff, ret);
+ DPRINTF("%s: ID " TARGET_FMT_plx " %" PRIx64 "\n", __func__, boff, ret);
break;
- case 0xA0:
- case 0x10:
- case 0x30:
+ case 0x10: /* Chip Erase */
+ case 0x30: /* Sector Erase */
+ /* Toggle bit 2 during erase, but not program. */
+ toggle_dq2(pfl);
+ case 0xA0: /* Program */
+ /* Toggle bit 6 */
+ toggle_dq6(pfl);
/* Status register read */
ret = pfl->status;
- DPRINTF("%s: status %x\n", __func__, ret);
- /* Toggle bit 6 */
- pfl->status ^= 0x40;
+ DPRINTF("%s: status %" PRIx64 "\n", __func__, ret);
break;
case 0x98:
/* CFI query mode */
}
break;
}
+ trace_pflash_io_read(offset, width, width << 1, ret, pfl->cmd, pfl->wcycle);
return ret;
}
/* update flash content on disk */
-static void pflash_update(PFlashCFI02 *pfl, int offset,
- int size)
+static void pflash_update(PFlashCFI02 *pfl, int offset, int size)
{
int offset_end;
if (pfl->blk) {
}
}
-static void pflash_write(PFlashCFI02 *pfl, hwaddr offset,
- uint32_t value, int width, int be)
+static void pflash_sector_erase(PFlashCFI02 *pfl, hwaddr offset)
{
+ SectorInfo sector_info = pflash_sector_info(pfl, offset);
+ uint64_t sector_len = sector_info.len;
+ offset &= ~(sector_len - 1);
+ DPRINTF("%s: start sector erase at %0*" PRIx64 "-%0*" PRIx64 "\n",
+ __func__, pfl->width * 2, offset,
+ pfl->width * 2, offset + sector_len - 1);
+ if (!pfl->ro) {
+ uint8_t *p = pfl->storage;
+ memset(p + offset, 0xff, sector_len);
+ pflash_update(pfl, offset, sector_len);
+ }
+ set_dq7(pfl, 0x00);
+ ++pfl->sectors_to_erase;
+ set_bit(sector_info.num, pfl->sector_erase_map);
+ /* Set (or reset) the 50 us timer for additional erase commands. */
+ timer_mod(&pfl->timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + 50000);
+}
+
+static void pflash_write(void *opaque, hwaddr offset, uint64_t value,
+ unsigned int width)
+{
+ PFlashCFI02 *pfl = opaque;
hwaddr boff;
uint8_t *p;
uint8_t cmd;
+ trace_pflash_io_write(offset, width, width << 1, value, pfl->wcycle);
cmd = value;
- if (pfl->cmd != 0xA0 && cmd == 0xF0) {
-#if 0
- DPRINTF("%s: flash reset asked (%02x %02x)\n",
- __func__, pfl->cmd, cmd);
-#endif
- goto reset_flash;
+ if (pfl->cmd != 0xA0) {
+ /* Reset does nothing during chip erase and sector erase. */
+ if (cmd == 0xF0 && pfl->cmd != 0x10 && pfl->cmd != 0x30) {
+ if (pfl->wcycle == WCYCLE_AUTOSELECT_CFI) {
+ /* Return to autoselect mode. */
+ pfl->wcycle = 3;
+ pfl->cmd = 0x90;
+ return;
+ }
+ goto reset_flash;
+ }
}
- trace_pflash_write(offset, value, width, pfl->wcycle);
offset &= pfl->chip_len - 1;
- DPRINTF("%s: offset " TARGET_FMT_plx " %08x %d\n", __func__,
- offset, value, width);
- boff = offset & (pfl->sector_len - 1);
- if (pfl->width == 2)
+ boff = offset;
+ if (pfl->width == 2) {
boff = boff >> 1;
- else if (pfl->width == 4)
- boff = boff >> 2;
+ }
+ /* Only the least-significant 11 bits are used in most cases. */
+ boff &= 0x7FF;
switch (pfl->wcycle) {
case 0:
/* Set the device in I/O access mode if required */
/* We're in read mode */
check_unlock0:
if (boff == 0x55 && cmd == 0x98) {
- enter_CFI_mode:
/* Enter CFI query mode */
- pfl->wcycle = 7;
+ pfl->wcycle = WCYCLE_CFI;
pfl->cmd = 0x98;
return;
}
+ /* Handle erase resume in erase suspend mode, otherwise reset. */
+ if (cmd == 0x30) { /* Erase Resume */
+ if (pflash_erase_suspend_mode(pfl)) {
+ /* Resume the erase. */
+ timer_mod(&pfl->timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
+ pfl->erase_time_remaining);
+ pfl->erase_time_remaining = 0;
+ pfl->wcycle = 6;
+ pfl->cmd = 0x30;
+ set_dq7(pfl, 0x00);
+ assert_dq3(pfl);
+ return;
+ }
+ goto reset_flash;
+ }
+ /* Ignore erase suspend. */
+ if (cmd == 0xB0) { /* Erase Suspend */
+ return;
+ }
if (boff != pfl->unlock_addr0 || cmd != 0xAA) {
DPRINTF("%s: unlock0 failed " TARGET_FMT_plx " %02x %04x\n",
__func__, boff, cmd, pfl->unlock_addr0);
case 0x20:
pfl->bypass = 1;
goto do_bypass;
- case 0x80:
- case 0x90:
- case 0xA0:
+ case 0x80: /* Erase */
+ case 0x90: /* Autoselect */
+ case 0xA0: /* Program */
pfl->cmd = cmd;
DPRINTF("%s: starting command %02x\n", __func__, cmd);
break;
break;
case 3:
switch (pfl->cmd) {
- case 0x80:
+ case 0x80: /* Erase */
/* We need another unlock sequence */
goto check_unlock0;
- case 0xA0:
- trace_pflash_data_write(offset, value, width, 0);
- p = pfl->storage;
+ case 0xA0: /* Program */
+ if (pflash_erase_suspend_mode(pfl) &&
+ pflash_sector_is_erasing(pfl, offset)) {
+ /* Ignore writes to erasing sectors. */
+ if (pfl->bypass) {
+ goto do_bypass;
+ }
+ goto reset_flash;
+ }
+ trace_pflash_data_write(offset, width << 1, value, 0);
if (!pfl->ro) {
- switch (width) {
- case 1:
- p[offset] &= value;
- pflash_update(pfl, offset, 1);
- break;
- case 2:
- if (be) {
- p[offset] &= value >> 8;
- p[offset + 1] &= value;
- } else {
- p[offset] &= value;
- p[offset + 1] &= value >> 8;
- }
- pflash_update(pfl, offset, 2);
- break;
- case 4:
- if (be) {
- p[offset] &= value >> 24;
- p[offset + 1] &= value >> 16;
- p[offset + 2] &= value >> 8;
- p[offset + 3] &= value;
- } else {
- p[offset] &= value;
- p[offset + 1] &= value >> 8;
- p[offset + 2] &= value >> 16;
- p[offset + 3] &= value >> 24;
- }
- pflash_update(pfl, offset, 4);
- break;
+ p = (uint8_t *)pfl->storage + offset;
+ if (pfl->be) {
+ uint64_t current = ldn_be_p(p, width);
+ stn_be_p(p, width, current & value);
+ } else {
+ uint64_t current = ldn_le_p(p, width);
+ stn_le_p(p, width, current & value);
}
+ pflash_update(pfl, offset, width);
}
- pfl->status = 0x00 | ~(value & 0x80);
+ /*
+ * While programming, status bit DQ7 should hold the opposite
+ * value from how it was programmed.
+ */
+ set_dq7(pfl, ~value);
/* Let's pretend write is immediate */
if (pfl->bypass)
goto do_bypass;
goto reset_flash;
- case 0x90:
+ case 0x90: /* Autoselect */
if (pfl->bypass && cmd == 0x00) {
/* Unlock bypass reset */
goto reset_flash;
}
- /* We can enter CFI query mode from autoselect mode */
- if (boff == 0x55 && cmd == 0x98)
- goto enter_CFI_mode;
+ /*
+ * We can enter CFI query mode from autoselect mode, but we must
+ * return to autoselect mode after a reset.
+ */
+ if (boff == 0x55 && cmd == 0x98) {
+ /* Enter autoselect CFI query mode */
+ pfl->wcycle = WCYCLE_AUTOSELECT_CFI;
+ pfl->cmd = 0x98;
+ return;
+ }
/* No break here */
default:
DPRINTF("%s: invalid write for command %02x\n",
}
case 4:
switch (pfl->cmd) {
- case 0xA0:
+ case 0xA0: /* Program */
/* Ignore writes while flash data write is occurring */
/* As we suppose write is immediate, this should never happen */
return;
- case 0x80:
+ case 0x80: /* Erase */
goto check_unlock1;
default:
/* Should never happen */
}
break;
case 5:
+ if (pflash_erase_suspend_mode(pfl)) {
+ /* Erasing is not supported in erase suspend mode. */
+ goto reset_flash;
+ }
switch (cmd) {
- case 0x10:
+ case 0x10: /* Chip Erase */
if (boff != pfl->unlock_addr0) {
DPRINTF("%s: chip erase: invalid address " TARGET_FMT_plx "\n",
__func__, offset);
/* Chip erase */
DPRINTF("%s: start chip erase\n", __func__);
if (!pfl->ro) {
- memset(pfl->storage, 0xFF, pfl->chip_len);
+ memset(pfl->storage, 0xff, pfl->chip_len);
pflash_update(pfl, 0, pfl->chip_len);
}
- pfl->status = 0x00;
- /* Let's wait 5 seconds before chip erase is done */
+ set_dq7(pfl, 0x00);
+ /* Wait the time specified at CFI address 0x22. */
timer_mod(&pfl->timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
- (NANOSECONDS_PER_SECOND * 5));
+ (1ULL << pfl->cfi_table[0x22]) * SCALE_MS);
break;
- case 0x30:
- /* Sector erase */
- p = pfl->storage;
- offset &= ~(pfl->sector_len - 1);
- DPRINTF("%s: start sector erase at " TARGET_FMT_plx "\n", __func__,
- offset);
- if (!pfl->ro) {
- memset(p + offset, 0xFF, pfl->sector_len);
- pflash_update(pfl, offset, pfl->sector_len);
- }
- pfl->status = 0x00;
- /* Let's wait 1/2 second before sector erase is done */
- timer_mod(&pfl->timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
- (NANOSECONDS_PER_SECOND / 2));
+ case 0x30: /* Sector erase */
+ pflash_sector_erase(pfl, offset);
break;
default:
DPRINTF("%s: invalid command %02x (wc 5)\n", __func__, cmd);
break;
case 6:
switch (pfl->cmd) {
- case 0x10:
+ case 0x10: /* Chip Erase */
/* Ignore writes during chip erase */
return;
- case 0x30:
- /* Ignore writes during sector erase */
+ case 0x30: /* Sector erase */
+ if (cmd == 0xB0) {
+ /*
+ * If erase suspend happens during the erase timeout (so DQ3 is
+ * 0), then the device suspends erasing immediately. Set the
+ * remaining time to be the total time to erase. Otherwise,
+ * there is a maximum amount of time it can take to enter
+ * suspend mode. Let's ignore that and suspend immediately and
+ * set the remaining time to the actual time remaining on the
+ * timer.
+ */
+ if ((pfl->status & 0x08) == 0) {
+ pfl->erase_time_remaining = pflash_erase_time(pfl);
+ } else {
+ int64_t delta = timer_expire_time_ns(&pfl->timer) -
+ qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
+ /* Make sure we have a positive time remaining. */
+ pfl->erase_time_remaining = delta <= 0 ? 1 : delta;
+ }
+ reset_dq3(pfl);
+ timer_del(&pfl->timer);
+ pfl->wcycle = 0;
+ pfl->cmd = 0;
+ return;
+ }
+ /*
+ * If DQ3 is 0, additional sector erase commands can be
+ * written and anything else (other than an erase suspend) resets
+ * the device.
+ */
+ if ((pfl->status & 0x08) == 0) {
+ if (cmd == 0x30) {
+ pflash_sector_erase(pfl, offset);
+ } else {
+ goto reset_flash;
+ }
+ }
+ /* Ignore writes during the actual erase. */
return;
default:
/* Should never happen */
goto reset_flash;
}
break;
- case 7: /* Special value for CFI queries */
+ /* Special values for CFI queries */
+ case WCYCLE_CFI:
+ case WCYCLE_AUTOSELECT_CFI:
DPRINTF("%s: invalid write in CFI query mode\n", __func__);
goto reset_flash;
default:
pfl->cmd = 0;
}
-static uint64_t pflash_be_readfn(void *opaque, hwaddr addr, unsigned size)
-{
- return pflash_read(opaque, addr, size, 1);
-}
-
-static void pflash_be_writefn(void *opaque, hwaddr addr,
- uint64_t value, unsigned size)
-{
- pflash_write(opaque, addr, value, size, 1);
-}
-
-static uint64_t pflash_le_readfn(void *opaque, hwaddr addr, unsigned size)
-{
- return pflash_read(opaque, addr, size, 0);
-}
-
-static void pflash_le_writefn(void *opaque, hwaddr addr,
- uint64_t value, unsigned size)
-{
- pflash_write(opaque, addr, value, size, 0);
-}
-
-static const MemoryRegionOps pflash_cfi02_ops_be = {
- .read = pflash_be_readfn,
- .write = pflash_be_writefn,
- .valid.min_access_size = 1,
- .valid.max_access_size = 4,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static const MemoryRegionOps pflash_cfi02_ops_le = {
- .read = pflash_le_readfn,
- .write = pflash_le_writefn,
+static const MemoryRegionOps pflash_cfi02_ops = {
+ .read = pflash_read,
+ .write = pflash_write,
+ .impl.max_access_size = 2,
.valid.min_access_size = 1,
.valid.max_access_size = 4,
.endianness = DEVICE_NATIVE_ENDIAN,
static void pflash_cfi02_realize(DeviceState *dev, Error **errp)
{
PFlashCFI02 *pfl = PFLASH_CFI02(dev);
- uint32_t chip_len;
int ret;
Error *local_err = NULL;
- if (pfl->sector_len == 0) {
+ if (pfl->uniform_sector_len == 0 && pfl->sector_len[0] == 0) {
error_setg(errp, "attribute \"sector-length\" not specified or zero.");
return;
}
- if (pfl->nb_blocs == 0) {
+ if (pfl->uniform_nb_blocs == 0 && pfl->nb_blocs[0] == 0) {
error_setg(errp, "attribute \"num-blocks\" not specified or zero.");
return;
}
return;
}
- chip_len = pfl->sector_len * pfl->nb_blocs;
+ int nb_regions;
+ pfl->chip_len = 0;
+ pfl->total_sectors = 0;
+ for (nb_regions = 0; nb_regions < PFLASH_MAX_ERASE_REGIONS; ++nb_regions) {
+ if (pfl->nb_blocs[nb_regions] == 0) {
+ break;
+ }
+ pfl->total_sectors += pfl->nb_blocs[nb_regions];
+ uint64_t sector_len_per_device = pfl->sector_len[nb_regions];
+
+ /*
+ * The size of each flash sector must be a power of 2 and it must be
+ * aligned at the same power of 2.
+ */
+ if (sector_len_per_device & 0xff ||
+ sector_len_per_device >= (1 << 24) ||
+ !is_power_of_2(sector_len_per_device))
+ {
+ error_setg(errp, "unsupported configuration: "
+ "sector length[%d] per device = %" PRIx64 ".",
+ nb_regions, sector_len_per_device);
+ return;
+ }
+ if (pfl->chip_len & (sector_len_per_device - 1)) {
+ error_setg(errp, "unsupported configuration: "
+ "flash region %d not correctly aligned.",
+ nb_regions);
+ return;
+ }
+
+ pfl->chip_len += (uint64_t)pfl->sector_len[nb_regions] *
+ pfl->nb_blocs[nb_regions];
+ }
+
+ uint64_t uniform_len = (uint64_t)pfl->uniform_nb_blocs *
+ pfl->uniform_sector_len;
+ if (nb_regions == 0) {
+ nb_regions = 1;
+ pfl->nb_blocs[0] = pfl->uniform_nb_blocs;
+ pfl->sector_len[0] = pfl->uniform_sector_len;
+ pfl->chip_len = uniform_len;
+ pfl->total_sectors = pfl->uniform_nb_blocs;
+ } else if (uniform_len != 0 && uniform_len != pfl->chip_len) {
+ error_setg(errp, "\"num-blocks\"*\"sector-length\" "
+ "different from \"num-blocks0\"*\'sector-length0\" + ... + "
+ "\"num-blocks3\"*\"sector-length3\"");
+ return;
+ }
- memory_region_init_rom_device(&pfl->orig_mem, OBJECT(pfl), pfl->be ?
- &pflash_cfi02_ops_be : &pflash_cfi02_ops_le,
- pfl, pfl->name, chip_len, &local_err);
+ memory_region_init_rom_device(&pfl->orig_mem, OBJECT(pfl),
+ &pflash_cfi02_ops, pfl, pfl->name,
+ pfl->chip_len, &local_err);
if (local_err) {
error_propagate(errp, local_err);
return;
}
pfl->storage = memory_region_get_ram_ptr(&pfl->orig_mem);
- pfl->chip_len = chip_len;
if (pfl->blk) {
uint64_t perm;
}
if (pfl->blk) {
- if (!blk_check_size_and_read_all(pfl->blk, pfl->storage, chip_len,
- errp)) {
+ if (!blk_check_size_and_read_all(pfl->blk, pfl->storage,
+ pfl->chip_len, errp)) {
vmstate_unregister_ram(&pfl->orig_mem, DEVICE(pfl));
return;
}
}
+ /* Only 11 bits are used in the comparison. */
+ pfl->unlock_addr0 &= 0x7FF;
+ pfl->unlock_addr1 &= 0x7FF;
+
+ /* Allocate memory for a bitmap for sectors being erased. */
+ pfl->sector_erase_map = bitmap_new(pfl->total_sectors);
+
pflash_setup_mappings(pfl);
pfl->rom_mode = 1;
sysbus_init_mmio(SYS_BUS_DEVICE(dev), &pfl->mem);
pfl->wcycle = 0;
pfl->cmd = 0;
pfl->status = 0;
+
/* Hardcoded CFI table (mostly from SG29 Spansion flash) */
+ const uint16_t pri_ofs = 0x40;
/* Standard "QRY" string */
pfl->cfi_table[0x10] = 'Q';
pfl->cfi_table[0x11] = 'R';
pfl->cfi_table[0x13] = 0x02;
pfl->cfi_table[0x14] = 0x00;
/* Primary extended table address */
- pfl->cfi_table[0x15] = 0x31;
- pfl->cfi_table[0x16] = 0x00;
+ pfl->cfi_table[0x15] = pri_ofs;
+ pfl->cfi_table[0x16] = pri_ofs >> 8;
/* Alternate command set (none) */
pfl->cfi_table[0x17] = 0x00;
pfl->cfi_table[0x18] = 0x00;
pfl->cfi_table[0x1D] = 0x00;
/* Vpp max (no Vpp pin) */
pfl->cfi_table[0x1E] = 0x00;
- /* Reserved */
+ /* Timeout per single byte/word write (128 ms) */
pfl->cfi_table[0x1F] = 0x07;
/* Timeout for min size buffer write (NA) */
pfl->cfi_table[0x20] = 0x00;
/* Max timeout for chip erase */
pfl->cfi_table[0x26] = 0x0D;
/* Device size */
- pfl->cfi_table[0x27] = ctz32(chip_len);
+ pfl->cfi_table[0x27] = ctz32(pfl->chip_len);
/* Flash device interface (8 & 16 bits) */
pfl->cfi_table[0x28] = 0x02;
pfl->cfi_table[0x29] = 0x00;
// pfl->cfi_table[0x2A] = 0x05;
pfl->cfi_table[0x2A] = 0x00;
pfl->cfi_table[0x2B] = 0x00;
- /* Number of erase block regions (uniform) */
- pfl->cfi_table[0x2C] = 0x01;
- /* Erase block region 1 */
- pfl->cfi_table[0x2D] = pfl->nb_blocs - 1;
- pfl->cfi_table[0x2E] = (pfl->nb_blocs - 1) >> 8;
- pfl->cfi_table[0x2F] = pfl->sector_len >> 8;
- pfl->cfi_table[0x30] = pfl->sector_len >> 16;
+ /* Number of erase block regions */
+ pfl->cfi_table[0x2c] = nb_regions;
+ /* Erase block regions */
+ for (int i = 0; i < nb_regions; ++i) {
+ uint32_t sector_len_per_device = pfl->sector_len[i];
+ pfl->cfi_table[0x2d + 4 * i] = pfl->nb_blocs[i] - 1;
+ pfl->cfi_table[0x2e + 4 * i] = (pfl->nb_blocs[i] - 1) >> 8;
+ pfl->cfi_table[0x2f + 4 * i] = sector_len_per_device >> 8;
+ pfl->cfi_table[0x30 + 4 * i] = sector_len_per_device >> 16;
+ }
+ assert(0x2c + 4 * nb_regions < pri_ofs);
/* Extended */
- pfl->cfi_table[0x31] = 'P';
- pfl->cfi_table[0x32] = 'R';
- pfl->cfi_table[0x33] = 'I';
-
- pfl->cfi_table[0x34] = '1';
- pfl->cfi_table[0x35] = '0';
-
- pfl->cfi_table[0x36] = 0x00;
- pfl->cfi_table[0x37] = 0x00;
- pfl->cfi_table[0x38] = 0x00;
- pfl->cfi_table[0x39] = 0x00;
-
- pfl->cfi_table[0x3a] = 0x00;
-
- pfl->cfi_table[0x3b] = 0x00;
- pfl->cfi_table[0x3c] = 0x00;
+ pfl->cfi_table[0x00 + pri_ofs] = 'P';
+ pfl->cfi_table[0x01 + pri_ofs] = 'R';
+ pfl->cfi_table[0x02 + pri_ofs] = 'I';
+
+ /* Extended version 1.0 */
+ pfl->cfi_table[0x03 + pri_ofs] = '1';
+ pfl->cfi_table[0x04 + pri_ofs] = '0';
+
+ /* Address sensitive unlock required. */
+ pfl->cfi_table[0x05 + pri_ofs] = 0x00;
+ /* Erase suspend to read/write. */
+ pfl->cfi_table[0x06 + pri_ofs] = 0x02;
+ /* Sector protect not supported. */
+ pfl->cfi_table[0x07 + pri_ofs] = 0x00;
+ /* Temporary sector unprotect not supported. */
+ pfl->cfi_table[0x08 + pri_ofs] = 0x00;
+
+ /* Sector protect/unprotect scheme. */
+ pfl->cfi_table[0x09 + pri_ofs] = 0x00;
+
+ /* Simultaneous operation not supported. */
+ pfl->cfi_table[0x0a + pri_ofs] = 0x00;
+ /* Burst mode not supported. */
+ pfl->cfi_table[0x0b + pri_ofs] = 0x00;
+ /* Page mode not supported. */
+ pfl->cfi_table[0x0c + pri_ofs] = 0x00;
+ assert(0x0c + pri_ofs < ARRAY_SIZE(pfl->cfi_table));
}
static Property pflash_cfi02_properties[] = {
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_UINT32("num-blocks", PFlashCFI02, uniform_nb_blocs, 0),
+ DEFINE_PROP_UINT32("sector-length", PFlashCFI02, uniform_sector_len, 0),
+ DEFINE_PROP_UINT32("num-blocks0", PFlashCFI02, nb_blocs[0], 0),
+ DEFINE_PROP_UINT32("sector-length0", PFlashCFI02, sector_len[0], 0),
+ DEFINE_PROP_UINT32("num-blocks1", PFlashCFI02, nb_blocs[1], 0),
+ DEFINE_PROP_UINT32("sector-length1", PFlashCFI02, sector_len[1], 0),
+ DEFINE_PROP_UINT32("num-blocks2", PFlashCFI02, nb_blocs[2], 0),
+ DEFINE_PROP_UINT32("sector-length2", PFlashCFI02, sector_len[2], 0),
+ DEFINE_PROP_UINT32("num-blocks3", PFlashCFI02, nb_blocs[3], 0),
+ DEFINE_PROP_UINT32("sector-length3", PFlashCFI02, sector_len[3], 0),
DEFINE_PROP_UINT8("width", PFlashCFI02, width, 0),
DEFINE_PROP_UINT8("mappings", PFlashCFI02, mappings, 0),
DEFINE_PROP_UINT8("big-endian", PFlashCFI02, be, 0),
{
PFlashCFI02 *pfl = PFLASH_CFI02(dev);
timer_del(&pfl->timer);
+ g_free(pfl->sector_erase_map);
}
static void pflash_cfi02_class_init(ObjectClass *klass, void *data)
# pflash_cfi02.c
# pflash_cfi01.c
pflash_reset(void) "reset"
-pflash_read(uint64_t offset, uint8_t cmd, int width, uint8_t wcycle) "offset:0x%04"PRIx64" cmd:0x%02x width:%d wcycle:%u"
-pflash_write(uint64_t offset, uint32_t value, int width, uint8_t wcycle) "offset:0x%04"PRIx64" value:0x%03x width:%d wcycle:%u"
pflash_timer_expired(uint8_t cmd) "command 0x%02x done"
-pflash_data_read8(uint64_t offset, uint32_t value) "data offset:0x%04"PRIx64" value:0x%02x"
-pflash_data_read16(uint64_t offset, uint32_t value) "data offset:0x%04"PRIx64" value:0x%04x"
-pflash_data_read32(uint64_t offset, uint32_t value) "data offset:0x%04"PRIx64" value:0x%08x"
-pflash_data_write(uint64_t offset, uint32_t value, int width, uint64_t counter) "data offset:0x%04"PRIx64" value:0x%08x width:%d counter:0x%016"PRIx64
+pflash_io_read(uint64_t offset, int width, int fmt_width, uint32_t value, uint8_t cmd, uint8_t wcycle) "offset:0x%04"PRIx64" width:%d value:0x%0*x cmd:0x%02x wcycle:%u"
+pflash_io_write(uint64_t offset, int width, int fmt_width, uint32_t value, uint8_t wcycle) "offset:0x%04"PRIx64" width:%d value:0x%0*x wcycle:%u"
+pflash_data_read(uint64_t offset, int width, uint32_t value) "data offset:0x%04"PRIx64" value:0x%0*x"
+pflash_data_write(uint64_t offset, int width, uint32_t value, uint64_t counter) "data offset:0x%04"PRIx64" value:0x%0*x counter:0x%016"PRIx64
pflash_manufacturer_id(uint16_t id) "Read Manufacturer ID: 0x%04x"
pflash_device_id(uint16_t id) "Read Device ID: 0x%04x"
pflash_device_info(uint64_t offset) "Read Device Information offset:0x%04"PRIx64
static void vhost_user_blk_set_status(VirtIODevice *vdev, uint8_t status)
{
VHostUserBlk *s = VHOST_USER_BLK(vdev);
- bool should_start = vdev->started;
+ bool should_start = virtio_device_started(vdev, status);
int ret;
if (!vdev->vm_running) {
}
/* restore vhost state */
- if (vdev->started) {
+ if (virtio_device_started(vdev, vdev->status)) {
ret = vhost_user_blk_start(vdev);
if (ret < 0) {
error_report("vhost-user-blk: vhost start failed: %s",
#include "qemu/option.h"
#include "qapi/error.h"
#include "qapi/qapi-commands-block-core.h"
-#include "qapi/qapi-commands-misc.h"
+#include "qapi/qapi-commands-qom.h"
#include "qapi/qapi-visit-block-core.h"
#include "qapi/qobject-input-visitor.h"
#include "qapi/visitor.h"
common-obj-$(CONFIG_PLATFORM_BUS) += platform-bus.o
common-obj-$(CONFIG_SOFTMMU) += generic-loader.o
common-obj-$(CONFIG_SOFTMMU) += null-machine.o
+
+obj-$(CONFIG_SOFTMMU) += machine-qmp-cmds.o
+obj-$(CONFIG_SOFTMMU) += numa.o
+common-obj-$(CONFIG_SOFTMMU) += machine-hmp-cmds.o
--- /dev/null
+/*
+ * HMP commands related to machines and CPUs
+ *
+ * Copyright IBM, Corp. 2011
+ *
+ * Authors:
+ * Anthony Liguori <aliguori@us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2. See
+ * the COPYING file in the top-level directory.
+ *
+ * Contributions after 2012-01-13 are licensed under the terms of the
+ * GNU GPL, version 2 or (at your option) any later version.
+ */
+
+#include "qemu/osdep.h"
+#include "monitor/hmp.h"
+#include "monitor/monitor.h"
+#include "qapi/error.h"
+#include "qapi/qapi-builtin-visit.h"
+#include "qapi/qapi-commands-machine.h"
+#include "qapi/qmp/qdict.h"
+#include "qapi/string-output-visitor.h"
+#include "qemu/error-report.h"
+#include "sysemu/numa.h"
+
+void hmp_info_cpus(Monitor *mon, const QDict *qdict)
+{
+ CpuInfoFastList *cpu_list, *cpu;
+
+ cpu_list = qmp_query_cpus_fast(NULL);
+
+ for (cpu = cpu_list; cpu; cpu = cpu->next) {
+ int active = ' ';
+
+ if (cpu->value->cpu_index == monitor_get_cpu_index()) {
+ active = '*';
+ }
+
+ monitor_printf(mon, "%c CPU #%" PRId64 ":", active,
+ cpu->value->cpu_index);
+ monitor_printf(mon, " thread_id=%" PRId64 "\n", cpu->value->thread_id);
+ }
+
+ qapi_free_CpuInfoFastList(cpu_list);
+}
+
+void hmp_cpu_add(Monitor *mon, const QDict *qdict)
+{
+ int cpuid;
+ Error *err = NULL;
+
+ error_report("cpu_add is deprecated, please use device_add instead");
+
+ cpuid = qdict_get_int(qdict, "id");
+ qmp_cpu_add(cpuid, &err);
+ hmp_handle_error(mon, &err);
+}
+
+void hmp_hotpluggable_cpus(Monitor *mon, const QDict *qdict)
+{
+ Error *err = NULL;
+ HotpluggableCPUList *l = qmp_query_hotpluggable_cpus(&err);
+ HotpluggableCPUList *saved = l;
+ CpuInstanceProperties *c;
+
+ if (err != NULL) {
+ hmp_handle_error(mon, &err);
+ return;
+ }
+
+ monitor_printf(mon, "Hotpluggable CPUs:\n");
+ while (l) {
+ monitor_printf(mon, " type: \"%s\"\n", l->value->type);
+ monitor_printf(mon, " vcpus_count: \"%" PRIu64 "\"\n",
+ l->value->vcpus_count);
+ if (l->value->has_qom_path) {
+ monitor_printf(mon, " qom_path: \"%s\"\n", l->value->qom_path);
+ }
+
+ c = l->value->props;
+ monitor_printf(mon, " CPUInstance Properties:\n");
+ if (c->has_node_id) {
+ monitor_printf(mon, " node-id: \"%" PRIu64 "\"\n", c->node_id);
+ }
+ if (c->has_socket_id) {
+ monitor_printf(mon, " socket-id: \"%" PRIu64 "\"\n", c->socket_id);
+ }
+ if (c->has_core_id) {
+ monitor_printf(mon, " core-id: \"%" PRIu64 "\"\n", c->core_id);
+ }
+ if (c->has_thread_id) {
+ monitor_printf(mon, " thread-id: \"%" PRIu64 "\"\n", c->thread_id);
+ }
+
+ l = l->next;
+ }
+
+ qapi_free_HotpluggableCPUList(saved);
+}
+
+void hmp_info_memdev(Monitor *mon, const QDict *qdict)
+{
+ Error *err = NULL;
+ MemdevList *memdev_list = qmp_query_memdev(&err);
+ MemdevList *m = memdev_list;
+ Visitor *v;
+ char *str;
+
+ while (m) {
+ v = string_output_visitor_new(false, &str);
+ visit_type_uint16List(v, NULL, &m->value->host_nodes, NULL);
+ monitor_printf(mon, "memory backend: %s\n", m->value->id);
+ monitor_printf(mon, " size: %" PRId64 "\n", m->value->size);
+ monitor_printf(mon, " merge: %s\n",
+ m->value->merge ? "true" : "false");
+ monitor_printf(mon, " dump: %s\n",
+ m->value->dump ? "true" : "false");
+ monitor_printf(mon, " prealloc: %s\n",
+ m->value->prealloc ? "true" : "false");
+ monitor_printf(mon, " policy: %s\n",
+ HostMemPolicy_str(m->value->policy));
+ visit_complete(v, &str);
+ monitor_printf(mon, " host nodes: %s\n", str);
+
+ g_free(str);
+ visit_free(v);
+ m = m->next;
+ }
+
+ monitor_printf(mon, "\n");
+
+ qapi_free_MemdevList(memdev_list);
+ hmp_handle_error(mon, &err);
+}
+
+void hmp_info_numa(Monitor *mon, const QDict *qdict)
+{
+ int i;
+ NumaNodeMem *node_mem;
+ CpuInfoList *cpu_list, *cpu;
+
+ cpu_list = qmp_query_cpus(&error_abort);
+ node_mem = g_new0(NumaNodeMem, nb_numa_nodes);
+
+ query_numa_node_mem(node_mem);
+ monitor_printf(mon, "%d nodes\n", nb_numa_nodes);
+ for (i = 0; i < nb_numa_nodes; i++) {
+ monitor_printf(mon, "node %d cpus:", i);
+ for (cpu = cpu_list; cpu; cpu = cpu->next) {
+ if (cpu->value->has_props && cpu->value->props->has_node_id &&
+ cpu->value->props->node_id == i) {
+ monitor_printf(mon, " %" PRIi64, cpu->value->CPU);
+ }
+ }
+ monitor_printf(mon, "\n");
+ monitor_printf(mon, "node %d size: %" PRId64 " MB\n", i,
+ node_mem[i].node_mem >> 20);
+ monitor_printf(mon, "node %d plugged: %" PRId64 " MB\n", i,
+ node_mem[i].node_plugged_mem >> 20);
+ }
+ qapi_free_CpuInfoList(cpu_list);
+ g_free(node_mem);
+}
--- /dev/null
+/*
+ * QMP commands related to machines and CPUs
+ *
+ * Copyright (C) 2014 Red Hat Inc
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include "qemu/osdep.h"
+#include "cpu.h"
+#include "hw/boards.h"
+#include "qapi/error.h"
+#include "qapi/qapi-commands-machine.h"
+#include "qapi/qmp/qerror.h"
+#include "sysemu/hostmem.h"
+#include "sysemu/hw_accel.h"
+#include "sysemu/numa.h"
+#include "sysemu/sysemu.h"
+
+CpuInfoList *qmp_query_cpus(Error **errp)
+{
+ MachineState *ms = MACHINE(qdev_get_machine());
+ MachineClass *mc = MACHINE_GET_CLASS(ms);
+ CpuInfoList *head = NULL, *cur_item = NULL;
+ CPUState *cpu;
+
+ CPU_FOREACH(cpu) {
+ CpuInfoList *info;
+#if defined(TARGET_I386)
+ X86CPU *x86_cpu = X86_CPU(cpu);
+ CPUX86State *env = &x86_cpu->env;
+#elif defined(TARGET_PPC)
+ PowerPCCPU *ppc_cpu = POWERPC_CPU(cpu);
+ CPUPPCState *env = &ppc_cpu->env;
+#elif defined(TARGET_SPARC)
+ SPARCCPU *sparc_cpu = SPARC_CPU(cpu);
+ CPUSPARCState *env = &sparc_cpu->env;
+#elif defined(TARGET_RISCV)
+ RISCVCPU *riscv_cpu = RISCV_CPU(cpu);
+ CPURISCVState *env = &riscv_cpu->env;
+#elif defined(TARGET_MIPS)
+ MIPSCPU *mips_cpu = MIPS_CPU(cpu);
+ CPUMIPSState *env = &mips_cpu->env;
+#elif defined(TARGET_TRICORE)
+ TriCoreCPU *tricore_cpu = TRICORE_CPU(cpu);
+ CPUTriCoreState *env = &tricore_cpu->env;
+#elif defined(TARGET_S390X)
+ S390CPU *s390_cpu = S390_CPU(cpu);
+ CPUS390XState *env = &s390_cpu->env;
+#endif
+
+ cpu_synchronize_state(cpu);
+
+ info = g_malloc0(sizeof(*info));
+ info->value = g_malloc0(sizeof(*info->value));
+ info->value->CPU = cpu->cpu_index;
+ info->value->current = (cpu == first_cpu);
+ info->value->halted = cpu->halted;
+ info->value->qom_path = object_get_canonical_path(OBJECT(cpu));
+ info->value->thread_id = cpu->thread_id;
+#if defined(TARGET_I386)
+ info->value->arch = CPU_INFO_ARCH_X86;
+ info->value->u.x86.pc = env->eip + env->segs[R_CS].base;
+#elif defined(TARGET_PPC)
+ info->value->arch = CPU_INFO_ARCH_PPC;
+ info->value->u.ppc.nip = env->nip;
+#elif defined(TARGET_SPARC)
+ info->value->arch = CPU_INFO_ARCH_SPARC;
+ info->value->u.q_sparc.pc = env->pc;
+ info->value->u.q_sparc.npc = env->npc;
+#elif defined(TARGET_MIPS)
+ info->value->arch = CPU_INFO_ARCH_MIPS;
+ info->value->u.q_mips.PC = env->active_tc.PC;
+#elif defined(TARGET_TRICORE)
+ info->value->arch = CPU_INFO_ARCH_TRICORE;
+ info->value->u.tricore.PC = env->PC;
+#elif defined(TARGET_S390X)
+ info->value->arch = CPU_INFO_ARCH_S390;
+ info->value->u.s390.cpu_state = env->cpu_state;
+#elif defined(TARGET_RISCV)
+ info->value->arch = CPU_INFO_ARCH_RISCV;
+ info->value->u.riscv.pc = env->pc;
+#else
+ info->value->arch = CPU_INFO_ARCH_OTHER;
+#endif
+ info->value->has_props = !!mc->cpu_index_to_instance_props;
+ if (info->value->has_props) {
+ CpuInstanceProperties *props;
+ props = g_malloc0(sizeof(*props));
+ *props = mc->cpu_index_to_instance_props(ms, cpu->cpu_index);
+ info->value->props = props;
+ }
+
+ /* XXX: waiting for the qapi to support GSList */
+ if (!cur_item) {
+ head = cur_item = info;
+ } else {
+ cur_item->next = info;
+ cur_item = info;
+ }
+ }
+
+ return head;
+}
+
+static CpuInfoArch sysemu_target_to_cpuinfo_arch(SysEmuTarget target)
+{
+ /*
+ * The @SysEmuTarget -> @CpuInfoArch mapping below is based on the
+ * TARGET_ARCH -> TARGET_BASE_ARCH mapping in the "configure" script.
+ */
+ switch (target) {
+ case SYS_EMU_TARGET_I386:
+ case SYS_EMU_TARGET_X86_64:
+ return CPU_INFO_ARCH_X86;
+
+ case SYS_EMU_TARGET_PPC:
+ case SYS_EMU_TARGET_PPC64:
+ return CPU_INFO_ARCH_PPC;
+
+ case SYS_EMU_TARGET_SPARC:
+ case SYS_EMU_TARGET_SPARC64:
+ return CPU_INFO_ARCH_SPARC;
+
+ case SYS_EMU_TARGET_MIPS:
+ case SYS_EMU_TARGET_MIPSEL:
+ case SYS_EMU_TARGET_MIPS64:
+ case SYS_EMU_TARGET_MIPS64EL:
+ return CPU_INFO_ARCH_MIPS;
+
+ case SYS_EMU_TARGET_TRICORE:
+ return CPU_INFO_ARCH_TRICORE;
+
+ case SYS_EMU_TARGET_S390X:
+ return CPU_INFO_ARCH_S390;
+
+ case SYS_EMU_TARGET_RISCV32:
+ case SYS_EMU_TARGET_RISCV64:
+ return CPU_INFO_ARCH_RISCV;
+
+ default:
+ return CPU_INFO_ARCH_OTHER;
+ }
+}
+
+static void cpustate_to_cpuinfo_s390(CpuInfoS390 *info, const CPUState *cpu)
+{
+#ifdef TARGET_S390X
+ S390CPU *s390_cpu = S390_CPU(cpu);
+ CPUS390XState *env = &s390_cpu->env;
+
+ info->cpu_state = env->cpu_state;
+#else
+ abort();
+#endif
+}
+
+/*
+ * fast means: we NEVER interrupt vCPU threads to retrieve
+ * information from KVM.
+ */
+CpuInfoFastList *qmp_query_cpus_fast(Error **errp)
+{
+ MachineState *ms = MACHINE(qdev_get_machine());
+ MachineClass *mc = MACHINE_GET_CLASS(ms);
+ CpuInfoFastList *head = NULL, *cur_item = NULL;
+ SysEmuTarget target = qapi_enum_parse(&SysEmuTarget_lookup, TARGET_NAME,
+ -1, &error_abort);
+ CPUState *cpu;
+
+ CPU_FOREACH(cpu) {
+ CpuInfoFastList *info = g_malloc0(sizeof(*info));
+ info->value = g_malloc0(sizeof(*info->value));
+
+ info->value->cpu_index = cpu->cpu_index;
+ info->value->qom_path = object_get_canonical_path(OBJECT(cpu));
+ info->value->thread_id = cpu->thread_id;
+
+ info->value->has_props = !!mc->cpu_index_to_instance_props;
+ if (info->value->has_props) {
+ CpuInstanceProperties *props;
+ props = g_malloc0(sizeof(*props));
+ *props = mc->cpu_index_to_instance_props(ms, cpu->cpu_index);
+ info->value->props = props;
+ }
+
+ info->value->arch = sysemu_target_to_cpuinfo_arch(target);
+ info->value->target = target;
+ if (target == SYS_EMU_TARGET_S390X) {
+ cpustate_to_cpuinfo_s390(&info->value->u.s390x, cpu);
+ }
+
+ if (!cur_item) {
+ head = cur_item = info;
+ } else {
+ cur_item->next = info;
+ cur_item = info;
+ }
+ }
+
+ return head;
+}
+
+MachineInfoList *qmp_query_machines(Error **errp)
+{
+ GSList *el, *machines = object_class_get_list(TYPE_MACHINE, false);
+ MachineInfoList *mach_list = NULL;
+
+ for (el = machines; el; el = el->next) {
+ MachineClass *mc = el->data;
+ MachineInfoList *entry;
+ MachineInfo *info;
+
+ info = g_malloc0(sizeof(*info));
+ if (mc->is_default) {
+ info->has_is_default = true;
+ info->is_default = true;
+ }
+
+ if (mc->alias) {
+ info->has_alias = true;
+ info->alias = g_strdup(mc->alias);
+ }
+
+ info->name = g_strdup(mc->name);
+ info->cpu_max = !mc->max_cpus ? 1 : mc->max_cpus;
+ info->hotpluggable_cpus = mc->has_hotpluggable_cpus;
+
+ entry = g_malloc0(sizeof(*entry));
+ entry->value = info;
+ entry->next = mach_list;
+ mach_list = entry;
+ }
+
+ g_slist_free(machines);
+ return mach_list;
+}
+
+CurrentMachineParams *qmp_query_current_machine(Error **errp)
+{
+ CurrentMachineParams *params = g_malloc0(sizeof(*params));
+ params->wakeup_suspend_support = qemu_wakeup_suspend_enabled();
+
+ return params;
+}
+
+HotpluggableCPUList *qmp_query_hotpluggable_cpus(Error **errp)
+{
+ MachineState *ms = MACHINE(qdev_get_machine());
+ MachineClass *mc = MACHINE_GET_CLASS(ms);
+
+ if (!mc->has_hotpluggable_cpus) {
+ error_setg(errp, QERR_FEATURE_DISABLED, "query-hotpluggable-cpus");
+ return NULL;
+ }
+
+ return machine_query_hotpluggable_cpus(ms);
+}
+
+void qmp_cpu_add(int64_t id, Error **errp)
+{
+ MachineClass *mc;
+
+ mc = MACHINE_GET_CLASS(current_machine);
+ if (mc->hot_add_cpu) {
+ mc->hot_add_cpu(id, errp);
+ } else {
+ error_setg(errp, "Not supported");
+ }
+}
+
+void qmp_set_numa_node(NumaOptions *cmd, Error **errp)
+{
+ if (!runstate_check(RUN_STATE_PRECONFIG)) {
+ error_setg(errp, "The command is permitted only in '%s' state",
+ RunState_str(RUN_STATE_PRECONFIG));
+ return;
+ }
+
+ set_numa_options(MACHINE(qdev_get_machine()), cmd, errp);
+}
+
+static int query_memdev(Object *obj, void *opaque)
+{
+ MemdevList **list = opaque;
+ MemdevList *m = NULL;
+
+ if (object_dynamic_cast(obj, TYPE_MEMORY_BACKEND)) {
+ m = g_malloc0(sizeof(*m));
+
+ m->value = g_malloc0(sizeof(*m->value));
+
+ m->value->id = object_get_canonical_path_component(obj);
+ m->value->has_id = !!m->value->id;
+
+ m->value->size = object_property_get_uint(obj, "size",
+ &error_abort);
+ m->value->merge = object_property_get_bool(obj, "merge",
+ &error_abort);
+ m->value->dump = object_property_get_bool(obj, "dump",
+ &error_abort);
+ m->value->prealloc = object_property_get_bool(obj,
+ "prealloc",
+ &error_abort);
+ m->value->policy = object_property_get_enum(obj,
+ "policy",
+ "HostMemPolicy",
+ &error_abort);
+ object_property_get_uint16List(obj, "host-nodes",
+ &m->value->host_nodes,
+ &error_abort);
+
+ m->next = *list;
+ *list = m;
+ }
+
+ return 0;
+}
+
+MemdevList *qmp_query_memdev(Error **errp)
+{
+ Object *obj = object_get_objects_root();
+ MemdevList *list = NULL;
+
+ object_child_foreach(obj, query_memdev, &list);
+ return list;
+}
{ "bochs-display", "edid", "false" },
{ "virtio-vga", "edid", "false" },
{ "virtio-gpu-pci", "edid", "false" },
+ { "virtio-device", "use-started", "false" },
};
const size_t hw_compat_4_0_len = G_N_ELEMENTS(hw_compat_4_0);
--- /dev/null
+/*
+ * NUMA parameter parsing routines
+ *
+ * Copyright (c) 2014 Fujitsu Ltd.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "qemu/osdep.h"
+#include "sysemu/numa.h"
+#include "exec/cpu-common.h"
+#include "exec/ramlist.h"
+#include "qemu/bitmap.h"
+#include "qemu/error-report.h"
+#include "qapi/error.h"
+#include "qapi/opts-visitor.h"
+#include "qapi/qapi-visit-machine.h"
+#include "hw/mem/pc-dimm.h"
+#include "hw/mem/memory-device.h"
+#include "qemu/option.h"
+#include "qemu/config-file.h"
+#include "qemu/cutils.h"
+
+QemuOptsList qemu_numa_opts = {
+ .name = "numa",
+ .implied_opt_name = "type",
+ .head = QTAILQ_HEAD_INITIALIZER(qemu_numa_opts.head),
+ .desc = { { 0 } } /* validated with OptsVisitor */
+};
+
+static int have_memdevs = -1;
+static int max_numa_nodeid; /* Highest specified NUMA node ID, plus one.
+ * For all nodes, nodeid < max_numa_nodeid
+ */
+int nb_numa_nodes;
+bool have_numa_distance;
+NodeInfo numa_info[MAX_NODES];
+
+
+static void parse_numa_node(MachineState *ms, NumaNodeOptions *node,
+ Error **errp)
+{
+ Error *err = NULL;
+ uint16_t nodenr;
+ uint16List *cpus = NULL;
+ MachineClass *mc = MACHINE_GET_CLASS(ms);
+
+ if (node->has_nodeid) {
+ nodenr = node->nodeid;
+ } else {
+ nodenr = nb_numa_nodes;
+ }
+
+ if (nodenr >= MAX_NODES) {
+ error_setg(errp, "Max number of NUMA nodes reached: %"
+ PRIu16 "", nodenr);
+ return;
+ }
+
+ if (numa_info[nodenr].present) {
+ error_setg(errp, "Duplicate NUMA nodeid: %" PRIu16, nodenr);
+ return;
+ }
+
+ if (!mc->cpu_index_to_instance_props || !mc->get_default_cpu_node_id) {
+ error_setg(errp, "NUMA is not supported by this machine-type");
+ return;
+ }
+ for (cpus = node->cpus; cpus; cpus = cpus->next) {
+ CpuInstanceProperties props;
+ if (cpus->value >= max_cpus) {
+ error_setg(errp,
+ "CPU index (%" PRIu16 ")"
+ " should be smaller than maxcpus (%d)",
+ cpus->value, max_cpus);
+ return;
+ }
+ props = mc->cpu_index_to_instance_props(ms, cpus->value);
+ props.node_id = nodenr;
+ props.has_node_id = true;
+ machine_set_cpu_numa_node(ms, &props, &err);
+ if (err) {
+ error_propagate(errp, err);
+ return;
+ }
+ }
+
+ if (node->has_mem && node->has_memdev) {
+ error_setg(errp, "cannot specify both mem= and memdev=");
+ return;
+ }
+
+ if (have_memdevs == -1) {
+ have_memdevs = node->has_memdev;
+ }
+ if (node->has_memdev != have_memdevs) {
+ error_setg(errp, "memdev option must be specified for either "
+ "all or no nodes");
+ return;
+ }
+
+ if (node->has_mem) {
+ numa_info[nodenr].node_mem = node->mem;
+ }
+ if (node->has_memdev) {
+ Object *o;
+ o = object_resolve_path_type(node->memdev, TYPE_MEMORY_BACKEND, NULL);
+ if (!o) {
+ error_setg(errp, "memdev=%s is ambiguous", node->memdev);
+ return;
+ }
+
+ object_ref(o);
+ numa_info[nodenr].node_mem = object_property_get_uint(o, "size", NULL);
+ numa_info[nodenr].node_memdev = MEMORY_BACKEND(o);
+ }
+ numa_info[nodenr].present = true;
+ max_numa_nodeid = MAX(max_numa_nodeid, nodenr + 1);
+ nb_numa_nodes++;
+}
+
+static void parse_numa_distance(NumaDistOptions *dist, Error **errp)
+{
+ uint16_t src = dist->src;
+ uint16_t dst = dist->dst;
+ uint8_t val = dist->val;
+
+ if (src >= MAX_NODES || dst >= MAX_NODES) {
+ error_setg(errp, "Parameter '%s' expects an integer between 0 and %d",
+ src >= MAX_NODES ? "src" : "dst", MAX_NODES - 1);
+ return;
+ }
+
+ if (!numa_info[src].present || !numa_info[dst].present) {
+ error_setg(errp, "Source/Destination NUMA node is missing. "
+ "Please use '-numa node' option to declare it first.");
+ return;
+ }
+
+ if (val < NUMA_DISTANCE_MIN) {
+ error_setg(errp, "NUMA distance (%" PRIu8 ") is invalid, "
+ "it shouldn't be less than %d.",
+ val, NUMA_DISTANCE_MIN);
+ return;
+ }
+
+ if (src == dst && val != NUMA_DISTANCE_MIN) {
+ error_setg(errp, "Local distance of node %d should be %d.",
+ src, NUMA_DISTANCE_MIN);
+ return;
+ }
+
+ numa_info[src].distance[dst] = val;
+ have_numa_distance = true;
+}
+
+void set_numa_options(MachineState *ms, NumaOptions *object, Error **errp)
+{
+ Error *err = NULL;
+
+ switch (object->type) {
+ case NUMA_OPTIONS_TYPE_NODE:
+ parse_numa_node(ms, &object->u.node, &err);
+ if (err) {
+ goto end;
+ }
+ break;
+ case NUMA_OPTIONS_TYPE_DIST:
+ parse_numa_distance(&object->u.dist, &err);
+ if (err) {
+ goto end;
+ }
+ break;
+ case NUMA_OPTIONS_TYPE_CPU:
+ if (!object->u.cpu.has_node_id) {
+ error_setg(&err, "Missing mandatory node-id property");
+ goto end;
+ }
+ if (!numa_info[object->u.cpu.node_id].present) {
+ error_setg(&err, "Invalid node-id=%" PRId64 ", NUMA node must be "
+ "defined with -numa node,nodeid=ID before it's used with "
+ "-numa cpu,node-id=ID", object->u.cpu.node_id);
+ goto end;
+ }
+
+ machine_set_cpu_numa_node(ms, qapi_NumaCpuOptions_base(&object->u.cpu),
+ &err);
+ break;
+ default:
+ abort();
+ }
+
+end:
+ error_propagate(errp, err);
+}
+
+static int parse_numa(void *opaque, QemuOpts *opts, Error **errp)
+{
+ NumaOptions *object = NULL;
+ MachineState *ms = MACHINE(opaque);
+ Error *err = NULL;
+ Visitor *v = opts_visitor_new(opts);
+
+ visit_type_NumaOptions(v, NULL, &object, &err);
+ visit_free(v);
+ if (err) {
+ goto end;
+ }
+
+ /* Fix up legacy suffix-less format */
+ if ((object->type == NUMA_OPTIONS_TYPE_NODE) && object->u.node.has_mem) {
+ const char *mem_str = qemu_opt_get(opts, "mem");
+ qemu_strtosz_MiB(mem_str, NULL, &object->u.node.mem);
+ }
+
+ set_numa_options(ms, object, &err);
+
+end:
+ qapi_free_NumaOptions(object);
+ if (err) {
+ error_propagate(errp, err);
+ return -1;
+ }
+
+ return 0;
+}
+
+/* If all node pair distances are symmetric, then only distances
+ * in one direction are enough. If there is even one asymmetric
+ * pair, though, then all distances must be provided. The
+ * distance from a node to itself is always NUMA_DISTANCE_MIN,
+ * so providing it is never necessary.
+ */
+static void validate_numa_distance(void)
+{
+ int src, dst;
+ bool is_asymmetrical = false;
+
+ for (src = 0; src < nb_numa_nodes; src++) {
+ for (dst = src; dst < nb_numa_nodes; dst++) {
+ if (numa_info[src].distance[dst] == 0 &&
+ numa_info[dst].distance[src] == 0) {
+ if (src != dst) {
+ error_report("The distance between node %d and %d is "
+ "missing, at least one distance value "
+ "between each nodes should be provided.",
+ src, dst);
+ exit(EXIT_FAILURE);
+ }
+ }
+
+ if (numa_info[src].distance[dst] != 0 &&
+ numa_info[dst].distance[src] != 0 &&
+ numa_info[src].distance[dst] !=
+ numa_info[dst].distance[src]) {
+ is_asymmetrical = true;
+ }
+ }
+ }
+
+ if (is_asymmetrical) {
+ for (src = 0; src < nb_numa_nodes; src++) {
+ for (dst = 0; dst < nb_numa_nodes; dst++) {
+ if (src != dst && numa_info[src].distance[dst] == 0) {
+ error_report("At least one asymmetrical pair of "
+ "distances is given, please provide distances "
+ "for both directions of all node pairs.");
+ exit(EXIT_FAILURE);
+ }
+ }
+ }
+ }
+}
+
+static void complete_init_numa_distance(void)
+{
+ int src, dst;
+
+ /* Fixup NUMA distance by symmetric policy because if it is an
+ * asymmetric distance table, it should be a complete table and
+ * there would not be any missing distance except local node, which
+ * is verified by validate_numa_distance above.
+ */
+ for (src = 0; src < nb_numa_nodes; src++) {
+ for (dst = 0; dst < nb_numa_nodes; dst++) {
+ if (numa_info[src].distance[dst] == 0) {
+ if (src == dst) {
+ numa_info[src].distance[dst] = NUMA_DISTANCE_MIN;
+ } else {
+ numa_info[src].distance[dst] = numa_info[dst].distance[src];
+ }
+ }
+ }
+ }
+}
+
+void numa_legacy_auto_assign_ram(MachineClass *mc, NodeInfo *nodes,
+ int nb_nodes, ram_addr_t size)
+{
+ int i;
+ uint64_t usedmem = 0;
+
+ /* Align each node according to the alignment
+ * requirements of the machine class
+ */
+
+ for (i = 0; i < nb_nodes - 1; i++) {
+ nodes[i].node_mem = (size / nb_nodes) &
+ ~((1 << mc->numa_mem_align_shift) - 1);
+ usedmem += nodes[i].node_mem;
+ }
+ nodes[i].node_mem = size - usedmem;
+}
+
+void numa_default_auto_assign_ram(MachineClass *mc, NodeInfo *nodes,
+ int nb_nodes, ram_addr_t size)
+{
+ int i;
+ uint64_t usedmem = 0, node_mem;
+ uint64_t granularity = size / nb_nodes;
+ uint64_t propagate = 0;
+
+ for (i = 0; i < nb_nodes - 1; i++) {
+ node_mem = (granularity + propagate) &
+ ~((1 << mc->numa_mem_align_shift) - 1);
+ propagate = granularity + propagate - node_mem;
+ nodes[i].node_mem = node_mem;
+ usedmem += node_mem;
+ }
+ nodes[i].node_mem = size - usedmem;
+}
+
+void numa_complete_configuration(MachineState *ms)
+{
+ int i;
+ MachineClass *mc = MACHINE_GET_CLASS(ms);
+
+ /*
+ * If memory hotplug is enabled (slots > 0) but without '-numa'
+ * options explicitly on CLI, guestes will break.
+ *
+ * Windows: won't enable memory hotplug without SRAT table at all
+ *
+ * Linux: if QEMU is started with initial memory all below 4Gb
+ * and no SRAT table present, guest kernel will use nommu DMA ops,
+ * which breaks 32bit hw drivers when memory is hotplugged and
+ * guest tries to use it with that drivers.
+ *
+ * Enable NUMA implicitly by adding a new NUMA node automatically.
+ */
+ if (ms->ram_slots > 0 && nb_numa_nodes == 0 &&
+ mc->auto_enable_numa_with_memhp) {
+ NumaNodeOptions node = { };
+ parse_numa_node(ms, &node, &error_abort);
+ }
+
+ assert(max_numa_nodeid <= MAX_NODES);
+
+ /* No support for sparse NUMA node IDs yet: */
+ for (i = max_numa_nodeid - 1; i >= 0; i--) {
+ /* Report large node IDs first, to make mistakes easier to spot */
+ if (!numa_info[i].present) {
+ error_report("numa: Node ID missing: %d", i);
+ exit(1);
+ }
+ }
+
+ /* This must be always true if all nodes are present: */
+ assert(nb_numa_nodes == max_numa_nodeid);
+
+ if (nb_numa_nodes > 0) {
+ uint64_t numa_total;
+
+ if (nb_numa_nodes > MAX_NODES) {
+ nb_numa_nodes = MAX_NODES;
+ }
+
+ /* If no memory size is given for any node, assume the default case
+ * and distribute the available memory equally across all nodes
+ */
+ for (i = 0; i < nb_numa_nodes; i++) {
+ if (numa_info[i].node_mem != 0) {
+ break;
+ }
+ }
+ if (i == nb_numa_nodes) {
+ assert(mc->numa_auto_assign_ram);
+ mc->numa_auto_assign_ram(mc, numa_info, nb_numa_nodes, ram_size);
+ }
+
+ numa_total = 0;
+ for (i = 0; i < nb_numa_nodes; i++) {
+ numa_total += numa_info[i].node_mem;
+ }
+ if (numa_total != ram_size) {
+ error_report("total memory for NUMA nodes (0x%" PRIx64 ")"
+ " should equal RAM size (0x" RAM_ADDR_FMT ")",
+ numa_total, ram_size);
+ exit(1);
+ }
+
+ /* QEMU needs at least all unique node pair distances to build
+ * the whole NUMA distance table. QEMU treats the distance table
+ * as symmetric by default, i.e. distance A->B == distance B->A.
+ * Thus, QEMU is able to complete the distance table
+ * initialization even though only distance A->B is provided and
+ * distance B->A is not. QEMU knows the distance of a node to
+ * itself is always 10, so A->A distances may be omitted. When
+ * the distances of two nodes of a pair differ, i.e. distance
+ * A->B != distance B->A, then that means the distance table is
+ * asymmetric. In this case, the distances for both directions
+ * of all node pairs are required.
+ */
+ if (have_numa_distance) {
+ /* Validate enough NUMA distance information was provided. */
+ validate_numa_distance();
+
+ /* Validation succeeded, now fill in any missing distances. */
+ complete_init_numa_distance();
+ }
+ }
+}
+
+void parse_numa_opts(MachineState *ms)
+{
+ qemu_opts_foreach(qemu_find_opts("numa"), parse_numa, ms, &error_fatal);
+}
+
+void numa_cpu_pre_plug(const CPUArchId *slot, DeviceState *dev, Error **errp)
+{
+ int node_id = object_property_get_int(OBJECT(dev), "node-id", &error_abort);
+
+ if (node_id == CPU_UNSET_NUMA_NODE_ID) {
+ /* due to bug in libvirt, it doesn't pass node-id from props on
+ * device_add as expected, so we have to fix it up here */
+ if (slot->props.has_node_id) {
+ object_property_set_int(OBJECT(dev), slot->props.node_id,
+ "node-id", errp);
+ }
+ } else if (node_id != slot->props.node_id) {
+ error_setg(errp, "invalid node-id, must be %"PRId64,
+ slot->props.node_id);
+ }
+}
+
+static void allocate_system_memory_nonnuma(MemoryRegion *mr, Object *owner,
+ const char *name,
+ uint64_t ram_size)
+{
+ if (mem_path) {
+#ifdef __linux__
+ Error *err = NULL;
+ memory_region_init_ram_from_file(mr, owner, name, ram_size, 0, 0,
+ mem_path, &err);
+ if (err) {
+ error_report_err(err);
+ if (mem_prealloc) {
+ exit(1);
+ }
+ error_report("falling back to regular RAM allocation.");
+
+ /* Legacy behavior: if allocation failed, fall back to
+ * regular RAM allocation.
+ */
+ mem_path = NULL;
+ memory_region_init_ram_nomigrate(mr, owner, name, ram_size, &error_fatal);
+ }
+#else
+ fprintf(stderr, "-mem-path not supported on this host\n");
+ exit(1);
+#endif
+ } else {
+ memory_region_init_ram_nomigrate(mr, owner, name, ram_size, &error_fatal);
+ }
+ vmstate_register_ram_global(mr);
+}
+
+void memory_region_allocate_system_memory(MemoryRegion *mr, Object *owner,
+ const char *name,
+ uint64_t ram_size)
+{
+ uint64_t addr = 0;
+ int i;
+
+ if (nb_numa_nodes == 0 || !have_memdevs) {
+ allocate_system_memory_nonnuma(mr, owner, name, ram_size);
+ return;
+ }
+
+ memory_region_init(mr, owner, name, ram_size);
+ for (i = 0; i < nb_numa_nodes; i++) {
+ uint64_t size = numa_info[i].node_mem;
+ HostMemoryBackend *backend = numa_info[i].node_memdev;
+ if (!backend) {
+ continue;
+ }
+ MemoryRegion *seg = host_memory_backend_get_memory(backend);
+
+ if (memory_region_is_mapped(seg)) {
+ char *path = object_get_canonical_path_component(OBJECT(backend));
+ error_report("memory backend %s is used multiple times. Each "
+ "-numa option must use a different memdev value.",
+ path);
+ g_free(path);
+ exit(1);
+ }
+
+ host_memory_backend_set_mapped(backend, true);
+ memory_region_add_subregion(mr, addr, seg);
+ vmstate_register_ram_global(seg);
+ addr += size;
+ }
+}
+
+static void numa_stat_memory_devices(NumaNodeMem node_mem[])
+{
+ MemoryDeviceInfoList *info_list = qmp_memory_device_list();
+ MemoryDeviceInfoList *info;
+ PCDIMMDeviceInfo *pcdimm_info;
+ VirtioPMEMDeviceInfo *vpi;
+
+ for (info = info_list; info; info = info->next) {
+ MemoryDeviceInfo *value = info->value;
+
+ if (value) {
+ switch (value->type) {
+ case MEMORY_DEVICE_INFO_KIND_DIMM:
+ case MEMORY_DEVICE_INFO_KIND_NVDIMM:
+ pcdimm_info = value->type == MEMORY_DEVICE_INFO_KIND_DIMM ?
+ value->u.dimm.data : value->u.nvdimm.data;
+ node_mem[pcdimm_info->node].node_mem += pcdimm_info->size;
+ node_mem[pcdimm_info->node].node_plugged_mem +=
+ pcdimm_info->size;
+ break;
+ case MEMORY_DEVICE_INFO_KIND_VIRTIO_PMEM:
+ vpi = value->u.virtio_pmem.data;
+ /* TODO: once we support numa, assign to right node */
+ node_mem[0].node_mem += vpi->size;
+ node_mem[0].node_plugged_mem += vpi->size;
+ break;
+ default:
+ g_assert_not_reached();
+ }
+ }
+ }
+ qapi_free_MemoryDeviceInfoList(info_list);
+}
+
+void query_numa_node_mem(NumaNodeMem node_mem[])
+{
+ int i;
+
+ if (nb_numa_nodes <= 0) {
+ return;
+ }
+
+ numa_stat_memory_devices(node_mem);
+ for (i = 0; i < nb_numa_nodes; i++) {
+ node_mem[i].node_mem += numa_info[i].node_mem;
+ }
+}
+
+void ram_block_notifier_add(RAMBlockNotifier *n)
+{
+ QLIST_INSERT_HEAD(&ram_list.ramblock_notifiers, n, next);
+}
+
+void ram_block_notifier_remove(RAMBlockNotifier *n)
+{
+ QLIST_REMOVE(n, next);
+}
+
+void ram_block_notify_add(void *host, size_t size)
+{
+ RAMBlockNotifier *notifier;
+
+ QLIST_FOREACH(notifier, &ram_list.ramblock_notifiers, next) {
+ notifier->ram_block_added(notifier, host, size);
+ }
+}
+
+void ram_block_notify_remove(void *host, size_t size)
+{
+ RAMBlockNotifier *notifier;
+
+ QLIST_FOREACH(notifier, &ram_list.ramblock_notifiers, next) {
+ notifier->ram_block_removed(notifier, host, size);
+ }
+}
#include "hw/qdev.h"
#include "sysemu/sysemu.h"
#include "qapi/error.h"
-#include "qapi/qapi-events-misc.h"
+#include "qapi/qapi-events-qdev.h"
#include "qapi/qmp/qerror.h"
#include "qapi/visitor.h"
#include "qemu/error-report.h"
default y if PCI_DEVICES
depends on PCI
select VGA
+ select BITBANG_I2C
+ select DDC
#include "qapi/error.h"
#include "hw/hw.h"
#include "ui/console.h"
+#include "hw/display/i2c-ddc.h"
#include "trace.h"
#define ATI_DEBUG_HW_CURSOR 0
DPRINTF("Switching to %dx%d %d %d @ %x\n", h, v, stride, bpp, offs);
vbe_ioport_write_index(&s->vga, 0, VBE_DISPI_INDEX_ENABLE);
vbe_ioport_write_data(&s->vga, 0, VBE_DISPI_DISABLED);
+ s->vga.big_endian_fb = false;
/* reset VBE regs then set up mode */
s->vga.vbe_regs[VBE_DISPI_INDEX_XRES] = h;
s->vga.vbe_regs[VBE_DISPI_INDEX_YRES] = v;
}
}
+static uint64_t ati_i2c(bitbang_i2c_interface *i2c, uint64_t data, int base)
+{
+ bool c = (data & BIT(base + 17) ? !!(data & BIT(base + 1)) : 1);
+ bool d = (data & BIT(base + 16) ? !!(data & BIT(base)) : 1);
+
+ bitbang_i2c_set(i2c, BITBANG_I2C_SCL, c);
+ d = bitbang_i2c_set(i2c, BITBANG_I2C_SDA, d);
+
+ data &= ~0xf00ULL;
+ if (c) {
+ data |= BIT(base + 9);
+ }
+ if (d) {
+ data |= BIT(base + 8);
+ }
+ return data;
+}
+
static inline uint64_t ati_reg_read_offs(uint32_t reg, int offs,
unsigned int size)
{
case DAC_CNTL:
val = s->regs.dac_cntl;
break;
-/* case GPIO_MONID: FIXME hook up DDC I2C here */
+ case GPIO_VGA_DDC:
+ val = s->regs.gpio_vga_ddc;
+ break;
+ case GPIO_DVI_DDC:
+ val = s->regs.gpio_dvi_ddc;
+ break;
+ case GPIO_MONID ... GPIO_MONID + 3:
+ val = ati_reg_read_offs(s->regs.gpio_monid,
+ addr - GPIO_MONID, size);
+ break;
case PALETTE_INDEX:
/* FIXME unaligned access */
val = vga_ioport_read(&s->vga, VGA_PEL_IR) << 16;
break;
case DEFAULT_OFFSET:
val = s->regs.default_offset;
+ if (s->dev_id != PCI_DEVICE_ID_ATI_RAGE128_PF) {
+ val >>= 10;
+ val |= s->regs.default_pitch << 16;
+ val |= s->regs.default_tile << 30;
+ }
break;
case DEFAULT_PITCH:
val = s->regs.default_pitch;
+ val |= s->regs.default_tile << 16;
break;
case DEFAULT_SC_BOTTOM_RIGHT:
val = s->regs.default_sc_bottom_right;
s->regs.dac_cntl = data & 0xffffe3ff;
s->vga.dac_8bit = !!(data & DAC_8BIT_EN);
break;
-/* case GPIO_MONID: FIXME hook up DDC I2C here */
+ case GPIO_VGA_DDC:
+ if (s->dev_id != PCI_DEVICE_ID_ATI_RAGE128_PF) {
+ /* FIXME: Maybe add a property to select VGA or DVI port? */
+ }
+ break;
+ case GPIO_DVI_DDC:
+ if (s->dev_id != PCI_DEVICE_ID_ATI_RAGE128_PF) {
+ s->regs.gpio_dvi_ddc = ati_i2c(&s->bbi2c, data, 0);
+ }
+ break;
+ case GPIO_MONID ... GPIO_MONID + 3:
+ /* FIXME What does Radeon have here? */
+ if (s->dev_id == PCI_DEVICE_ID_ATI_RAGE128_PF) {
+ ati_reg_write_offs(&s->regs.gpio_monid,
+ addr - GPIO_MONID, data, size);
+ /*
+ * Rage128p accesses DDC used to get EDID via these bits.
+ * Only touch i2c when write overlaps 3rd byte because some
+ * drivers access this reg via multiple partial writes and
+ * without this spurious bits would be sent.
+ */
+ if ((s->regs.gpio_monid & BIT(25)) &&
+ addr <= GPIO_MONID + 2 && addr + size > GPIO_MONID + 2) {
+ s->regs.gpio_monid = ati_i2c(&s->bbi2c, s->regs.gpio_monid, 1);
+ }
+ }
+ break;
case PALETTE_INDEX ... PALETTE_INDEX + 3:
if (size == 4) {
vga_ioport_write(&s->vga, VGA_PEL_IR, (data >> 16) & 0xff);
case SRC_PITCH_OFFSET:
if (s->dev_id == PCI_DEVICE_ID_ATI_RAGE128_PF) {
s->regs.src_offset = (data & 0x1fffff) << 5;
- s->regs.src_pitch = (data >> 21) & 0x3ff;
+ s->regs.src_pitch = (data & 0x7fe00000) >> 21;
s->regs.src_tile = data >> 31;
} else {
- s->regs.src_offset = (data & 0x3fffff) << 11;
+ s->regs.src_offset = (data & 0x3fffff) << 10;
s->regs.src_pitch = (data & 0x3fc00000) >> 16;
s->regs.src_tile = (data >> 30) & 1;
}
case DST_PITCH_OFFSET:
if (s->dev_id == PCI_DEVICE_ID_ATI_RAGE128_PF) {
s->regs.dst_offset = (data & 0x1fffff) << 5;
- s->regs.dst_pitch = (data >> 21) & 0x3ff;
+ s->regs.dst_pitch = (data & 0x7fe00000) >> 21;
s->regs.dst_tile = data >> 31;
} else {
- s->regs.dst_offset = (data & 0x3fffff) << 11;
+ s->regs.dst_offset = (data & 0x3fffff) << 10;
s->regs.dst_pitch = (data & 0x3fc00000) >> 16;
s->regs.dst_tile = data >> 30;
}
s->regs.dp_write_mask = data;
break;
case DEFAULT_OFFSET:
- data &= (s->dev_id == PCI_DEVICE_ID_ATI_RAGE128_PF ?
- 0x03fffc00 : 0xfffffc00);
- s->regs.default_offset = data;
+ if (s->dev_id == PCI_DEVICE_ID_ATI_RAGE128_PF) {
+ s->regs.default_offset = data & 0xfffffff0;
+ } else {
+ /* Radeon has DEFAULT_PITCH_OFFSET here like DST_PITCH_OFFSET */
+ s->regs.default_offset = (data & 0x3fffff) << 10;
+ s->regs.default_pitch = (data & 0x3fc00000) >> 16;
+ s->regs.default_tile = data >> 30;
+ }
break;
case DEFAULT_PITCH:
if (s->dev_id == PCI_DEVICE_ID_ATI_RAGE128_PF) {
- s->regs.default_pitch = data & 0x103ff;
+ s->regs.default_pitch = data & 0x3fff;
+ s->regs.default_tile = (data >> 16) & 1;
}
break;
case DEFAULT_SC_BOTTOM_RIGHT:
vga->cursor_draw_line = ati_cursor_draw_line;
}
+ /* ddc, edid */
+ I2CBus *i2cbus = i2c_init_bus(DEVICE(s), "ati-vga.ddc");
+ bitbang_i2c_init(&s->bbi2c, i2cbus);
+ I2CSlave *i2cddc = I2C_SLAVE(qdev_create(BUS(i2cbus), TYPE_I2CDDC));
+ i2c_set_slave_address(i2cddc, 0x50);
+
/* mmio register space */
memory_region_init_io(&s->mm, OBJECT(s), &ati_mm_ops, s,
"ati.mmregs", 0x4000);
k->class_id = PCI_CLASS_DISPLAY_VGA;
k->vendor_id = PCI_VENDOR_ID_ATI;
k->device_id = PCI_DEVICE_ID_ATI_RAGE128_PF;
- k->romfile = "vgabios-stdvga.bin";
+ k->romfile = "vgabios-ati.bin";
k->realize = ati_vga_realize;
k->exit = ati_vga_exit;
}
}
}
+#define DEFAULT_CNTL (s->regs.dp_gui_master_cntl & GMC_DST_PITCH_OFFSET_CNTL)
+
void ati_2d_blt(ATIVGAState *s)
{
/* FIXME it is probably more complex than this and may need to be */
s->vga.vbe_start_addr, surface_data(ds), surface_stride(ds),
surface_bits_per_pixel(ds),
(s->regs.dp_mix & GMC_ROP3_MASK) >> 16);
- DPRINTF("%d %d, %d %d, (%d,%d) -> (%d,%d) %dx%d\n", s->regs.src_offset,
- s->regs.dst_offset, s->regs.src_pitch, s->regs.dst_pitch,
+ int dst_x = (s->regs.dp_cntl & DST_X_LEFT_TO_RIGHT ?
+ s->regs.dst_x : s->regs.dst_x + 1 - s->regs.dst_width);
+ int dst_y = (s->regs.dp_cntl & DST_Y_TOP_TO_BOTTOM ?
+ s->regs.dst_y : s->regs.dst_y + 1 - s->regs.dst_height);
+ int bpp = ati_bpp_from_datatype(s);
+ int dst_stride = DEFAULT_CNTL ? s->regs.dst_pitch : s->regs.default_pitch;
+ uint8_t *dst_bits = s->vga.vram_ptr + (DEFAULT_CNTL ?
+ s->regs.dst_offset : s->regs.default_offset);
+
+ if (s->dev_id == PCI_DEVICE_ID_ATI_RAGE128_PF) {
+ dst_bits += s->regs.crtc_offset & 0x07ffffff;
+ dst_stride *= bpp;
+ }
+ uint8_t *end = s->vga.vram_ptr + s->vga.vram_size;
+ if (dst_bits >= end || dst_bits + dst_x + (dst_y + s->regs.dst_height) *
+ dst_stride >= end) {
+ qemu_log_mask(LOG_UNIMP, "blt outside vram not implemented\n");
+ return;
+ }
+ DPRINTF("%d %d %d, %d %d %d, (%d,%d) -> (%d,%d) %dx%d %c %c\n",
+ s->regs.src_offset, s->regs.dst_offset, s->regs.default_offset,
+ s->regs.src_pitch, s->regs.dst_pitch, s->regs.default_pitch,
s->regs.src_x, s->regs.src_y, s->regs.dst_x, s->regs.dst_y,
- s->regs.dst_width, s->regs.dst_height);
+ s->regs.dst_width, s->regs.dst_height,
+ (s->regs.dp_cntl & DST_X_LEFT_TO_RIGHT ? '>' : '<'),
+ (s->regs.dp_cntl & DST_Y_TOP_TO_BOTTOM ? 'v' : '^'));
switch (s->regs.dp_mix & GMC_ROP3_MASK) {
case ROP3_SRCCOPY:
{
- uint8_t *src_bits, *dst_bits, *end;
- int src_stride, dst_stride, bpp = ati_bpp_from_datatype(s);
- src_bits = s->vga.vram_ptr + s->regs.src_offset;
- dst_bits = s->vga.vram_ptr + s->regs.dst_offset;
- src_stride = s->regs.src_pitch;
- dst_stride = s->regs.dst_pitch;
+ int src_x = (s->regs.dp_cntl & DST_X_LEFT_TO_RIGHT ?
+ s->regs.src_x : s->regs.src_x + 1 - s->regs.dst_width);
+ int src_y = (s->regs.dp_cntl & DST_Y_TOP_TO_BOTTOM ?
+ s->regs.src_y : s->regs.src_y + 1 - s->regs.dst_height);
+ int src_stride = DEFAULT_CNTL ?
+ s->regs.src_pitch : s->regs.default_pitch;
+ uint8_t *src_bits = s->vga.vram_ptr + (DEFAULT_CNTL ?
+ s->regs.src_offset : s->regs.default_offset);
if (s->dev_id == PCI_DEVICE_ID_ATI_RAGE128_PF) {
src_bits += s->regs.crtc_offset & 0x07ffffff;
- dst_bits += s->regs.crtc_offset & 0x07ffffff;
src_stride *= bpp;
- dst_stride *= bpp;
}
+ if (src_bits >= end || src_bits + src_x +
+ (src_y + s->regs.dst_height) * src_stride >= end) {
+ qemu_log_mask(LOG_UNIMP, "blt outside vram not implemented\n");
+ return;
+ }
+
src_stride /= sizeof(uint32_t);
dst_stride /= sizeof(uint32_t);
-
DPRINTF("pixman_blt(%p, %p, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d)\n",
src_bits, dst_bits, src_stride, dst_stride, bpp, bpp,
- s->regs.src_x, s->regs.src_y, s->regs.dst_x, s->regs.dst_y,
+ src_x, src_y, dst_x, dst_y,
s->regs.dst_width, s->regs.dst_height);
- end = s->vga.vram_ptr + s->vga.vram_size;
- if (src_bits >= end || dst_bits >= end ||
- src_bits + s->regs.src_x + (s->regs.src_y + s->regs.dst_height) *
- src_stride * sizeof(uint32_t) >= end ||
- dst_bits + s->regs.dst_x + (s->regs.dst_y + s->regs.dst_height) *
- dst_stride * sizeof(uint32_t) >= end) {
- qemu_log_mask(LOG_UNIMP, "blt outside vram not implemented\n");
- return;
+ if (s->regs.dp_cntl & DST_X_LEFT_TO_RIGHT &&
+ s->regs.dp_cntl & DST_Y_TOP_TO_BOTTOM) {
+ pixman_blt((uint32_t *)src_bits, (uint32_t *)dst_bits,
+ src_stride, dst_stride, bpp, bpp,
+ src_x, src_y, dst_x, dst_y,
+ s->regs.dst_width, s->regs.dst_height);
+ } else {
+ /* FIXME: We only really need a temporary if src and dst overlap */
+ int llb = s->regs.dst_width * (bpp / 8);
+ int tmp_stride = DIV_ROUND_UP(llb, sizeof(uint32_t));
+ uint32_t *tmp = g_malloc(tmp_stride * sizeof(uint32_t) *
+ s->regs.dst_height);
+ pixman_blt((uint32_t *)src_bits, tmp,
+ src_stride, tmp_stride, bpp, bpp,
+ src_x, src_y, 0, 0,
+ s->regs.dst_width, s->regs.dst_height);
+ pixman_blt(tmp, (uint32_t *)dst_bits,
+ tmp_stride, dst_stride, bpp, bpp,
+ 0, 0, dst_x, dst_y,
+ s->regs.dst_width, s->regs.dst_height);
+ g_free(tmp);
}
- pixman_blt((uint32_t *)src_bits, (uint32_t *)dst_bits,
- src_stride, dst_stride, bpp, bpp,
- s->regs.src_x, s->regs.src_y,
- s->regs.dst_x, s->regs.dst_y,
- s->regs.dst_width, s->regs.dst_height);
if (dst_bits >= s->vga.vram_ptr + s->vga.vbe_start_addr &&
dst_bits < s->vga.vram_ptr + s->vga.vbe_start_addr +
s->vga.vbe_regs[VBE_DISPI_INDEX_YRES] * s->vga.vbe_line_offset) {
memory_region_set_dirty(&s->vga.vram, s->vga.vbe_start_addr +
s->regs.dst_offset +
- s->regs.dst_y * surface_stride(ds),
+ dst_y * surface_stride(ds),
s->regs.dst_height * surface_stride(ds));
}
s->regs.dst_x += s->regs.dst_width;
case ROP3_BLACKNESS:
case ROP3_WHITENESS:
{
- uint8_t *dst_bits, *end;
- int dst_stride, bpp = ati_bpp_from_datatype(s);
uint32_t filler = 0;
- dst_bits = s->vga.vram_ptr + s->regs.dst_offset;
- dst_stride = s->regs.dst_pitch;
-
- if (s->dev_id == PCI_DEVICE_ID_ATI_RAGE128_PF) {
- dst_bits += s->regs.crtc_offset & 0x07ffffff;
- dst_stride *= bpp;
- }
- dst_stride /= sizeof(uint32_t);
switch (s->regs.dp_mix & GMC_ROP3_MASK) {
case ROP3_PATCOPY:
- filler = bswap32(s->regs.dp_brush_frgd_clr);
+ filler = s->regs.dp_brush_frgd_clr;
break;
case ROP3_BLACKNESS:
- filler = rgb_to_pixel32(s->vga.palette[0], s->vga.palette[1],
- s->vga.palette[2]) << 8 | 0xff;
+ filler = 0xffUL << 24 | rgb_to_pixel32(s->vga.palette[0],
+ s->vga.palette[1], s->vga.palette[2]);
break;
case ROP3_WHITENESS:
- filler = rgb_to_pixel32(s->vga.palette[3], s->vga.palette[4],
- s->vga.palette[5]) << 8 | 0xff;
+ filler = 0xffUL << 24 | rgb_to_pixel32(s->vga.palette[3],
+ s->vga.palette[4], s->vga.palette[5]);
break;
}
+ dst_stride /= sizeof(uint32_t);
DPRINTF("pixman_fill(%p, %d, %d, %d, %d, %d, %d, %x)\n",
dst_bits, dst_stride, bpp,
s->regs.dst_x, s->regs.dst_y,
s->regs.dst_width, s->regs.dst_height,
filler);
- end = s->vga.vram_ptr + s->vga.vram_size;
- if (dst_bits >= end ||
- dst_bits + s->regs.dst_x + (s->regs.dst_y + s->regs.dst_height) *
- dst_stride * sizeof(uint32_t) >= end) {
- qemu_log_mask(LOG_UNIMP, "blt outside vram not implemented\n");
- return;
- }
pixman_fill((uint32_t *)dst_bits, dst_stride, bpp,
- s->regs.dst_x, s->regs.dst_y,
- s->regs.dst_width, s->regs.dst_height,
- filler);
+ s->regs.dst_x, s->regs.dst_y,
+ s->regs.dst_width, s->regs.dst_height,
+ filler);
if (dst_bits >= s->vga.vram_ptr + s->vga.vbe_start_addr &&
dst_bits < s->vga.vram_ptr + s->vga.vbe_start_addr +
s->vga.vbe_regs[VBE_DISPI_INDEX_YRES] * s->vga.vbe_line_offset) {
memory_region_set_dirty(&s->vga.vram, s->vga.vbe_start_addr +
s->regs.dst_offset +
- s->regs.dst_y * surface_stride(ds),
+ dst_y * surface_stride(ds),
s->regs.dst_height * surface_stride(ds));
}
s->regs.dst_y += s->regs.dst_height;
{"CRTC_GEN_CNTL", 0x0050},
{"CRTC_EXT_CNTL", 0x0054},
{"DAC_CNTL", 0x0058},
+ {"GPIO_VGA_DDC", 0x0060},
+ {"GPIO_DVI_DDC", 0x0064},
{"GPIO_MONID", 0x0068},
{"I2C_CNTL_1", 0x0094},
{"PALETTE_INDEX", 0x00b0},
#define ATI_INT_H
#include "hw/pci/pci.h"
+#include "hw/i2c/bitbang_i2c.h"
#include "vga_int.h"
/*#define DEBUG_ATI*/
uint32_t crtc_gen_cntl;
uint32_t crtc_ext_cntl;
uint32_t dac_cntl;
+ uint32_t gpio_vga_ddc;
+ uint32_t gpio_dvi_ddc;
+ uint32_t gpio_monid;
uint32_t crtc_h_total_disp;
uint32_t crtc_h_sync_strt_wid;
uint32_t crtc_v_total_disp;
uint32_t dp_write_mask;
uint32_t default_offset;
uint32_t default_pitch;
+ uint32_t default_tile;
uint32_t default_sc_bottom_right;
} ATIVGARegs;
uint16_t cursor_size;
uint32_t cursor_offset;
QEMUCursor *cursor;
+ bitbang_i2c_interface bbi2c;
MemoryRegion io;
MemoryRegion mm;
ATIVGARegs regs;
#define CRTC_GEN_CNTL 0x0050
#define CRTC_EXT_CNTL 0x0054
#define DAC_CNTL 0x0058
+#define GPIO_VGA_DDC 0x0060
+#define GPIO_DVI_DDC 0x0064
#define GPIO_MONID 0x0068
#define I2C_CNTL_1 0x0094
#define PALETTE_INDEX 0x00b0
#define BRUSH_SOLIDCOLOR 0x00000d00
/* DP_GUI_MASTER_CNTL bit constants */
-#define GMC_SRC_PITCH_OFFSET_DEFAULT 0x00000000
-#define GMC_DST_PITCH_OFFSET_DEFAULT 0x00000000
+#define GMC_SRC_PITCH_OFFSET_CNTL 0x00000001
+#define GMC_DST_PITCH_OFFSET_CNTL 0x00000002
#define GMC_SRC_CLIP_DEFAULT 0x00000000
#define GMC_DST_CLIP_DEFAULT 0x00000000
#define GMC_BRUSH_SOLIDCOLOR 0x000000d0
resource_id = qemu_get_be32(f);
while (resource_id != 0) {
+ res = virtio_gpu_find_resource(g, resource_id);
+ if (res) {
+ return -EINVAL;
+ }
+
res = g_new0(struct virtio_gpu_simple_resource, 1);
res->resource_id = resource_id;
res->width = qemu_get_be32(f);
if (res->iov[i].iov_base) {
dma_memory_unmap(VIRTIO_DEVICE(g)->dma_as,
res->iov[i].iov_base,
- res->iov[i].iov_len,
+ len,
DMA_DIRECTION_TO_DEVICE,
- res->iov[i].iov_len);
+ 0);
}
/* ...and the mappings for previous loop iterations */
res->iov_cnt = i;
#include "qemu/osdep.h"
#include "hw/hw.h"
-#include "bitbang_i2c.h"
+#include "hw/i2c/bitbang_i2c.h"
#include "hw/sysbus.h"
#include "qemu/module.h"
#define DPRINTF(fmt, ...) do {} while(0)
#endif
-typedef enum bitbang_i2c_state {
- STOPPED = 0,
- SENDING_BIT7,
- SENDING_BIT6,
- SENDING_BIT5,
- SENDING_BIT4,
- SENDING_BIT3,
- SENDING_BIT2,
- SENDING_BIT1,
- SENDING_BIT0,
- WAITING_FOR_ACK,
- RECEIVING_BIT7,
- RECEIVING_BIT6,
- RECEIVING_BIT5,
- RECEIVING_BIT4,
- RECEIVING_BIT3,
- RECEIVING_BIT2,
- RECEIVING_BIT1,
- RECEIVING_BIT0,
- SENDING_ACK,
- SENT_NACK
-} bitbang_i2c_state;
-
-struct bitbang_i2c_interface {
- I2CBus *bus;
- bitbang_i2c_state state;
- int last_data;
- int last_clock;
- int device_out;
- uint8_t buffer;
- int current_addr;
-};
-
static void bitbang_i2c_enter_stop(bitbang_i2c_interface *i2c)
{
DPRINTF("STOP\n");
abort();
}
-bitbang_i2c_interface *bitbang_i2c_init(I2CBus *bus)
+void bitbang_i2c_init(bitbang_i2c_interface *s, I2CBus *bus)
{
- bitbang_i2c_interface *s;
-
- s = g_malloc0(sizeof(bitbang_i2c_interface));
-
s->bus = bus;
s->last_data = 1;
s->last_clock = 1;
s->device_out = 1;
-
- return s;
}
/* GPIO interface. */
SysBusDevice parent_obj;
MemoryRegion dummy_iomem;
- bitbang_i2c_interface *bitbang;
+ bitbang_i2c_interface bitbang;
int last_level;
qemu_irq out;
} GPIOI2CState;
{
GPIOI2CState *s = opaque;
- level = bitbang_i2c_set(s->bitbang, irq, level);
+ level = bitbang_i2c_set(&s->bitbang, irq, level);
if (level != s->last_level) {
s->last_level = level;
qemu_set_irq(s->out, level);
sysbus_init_mmio(sbd, &s->dummy_iomem);
bus = i2c_init_bus(dev, "i2c");
- s->bitbang = bitbang_i2c_init(bus);
+ bitbang_i2c_init(&s->bitbang, bus);
qdev_init_gpio_in(dev, bitbang_i2c_gpio_set, 2);
qdev_init_gpio_out(dev, &s->out, 1);
+++ /dev/null
-#ifndef BITBANG_I2C_H
-#define BITBANG_I2C_H
-
-#include "hw/i2c/i2c.h"
-
-#define BITBANG_I2C_SDA 0
-#define BITBANG_I2C_SCL 1
-
-bitbang_i2c_interface *bitbang_i2c_init(I2CBus *bus);
-int bitbang_i2c_set(bitbang_i2c_interface *i2c, int line, int level);
-
-#endif
#include "cpu.h"
#include "hw/hw.h"
#include "hw/i2c/ppc4xx_i2c.h"
-#include "bitbang_i2c.h"
#define PPC4xx_I2C_MEM_SIZE 18
case IIC_DIRECTCNTL:
i2c->directcntl = value & (IIC_DIRECTCNTL_SDAC & IIC_DIRECTCNTL_SCLC);
i2c->directcntl |= (value & IIC_DIRECTCNTL_SCLC ? 1 : 0);
- bitbang_i2c_set(i2c->bitbang, BITBANG_I2C_SCL,
+ bitbang_i2c_set(&i2c->bitbang, BITBANG_I2C_SCL,
i2c->directcntl & IIC_DIRECTCNTL_MSCL);
- i2c->directcntl |= bitbang_i2c_set(i2c->bitbang, BITBANG_I2C_SDA,
+ i2c->directcntl |= bitbang_i2c_set(&i2c->bitbang, BITBANG_I2C_SDA,
(value & IIC_DIRECTCNTL_SDAC) != 0) << 1;
break;
default:
sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->iomem);
sysbus_init_irq(SYS_BUS_DEVICE(s), &s->irq);
s->bus = i2c_init_bus(DEVICE(s), "i2c");
- s->bitbang = bitbang_i2c_init(s->bus);
+ bitbang_i2c_init(&s->bitbang, s->bus);
}
static void ppc4xx_i2c_class_init(ObjectClass *klass, void *data)
#include "qemu/osdep.h"
#include "hw/sysbus.h"
-#include "bitbang_i2c.h"
+#include "hw/i2c/bitbang_i2c.h"
#include "qemu/log.h"
#include "qemu/module.h"
SysBusDevice parent_obj;
MemoryRegion iomem;
- bitbang_i2c_interface *bitbang;
+ bitbang_i2c_interface bitbang;
int out;
int in;
} VersatileI2CState;
qemu_log_mask(LOG_GUEST_ERROR,
"%s: Bad offset 0x%x\n", __func__, (int)offset);
}
- bitbang_i2c_set(s->bitbang, BITBANG_I2C_SCL, (s->out & 1) != 0);
- s->in = bitbang_i2c_set(s->bitbang, BITBANG_I2C_SDA, (s->out & 2) != 0);
+ bitbang_i2c_set(&s->bitbang, BITBANG_I2C_SCL, (s->out & 1) != 0);
+ s->in = bitbang_i2c_set(&s->bitbang, BITBANG_I2C_SDA, (s->out & 2) != 0);
}
static const MemoryRegionOps versatile_i2c_ops = {
I2CBus *bus;
bus = i2c_init_bus(dev, "i2c");
- s->bitbang = bitbang_i2c_init(bus);
+ bitbang_i2c_init(&s->bitbang, bus);
memory_region_init_io(&s->iomem, obj, &versatile_i2c_ops, s,
"versatile_i2c", 0x1000);
sysbus_init_mmio(sbd, &s->iomem);
# For ACPI builder:
select SERIAL_ISA
select ACPI_VMGENID
+ select VIRTIO_PMEM_SUPPORTED
config PC_PCI
bool
#include "hw/i386/intel_iommu.h"
#include "hw/net/ne2000-isa.h"
#include "standard-headers/asm-x86/bootparam.h"
+#include "hw/virtio/virtio-pmem-pci.h"
+#include "hw/mem/memory-device.h"
/* debug PC/ISA interrupts */
//#define DEBUG_IRQ
return false;
}
-/* Enables contiguous-apic-ID mode, for compatibility */
-static bool compat_apic_id_mode;
-
-void enable_compat_apic_id_mode(void)
-{
- compat_apic_id_mode = true;
-}
-
/* Calculates initial APIC ID for a specific CPU index
*
* Currently we need to be able to calculate the APIC ID from the CPU index
* no concept of "CPU index", and the NUMA tables on fw_cfg need the APIC ID of
* all CPUs up to max_cpus.
*/
-static uint32_t x86_cpu_apic_id_from_index(unsigned int cpu_index)
+static uint32_t x86_cpu_apic_id_from_index(PCMachineState *pcms,
+ unsigned int cpu_index)
{
+ PCMachineClass *pcmc = PC_MACHINE_GET_CLASS(pcms);
uint32_t correct_id;
static bool warned;
correct_id = x86_apicid_from_cpu_idx(smp_cores, smp_threads, cpu_index);
- if (compat_apic_id_mode) {
+ if (pcmc->compat_apic_id_mode) {
if (cpu_index != correct_id && !warned && !qtest_enabled()) {
error_report("APIC IDs set in compatibility mode, "
"CPU topology won't match the configuration");
void pc_hot_add_cpu(const int64_t id, Error **errp)
{
MachineState *ms = MACHINE(qdev_get_machine());
- int64_t apic_id = x86_cpu_apic_id_from_index(id);
+ PCMachineState *pcms = PC_MACHINE(ms);
+ int64_t apic_id = x86_cpu_apic_id_from_index(pcms, id);
Error *local_err = NULL;
if (id < 0) {
*
* This is used for FW_CFG_MAX_CPUS. See comments on bochs_bios_init().
*/
- pcms->apic_id_limit = x86_cpu_apic_id_from_index(max_cpus - 1) + 1;
+ pcms->apic_id_limit = x86_cpu_apic_id_from_index(pcms, max_cpus - 1) + 1;
possible_cpus = mc->possible_cpu_arch_ids(ms);
for (i = 0; i < smp_cpus; i++) {
pc_new_cpu(possible_cpus->cpus[i].type, possible_cpus->cpus[i].arch_id,
numa_cpu_pre_plug(cpu_slot, dev, errp);
}
+static void pc_virtio_pmem_pci_pre_plug(HotplugHandler *hotplug_dev,
+ DeviceState *dev, Error **errp)
+{
+ HotplugHandler *hotplug_dev2 = qdev_get_bus_hotplug_handler(dev);
+ Error *local_err = NULL;
+
+ if (!hotplug_dev2) {
+ /*
+ * Without a bus hotplug handler, we cannot control the plug/unplug
+ * order. This should never be the case on x86, however better add
+ * a safety net.
+ */
+ error_setg(errp, "virtio-pmem-pci not supported on this bus.");
+ return;
+ }
+ /*
+ * First, see if we can plug this memory device at all. If that
+ * succeeds, branch of to the actual hotplug handler.
+ */
+ memory_device_pre_plug(MEMORY_DEVICE(dev), MACHINE(hotplug_dev), NULL,
+ &local_err);
+ if (!local_err) {
+ hotplug_handler_pre_plug(hotplug_dev2, dev, &local_err);
+ }
+ error_propagate(errp, local_err);
+}
+
+static void pc_virtio_pmem_pci_plug(HotplugHandler *hotplug_dev,
+ DeviceState *dev, Error **errp)
+{
+ HotplugHandler *hotplug_dev2 = qdev_get_bus_hotplug_handler(dev);
+ Error *local_err = NULL;
+
+ /*
+ * Plug the memory device first and then branch off to the actual
+ * hotplug handler. If that one fails, we can easily undo the memory
+ * device bits.
+ */
+ memory_device_plug(MEMORY_DEVICE(dev), MACHINE(hotplug_dev));
+ hotplug_handler_plug(hotplug_dev2, dev, &local_err);
+ if (local_err) {
+ memory_device_unplug(MEMORY_DEVICE(dev), MACHINE(hotplug_dev));
+ }
+ error_propagate(errp, local_err);
+}
+
+static void pc_virtio_pmem_pci_unplug_request(HotplugHandler *hotplug_dev,
+ DeviceState *dev, Error **errp)
+{
+ /* We don't support virtio pmem hot unplug */
+ error_setg(errp, "virtio pmem device unplug not supported.");
+}
+
+static void pc_virtio_pmem_pci_unplug(HotplugHandler *hotplug_dev,
+ DeviceState *dev, Error **errp)
+{
+ /* We don't support virtio pmem hot unplug */
+}
+
static void pc_machine_device_pre_plug_cb(HotplugHandler *hotplug_dev,
DeviceState *dev, Error **errp)
{
pc_memory_pre_plug(hotplug_dev, dev, errp);
} else if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) {
pc_cpu_pre_plug(hotplug_dev, dev, errp);
+ } else if (object_dynamic_cast(OBJECT(dev), TYPE_VIRTIO_PMEM_PCI)) {
+ pc_virtio_pmem_pci_pre_plug(hotplug_dev, dev, errp);
}
}
pc_memory_plug(hotplug_dev, dev, errp);
} else if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) {
pc_cpu_plug(hotplug_dev, dev, errp);
+ } else if (object_dynamic_cast(OBJECT(dev), TYPE_VIRTIO_PMEM_PCI)) {
+ pc_virtio_pmem_pci_plug(hotplug_dev, dev, errp);
}
}
pc_memory_unplug_request(hotplug_dev, dev, errp);
} else if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) {
pc_cpu_unplug_request_cb(hotplug_dev, dev, errp);
+ } else if (object_dynamic_cast(OBJECT(dev), TYPE_VIRTIO_PMEM_PCI)) {
+ pc_virtio_pmem_pci_unplug_request(hotplug_dev, dev, errp);
} else {
error_setg(errp, "acpi: device unplug request for not supported device"
" type: %s", object_get_typename(OBJECT(dev)));
pc_memory_unplug(hotplug_dev, dev, errp);
} else if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) {
pc_cpu_unplug_cb(hotplug_dev, dev, errp);
+ } else if (object_dynamic_cast(OBJECT(dev), TYPE_VIRTIO_PMEM_PCI)) {
+ pc_virtio_pmem_pci_unplug(hotplug_dev, dev, errp);
} else {
error_setg(errp, "acpi: device unplug for not supported device"
" type: %s", object_get_typename(OBJECT(dev)));
DeviceState *dev)
{
if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM) ||
- object_dynamic_cast(OBJECT(dev), TYPE_CPU)) {
+ object_dynamic_cast(OBJECT(dev), TYPE_CPU) ||
+ object_dynamic_cast(OBJECT(dev), TYPE_VIRTIO_PMEM_PCI)) {
return HOTPLUG_HANDLER(machine);
}
static const CPUArchIdList *pc_possible_cpu_arch_ids(MachineState *ms)
{
+ PCMachineState *pcms = PC_MACHINE(ms);
int i;
if (ms->possible_cpus) {
ms->possible_cpus->cpus[i].type = ms->cpu_type;
ms->possible_cpus->cpus[i].vcpus_count = 1;
- ms->possible_cpus->cpus[i].arch_id = x86_cpu_apic_id_from_index(i);
+ ms->possible_cpus->cpus[i].arch_id = x86_cpu_apic_id_from_index(pcms, i);
x86_topo_ids_from_apicid(ms->possible_cpus->cpus[i].arch_id,
smp_cores, smp_threads, &topo);
ms->possible_cpus->cpus[i].props.has_socket_id = true;
static void pc_compat_1_3(MachineState *machine)
{
pc_compat_1_4_fn(machine);
- enable_compat_apic_id_mode();
}
/* PC compat function for pc-0.14 to pc-1.2 */
static void pc_i440fx_1_3_machine_options(MachineClass *m)
{
+ PCMachineClass *pcmc = PC_MACHINE_CLASS(m);
static GlobalProperty compat[] = {
PC_CPU_MODEL_IDS("1.3.0")
{ "usb-tablet", "usb_version", "1" },
pc_i440fx_1_4_machine_options(m);
m->hw_version = "1.3.0";
+ pcmc->compat_apic_id_mode = true;
compat_props_add(m->compat_props, compat, G_N_ELEMENTS(compat));
}
int armv7m_nvic_complete_irq(void *opaque, int irq, bool secure)
{
NVICState *s = (NVICState *)opaque;
- VecInfo *vec;
+ VecInfo *vec = NULL;
int ret;
assert(irq > ARMV7M_EXCP_RESET && irq < s->num_irq);
- if (secure && exc_is_banked(irq)) {
- vec = &s->sec_vectors[irq];
- } else {
- vec = &s->vectors[irq];
+ /*
+ * For negative priorities, v8M will forcibly deactivate the appropriate
+ * NMI or HardFault regardless of what interrupt we're being asked to
+ * deactivate (compare the DeActivate() pseudocode). This is a guard
+ * against software returning from NMI or HardFault with a corrupted
+ * IPSR and leaving the CPU in a negative-priority state.
+ * v7M does not do this, but simply deactivates the requested interrupt.
+ */
+ if (arm_feature(&s->cpu->env, ARM_FEATURE_V8)) {
+ switch (armv7m_nvic_raw_execution_priority(s)) {
+ case -1:
+ if (s->cpu->env.v7m.aircr & R_V7M_AIRCR_BFHFNMINS_MASK) {
+ vec = &s->vectors[ARMV7M_EXCP_HARD];
+ } else {
+ vec = &s->sec_vectors[ARMV7M_EXCP_HARD];
+ }
+ break;
+ case -2:
+ vec = &s->vectors[ARMV7M_EXCP_NMI];
+ break;
+ case -3:
+ vec = &s->sec_vectors[ARMV7M_EXCP_HARD];
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (!vec) {
+ if (secure && exc_is_banked(irq)) {
+ vec = &s->sec_vectors[irq];
+ } else {
+ vec = &s->vectors[irq];
+ }
}
trace_nvic_complete_irq(irq, secure);
return -1;
}
- ret = nvic_rettobase(s);
+ /*
+ * If this is a configurable exception and it is currently
+ * targeting the opposite security state from the one we're trying
+ * to complete it for, this counts as an illegal exception return.
+ * We still need to deactivate whatever vector the logic above has
+ * selected, though, as it might not be the same as the one for the
+ * requested exception number.
+ */
+ if (!exc_is_banked(irq) && exc_targets_secure(s, irq) != secure) {
+ ret = -1;
+ } else {
+ ret = nvic_rettobase(s);
+ }
vec->active = 0;
if (vec->level) {
static uint64_t aspeed_vic_read(void *opaque, hwaddr offset, unsigned size)
{
- uint64_t val;
- const bool high = !!(offset & 0x4);
- hwaddr n_offset = (offset & ~0x4);
AspeedVICState *s = (AspeedVICState *)opaque;
+ hwaddr n_offset;
+ uint64_t val;
+ bool high;
if (offset < AVIC_NEW_BASE_OFFSET) {
- qemu_log_mask(LOG_UNIMP, "%s: Ignoring read from legacy registers "
- "at 0x%" HWADDR_PRIx "[%u]\n", __func__, offset, size);
- return 0;
+ high = false;
+ n_offset = offset;
+ } else {
+ high = !!(offset & 0x4);
+ n_offset = (offset & ~0x4);
}
- n_offset -= AVIC_NEW_BASE_OFFSET;
-
switch (n_offset) {
- case 0x0: /* IRQ Status */
+ case 0x80: /* IRQ Status */
+ case 0x00:
val = s->raw & ~s->select & s->enable;
break;
- case 0x08: /* FIQ Status */
+ case 0x88: /* FIQ Status */
+ case 0x04:
val = s->raw & s->select & s->enable;
break;
- case 0x10: /* Raw Interrupt Status */
+ case 0x90: /* Raw Interrupt Status */
+ case 0x08:
val = s->raw;
break;
- case 0x18: /* Interrupt Selection */
+ case 0x98: /* Interrupt Selection */
+ case 0x0c:
val = s->select;
break;
- case 0x20: /* Interrupt Enable */
+ case 0xa0: /* Interrupt Enable */
+ case 0x10:
val = s->enable;
break;
- case 0x30: /* Software Interrupt */
+ case 0xb0: /* Software Interrupt */
+ case 0x18:
val = s->trigger;
break;
- case 0x40: /* Interrupt Sensitivity */
+ case 0xc0: /* Interrupt Sensitivity */
+ case 0x24:
val = s->sense;
break;
- case 0x48: /* Interrupt Both Edge Trigger Control */
+ case 0xc8: /* Interrupt Both Edge Trigger Control */
+ case 0x28:
val = s->dual_edge;
break;
- case 0x50: /* Interrupt Event */
+ case 0xd0: /* Interrupt Event */
+ case 0x2c:
val = s->event;
break;
- case 0x60: /* Edge Triggered Interrupt Status */
+ case 0xe0: /* Edge Triggered Interrupt Status */
val = s->raw & ~s->sense;
break;
/* Illegal */
- case 0x28: /* Interrupt Enable Clear */
- case 0x38: /* Software Interrupt Clear */
- case 0x58: /* Edge Triggered Interrupt Clear */
+ case 0xa8: /* Interrupt Enable Clear */
+ case 0xb8: /* Software Interrupt Clear */
+ case 0xd8: /* Edge Triggered Interrupt Clear */
qemu_log_mask(LOG_GUEST_ERROR,
"%s: Read of write-only register with offset 0x%"
HWADDR_PRIx "\n", __func__, offset);
}
if (high) {
val = extract64(val, 32, 19);
+ } else {
+ val = extract64(val, 0, 32);
}
trace_aspeed_vic_read(offset, size, val);
return val;
static void aspeed_vic_write(void *opaque, hwaddr offset, uint64_t data,
unsigned size)
{
- const bool high = !!(offset & 0x4);
- hwaddr n_offset = (offset & ~0x4);
AspeedVICState *s = (AspeedVICState *)opaque;
+ hwaddr n_offset;
+ bool high;
if (offset < AVIC_NEW_BASE_OFFSET) {
- qemu_log_mask(LOG_UNIMP,
- "%s: Ignoring write to legacy registers at 0x%"
- HWADDR_PRIx "[%u] <- 0x%" PRIx64 "\n", __func__, offset,
- size, data);
- return;
+ high = false;
+ n_offset = offset;
+ } else {
+ high = !!(offset & 0x4);
+ n_offset = (offset & ~0x4);
}
- n_offset -= AVIC_NEW_BASE_OFFSET;
trace_aspeed_vic_write(offset, size, data);
/* Given we have members using separate enable/clear registers, deposit64()
}
switch (n_offset) {
- case 0x18: /* Interrupt Selection */
+ case 0x98: /* Interrupt Selection */
+ case 0x0c:
/* Register has deposit64() semantics - overwrite requested 32 bits */
if (high) {
s->select &= AVIC_L_MASK;
}
s->select |= data;
break;
- case 0x20: /* Interrupt Enable */
+ case 0xa0: /* Interrupt Enable */
+ case 0x10:
s->enable |= data;
break;
- case 0x28: /* Interrupt Enable Clear */
+ case 0xa8: /* Interrupt Enable Clear */
+ case 0x14:
s->enable &= ~data;
break;
- case 0x30: /* Software Interrupt */
+ case 0xb0: /* Software Interrupt */
+ case 0x18:
qemu_log_mask(LOG_UNIMP, "%s: Software interrupts unavailable. "
"IRQs requested: 0x%016" PRIx64 "\n", __func__, data);
break;
- case 0x38: /* Software Interrupt Clear */
+ case 0xb8: /* Software Interrupt Clear */
+ case 0x1c:
qemu_log_mask(LOG_UNIMP, "%s: Software interrupts unavailable. "
"IRQs to be cleared: 0x%016" PRIx64 "\n", __func__, data);
break;
- case 0x50: /* Interrupt Event */
+ case 0xd0: /* Interrupt Event */
/* Register has deposit64() semantics - overwrite the top four valid
* IRQ bits, as only the top four IRQs (GPIOs) can change their event
* type */
"Ignoring invalid write to interrupt event register");
}
break;
- case 0x58: /* Edge Triggered Interrupt Clear */
+ case 0xd8: /* Edge Triggered Interrupt Clear */
+ case 0x38:
s->raw &= ~(data & ~s->sense);
break;
- case 0x00: /* IRQ Status */
- case 0x08: /* FIQ Status */
- case 0x10: /* Raw Interrupt Status */
- case 0x40: /* Interrupt Sensitivity */
- case 0x48: /* Interrupt Both Edge Trigger Control */
- case 0x60: /* Edge Triggered Interrupt Status */
+ case 0x80: /* IRQ Status */
+ case 0x00:
+ case 0x88: /* FIQ Status */
+ case 0x04:
+ case 0x90: /* Raw Interrupt Status */
+ case 0x08:
+ case 0xc0: /* Interrupt Sensitivity */
+ case 0x24:
+ case 0xc8: /* Interrupt Both Edge Trigger Control */
+ case 0x28:
+ case 0xe0: /* Edge Triggered Interrupt Status */
qemu_log_mask(LOG_GUEST_ERROR,
"%s: Write of read-only register with offset 0x%"
HWADDR_PRIx "\n", __func__, offset);
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);
+ xive_error(xive, "VST: invalid %s entry %x !?", info->name, idx);
return 0;
}
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);
+ xive_error(xive, "VST: invalid %s entry %x !?", info->name, idx);
return 0;
}
word_number);
}
-static int pnv_xive_end_update(PnvXive *xive, uint8_t blk, uint32_t idx)
+static int pnv_xive_end_update(PnvXive *xive)
{
+ uint8_t blk = GETFIELD(VC_EQC_CWATCH_BLOCKID,
+ xive->regs[(VC_EQC_CWATCH_SPEC >> 3)]);
+ uint32_t idx = GETFIELD(VC_EQC_CWATCH_OFFSET,
+ xive->regs[(VC_EQC_CWATCH_SPEC >> 3)]);
int i;
uint64_t eqc_watch[4];
XIVE_VST_WORD_ALL);
}
+static void pnv_xive_end_cache_load(PnvXive *xive)
+{
+ uint8_t blk = GETFIELD(VC_EQC_CWATCH_BLOCKID,
+ xive->regs[(VC_EQC_CWATCH_SPEC >> 3)]);
+ uint32_t idx = GETFIELD(VC_EQC_CWATCH_OFFSET,
+ xive->regs[(VC_EQC_CWATCH_SPEC >> 3)]);
+ uint64_t eqc_watch[4] = { 0 };
+ int i;
+
+ if (pnv_xive_vst_read(xive, VST_TSEL_EQDT, blk, idx, eqc_watch)) {
+ xive_error(xive, "VST: no END entry %x/%x !?", blk, idx);
+ }
+
+ for (i = 0; i < ARRAY_SIZE(eqc_watch); i++) {
+ xive->regs[(VC_EQC_CWATCH_DAT0 >> 3) + i] = be64_to_cpu(eqc_watch[i]);
+ }
+}
+
static int pnv_xive_get_nvt(XiveRouter *xrtr, uint8_t blk, uint32_t idx,
XiveNVT *nvt)
{
word_number);
}
-static int pnv_xive_nvt_update(PnvXive *xive, uint8_t blk, uint32_t idx)
+static int pnv_xive_nvt_update(PnvXive *xive)
{
+ uint8_t blk = GETFIELD(PC_VPC_CWATCH_BLOCKID,
+ xive->regs[(PC_VPC_CWATCH_SPEC >> 3)]);
+ uint32_t idx = GETFIELD(PC_VPC_CWATCH_OFFSET,
+ xive->regs[(PC_VPC_CWATCH_SPEC >> 3)]);
int i;
uint64_t vpc_watch[8];
XIVE_VST_WORD_ALL);
}
+static void pnv_xive_nvt_cache_load(PnvXive *xive)
+{
+ uint8_t blk = GETFIELD(PC_VPC_CWATCH_BLOCKID,
+ xive->regs[(PC_VPC_CWATCH_SPEC >> 3)]);
+ uint32_t idx = GETFIELD(PC_VPC_CWATCH_OFFSET,
+ xive->regs[(PC_VPC_CWATCH_SPEC >> 3)]);
+ uint64_t vpc_watch[8] = { 0 };
+ int i;
+
+ if (pnv_xive_vst_read(xive, VST_TSEL_VPDT, blk, idx, vpc_watch)) {
+ xive_error(xive, "VST: no NVT entry %x/%x !?", blk, idx);
+ }
+
+ for (i = 0; i < ARRAY_SIZE(vpc_watch); i++) {
+ xive->regs[(PC_VPC_CWATCH_DAT0 >> 3) + i] = be64_to_cpu(vpc_watch[i]);
+ }
+}
+
static int pnv_xive_get_eas(XiveRouter *xrtr, uint8_t blk, uint32_t idx,
XiveEAS *eas)
{
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);
* 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);
+ xive->ipi_source.esb_flags |= XIVE_SRC_STORE_EOI;
}
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:
+ val &= ~VC_EQC_CWATCH_CONFLICT; /* HW resets this bit */
+ break;
+ case VC_EQC_CWATCH_DAT1 ... VC_EQC_CWATCH_DAT3:
break;
+ case VC_EQC_CWATCH_DAT0:
+ /* writing to DATA0 triggers the cache write */
+ xive->regs[reg] = val;
+ pnv_xive_end_update(xive);
+ break;
+ case VC_EQC_SCRUB_MASK:
case VC_EQC_SCRUB_TRIG:
- pnv_xive_end_update(xive, GETFIELD(VC_SCRUB_BLOCK_ID, val),
- GETFIELD(VC_SCRUB_OFFSET, val));
+ /*
+ * The scrubbing registers flush the cache in RAM and can also
+ * invalidate.
+ */
break;
- case PC_VPC_SCRUB_MASK:
case PC_VPC_CWATCH_SPEC:
- case PC_VPC_CWATCH_DAT0 ... PC_VPC_CWATCH_DAT7:
+ val &= ~PC_VPC_CWATCH_CONFLICT; /* HW resets this bit */
+ break;
+ case PC_VPC_CWATCH_DAT1 ... PC_VPC_CWATCH_DAT7:
break;
+ case PC_VPC_CWATCH_DAT0:
+ /* writing to DATA0 triggers the cache write */
+ xive->regs[reg] = val;
+ pnv_xive_nvt_update(xive);
+ break;
+ case PC_VPC_SCRUB_MASK:
case PC_VPC_SCRUB_TRIG:
- pnv_xive_nvt_update(xive, GETFIELD(PC_SCRUB_BLOCK_ID, val),
- GETFIELD(PC_SCRUB_OFFSET, val));
+ /*
+ * The scrubbing registers flush the cache in RAM and can also
+ * invalidate.
+ */
break;
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_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:
/*
* XIVE PC & VC cache updates for EAS, NVT and END
*/
+ case VC_EQC_CWATCH_SPEC:
+ xive->regs[reg] = ~(VC_EQC_CWATCH_FULL | VC_EQC_CWATCH_CONFLICT);
+ val = xive->regs[reg];
+ break;
+ case VC_EQC_CWATCH_DAT0:
+ /*
+ * Load DATA registers from cache with data requested by the
+ * SPEC register
+ */
+ pnv_xive_end_cache_load(xive);
+ val = xive->regs[reg];
+ break;
+ case VC_EQC_CWATCH_DAT1 ... VC_EQC_CWATCH_DAT3:
+ val = xive->regs[reg];
+ break;
+
+ case PC_VPC_CWATCH_SPEC:
+ xive->regs[reg] = ~(PC_VPC_CWATCH_FULL | PC_VPC_CWATCH_CONFLICT);
+ val = xive->regs[reg];
+ break;
+ case PC_VPC_CWATCH_DAT0:
+ /*
+ * Load DATA registers from cache with data requested by the
+ * SPEC register
+ */
+ pnv_xive_nvt_cache_load(xive);
+ val = xive->regs[reg];
+ break;
+ case PC_VPC_CWATCH_DAT1 ... PC_VPC_CWATCH_DAT7:
+ val = xive->regs[reg];
+ break;
+
case PC_VPC_SCRUB_TRIG:
case VC_IVC_SCRUB_TRIG:
case VC_EQC_SCRUB_TRIG:
}
}
-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)
{
memory_region_set_enabled(&xive->source.esb_mmio, enable);
error_propagate(errp, local_err);
return;
}
+ sysbus_init_mmio(SYS_BUS_DEVICE(xive), &xsrc->esb_mmio);
/*
* Initialize the END ESB source
error_propagate(errp, local_err);
return;
}
+ sysbus_init_mmio(SYS_BUS_DEVICE(xive), &end_xsrc->esb_mmio);
/* Set the mapping address of the END ESB pages after the source ESBs */
xive->end_base = xive->vc_base + (1ull << xsrc->esb_shift) * xsrc->nr_irqs;
qemu_register_reset(spapr_xive_reset, dev);
- /* Define all XIVE MMIO regions on SysBus */
- sysbus_init_mmio(SYS_BUS_DEVICE(xive), &xsrc->esb_mmio);
- sysbus_init_mmio(SYS_BUS_DEVICE(xive), &end_xsrc->esb_mmio);
- sysbus_init_mmio(SYS_BUS_DEVICE(xive), &xive->tm_mmio);
-}
-
-void spapr_xive_init(SpaprXive *xive, Error **errp)
-{
- XiveSource *xsrc = &xive->source;
-
- /*
- * The emulated XIVE device can only be initialized once. If the
- * ESB memory region has been already mapped, it means we have been
- * through there.
- */
- if (memory_region_is_mapped(&xsrc->esb_mmio)) {
- return;
- }
-
/* TIMA initialization */
memory_region_init_io(&xive->tm_mmio, OBJECT(xive), &xive_tm_ops, xive,
"xive.tima", 4ull << TM_SHIFT);
+ sysbus_init_mmio(SYS_BUS_DEVICE(xive), &xive->tm_mmio);
- /* Map all regions */
- spapr_xive_map_mmio(xive);
+ /*
+ * Map all regions. These will be enabled or disabled at reset and
+ * can also be overridden by KVM memory regions if active
+ */
+ 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);
}
static int spapr_xive_get_eas(XiveRouter *xrtr, uint8_t eas_blk,
xsrc->esb_mmap = kvmppc_xive_mmap(xive, KVM_XIVE_ESB_PAGE_OFFSET, esb_len,
&local_err);
if (local_err) {
- error_propagate(errp, local_err);
- return;
+ goto fail;
}
- memory_region_init_ram_device_ptr(&xsrc->esb_mmio, OBJECT(xsrc),
+ memory_region_init_ram_device_ptr(&xsrc->esb_mmio_kvm, OBJECT(xsrc),
"xive.esb", esb_len, xsrc->esb_mmap);
+ memory_region_add_subregion_overlap(&xsrc->esb_mmio, 0,
+ &xsrc->esb_mmio_kvm, 1);
/*
* 2. END ESB pages (No KVM support yet)
xive->tm_mmap = kvmppc_xive_mmap(xive, KVM_XIVE_TIMA_PAGE_OFFSET, tima_len,
&local_err);
if (local_err) {
- error_propagate(errp, local_err);
- return;
+ goto fail;
}
- memory_region_init_ram_device_ptr(&xive->tm_mmio, OBJECT(xive),
+ memory_region_init_ram_device_ptr(&xive->tm_mmio_kvm, OBJECT(xive),
"xive.tima", tima_len, xive->tm_mmap);
+ memory_region_add_subregion_overlap(&xive->tm_mmio, 0,
+ &xive->tm_mmio_kvm, 1);
xive->change = qemu_add_vm_change_state_handler(
kvmppc_xive_change_state_handler, xive);
kvmppc_xive_cpu_connect(spapr_cpu_state(cpu)->tctx, &local_err);
if (local_err) {
- error_propagate(errp, local_err);
- return;
+ goto fail;
}
}
/* Update the KVM sources */
kvmppc_xive_source_reset(xsrc, &local_err);
if (local_err) {
- error_propagate(errp, local_err);
- return;
+ goto fail;
}
kvm_kernel_irqchip = true;
kvm_msi_via_irqfd_allowed = true;
kvm_gsi_direct_mapping = true;
+ return;
- /* Map all regions */
- spapr_xive_map_mmio(xive);
+fail:
+ error_propagate(errp, local_err);
+ kvmppc_xive_disconnect(xive, NULL);
}
void kvmppc_xive_disconnect(SpaprXive *xive, Error **errp)
xsrc = &xive->source;
esb_len = (1ull << xsrc->esb_shift) * xsrc->nr_irqs;
- sysbus_mmio_unmap(SYS_BUS_DEVICE(xive), 0);
- munmap(xsrc->esb_mmap, esb_len);
-
- sysbus_mmio_unmap(SYS_BUS_DEVICE(xive), 1);
+ if (xsrc->esb_mmap) {
+ memory_region_del_subregion(&xsrc->esb_mmio, &xsrc->esb_mmio_kvm);
+ object_unparent(OBJECT(&xsrc->esb_mmio_kvm));
+ munmap(xsrc->esb_mmap, esb_len);
+ xsrc->esb_mmap = NULL;
+ }
- sysbus_mmio_unmap(SYS_BUS_DEVICE(xive), 2);
- munmap(xive->tm_mmap, 4ull << TM_SHIFT);
+ if (xive->tm_mmap) {
+ memory_region_del_subregion(&xive->tm_mmio, &xive->tm_mmio_kvm);
+ object_unparent(OBJECT(&xive->tm_mmio_kvm));
+ munmap(xive->tm_mmap, 4ull << TM_SHIFT);
+ xive->tm_mmap = NULL;
+ }
/*
* When the KVM device fd is closed, the KVM device is destroyed
* and removed from the list of devices of the VM. The VCPU
* presenters are also detached from the device.
*/
- close(xive->fd);
- xive->fd = -1;
+ if (xive->fd != -1) {
+ close(xive->fd);
+ xive->fd = -1;
+ }
kvm_kernel_irqchip = false;
kvm_msi_via_irqfd_allowed = false;
kvm_cpu_disable_all();
/* VM Change state handler is not needed anymore */
- qemu_del_vm_change_state_handler(xive->change);
+ if (xive->change) {
+ qemu_del_vm_change_state_handler(xive->change);
+ xive->change = NULL;
+ }
}
ICPState *icp = opaque;
if (kvm_irqchip_in_kernel()) {
- return icp_set_kvm_state(icp);
+ Error *local_err = NULL;
+ int ret;
+
+ ret = icp_set_kvm_state(icp, &local_err);
+ if (ret < 0) {
+ error_report_err(local_err);
+ return ret;
+ }
}
return 0;
qemu_set_irq(icp->output, 0);
if (kvm_irqchip_in_kernel()) {
- icp_set_kvm_state(ICP(dev));
+ Error *local_err = NULL;
+
+ icp_set_kvm_state(ICP(dev), &local_err);
+ if (local_err) {
+ error_report_err(local_err);
+ }
}
}
return;
}
+ /* Connect the presenter to the VCPU (required for CPU hotplug) */
if (kvm_irqchip_in_kernel()) {
icp_kvm_realize(dev, &err);
if (err) {
icsc->parent_reset(dev);
if (kvm_irqchip_in_kernel()) {
- ics_set_kvm_state(ICS_BASE(dev));
+ Error *local_err = NULL;
+
+ ics_set_kvm_state(ICS_BASE(dev), &local_err);
+ if (local_err) {
+ error_report_err(local_err);
+ }
}
}
ICSState *ics = opaque;
if (kvm_irqchip_in_kernel()) {
- return ics_set_kvm_state(ics);
+ Error *local_err = NULL;
+ int ret;
+
+ ret = ics_set_kvm_state(ics, &local_err);
+ if (ret < 0) {
+ error_report_err(local_err);
+ return ret;
+ }
}
return 0;
lsi ? XICS_FLAGS_IRQ_LSI : XICS_FLAGS_IRQ_MSI;
if (kvm_irqchip_in_kernel()) {
+ Error *local_err = NULL;
+
ics_reset_irq(ics->irqs + srcno);
- ics_set_kvm_state_one(ics, srcno);
+ ics_set_kvm_state_one(ics, srcno, &local_err);
+ if (local_err) {
+ error_report_err(local_err);
+ }
}
}
}
}
-int icp_set_kvm_state(ICPState *icp)
+int icp_set_kvm_state(ICPState *icp, Error **errp)
{
uint64_t state;
int ret;
| ((uint64_t)icp->pending_priority << KVM_REG_PPC_ICP_PPRI_SHIFT);
ret = kvm_set_one_reg(icp->cs, KVM_REG_PPC_ICP_STATE, &state);
- if (ret != 0) {
- error_report("Unable to restore KVM interrupt controller state (0x%"
- PRIx64 ") for CPU %ld: %s", state, kvm_arch_vcpu_id(icp->cs),
- strerror(errno));
+ if (ret < 0) {
+ error_setg_errno(errp, -ret,
+ "Unable to restore KVM interrupt controller state (0x%"
+ PRIx64 ") for CPU %ld", state,
+ kvm_arch_vcpu_id(icp->cs));
return ret;
}
ics_get_kvm_state(ics);
}
-int ics_set_kvm_state_one(ICSState *ics, int srcno)
+int ics_set_kvm_state_one(ICSState *ics, int srcno, Error **errp)
{
uint64_t state;
- Error *local_err = NULL;
ICSIRQState *irq = &ics->irqs[srcno];
int ret;
}
ret = kvm_device_access(kernel_xics_fd, KVM_DEV_XICS_GRP_SOURCES,
- srcno + ics->offset, &state, true, &local_err);
- if (local_err) {
- error_report_err(local_err);
+ srcno + ics->offset, &state, true, errp);
+ if (ret < 0) {
return ret;
}
return 0;
}
-int ics_set_kvm_state(ICSState *ics)
+int ics_set_kvm_state(ICSState *ics, Error **errp)
{
int i;
}
for (i = 0; i < ics->nr_irqs; i++) {
+ Error *local_err = NULL;
int ret;
- ret = ics_set_kvm_state_one(ics, i);
- if (ret) {
+ ret = ics_set_kvm_state_one(ics, i, &local_err);
+ if (ret < 0) {
+ error_propagate(errp, local_err);
return ret;
}
}
}
}
-static void rtas_dummy(PowerPCCPU *cpu, SpaprMachineState *spapr,
- uint32_t token,
- uint32_t nargs, target_ulong args,
- uint32_t nret, target_ulong rets)
-{
- error_report("pseries: %s must never be called for in-kernel XICS",
- __func__);
-}
-
-int xics_kvm_init(SpaprMachineState *spapr, Error **errp)
+int xics_kvm_connect(SpaprMachineState *spapr, Error **errp)
{
int rc;
CPUState *cs;
if (!kvm_enabled() || !kvm_check_extension(kvm_state, KVM_CAP_IRQ_XICS)) {
error_setg(errp,
"KVM and IRQ_XICS capability must be present for in-kernel XICS");
- goto fail;
+ return -1;
}
- spapr_rtas_register(RTAS_IBM_SET_XIVE, "ibm,set-xive", rtas_dummy);
- spapr_rtas_register(RTAS_IBM_GET_XIVE, "ibm,get-xive", rtas_dummy);
- spapr_rtas_register(RTAS_IBM_INT_OFF, "ibm,int-off", rtas_dummy);
- spapr_rtas_register(RTAS_IBM_INT_ON, "ibm,int-on", rtas_dummy);
-
rc = kvmppc_define_rtas_kernel_token(RTAS_IBM_SET_XIVE, "ibm,set-xive");
if (rc < 0) {
- error_setg(errp, "kvmppc_define_rtas_kernel_token: ibm,set-xive");
+ error_setg_errno(&local_err, -rc,
+ "kvmppc_define_rtas_kernel_token: ibm,set-xive");
goto fail;
}
rc = kvmppc_define_rtas_kernel_token(RTAS_IBM_GET_XIVE, "ibm,get-xive");
if (rc < 0) {
- error_setg(errp, "kvmppc_define_rtas_kernel_token: ibm,get-xive");
+ error_setg_errno(&local_err, -rc,
+ "kvmppc_define_rtas_kernel_token: ibm,get-xive");
goto fail;
}
rc = kvmppc_define_rtas_kernel_token(RTAS_IBM_INT_ON, "ibm,int-on");
if (rc < 0) {
- error_setg(errp, "kvmppc_define_rtas_kernel_token: ibm,int-on");
+ error_setg_errno(&local_err, -rc,
+ "kvmppc_define_rtas_kernel_token: ibm,int-on");
goto fail;
}
rc = kvmppc_define_rtas_kernel_token(RTAS_IBM_INT_OFF, "ibm,int-off");
if (rc < 0) {
- error_setg(errp, "kvmppc_define_rtas_kernel_token: ibm,int-off");
+ error_setg_errno(&local_err, -rc,
+ "kvmppc_define_rtas_kernel_token: ibm,int-off");
goto fail;
}
/* Create the KVM XICS device */
rc = kvm_create_device(kvm_state, KVM_DEV_TYPE_XICS, false);
if (rc < 0) {
- error_setg_errno(errp, -rc, "Error on KVM_CREATE_DEVICE for XICS");
+ error_setg_errno(&local_err, -rc, "Error on KVM_CREATE_DEVICE for XICS");
goto fail;
}
icp_kvm_realize(DEVICE(spapr_cpu_state(cpu)->icp), &local_err);
if (local_err) {
- error_propagate(errp, local_err);
goto fail;
}
}
/* Update the KVM sources */
- ics_set_kvm_state(spapr->ics);
+ ics_set_kvm_state(spapr->ics, &local_err);
+ if (local_err) {
+ goto fail;
+ }
/* Connect the presenters to the initial VCPUs of the machine */
CPU_FOREACH(cs) {
PowerPCCPU *cpu = POWERPC_CPU(cs);
- icp_set_kvm_state(spapr_cpu_state(cpu)->icp);
+ icp_set_kvm_state(spapr_cpu_state(cpu)->icp, &local_err);
+ if (local_err) {
+ goto fail;
+ }
}
return 0;
fail:
- kvmppc_define_rtas_kernel_token(0, "ibm,set-xive");
- kvmppc_define_rtas_kernel_token(0, "ibm,get-xive");
- kvmppc_define_rtas_kernel_token(0, "ibm,int-on");
- kvmppc_define_rtas_kernel_token(0, "ibm,int-off");
+ error_propagate(errp, local_err);
+ xics_kvm_disconnect(spapr, NULL);
return -1;
}
* removed from the list of devices of the VM. The VCPU presenters
* are also detached from the device.
*/
- close(kernel_xics_fd);
- kernel_xics_fd = -1;
-
- spapr_rtas_unregister(RTAS_IBM_SET_XIVE);
- spapr_rtas_unregister(RTAS_IBM_GET_XIVE);
- spapr_rtas_unregister(RTAS_IBM_INT_OFF);
- spapr_rtas_unregister(RTAS_IBM_INT_ON);
+ if (kernel_xics_fd != -1) {
+ close(kernel_xics_fd);
+ kernel_xics_fd = -1;
+ }
kvmppc_define_rtas_kernel_token(0, "ibm,set-xive");
kvmppc_define_rtas_kernel_token(0, "ibm,get-xive");
/* Clear the presenter from the VCPUs */
kvm_disable_icps();
}
+
+/*
+ * This is a heuristic to detect older KVMs on POWER9 hosts that don't
+ * support destruction of a KVM XICS device while the VM is running.
+ * Required to start a spapr machine with ic-mode=dual,kernel-irqchip=on.
+ */
+bool xics_kvm_has_broken_disconnect(SpaprMachineState *spapr)
+{
+ int rc;
+
+ rc = kvm_create_device(kvm_state, KVM_DEV_TYPE_XICS, false);
+ if (rc < 0) {
+ /*
+ * The error is ignored on purpose. The KVM XICS setup code
+ * will catch it again anyway. The goal here is to see if
+ * close() actually destroys the device or not.
+ */
+ return false;
+ }
+
+ close(rc);
+
+ rc = kvm_create_device(kvm_state, KVM_DEV_TYPE_XICS, false);
+ if (rc >= 0) {
+ close(rc);
+ return false;
+ }
+
+ return errno == EEXIST;
+}
* Guest interfaces
*/
+static bool check_emulated_xics(SpaprMachineState *spapr, const char *func)
+{
+ if (spapr_ovec_test(spapr->ov5_cas, OV5_XIVE_EXPLOIT) ||
+ kvm_irqchip_in_kernel()) {
+ error_report("pseries: %s must only be called for emulated XICS",
+ func);
+ return false;
+ }
+
+ return true;
+}
+
+#define CHECK_EMULATED_XICS_HCALL(spapr) \
+ do { \
+ if (!check_emulated_xics((spapr), __func__)) { \
+ return H_HARDWARE; \
+ } \
+ } while (0)
+
static target_ulong h_cppr(PowerPCCPU *cpu, SpaprMachineState *spapr,
target_ulong opcode, target_ulong *args)
{
target_ulong cppr = args[0];
+ CHECK_EMULATED_XICS_HCALL(spapr);
+
icp_set_cppr(spapr_cpu_state(cpu)->icp, cppr);
return H_SUCCESS;
}
target_ulong mfrr = args[1];
ICPState *icp = xics_icp_get(XICS_FABRIC(spapr), args[0]);
+ CHECK_EMULATED_XICS_HCALL(spapr);
+
if (!icp) {
return H_PARAMETER;
}
{
uint32_t xirr = icp_accept(spapr_cpu_state(cpu)->icp);
+ CHECK_EMULATED_XICS_HCALL(spapr);
+
args[0] = xirr;
return H_SUCCESS;
}
{
uint32_t xirr = icp_accept(spapr_cpu_state(cpu)->icp);
+ CHECK_EMULATED_XICS_HCALL(spapr);
+
args[0] = xirr;
args[1] = cpu_get_host_ticks();
return H_SUCCESS;
{
target_ulong xirr = args[0];
+ CHECK_EMULATED_XICS_HCALL(spapr);
+
icp_eoi(spapr_cpu_state(cpu)->icp, xirr);
return H_SUCCESS;
}
uint32_t mfrr;
uint32_t xirr;
+ CHECK_EMULATED_XICS_HCALL(spapr);
+
if (!icp) {
return H_PARAMETER;
}
return H_SUCCESS;
}
+#define CHECK_EMULATED_XICS_RTAS(spapr, rets) \
+ do { \
+ if (!check_emulated_xics((spapr), __func__)) { \
+ rtas_st((rets), 0, RTAS_OUT_HW_ERROR); \
+ return; \
+ } \
+ } while (0)
+
static void rtas_set_xive(PowerPCCPU *cpu, SpaprMachineState *spapr,
uint32_t token,
uint32_t nargs, target_ulong args,
ICSState *ics = spapr->ics;
uint32_t nr, srcno, server, priority;
+ CHECK_EMULATED_XICS_RTAS(spapr, rets);
+
if ((nargs != 3) || (nret != 1)) {
rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
return;
ICSState *ics = spapr->ics;
uint32_t nr, srcno;
+ CHECK_EMULATED_XICS_RTAS(spapr, rets);
+
if ((nargs != 1) || (nret != 3)) {
rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
return;
ICSState *ics = spapr->ics;
uint32_t nr, srcno;
+ CHECK_EMULATED_XICS_RTAS(spapr, rets);
+
if ((nargs != 1) || (nret != 1)) {
rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
return;
ICSState *ics = spapr->ics;
uint32_t nr, srcno;
+ CHECK_EMULATED_XICS_RTAS(spapr, rets);
+
if ((nargs != 1) || (nret != 1)) {
rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
return;
void xics_spapr_init(SpaprMachineState *spapr)
{
- /* Emulated mode can only be initialized once. */
- if (spapr->ics->init) {
- return;
- }
-
- spapr->ics->init = true;
-
- /* Registration of global state belongs into realize */
spapr_rtas_register(RTAS_IBM_SET_XIVE, "ibm,set-xive", rtas_set_xive);
spapr_rtas_register(RTAS_IBM_GET_XIVE, "ibm,get-xive", rtas_get_xive);
spapr_rtas_register(RTAS_IBM_INT_OFF, "ibm,int-off", rtas_int_off);
xive_tctx_notify(tctx, ring);
}
+static inline uint32_t xive_tctx_word2(uint8_t *ring)
+{
+ return *((uint32_t *) &ring[TM_WORD2]);
+}
+
/*
* XIVE Thread Interrupt Management Area (TIMA)
*/
static uint64_t xive_tm_pull_pool_ctx(XiveTCTX *tctx, hwaddr offset,
unsigned size)
{
- uint64_t ret;
+ uint32_t qw2w2_prev = xive_tctx_word2(&tctx->regs[TM_QW2_HV_POOL]);
+ uint32_t qw2w2;
- 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;
+ qw2w2 = xive_set_field32(TM_QW2W2_VP, qw2w2_prev, 0);
+ memcpy(&tctx->regs[TM_QW2_HV_POOL + TM_WORD2], &qw2w2, 4);
+ return qw2w2;
}
static void xive_tm_vt_push(XiveTCTX *tctx, hwaddr offset,
*/
static const uint8_t xive_tm_hw_view[] = {
- /* QW-0 User */ 3, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 0, 0, 0, 0,
- /* QW-1 OS */ 3, 3, 3, 3, 3, 3, 0, 3, 3, 3, 3, 3, 0, 0, 0, 0,
- /* QW-2 POOL */ 0, 0, 3, 3, 0, 0, 0, 0, 3, 3, 3, 3, 0, 0, 0, 0,
- /* QW-3 PHYS */ 3, 3, 3, 3, 0, 3, 0, 3, 3, 0, 0, 3, 3, 3, 3, 0,
+ 3, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 0, 0, 0, 0, /* QW-0 User */
+ 3, 3, 3, 3, 3, 3, 0, 2, 3, 3, 3, 3, 0, 0, 0, 0, /* QW-1 OS */
+ 0, 0, 3, 3, 0, 0, 0, 0, 3, 3, 3, 3, 0, 0, 0, 0, /* QW-2 POOL */
+ 3, 3, 3, 3, 0, 3, 0, 2, 3, 0, 0, 3, 3, 3, 3, 0, /* QW-3 PHYS */
};
static const uint8_t xive_tm_hv_view[] = {
- /* QW-0 User */ 3, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 0, 0, 0, 0,
- /* QW-1 OS */ 3, 3, 3, 3, 3, 3, 0, 3, 3, 3, 3, 3, 0, 0, 0, 0,
- /* QW-2 POOL */ 0, 0, 3, 3, 0, 0, 0, 0, 0, 3, 3, 3, 0, 0, 0, 0,
- /* QW-3 PHYS */ 3, 3, 3, 3, 0, 3, 0, 3, 3, 0, 0, 3, 0, 0, 0, 0,
+ 3, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 0, 0, 0, 0, /* QW-0 User */
+ 3, 3, 3, 3, 3, 3, 0, 2, 3, 3, 3, 3, 0, 0, 0, 0, /* QW-1 OS */
+ 0, 0, 3, 3, 0, 0, 0, 0, 0, 3, 3, 3, 0, 0, 0, 0, /* QW-2 POOL */
+ 3, 3, 3, 3, 0, 3, 0, 2, 3, 0, 0, 3, 0, 0, 0, 0, /* QW-3 PHYS */
};
static const uint8_t xive_tm_os_view[] = {
- /* QW-0 User */ 3, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 0, 0, 0, 0,
- /* QW-1 OS */ 2, 3, 2, 2, 2, 2, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0,
- /* QW-2 POOL */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- /* QW-3 PHYS */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 3, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 0, 0, 0, 0, /* QW-0 User */
+ 2, 3, 2, 2, 2, 2, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, /* QW-1 OS */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* QW-2 POOL */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* QW-3 PHYS */
};
static const uint8_t xive_tm_user_view[] = {
- /* QW-0 User */ 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- /* QW-1 OS */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- /* QW-2 POOL */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- /* QW-3 PHYS */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* QW-0 User */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* QW-1 OS */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* QW-2 POOL */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* QW-3 PHYS */
};
/*
},
};
-static inline uint32_t xive_tctx_word2(uint8_t *ring)
-{
- return *((uint32_t *) &ring[TM_WORD2]);
-}
-
static char *xive_tctx_ring_print(uint8_t *ring)
{
uint32_t w2 = xive_tctx_word2(ring);
}
/*
- * By default on P9, the HW CAM line (23bits) is hardwired to :
- *
- * 0x000||0b1||4Bit chip number||7Bit Thread number.
+ * Encode the HW CAM line in the block group mode format :
*
- * When the block grouping is enabled, the CAM line is changed to :
- *
- * 4Bit chip number||0x001||7Bit Thread number.
+ * chip << 19 | 0000000 0 0001 thread (7Bit)
*/
-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)
+static uint32_t xive_tctx_hw_cam_line(XiveTCTX *tctx)
{
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);
+ return xive_nvt_cam_line((pir >> 8) & 0xf, 1 << 7 | (pir & 0x7f));
}
/*
/* PHYS ring */
if ((be32_to_cpu(qw3w2) & TM_QW3W2_VT) &&
- xive_presenter_tctx_match_hw(tctx, nvt_blk, nvt_idx)) {
+ cam == xive_tctx_hw_cam_line(tctx)) {
return TM_QW3_HV_PHYS;
}
config R4K
bool
+ select ISA_BUS
+ select SERIAL_ISA
+ select I8259
+ select I8254
+ select MC146818RTC
+ imply VGA_ISA
+ imply NE2000_ISA
+ select IDE_ISA
+ select PCKBD
+ select PFLASH_CFI01
config MALTA
bool
config MIPSSIM
bool
+ select ISA_BUS
+ select SERIAL_ISA
+ select MIPSNET
config JAZZ
bool
+ select ISA_BUS
+ select RC4030
+ select I8259
+ select I8254
+ select I8257
+ select PCSPK
+ select VGA_ISA_MM
+ select G364FB
+ select DP8393X
+ select ESP
+ select FDC
+ select MC146818RTC
+ select PCKBD
+ select SERIAL
+ select PARALLEL
+ select DS1225Y
+ select JAZZ_LED
config FULONG
bool
obj-$(CONFIG_PVPANIC) += pvpanic.o
obj-$(CONFIG_AUX) += auxbus.o
+obj-$(CONFIG_ASPEED_SOC) += aspeed_xdma.o
obj-$(CONFIG_ASPEED_SOC) += aspeed_scu.o aspeed_sdmc.o
obj-$(CONFIG_MSF2) += msf2-sysreg.o
obj-$(CONFIG_NRF51_SOC) += nrf51_rng.o
--- /dev/null
+/*
+ * ASPEED XDMA Controller
+ * Eddie James <eajames@linux.ibm.com>
+ *
+ * Copyright (C) 2019 IBM Corp
+ * SPDX-License-Identifer: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/log.h"
+#include "qemu/error-report.h"
+#include "hw/misc/aspeed_xdma.h"
+#include "qapi/error.h"
+
+#include "trace.h"
+
+#define XDMA_BMC_CMDQ_ADDR 0x10
+#define XDMA_BMC_CMDQ_ENDP 0x14
+#define XDMA_BMC_CMDQ_WRP 0x18
+#define XDMA_BMC_CMDQ_W_MASK 0x0003FFFF
+#define XDMA_BMC_CMDQ_RDP 0x1C
+#define XDMA_BMC_CMDQ_RDP_MAGIC 0xEE882266
+#define XDMA_IRQ_ENG_CTRL 0x20
+#define XDMA_IRQ_ENG_CTRL_US_COMP BIT(4)
+#define XDMA_IRQ_ENG_CTRL_DS_COMP BIT(5)
+#define XDMA_IRQ_ENG_CTRL_W_MASK 0xBFEFF07F
+#define XDMA_IRQ_ENG_STAT 0x24
+#define XDMA_IRQ_ENG_STAT_US_COMP BIT(4)
+#define XDMA_IRQ_ENG_STAT_DS_COMP BIT(5)
+#define XDMA_IRQ_ENG_STAT_RESET 0xF8000000
+#define XDMA_MEM_SIZE 0x1000
+
+#define TO_REG(addr) ((addr) / sizeof(uint32_t))
+
+static uint64_t aspeed_xdma_read(void *opaque, hwaddr addr, unsigned int size)
+{
+ uint32_t val = 0;
+ AspeedXDMAState *xdma = opaque;
+
+ if (addr < ASPEED_XDMA_REG_SIZE) {
+ val = xdma->regs[TO_REG(addr)];
+ }
+
+ return (uint64_t)val;
+}
+
+static void aspeed_xdma_write(void *opaque, hwaddr addr, uint64_t val,
+ unsigned int size)
+{
+ unsigned int idx;
+ uint32_t val32 = (uint32_t)val;
+ AspeedXDMAState *xdma = opaque;
+
+ if (addr >= ASPEED_XDMA_REG_SIZE) {
+ return;
+ }
+
+ switch (addr) {
+ case XDMA_BMC_CMDQ_ENDP:
+ xdma->regs[TO_REG(addr)] = val32 & XDMA_BMC_CMDQ_W_MASK;
+ break;
+ case XDMA_BMC_CMDQ_WRP:
+ idx = TO_REG(addr);
+ xdma->regs[idx] = val32 & XDMA_BMC_CMDQ_W_MASK;
+ xdma->regs[TO_REG(XDMA_BMC_CMDQ_RDP)] = xdma->regs[idx];
+
+ trace_aspeed_xdma_write(addr, val);
+
+ if (xdma->bmc_cmdq_readp_set) {
+ xdma->bmc_cmdq_readp_set = 0;
+ } else {
+ xdma->regs[TO_REG(XDMA_IRQ_ENG_STAT)] |=
+ XDMA_IRQ_ENG_STAT_US_COMP | XDMA_IRQ_ENG_STAT_DS_COMP;
+
+ if (xdma->regs[TO_REG(XDMA_IRQ_ENG_CTRL)] &
+ (XDMA_IRQ_ENG_CTRL_US_COMP | XDMA_IRQ_ENG_CTRL_DS_COMP))
+ qemu_irq_raise(xdma->irq);
+ }
+ break;
+ case XDMA_BMC_CMDQ_RDP:
+ trace_aspeed_xdma_write(addr, val);
+
+ if (val32 == XDMA_BMC_CMDQ_RDP_MAGIC) {
+ xdma->bmc_cmdq_readp_set = 1;
+ }
+ break;
+ case XDMA_IRQ_ENG_CTRL:
+ xdma->regs[TO_REG(addr)] = val32 & XDMA_IRQ_ENG_CTRL_W_MASK;
+ break;
+ case XDMA_IRQ_ENG_STAT:
+ trace_aspeed_xdma_write(addr, val);
+
+ idx = TO_REG(addr);
+ if (val32 & (XDMA_IRQ_ENG_STAT_US_COMP | XDMA_IRQ_ENG_STAT_DS_COMP)) {
+ xdma->regs[idx] &=
+ ~(XDMA_IRQ_ENG_STAT_US_COMP | XDMA_IRQ_ENG_STAT_DS_COMP);
+ qemu_irq_lower(xdma->irq);
+ }
+ break;
+ default:
+ xdma->regs[TO_REG(addr)] = val32;
+ break;
+ }
+}
+
+static const MemoryRegionOps aspeed_xdma_ops = {
+ .read = aspeed_xdma_read,
+ .write = aspeed_xdma_write,
+ .endianness = DEVICE_NATIVE_ENDIAN,
+ .valid.min_access_size = 4,
+ .valid.max_access_size = 4,
+};
+
+static void aspeed_xdma_realize(DeviceState *dev, Error **errp)
+{
+ SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
+ AspeedXDMAState *xdma = ASPEED_XDMA(dev);
+
+ sysbus_init_irq(sbd, &xdma->irq);
+ memory_region_init_io(&xdma->iomem, OBJECT(xdma), &aspeed_xdma_ops, xdma,
+ TYPE_ASPEED_XDMA, XDMA_MEM_SIZE);
+ sysbus_init_mmio(sbd, &xdma->iomem);
+}
+
+static void aspeed_xdma_reset(DeviceState *dev)
+{
+ AspeedXDMAState *xdma = ASPEED_XDMA(dev);
+
+ xdma->bmc_cmdq_readp_set = 0;
+ memset(xdma->regs, 0, ASPEED_XDMA_REG_SIZE);
+ xdma->regs[TO_REG(XDMA_IRQ_ENG_STAT)] = XDMA_IRQ_ENG_STAT_RESET;
+
+ qemu_irq_lower(xdma->irq);
+}
+
+static const VMStateDescription aspeed_xdma_vmstate = {
+ .name = TYPE_ASPEED_XDMA,
+ .version_id = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT32_ARRAY(regs, AspeedXDMAState, ASPEED_XDMA_NUM_REGS),
+ VMSTATE_END_OF_LIST(),
+ },
+};
+
+static void aspeed_xdma_class_init(ObjectClass *classp, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(classp);
+
+ dc->realize = aspeed_xdma_realize;
+ dc->reset = aspeed_xdma_reset;
+ dc->vmsd = &aspeed_xdma_vmstate;
+}
+
+static const TypeInfo aspeed_xdma_info = {
+ .name = TYPE_ASPEED_XDMA,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(AspeedXDMAState),
+ .class_init = aspeed_xdma_class_init,
+};
+
+static void aspeed_xdma_register_type(void)
+{
+ type_register_static(&aspeed_xdma_info);
+}
+type_init(aspeed_xdma_register_type);
# armsse-mhu.c
armsse_mhu_read(uint64_t offset, uint64_t data, unsigned size) "SSE-200 MHU read: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u"
armsse_mhu_write(uint64_t offset, uint64_t data, unsigned size) "SSE-200 MHU write: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u"
+
+# aspeed_xdma.c
+aspeed_xdma_write(uint64_t offset, uint64_t data) "XDMA write: offset 0x%" PRIx64 " data 0x%" PRIx64
sysbus_init_irq(sbd, &s->irq);
qemu_macaddr_default_if_unset(&s->conf.macaddr);
- s->conf.peers.ncs[0] = nd_table[0].netdev;
-
s->nic = qemu_new_nic(&net_ftgmac100_info, &s->conf,
object_get_typename(OBJECT(dev)), DEVICE(dev)->id,
s);
#define HME_SEBI_STAT 0x100
#define HME_SEBI_STAT_LINUXBUG 0x108
#define HME_SEB_STAT_RXTOHOST 0x10000
+#define HME_SEB_STAT_NORXD 0x20000
#define HME_SEB_STAT_MIFIRQ 0x800000
#define HME_SEB_STAT_HOSTTOTX 0x1000000
#define HME_SEB_STAT_TXALL 0x2000000
}
level = (seb ? 1 : 0);
+ trace_sunhme_update_irq(mifmask, mif, sebmask, seb, level);
+
pci_set_irq(d, level);
}
uint64_t val, unsigned size)
{
SunHMEState *s = SUNHME(opaque);
+ uint64_t oldval = s->macregs[addr >> 2];
trace_sunhme_mac_write(addr, val);
s->macregs[addr >> 2] = val;
+
+ switch (addr) {
+ case HME_MACI_RXCFG:
+ if (!(oldval & HME_MAC_RXCFG_ENABLE) &&
+ (val & HME_MAC_RXCFG_ENABLE)) {
+ qemu_flush_queued_packets(qemu_get_queue(s->nic));
+ }
+ break;
+ }
}
static uint64_t sunhme_mac_read(void *opaque, hwaddr addr,
{
SunHMEState *s = qemu_get_nic_opaque(nc);
- return s->macregs[HME_MAC_RXCFG_ENABLE >> 2] & HME_MAC_RXCFG_ENABLE;
+ return s->macregs[HME_MACI_RXCFG >> 2] & HME_MAC_RXCFG_ENABLE;
}
static void sunhme_link_status_changed(NetClientState *nc)
/* Do nothing if MAC RX disabled */
if (!(s->macregs[HME_MACI_RXCFG >> 2] & HME_MAC_RXCFG_ENABLE)) {
- return -1;
+ return 0;
}
trace_sunhme_rx_filter_destmac(buf[0], buf[1], buf[2],
/* Didn't match hash filter */
trace_sunhme_rx_filter_hash_nomatch();
trace_sunhme_rx_filter_reject();
- return 0;
+ return -1;
} else {
trace_sunhme_rx_filter_hash_match();
}
} else {
/* Not for us */
trace_sunhme_rx_filter_reject();
- return 0;
+ return -1;
}
} else {
trace_sunhme_rx_filter_promisc_match();
pci_dma_read(d, rb + cr * HME_DESC_SIZE, &status, 4);
pci_dma_read(d, rb + cr * HME_DESC_SIZE + 4, &buffer, 4);
+ /* If we don't own the current descriptor then indicate overflow error */
+ if (!(status & HME_XD_OWN)) {
+ s->sebregs[HME_SEBI_STAT >> 2] |= HME_SEB_STAT_NORXD;
+ sunhme_update_irq(s);
+ trace_sunhme_rx_norxd();
+ return -1;
+ }
+
rxoffset = (s->erxregs[HME_ERXI_CFG >> 2] & HME_ERX_CFG_BYTEOFFSET) >>
HME_ERX_CFG_BYTEOFFSET_SHIFT;
sunhme_rx_filter_accept(void) "accepting incoming frame"
sunhme_rx_desc(uint32_t addr, int offset, uint32_t status, int len, int cr, int nr) "addr 0x%"PRIx32"(+0x%x) status 0x%"PRIx32 " len %d (ring %d/%d)"
sunhme_rx_xsum_calc(uint16_t xsum) "calculated incoming xsum as 0x%x"
+sunhme_rx_norxd(void) "no free rx descriptors available"
+sunhme_update_irq(uint32_t mifmask, uint32_t mif, uint32_t sebmask, uint32_t seb, int level) "mifmask: 0x%x mif: 0x%x sebmask: 0x%x seb: 0x%x level: %d"
# virtio-net.c
virtio_net_announce_notify(void) ""
timer_mod(n->announce_timer.tm,
qemu_clock_get_ms(n->announce_timer.type));
} else {
- qemu_announce_timer_del(&n->announce_timer);
+ qemu_announce_timer_del(&n->announce_timer, false);
}
}
virtio_net_del_queue(n, i);
}
- qemu_announce_timer_del(&n->announce_timer);
+ qemu_announce_timer_del(&n->announce_timer, false);
g_free(n->vqs);
qemu_del_nic(n->nic);
virtio_net_rsc_cleanup(n);
{
uint32_t root_cmd =
pci_get_long(d->config + d->exp.aer_cap + PCI_ERR_ROOT_COMMAND);
+ uint16_t slt_ctl, slt_sta;
+
+ pcie_cap_slot_get(d, &slt_ctl, &slt_sta);
pci_bridge_write_config(d, address, val, len);
rp_aer_vector_update(d);
- pcie_cap_slot_write_config(d, address, val, len);
+ pcie_cap_slot_write_config(d, slt_ctl, slt_sta, address, val, len);
pcie_aer_write_config(d, address, val, len);
pcie_aer_root_write_config(d, address, val, len, root_cmd);
}
static void xio3130_downstream_write_config(PCIDevice *d, uint32_t address,
uint32_t val, int len)
{
+ uint16_t slt_ctl, slt_sta;
+
+ pcie_cap_slot_get(d, &slt_sta, &slt_ctl);
pci_bridge_write_config(d, address, val, len);
pcie_cap_flr_write_config(d, address, val, len);
- pcie_cap_slot_write_config(d, address, val, len);
+ pcie_cap_slot_write_config(d, slt_ctl, slt_sta, address, val, len);
pcie_aer_write_config(d, address, val, len);
}
#define DESIGNWARE_PCIE_ATU_DEVFN(x) (((x) >> 16) & 0xff)
#define DESIGNWARE_PCIE_ATU_UPPER_TARGET 0x91C
+#define DESIGNWARE_PCIE_IRQ_MSI 3
+
static DesignwarePCIEHost *
designware_pcie_root_to_host(DesignwarePCIERoot *root)
{
root->msi.intr[0].status |= BIT(val) & root->msi.intr[0].enable;
if (root->msi.intr[0].status & ~root->msi.intr[0].mask) {
- qemu_set_irq(host->pci.irqs[0], 1);
+ qemu_set_irq(host->pci.irqs[DESIGNWARE_PCIE_IRQ_MSI], 1);
}
}
case DESIGNWARE_PCIE_MSI_ADDR_LO:
root->msi.base &= 0xFFFFFFFF00000000ULL;
root->msi.base |= val;
+ designware_pcie_root_update_msi_mapping(root);
break;
case DESIGNWARE_PCIE_MSI_ADDR_HI:
root->msi.base &= 0x00000000FFFFFFFFULL;
root->msi.base |= (uint64_t)val << 32;
+ designware_pcie_root_update_msi_mapping(root);
break;
- case DESIGNWARE_PCIE_MSI_INTR0_ENABLE: {
- const bool update_msi_mapping = !root->msi.intr[0].enable ^ !!val;
-
+ case DESIGNWARE_PCIE_MSI_INTR0_ENABLE:
root->msi.intr[0].enable = val;
-
- if (update_msi_mapping) {
- designware_pcie_root_update_msi_mapping(root);
- }
+ designware_pcie_root_update_msi_mapping(root);
break;
- }
case DESIGNWARE_PCIE_MSI_INTR0_MASK:
root->msi.intr[0].mask = val;
case DESIGNWARE_PCIE_MSI_INTR0_STATUS:
root->msi.intr[0].status ^= val;
if (!root->msi.intr[0].status) {
- qemu_set_irq(host->pci.irqs[0], 0);
+ qemu_set_irq(host->pci.irqs[DESIGNWARE_PCIE_IRQ_MSI], 0);
}
break;
{
/* Minor optimization: if nothing changed - no event is needed. */
if (pci_word_test_and_set_mask(dev->config + dev->exp.exp_cap +
- PCI_EXP_SLTSTA, event)) {
+ PCI_EXP_SLTSTA, event) == event) {
return;
}
hotplug_event_notify(dev);
hotplug_event_update_event_status(dev);
}
+void pcie_cap_slot_get(PCIDevice *dev, uint16_t *slt_ctl, uint16_t *slt_sta)
+{
+ uint32_t pos = dev->exp.exp_cap;
+ uint8_t *exp_cap = dev->config + pos;
+ *slt_ctl = pci_get_word(exp_cap + PCI_EXP_SLTCTL);
+ *slt_sta = pci_get_word(exp_cap + PCI_EXP_SLTSTA);
+}
+
void pcie_cap_slot_write_config(PCIDevice *dev,
+ uint16_t old_slt_ctl, uint16_t old_slt_sta,
uint32_t addr, uint32_t val, int len)
{
uint32_t pos = dev->exp.exp_cap;
uint16_t sltsta = pci_get_word(exp_cap + PCI_EXP_SLTSTA);
if (ranges_overlap(addr, len, pos + PCI_EXP_SLTSTA, 2)) {
+ /*
+ * Guests tend to clears all bits during init.
+ * If they clear bits that weren't set this is racy and will lose events:
+ * not a big problem for manual button presses, but a problem for us.
+ * As a work-around, detect this and revert status to what it was
+ * before the write.
+ *
+ * Note: in theory this can be detected as a duplicate button press
+ * which cancels the previous press. Does not seem to happen in
+ * practice as guests seem to only have this bug during init.
+ */
+#define PCIE_SLOT_EVENTS (PCI_EXP_SLTSTA_ABP | PCI_EXP_SLTSTA_PFD | \
+ PCI_EXP_SLTSTA_MRLSC | PCI_EXP_SLTSTA_PDC | \
+ PCI_EXP_SLTSTA_CC)
+
+ if (val & ~old_slt_sta & PCIE_SLOT_EVENTS) {
+ sltsta = (sltsta & ~PCIE_SLOT_EVENTS) | (old_slt_sta & PCIE_SLOT_EVENTS);
+ pci_set_word(exp_cap + PCI_EXP_SLTSTA, sltsta);
+ }
hotplug_event_clear(dev);
}
}
/*
- * If the slot is polulated, power indicator is off and power
+ * If the slot is populated, power indicator is off and power
* controller is off, it is safe to detach the devices.
+ *
+ * Note: don't detach if condition was already true:
+ * this is a work around for guests that overwrite
+ * control of powered off slots before powering them on.
*/
if ((sltsta & PCI_EXP_SLTSTA_PDS) && (val & PCI_EXP_SLTCTL_PCC) &&
- ((val & PCI_EXP_SLTCTL_PIC_OFF) == PCI_EXP_SLTCTL_PIC_OFF)) {
+ (val & PCI_EXP_SLTCTL_PIC_OFF) == PCI_EXP_SLTCTL_PIC_OFF &&
+ (!(old_slt_ctl & PCI_EXP_SLTCTL_PCC) ||
+ (old_slt_ctl & PCI_EXP_SLTCTL_PIC_OFF) != PCI_EXP_SLTCTL_PIC_OFF)) {
PCIBus *sec_bus = pci_bridge_get_sec_bus(PCI_BRIDGE(dev));
pci_for_each_device(sec_bus, pci_bus_num(sec_bus),
pcie_unplug_device, NULL);
}
/* The NewWorld NVRAM is not located in the MacIO device */
-#ifdef CONFIG_KVM
if (kvm_enabled() && getpagesize() > 4096) {
/* We can't combine read-write and read-only in a single page, so
move the NVRAM out of ROM again for KVM */
nvram_addr = 0xFFE00000;
}
-#endif
dev = qdev_create(NULL, TYPE_MACIO_NVRAM);
qdev_prop_set_uint32(dev, "size", 0x2000);
qdev_prop_set_uint32(dev, "it_shift", 1);
fw_cfg_add_i32(fw_cfg, FW_CFG_PPC_IS_KVM, kvm_enabled());
if (kvm_enabled()) {
-#ifdef CONFIG_KVM
uint8_t *hypercall;
hypercall = g_malloc(16);
kvmppc_get_hypercall(env, hypercall, 16);
fw_cfg_add_bytes(fw_cfg, FW_CFG_PPC_KVM_HC, hypercall, 16);
fw_cfg_add_i32(fw_cfg, FW_CFG_PPC_KVM_PID, getpid());
-#endif
}
fw_cfg_add_i32(fw_cfg, FW_CFG_PPC_TBFREQ, tbfreq);
/* Mac OS X requires a "known good" clock-frequency value; pass it one. */
fw_cfg_add_i32(fw_cfg, FW_CFG_PPC_IS_KVM, kvm_enabled());
if (kvm_enabled()) {
-#ifdef CONFIG_KVM
uint8_t *hypercall;
hypercall = g_malloc(16);
kvmppc_get_hypercall(env, hypercall, 16);
fw_cfg_add_bytes(fw_cfg, FW_CFG_PPC_KVM_HC, hypercall, 16);
fw_cfg_add_i32(fw_cfg, FW_CFG_PPC_KVM_PID, getpid());
-#endif
}
fw_cfg_add_i32(fw_cfg, FW_CFG_PPC_TBFREQ, tbfreq);
/* Mac OS X requires a "known good" clock-frequency value; pass it one. */
Pnv8Psi *psi8 = &chip8->psi;
Error *local_err = NULL;
+ /* XSCOM bridge is first */
+ pnv_xscom_realize(chip, PNV_XSCOM_SIZE, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ return;
+ }
+ sysbus_mmio_map(SYS_BUS_DEVICE(chip), 0, PNV_XSCOM_BASE(chip));
+
pcc->parent_realize(dev, &local_err);
if (local_err) {
error_propagate(errp, local_err);
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";
device_class_set_parent_realize(dc, pnv_chip_power8_realize,
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";
device_class_set_parent_realize(dc, pnv_chip_power8_realize,
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";
device_class_set_parent_realize(dc, pnv_chip_power8_realize,
Pnv9Psi *psi9 = &chip9->psi;
Error *local_err = NULL;
+ /* XSCOM bridge is first */
+ pnv_xscom_realize(chip, PNV9_XSCOM_SIZE, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ return;
+ }
+ sysbus_mmio_map(SYS_BUS_DEVICE(chip), 0, PNV9_XSCOM_BASE(chip));
+
pcc->parent_realize(dev, &local_err);
if (local_err) {
error_propagate(errp, local_err);
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";
device_class_set_parent_realize(dc, pnv_chip_power9_realize,
}
}
-static void pnv_chip_instance_init(Object *obj)
-{
- PNV_CHIP(obj)->xscom_base = PNV_CHIP_GET_CLASS(obj)->xscom_base;
-}
-
static void pnv_chip_core_realize(PnvChip *chip, Error **errp)
{
Error *error = NULL;
PnvChip *chip = PNV_CHIP(dev);
Error *error = NULL;
- /* XSCOM bridge */
- pnv_xscom_realize(chip, &error);
- if (error) {
- error_propagate(errp, error);
- return;
- }
- sysbus_mmio_map(SYS_BUS_DEVICE(chip), 0, PNV_XSCOM_BASE(chip));
-
/* Cores */
pnv_chip_core_realize(chip, &error);
if (error) {
.name = TYPE_PNV_CHIP,
.parent = TYPE_SYS_BUS_DEVICE,
.class_init = pnv_chip_class_init,
- .instance_init = pnv_chip_instance_init,
.instance_size = sizeof(PnvChip),
.class_size = sizeof(PnvChipClass),
.abstract = true,
.endianness = DEVICE_BIG_ENDIAN,
};
-void pnv_xscom_realize(PnvChip *chip, Error **errp)
+void pnv_xscom_realize(PnvChip *chip, uint64_t size, Error **errp)
{
SysBusDevice *sbd = SYS_BUS_DEVICE(chip);
char *name;
name = g_strdup_printf("xscom-%x", chip->chip_id);
memory_region_init_io(&chip->xscom_mmio, OBJECT(chip), &pnv_xscom_ops,
- chip, name, PNV_XSCOM_SIZE);
+ chip, name, size);
sysbus_init_mmio(sbd, &chip->xscom_mmio);
- memory_region_init(&chip->xscom, OBJECT(chip), name, PNV_XSCOM_SIZE);
+ memory_region_init(&chip->xscom, OBJECT(chip), name, size);
address_space_init(&chip->xscom_as, &chip->xscom, name);
g_free(name);
}
int pnv_dt_xscom(PnvChip *chip, void *fdt, int root_offset)
{
- uint64_t reg[] = { cpu_to_be64(PNV_XSCOM_BASE(chip)),
- cpu_to_be64(PNV_XSCOM_SIZE) };
+ uint64_t reg[2];
int xscom_offset;
ForeachPopulateArgs args;
char *name;
+ if (pnv_chip_is_power9(chip)) {
+ reg[0] = cpu_to_be64(PNV9_XSCOM_BASE(chip));
+ reg[1] = cpu_to_be64(PNV9_XSCOM_SIZE);
+ } else {
+ reg[0] = cpu_to_be64(PNV_XSCOM_BASE(chip));
+ reg[1] = cpu_to_be64(PNV_XSCOM_SIZE);
+ }
+
name = g_strdup_printf("xscom@%" PRIx64, be64_to_cpu(reg[0]));
xscom_offset = fdt_add_subnode(fdt, root_offset, name);
_FDT(xscom_offset);
}
if (old_pending != env->pending_interrupts) {
-#ifdef CONFIG_KVM
kvmppc_set_interrupt(cpu, n_IRQ, level);
-#endif
}
CPU_FOREACH(cpu) {
PowerPCCPU *pcpu = POWERPC_CPU(cpu);
pcpu->env.tb_env->tb_offset = tb_off_adj;
-#if defined(CONFIG_KVM)
- kvm_set_one_reg(cpu, KVM_REG_PPC_TB_OFFSET,
- &pcpu->env.tb_env->tb_offset);
-#endif
+ kvmppc_set_reg_tb_offset(pcpu, pcpu->env.tb_env->tb_offset);
}
}
fw_cfg_add_i32(fw_cfg, FW_CFG_PPC_IS_KVM, kvm_enabled());
if (kvm_enabled()) {
-#ifdef CONFIG_KVM
uint8_t *hypercall;
fw_cfg_add_i32(fw_cfg, FW_CFG_PPC_TBFREQ, kvmppc_get_tbfreq());
kvmppc_get_hypercall(env, hypercall, 16);
fw_cfg_add_bytes(fw_cfg, FW_CFG_PPC_KVM_HC, hypercall, 16);
fw_cfg_add_i32(fw_cfg, FW_CFG_PPC_KVM_PID, getpid());
-#endif
} else {
fw_cfg_add_i32(fw_cfg, FW_CFG_PPC_TBFREQ, NANOSECONDS_PER_SECOND);
}
bitmap_clear(spapr->irq_map, 0, spapr->irq_map_nr);
}
-static void spapr_irq_init_device(SpaprMachineState *spapr,
+static void spapr_irq_init_kvm(SpaprMachineState *spapr,
SpaprIrq *irq, Error **errp)
{
MachineState *machine = MACHINE(spapr);
error_prepend(&local_err, "kernel_irqchip allowed but unavailable: ");
warn_report_err(local_err);
}
-
- irq->init_emu(spapr, errp);
}
/*
}
spapr->ics = ICS_BASE(obj);
+
+ xics_spapr_init(spapr);
}
#define ICS_IRQ_FREE(ics, srcno) \
{
Error *local_err = NULL;
- spapr_irq_init_device(spapr, &spapr_irq_xics, &local_err);
+ spapr_irq_init_kvm(spapr, &spapr_irq_xics, &local_err);
if (local_err) {
error_propagate(errp, local_err);
return;
return XICS_NODENAME;
}
-static void spapr_irq_init_emu_xics(SpaprMachineState *spapr, Error **errp)
-{
- xics_spapr_init(spapr);
-}
-
static void spapr_irq_init_kvm_xics(SpaprMachineState *spapr, Error **errp)
{
if (kvm_enabled()) {
- xics_kvm_init(spapr, errp);
+ xics_kvm_connect(spapr, errp);
}
}
.reset = spapr_irq_reset_xics,
.set_irq = spapr_irq_set_irq_xics,
.get_nodename = spapr_irq_get_nodename_xics,
- .init_emu = spapr_irq_init_emu_xics,
.init_kvm = spapr_irq_init_kvm_xics,
};
spapr_xive_set_tctx_os_cam(spapr_cpu_state(cpu)->tctx);
}
- spapr_irq_init_device(spapr, &spapr_irq_xive, &local_err);
+ spapr_irq_init_kvm(spapr, &spapr_irq_xive, &local_err);
if (local_err) {
error_propagate(errp, local_err);
return;
return spapr->xive->nodename;
}
-static void spapr_irq_init_emu_xive(SpaprMachineState *spapr, Error **errp)
-{
- spapr_xive_init(spapr->xive, errp);
-}
-
static void spapr_irq_init_kvm_xive(SpaprMachineState *spapr, Error **errp)
{
if (kvm_enabled()) {
.reset = spapr_irq_reset_xive,
.set_irq = spapr_irq_set_irq_xive,
.get_nodename = spapr_irq_get_nodename_xive,
- .init_emu = spapr_irq_init_emu_xive,
.init_kvm = spapr_irq_init_kvm_xive,
};
.reset = spapr_irq_reset_dual,
.set_irq = spapr_irq_set_irq_dual,
.get_nodename = spapr_irq_get_nodename_dual,
- .init_emu = NULL, /* should not be used */
.init_kvm = NULL, /* should not be used */
};
return;
}
}
+
+ /*
+ * On a POWER9 host, some older KVM XICS devices cannot be destroyed and
+ * re-created. Detect that early to avoid QEMU to exit later when the
+ * guest reboots.
+ */
+ if (kvm_enabled() &&
+ spapr->irq == &spapr_irq_dual &&
+ machine_kernel_irqchip_required(machine) &&
+ xics_kvm_has_broken_disconnect(spapr)) {
+ error_setg(errp, "KVM is too old to support ic-mode=dual,kernel-irqchip=on");
+ return;
+ }
}
/*
.reset = spapr_irq_reset_xics,
.set_irq = spapr_irq_set_irq_xics,
.get_nodename = spapr_irq_get_nodename_xics,
- .init_emu = spapr_irq_init_emu_xics,
.init_kvm = spapr_irq_init_kvm_xics,
};
static int spapr_dt_pci_bus(SpaprPhbState *sphb, PCIBus *bus,
void *fdt, int offset)
{
+ Object *owner;
PciWalkFdt cbinfo = {
.fdt = fdt,
.offset = offset,
_FDT(fdt_setprop_cell(fdt, offset, "#size-cells",
RESOURCE_CELLS_SIZE));
- if (bus) {
- pci_for_each_device_reverse(bus, pci_bus_num(bus),
- spapr_dt_pci_device_cb, &cbinfo);
- if (cbinfo.err) {
- return cbinfo.err;
- }
+ assert(bus);
+ pci_for_each_device_reverse(bus, pci_bus_num(bus),
+ spapr_dt_pci_device_cb, &cbinfo);
+ if (cbinfo.err) {
+ return cbinfo.err;
}
- ret = spapr_dt_drc(fdt, offset, OBJECT(bus->parent_dev),
+ if (pci_bus_is_root(bus)) {
+ owner = OBJECT(sphb);
+ } else {
+ owner = OBJECT(pci_bridge_get_device(bus));
+ }
+
+ ret = spapr_dt_drc(fdt, offset, owner,
SPAPR_DR_CONNECTOR_TYPE_PCI);
if (ret) {
return ret;
memory_region_del_subregion(&sphb->iommu_root, &sphb->msiwindow);
+ /*
+ * An attached PCI device may have memory listeners, eg. VFIO PCI. We have
+ * unmapped all sections. Remove the listeners now, before destroying the
+ * address space.
+ */
+ address_space_remove_listeners(&sphb->iommu_as);
address_space_destroy(&sphb->iommu_as);
qbus_set_hotplug_handler(BUS(phb->bus), NULL, &error_abort);
* For KVM we want to ensure that this memory is a full page so that
* our memory slot is of page size granularity.
*/
-#ifdef CONFIG_KVM
if (kvm_enabled()) {
msi_window_size = getpagesize();
}
-#endif
memory_region_init_io(&sphb->msiwindow, OBJECT(sphb), &spapr_msi_ops, spapr,
"msi", msi_window_size);
#include "sysemu/sysemu.h"
#include "hw/ppc/spapr.h"
#include "qapi/error.h"
-#include "qapi/qapi-events-target.h"
+#include "qapi/qapi-events-misc-target.h"
#include "qemu/cutils.h"
#include "qemu/module.h"
+obj-y += boot.o
obj-$(CONFIG_SPIKE) += riscv_htif.o
obj-$(CONFIG_HART) += riscv_hart.o
obj-$(CONFIG_SIFIVE_E) += sifive_e.o
--- /dev/null
+/*
+ * QEMU RISC-V Boot Helper
+ *
+ * Copyright (c) 2017 SiFive, Inc.
+ * Copyright (c) 2019 Alistair Francis <alistair.francis@wdc.com>
+ *
+ * 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/>.
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/units.h"
+#include "qemu/error-report.h"
+#include "exec/cpu-defs.h"
+#include "hw/loader.h"
+#include "hw/riscv/boot.h"
+#include "hw/boards.h"
+#include "elf.h"
+
+#if defined(TARGET_RISCV32)
+# define KERNEL_BOOT_ADDRESS 0x80400000
+#else
+# define KERNEL_BOOT_ADDRESS 0x80200000
+#endif
+
+target_ulong riscv_load_firmware(const char *firmware_filename,
+ hwaddr firmware_load_addr)
+{
+ uint64_t firmware_entry, firmware_start, firmware_end;
+
+ if (load_elf(firmware_filename, NULL, NULL, NULL, &firmware_entry,
+ &firmware_start, &firmware_end, 0, EM_RISCV, 1, 0) > 0) {
+ return firmware_entry;
+ }
+
+ if (load_image_targphys_as(firmware_filename, firmware_load_addr,
+ ram_size, NULL) > 0) {
+ return firmware_load_addr;
+ }
+
+ error_report("could not load firmware '%s'", firmware_filename);
+ exit(1);
+}
+
+target_ulong riscv_load_kernel(const char *kernel_filename)
+{
+ uint64_t kernel_entry, kernel_high;
+
+ if (load_elf(kernel_filename, NULL, NULL, NULL,
+ &kernel_entry, NULL, &kernel_high, 0, EM_RISCV, 1, 0) > 0) {
+ return kernel_entry;
+ }
+
+ if (load_uimage_as(kernel_filename, &kernel_entry, NULL, NULL,
+ NULL, NULL, NULL) > 0) {
+ return kernel_entry;
+ }
+
+ if (load_image_targphys_as(kernel_filename, KERNEL_BOOT_ADDRESS,
+ ram_size, NULL) > 0) {
+ return KERNEL_BOOT_ADDRESS;
+ }
+
+ error_report("could not load kernel '%s'", kernel_filename);
+ exit(1);
+}
+
+hwaddr riscv_load_initrd(const char *filename, uint64_t mem_size,
+ uint64_t kernel_entry, hwaddr *start)
+{
+ int size;
+
+ /*
+ * We want to put the initrd far enough into RAM that when the
+ * kernel is uncompressed it will not clobber the initrd. However
+ * on boards without much RAM we must ensure that we still leave
+ * enough room for a decent sized initrd, and on boards with large
+ * amounts of RAM we must avoid the initrd being so far up in RAM
+ * that it is outside lowmem and inaccessible to the kernel.
+ * So for boards with less than 256MB of RAM we put the initrd
+ * halfway into RAM, and for boards with 256MB of RAM or more we put
+ * the initrd at 128MB.
+ */
+ *start = kernel_entry + MIN(mem_size / 2, 128 * MiB);
+
+ size = load_ramdisk(filename, *start, mem_size - *start);
+ if (size == -1) {
+ size = load_image_targphys(filename, *start, mem_size - *start);
+ if (size == -1) {
+ error_report("could not load ramdisk '%s'", filename);
+ exit(1);
+ }
+ }
+
+ return *start + size;
+}
#include "hw/riscv/sifive_prci.h"
#include "hw/riscv/sifive_uart.h"
#include "hw/riscv/sifive_e.h"
+#include "hw/riscv/boot.h"
#include "chardev/char.h"
#include "sysemu/arch_init.h"
#include "exec/address-spaces.h"
-#include "elf.h"
static const struct MemmapEntry {
hwaddr base;
[SIFIVE_E_DTIM] = { 0x80000000, 0x4000 }
};
-static target_ulong load_kernel(const char *kernel_filename)
-{
- uint64_t kernel_entry, kernel_high;
-
- if (load_elf(kernel_filename, NULL, NULL, NULL,
- &kernel_entry, NULL, &kernel_high,
- 0, EM_RISCV, 1, 0) < 0) {
- error_report("could not load kernel '%s'", kernel_filename);
- exit(1);
- }
- return kernel_entry;
-}
-
static void sifive_mmio_emulate(MemoryRegion *parent, const char *name,
uintptr_t offset, uintptr_t length)
{
memmap[SIFIVE_E_MROM].base, &address_space_memory);
if (machine->kernel_filename) {
- load_kernel(machine->kernel_filename);
+ riscv_load_kernel(machine->kernel_filename);
}
}
SiFiveESoCState *s = RISCV_E_SOC(dev);
MemoryRegion *sys_mem = get_system_memory();
- MemoryRegion *xip_mem = g_new(MemoryRegion, 1);
- MemoryRegion *mask_rom = g_new(MemoryRegion, 1);
object_property_set_bool(OBJECT(&s->cpus), true, "realized",
&error_abort);
/* Mask ROM */
- memory_region_init_rom(mask_rom, NULL, "riscv.sifive.e.mrom",
+ memory_region_init_rom(&s->mask_rom, NULL, "riscv.sifive.e.mrom",
memmap[SIFIVE_E_MROM].size, &error_fatal);
memory_region_add_subregion(sys_mem,
- memmap[SIFIVE_E_MROM].base, mask_rom);
+ memmap[SIFIVE_E_MROM].base, &s->mask_rom);
/* MMIO */
s->plic = sifive_plic_create(memmap[SIFIVE_E_PLIC].base,
memmap[SIFIVE_E_PWM2].base, memmap[SIFIVE_E_PWM2].size);
/* Flash memory */
- memory_region_init_ram(xip_mem, NULL, "riscv.sifive.e.xip",
+ memory_region_init_ram(&s->xip_mem, NULL, "riscv.sifive.e.xip",
memmap[SIFIVE_E_XIP].size, &error_fatal);
- memory_region_set_readonly(xip_mem, true);
- memory_region_add_subregion(sys_mem, memmap[SIFIVE_E_XIP].base, xip_mem);
+ memory_region_set_readonly(&s->xip_mem, true);
+ memory_region_add_subregion(sys_mem, memmap[SIFIVE_E_XIP].base,
+ &s->xip_mem);
}
static void riscv_sifive_e_machine_init(MachineClass *mc)
#include "target/riscv/cpu.h"
#include "hw/riscv/sifive_prci.h"
-/* currently implements enough to mock freedom-e-sdk BSP clock programming */
-
static uint64_t sifive_prci_read(void *opaque, hwaddr addr, unsigned int size)
{
- if (addr == 0 /* PRCI_HFROSCCFG */) {
- return 1 << 31; /* ROSC_RDY */
- }
- if (addr == 8 /* PRCI_PLLCFG */) {
- return 1 << 31; /* PLL_LOCK */
+ SiFivePRCIState *s = opaque;
+ switch (addr) {
+ case SIFIVE_PRCI_HFROSCCFG:
+ return s->hfrosccfg;
+ case SIFIVE_PRCI_HFXOSCCFG:
+ return s->hfxosccfg;
+ case SIFIVE_PRCI_PLLCFG:
+ return s->pllcfg;
+ case SIFIVE_PRCI_PLLOUTDIV:
+ return s->plloutdiv;
}
hw_error("%s: read: addr=0x%x\n", __func__, (int)addr);
return 0;
static void sifive_prci_write(void *opaque, hwaddr addr,
uint64_t val64, unsigned int size)
{
- /* discard writes */
+ SiFivePRCIState *s = opaque;
+ switch (addr) {
+ case SIFIVE_PRCI_HFROSCCFG:
+ s->hfrosccfg = (uint32_t) val64;
+ /* OSC stays ready */
+ s->hfrosccfg |= SIFIVE_PRCI_HFROSCCFG_RDY;
+ break;
+ case SIFIVE_PRCI_HFXOSCCFG:
+ s->hfxosccfg = (uint32_t) val64;
+ /* OSC stays ready */
+ s->hfxosccfg |= SIFIVE_PRCI_HFXOSCCFG_RDY;
+ break;
+ case SIFIVE_PRCI_PLLCFG:
+ s->pllcfg = (uint32_t) val64;
+ /* PLL stays locked */
+ s->pllcfg |= SIFIVE_PRCI_PLLCFG_LOCK;
+ break;
+ case SIFIVE_PRCI_PLLOUTDIV:
+ s->plloutdiv = (uint32_t) val64;
+ break;
+ default:
+ hw_error("%s: bad write: addr=0x%x v=0x%x\n",
+ __func__, (int)addr, (int)val64);
+ }
}
static const MemoryRegionOps sifive_prci_ops = {
memory_region_init_io(&s->mmio, obj, &sifive_prci_ops, s,
TYPE_SIFIVE_PRCI, 0x8000);
sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio);
+
+ s->hfrosccfg = (SIFIVE_PRCI_HFROSCCFG_RDY | SIFIVE_PRCI_HFROSCCFG_EN);
+ s->hfxosccfg = (SIFIVE_PRCI_HFROSCCFG_RDY | SIFIVE_PRCI_HFROSCCFG_EN);
+ s->pllcfg = (SIFIVE_PRCI_PLLCFG_REFSEL | SIFIVE_PRCI_PLLCFG_BYPASS |
+ SIFIVE_PRCI_PLLCFG_LOCK);
+ s->plloutdiv = SIFIVE_PRCI_PLLOUTDIV_DIV1;
+
}
static const TypeInfo sifive_prci_info = {
#include "hw/riscv/sifive_uart.h"
#include "hw/riscv/sifive_prci.h"
#include "hw/riscv/sifive_u.h"
+#include "hw/riscv/boot.h"
#include "chardev/char.h"
#include "sysemu/arch_init.h"
#include "sysemu/device_tree.h"
#include "exec/address-spaces.h"
-#include "elf.h"
#include <libfdt.h>
#define GEM_REVISION 0x10070109
-static target_ulong load_kernel(const char *kernel_filename)
-{
- uint64_t kernel_entry, kernel_high;
-
- if (load_elf(kernel_filename, NULL, NULL, NULL,
- &kernel_entry, NULL, &kernel_high,
- 0, EM_RISCV, 1, 0) < 0) {
- error_report("could not load kernel '%s'", kernel_filename);
- exit(1);
- }
- return kernel_entry;
-}
-
static void create_fdt(SiFiveUState *s, const struct MemmapEntry *memmap,
uint64_t mem_size, const char *cmdline)
{
uint32_t *cells;
char *nodename;
char ethclk_names[] = "pclk\0hclk\0tx_clk";
- uint32_t plic_phandle, ethclk_phandle;
+ uint32_t plic_phandle, ethclk_phandle, phandle = 1;
fdt = s->fdt = create_device_tree(&s->fdt_size);
if (!fdt) {
qemu_fdt_setprop_cell(fdt, "/cpus", "#address-cells", 0x1);
for (cpu = s->soc.cpus.num_harts - 1; cpu >= 0; cpu--) {
+ int cpu_phandle = phandle++;
nodename = g_strdup_printf("/cpus/cpu@%d", cpu);
char *intc = g_strdup_printf("/cpus/cpu@%d/interrupt-controller", cpu);
char *isa = riscv_isa_string(&s->soc.cpus.harts[cpu]);
qemu_fdt_setprop_cell(fdt, nodename, "reg", cpu);
qemu_fdt_setprop_string(fdt, nodename, "device_type", "cpu");
qemu_fdt_add_subnode(fdt, intc);
- qemu_fdt_setprop_cell(fdt, intc, "phandle", 1);
- qemu_fdt_setprop_cell(fdt, intc, "linux,phandle", 1);
+ qemu_fdt_setprop_cell(fdt, intc, "phandle", cpu_phandle);
+ qemu_fdt_setprop_cell(fdt, intc, "linux,phandle", cpu_phandle);
qemu_fdt_setprop_string(fdt, intc, "compatible", "riscv,cpu-intc");
qemu_fdt_setprop(fdt, intc, "interrupt-controller", NULL, 0);
qemu_fdt_setprop_cell(fdt, intc, "#interrupt-cells", 1);
g_free(cells);
g_free(nodename);
+ plic_phandle = phandle++;
cells = g_new0(uint32_t, s->soc.cpus.num_harts * 4);
for (cpu = 0; cpu < s->soc.cpus.num_harts; cpu++) {
nodename =
qemu_fdt_setprop_string(fdt, nodename, "reg-names", "control");
qemu_fdt_setprop_cell(fdt, nodename, "riscv,max-priority", 7);
qemu_fdt_setprop_cell(fdt, nodename, "riscv,ndev", 0x35);
- qemu_fdt_setprop_cells(fdt, nodename, "phandle", 2);
- qemu_fdt_setprop_cells(fdt, nodename, "linux,phandle", 2);
+ qemu_fdt_setprop_cells(fdt, nodename, "phandle", plic_phandle);
+ qemu_fdt_setprop_cells(fdt, nodename, "linux,phandle", plic_phandle);
plic_phandle = qemu_fdt_get_phandle(fdt, nodename);
g_free(cells);
g_free(nodename);
+ ethclk_phandle = phandle++;
nodename = g_strdup_printf("/soc/ethclk");
qemu_fdt_add_subnode(fdt, nodename);
qemu_fdt_setprop_string(fdt, nodename, "compatible", "fixed-clock");
qemu_fdt_setprop_cell(fdt, nodename, "#clock-cells", 0x0);
qemu_fdt_setprop_cell(fdt, nodename, "clock-frequency",
SIFIVE_U_GEM_CLOCK_FREQ);
- qemu_fdt_setprop_cell(fdt, nodename, "phandle", 3);
- qemu_fdt_setprop_cell(fdt, nodename, "linux,phandle", 3);
+ qemu_fdt_setprop_cell(fdt, nodename, "phandle", ethclk_phandle);
+ qemu_fdt_setprop_cell(fdt, nodename, "linux,phandle", ethclk_phandle);
ethclk_phandle = qemu_fdt_get_phandle(fdt, nodename);
g_free(nodename);
/* create device tree */
create_fdt(s, memmap, machine->ram_size, machine->kernel_cmdline);
+ if (machine->firmware) {
+ riscv_load_firmware(machine->firmware, memmap[SIFIVE_U_DRAM].base);
+ }
+
if (machine->kernel_filename) {
- load_kernel(machine->kernel_filename);
+ riscv_load_kernel(machine->kernel_filename);
}
/* reset vector */
MemoryRegion *system_memory = get_system_memory();
MemoryRegion *mask_rom = g_new(MemoryRegion, 1);
qemu_irq plic_gpios[SIFIVE_U_PLIC_NUM_SOURCES];
+ char *plic_hart_config;
+ size_t plic_hart_config_len;
int i;
Error *err = NULL;
NICInfo *nd = &nd_table[0];
memory_region_add_subregion(system_memory, memmap[SIFIVE_U_MROM].base,
mask_rom);
+ /* create PLIC hart topology configuration string */
+ plic_hart_config_len = (strlen(SIFIVE_U_PLIC_HART_CONFIG) + 1) * smp_cpus;
+ plic_hart_config = g_malloc0(plic_hart_config_len);
+ for (i = 0; i < smp_cpus; i++) {
+ if (i != 0) {
+ strncat(plic_hart_config, ",", plic_hart_config_len);
+ }
+ strncat(plic_hart_config, SIFIVE_U_PLIC_HART_CONFIG,
+ plic_hart_config_len);
+ plic_hart_config_len -= (strlen(SIFIVE_U_PLIC_HART_CONFIG) + 1);
+ }
+
/* MMIO */
s->plic = sifive_plic_create(memmap[SIFIVE_U_PLIC].base,
- (char *)SIFIVE_U_PLIC_HART_CONFIG,
+ plic_hart_config,
SIFIVE_U_PLIC_NUM_SOURCES,
SIFIVE_U_PLIC_NUM_PRIORITIES,
SIFIVE_U_PLIC_PRIORITY_BASE,
#include "hw/riscv/riscv_hart.h"
#include "hw/riscv/sifive_clint.h"
#include "hw/riscv/spike.h"
+#include "hw/riscv/boot.h"
#include "chardev/char.h"
#include "sysemu/arch_init.h"
#include "sysemu/device_tree.h"
#include "sysemu/qtest.h"
#include "exec/address-spaces.h"
-#include "elf.h"
#include <libfdt.h>
[SPIKE_DRAM] = { 0x80000000, 0x0 },
};
-static target_ulong load_kernel(const char *kernel_filename)
-{
- uint64_t kernel_entry, kernel_high;
-
- if (load_elf_ram_sym(kernel_filename, NULL, NULL, NULL,
- &kernel_entry, NULL, &kernel_high, 0, EM_RISCV, 1, 0,
- NULL, true, htif_symbol_callback) < 0) {
- error_report("could not load kernel '%s'", kernel_filename);
- exit(1);
- }
- return kernel_entry;
-}
-
static void create_fdt(SpikeState *s, const struct MemmapEntry *memmap,
uint64_t mem_size, const char *cmdline)
{
mask_rom);
if (machine->kernel_filename) {
- load_kernel(machine->kernel_filename);
+ riscv_load_kernel(machine->kernel_filename);
}
/* reset vector */
mask_rom);
if (machine->kernel_filename) {
- load_kernel(machine->kernel_filename);
+ riscv_load_kernel(machine->kernel_filename);
}
/* reset vector */
mask_rom);
if (machine->kernel_filename) {
- load_kernel(machine->kernel_filename);
+ riscv_load_kernel(machine->kernel_filename);
}
/* reset vector */
#include "hw/riscv/sifive_clint.h"
#include "hw/riscv/sifive_test.h"
#include "hw/riscv/virt.h"
+#include "hw/riscv/boot.h"
#include "chardev/char.h"
#include "sysemu/arch_init.h"
#include "sysemu/device_tree.h"
#include "exec/address-spaces.h"
#include "hw/pci/pci.h"
#include "hw/pci-host/gpex.h"
-#include "elf.h"
#include <libfdt.h>
[VIRT_PCIE_ECAM] = { 0x30000000, 0x10000000 },
};
-static target_ulong load_kernel(const char *kernel_filename)
-{
- uint64_t kernel_entry, kernel_high;
-
- if (load_elf(kernel_filename, NULL, NULL, NULL,
- &kernel_entry, NULL, &kernel_high,
- 0, EM_RISCV, 1, 0) < 0) {
- error_report("could not load kernel '%s'", kernel_filename);
- exit(1);
- }
- return kernel_entry;
-}
-
-static hwaddr load_initrd(const char *filename, uint64_t mem_size,
- uint64_t kernel_entry, hwaddr *start)
-{
- int size;
-
- /* We want to put the initrd far enough into RAM that when the
- * kernel is uncompressed it will not clobber the initrd. However
- * on boards without much RAM we must ensure that we still leave
- * enough room for a decent sized initrd, and on boards with large
- * amounts of RAM we must avoid the initrd being so far up in RAM
- * that it is outside lowmem and inaccessible to the kernel.
- * So for boards with less than 256MB of RAM we put the initrd
- * halfway into RAM, and for boards with 256MB of RAM or more we put
- * the initrd at 128MB.
- */
- *start = kernel_entry + MIN(mem_size / 2, 128 * MiB);
-
- size = load_ramdisk(filename, *start, mem_size - *start);
- if (size == -1) {
- size = load_image_targphys(filename, *start, mem_size - *start);
- if (size == -1) {
- error_report("could not load ramdisk '%s'", filename);
- exit(1);
- }
- }
- return *start + size;
-}
-
static void create_pcie_irq_map(void *fdt, char *nodename,
uint32_t plic_phandle)
{
for (cpu = s->soc.num_harts - 1; cpu >= 0; cpu--) {
int cpu_phandle = phandle++;
+ int intc_phandle;
nodename = g_strdup_printf("/cpus/cpu@%d", cpu);
char *intc = g_strdup_printf("/cpus/cpu@%d/interrupt-controller", cpu);
char *isa = riscv_isa_string(&s->soc.harts[cpu]);
qemu_fdt_setprop_string(fdt, nodename, "status", "okay");
qemu_fdt_setprop_cell(fdt, nodename, "reg", cpu);
qemu_fdt_setprop_string(fdt, nodename, "device_type", "cpu");
+ qemu_fdt_setprop_cell(fdt, nodename, "phandle", cpu_phandle);
+ qemu_fdt_setprop_cell(fdt, nodename, "linux,phandle", cpu_phandle);
+ intc_phandle = phandle++;
qemu_fdt_add_subnode(fdt, intc);
- qemu_fdt_setprop_cell(fdt, intc, "phandle", cpu_phandle);
- qemu_fdt_setprop_cell(fdt, intc, "linux,phandle", cpu_phandle);
+ qemu_fdt_setprop_cell(fdt, intc, "phandle", intc_phandle);
+ qemu_fdt_setprop_cell(fdt, intc, "linux,phandle", intc_phandle);
qemu_fdt_setprop_string(fdt, intc, "compatible", "riscv,cpu-intc");
qemu_fdt_setprop(fdt, intc, "interrupt-controller", NULL, 0);
qemu_fdt_setprop_cell(fdt, intc, "#interrupt-cells", 1);
g_free(nodename);
}
+ /* Add cpu-topology node */
+ qemu_fdt_add_subnode(fdt, "/cpus/cpu-map");
+ qemu_fdt_add_subnode(fdt, "/cpus/cpu-map/cluster0");
+ for (cpu = s->soc.num_harts - 1; cpu >= 0; cpu--) {
+ char *core_nodename = g_strdup_printf("/cpus/cpu-map/cluster0/core%d",
+ cpu);
+ char *cpu_nodename = g_strdup_printf("/cpus/cpu@%d", cpu);
+ uint32_t intc_phandle = qemu_fdt_get_phandle(fdt, cpu_nodename);
+ qemu_fdt_add_subnode(fdt, core_nodename);
+ qemu_fdt_setprop_cell(fdt, core_nodename, "cpu", intc_phandle);
+ g_free(core_nodename);
+ g_free(cpu_nodename);
+ }
+
cells = g_new0(uint32_t, s->soc.num_harts * 4);
for (cpu = 0; cpu < s->soc.num_harts; cpu++) {
nodename =
qemu_fdt_setprop_string(fdt, nodename, "device_type", "pci");
qemu_fdt_setprop_cell(fdt, nodename, "linux,pci-domain", 0);
qemu_fdt_setprop_cells(fdt, nodename, "bus-range", 0,
- memmap[VIRT_PCIE_ECAM].base /
+ memmap[VIRT_PCIE_ECAM].size /
PCIE_MMCFG_SIZE_MIN - 1);
qemu_fdt_setprop(fdt, nodename, "dma-coherent", NULL, 0);
qemu_fdt_setprop_cells(fdt, nodename, "reg", 0, memmap[VIRT_PCIE_ECAM].base,
memory_region_add_subregion(system_memory, memmap[VIRT_MROM].base,
mask_rom);
+ if (machine->firmware) {
+ riscv_load_firmware(machine->firmware, memmap[VIRT_DRAM].base);
+ }
+
if (machine->kernel_filename) {
- uint64_t kernel_entry = load_kernel(machine->kernel_filename);
+ uint64_t kernel_entry = riscv_load_kernel(machine->kernel_filename);
if (machine->initrd_filename) {
hwaddr start;
- hwaddr end = load_initrd(machine->initrd_filename,
- machine->ram_size, kernel_entry,
- &start);
+ hwaddr end = riscv_load_initrd(machine->initrd_filename,
+ machine->ram_size, kernel_entry,
+ &start);
qemu_fdt_setprop_cell(fdt, "/chosen",
"linux,initrd-start", start);
qemu_fdt_setprop_cell(fdt, "/chosen", "linux,initrd-end",
#include "trace.h"
#include "hw/s390x/s390_flic.h"
#include "hw/s390x/s390-virtio-ccw.h"
+#include "hw/s390x/s390-ccw.h"
typedef struct CrwContainer {
CRW crw;
}
+static void sch_handle_halt_func_passthrough(SubchDev *sch)
+{
+ int ret;
+
+ ret = s390_ccw_halt(sch);
+ if (ret == -ENOSYS) {
+ sch_handle_halt_func(sch);
+ }
+}
+
+static void sch_handle_clear_func_passthrough(SubchDev *sch)
+{
+ int ret;
+
+ ret = s390_ccw_clear(sch);
+ if (ret == -ENOSYS) {
+ sch_handle_clear_func(sch);
+ }
+}
+
static IOInstEnding sch_handle_start_func_passthrough(SubchDev *sch)
{
SCHIB *schib = &sch->curr_status;
SCHIB *schib = &sch->curr_status;
if (schib->scsw.ctrl & SCSW_FCTL_CLEAR_FUNC) {
- /* TODO: Clear handling */
- sch_handle_clear_func(sch);
+ sch_handle_clear_func_passthrough(sch);
} else if (schib->scsw.ctrl & SCSW_FCTL_HALT_FUNC) {
- /* TODO: Halt handling */
- sch_handle_halt_func(sch);
+ sch_handle_halt_func_passthrough(sch);
} else if (schib->scsw.ctrl & SCSW_FCTL_START_FUNC) {
return sch_handle_start_func_passthrough(sch);
}
return cdc->handle_request(sch);
}
+int s390_ccw_halt(SubchDev *sch)
+{
+ S390CCWDeviceClass *cdc = S390_CCW_DEVICE_GET_CLASS(sch->driver_data);
+
+ if (!cdc->handle_halt) {
+ return -ENOSYS;
+ }
+ return cdc->handle_halt(sch);
+}
+
+int s390_ccw_clear(SubchDev *sch)
+{
+ S390CCWDeviceClass *cdc = S390_CCW_DEVICE_GET_CLASS(sch->driver_data);
+
+ if (!cdc->handle_clear) {
+ return -ENOSYS;
+ }
+ return cdc->handle_clear(sch);
+}
+
static void s390_ccw_get_dev_info(S390CCWDevice *cdev,
char *sysfsdev,
Error **errp)
#include "hw/boards.h"
#include "hw/s390x/storage-keys.h"
#include "qapi/error.h"
-#include "qapi/qapi-commands-target.h"
+#include "qapi/qapi-commands-misc-target.h"
#include "qapi/qmp/qdict.h"
#include "qemu/error-report.h"
#include "sysemu/kvm.h"
mc->is_default = 1;
mc->default_boot_order = "c";
mc->default_cpu_type = SPARC_CPU_TYPE_NAME("Fujitsu-MB86904");
+ mc->default_display = "tcx";
}
static const TypeInfo ss5_type = {
mc->max_cpus = 4;
mc->default_boot_order = "c";
mc->default_cpu_type = SPARC_CPU_TYPE_NAME("TI-SuperSparc-II");
+ mc->default_display = "tcx";
}
static const TypeInfo ss10_type = {
mc->max_cpus = 4;
mc->default_boot_order = "c";
mc->default_cpu_type = SPARC_CPU_TYPE_NAME("TI-SuperSparc-II");
+ mc->default_display = "tcx";
}
static const TypeInfo ss600mp_type = {
mc->max_cpus = 4;
mc->default_boot_order = "c";
mc->default_cpu_type = SPARC_CPU_TYPE_NAME("TI-SuperSparc-II");
+ mc->default_display = "tcx";
}
static const TypeInfo ss20_type = {
mc->block_default_type = IF_SCSI;
mc->default_boot_order = "c";
mc->default_cpu_type = SPARC_CPU_TYPE_NAME("Fujitsu-MB86904");
+ mc->default_display = "tcx";
}
static const TypeInfo voyager_type = {
mc->block_default_type = IF_SCSI;
mc->default_boot_order = "c";
mc->default_cpu_type = SPARC_CPU_TYPE_NAME("TI-MicroSparc-I");
+ mc->default_display = "tcx";
}
static const TypeInfo ss_lx_type = {
mc->block_default_type = IF_SCSI;
mc->default_boot_order = "c";
mc->default_cpu_type = SPARC_CPU_TYPE_NAME("Fujitsu-MB86904");
+ mc->default_display = "tcx";
}
static const TypeInfo ss4_type = {
mc->block_default_type = IF_SCSI;
mc->default_boot_order = "c";
mc->default_cpu_type = SPARC_CPU_TYPE_NAME("TI-MicroSparc-I");
+ mc->default_display = "tcx";
}
static const TypeInfo scls_type = {
mc->block_default_type = IF_SCSI;
mc->default_boot_order = "c";
mc->default_cpu_type = SPARC_CPU_TYPE_NAME("TI-MicroSparc-I");
+ mc->default_display = "tcx";
}
static const TypeInfo sbook_type = {
static Property aspeed_smc_properties[] = {
DEFINE_PROP_UINT32("num-cs", AspeedSMCState, num_cs, 1),
+ DEFINE_PROP_UINT64("sdram-base", AspeedSMCState, sdram_base, 0),
DEFINE_PROP_END_OF_LIST(),
};
obj-$(CONFIG_ALLWINNER_A10_PIT) += allwinner-a10-pit.o
common-obj-$(CONFIG_STM32F2XX_TIMER) += stm32f2xx_timer.o
-common-obj-$(CONFIG_ASPEED_SOC) += aspeed_timer.o
+common-obj-$(CONFIG_ASPEED_SOC) += aspeed_timer.o aspeed_rtc.o
common-obj-$(CONFIG_SUN4V_RTC) += sun4v-rtc.o
common-obj-$(CONFIG_CMSDK_APB_TIMER) += cmsdk-apb-timer.o
}
}
-static uint64_t systick_read(void *opaque, hwaddr addr, unsigned size)
+static MemTxResult systick_read(void *opaque, hwaddr addr, uint64_t *data,
+ unsigned size, MemTxAttrs attrs)
{
SysTickState *s = opaque;
uint32_t val;
+ if (attrs.user) {
+ /* Generate BusFault for unprivileged accesses */
+ return MEMTX_ERROR;
+ }
+
switch (addr) {
case 0x0: /* SysTick Control and Status. */
val = s->control;
}
trace_systick_read(addr, val, size);
- return val;
+ *data = val;
+ return MEMTX_OK;
}
-static void systick_write(void *opaque, hwaddr addr,
- uint64_t value, unsigned size)
+static MemTxResult systick_write(void *opaque, hwaddr addr,
+ uint64_t value, unsigned size,
+ MemTxAttrs attrs)
{
SysTickState *s = opaque;
+ if (attrs.user) {
+ /* Generate BusFault for unprivileged accesses */
+ return MEMTX_ERROR;
+ }
+
trace_systick_write(addr, value, size);
switch (addr) {
qemu_log_mask(LOG_GUEST_ERROR,
"SysTick: Bad write offset 0x%" HWADDR_PRIx "\n", addr);
}
+ return MEMTX_OK;
}
static const MemoryRegionOps systick_ops = {
- .read = systick_read,
- .write = systick_write,
+ .read_with_attrs = systick_read,
+ .write_with_attrs = systick_write,
.endianness = DEVICE_NATIVE_ENDIAN,
.valid.min_access_size = 4,
.valid.max_access_size = 4,
--- /dev/null
+/*
+ * ASPEED Real Time Clock
+ * Joel Stanley <joel@jms.id.au>
+ *
+ * Copyright 2019 IBM Corp
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "qemu-common.h"
+#include "hw/timer/aspeed_rtc.h"
+#include "qemu/log.h"
+#include "qemu/timer.h"
+
+#include "trace.h"
+
+#define COUNTER1 (0x00 / 4)
+#define COUNTER2 (0x04 / 4)
+#define ALARM (0x08 / 4)
+#define CONTROL (0x10 / 4)
+#define ALARM_STATUS (0x14 / 4)
+
+#define RTC_UNLOCKED BIT(1)
+#define RTC_ENABLED BIT(0)
+
+static void aspeed_rtc_calc_offset(AspeedRtcState *rtc)
+{
+ struct tm tm;
+ uint32_t year, cent;
+ uint32_t reg1 = rtc->reg[COUNTER1];
+ uint32_t reg2 = rtc->reg[COUNTER2];
+
+ tm.tm_mday = (reg1 >> 24) & 0x1f;
+ tm.tm_hour = (reg1 >> 16) & 0x1f;
+ tm.tm_min = (reg1 >> 8) & 0x3f;
+ tm.tm_sec = (reg1 >> 0) & 0x3f;
+
+ cent = (reg2 >> 16) & 0x1f;
+ year = (reg2 >> 8) & 0x7f;
+ tm.tm_mon = ((reg2 >> 0) & 0x0f) - 1;
+ tm.tm_year = year + (cent * 100) - 1900;
+
+ rtc->offset = qemu_timedate_diff(&tm);
+}
+
+static uint32_t aspeed_rtc_get_counter(AspeedRtcState *rtc, int r)
+{
+ uint32_t year, cent;
+ struct tm now;
+
+ qemu_get_timedate(&now, rtc->offset);
+
+ switch (r) {
+ case COUNTER1:
+ return (now.tm_mday << 24) | (now.tm_hour << 16) |
+ (now.tm_min << 8) | now.tm_sec;
+ case COUNTER2:
+ cent = (now.tm_year + 1900) / 100;
+ year = now.tm_year % 100;
+ return ((cent & 0x1f) << 16) | ((year & 0x7f) << 8) |
+ ((now.tm_mon + 1) & 0xf);
+ default:
+ g_assert_not_reached();
+ }
+}
+
+static uint64_t aspeed_rtc_read(void *opaque, hwaddr addr,
+ unsigned size)
+{
+ AspeedRtcState *rtc = opaque;
+ uint64_t val;
+ uint32_t r = addr >> 2;
+
+ switch (r) {
+ case COUNTER1:
+ case COUNTER2:
+ if (rtc->reg[CONTROL] & RTC_ENABLED) {
+ rtc->reg[r] = aspeed_rtc_get_counter(rtc, r);
+ }
+ /* fall through */
+ case CONTROL:
+ val = rtc->reg[r];
+ break;
+ case ALARM:
+ case ALARM_STATUS:
+ default:
+ qemu_log_mask(LOG_UNIMP, "%s: 0x%" HWADDR_PRIx "\n", __func__, addr);
+ return 0;
+ }
+
+ trace_aspeed_rtc_read(addr, val);
+
+ return val;
+}
+
+static void aspeed_rtc_write(void *opaque, hwaddr addr,
+ uint64_t val, unsigned size)
+{
+ AspeedRtcState *rtc = opaque;
+ uint32_t r = addr >> 2;
+
+ switch (r) {
+ case COUNTER1:
+ case COUNTER2:
+ if (!(rtc->reg[CONTROL] & RTC_UNLOCKED)) {
+ break;
+ }
+ /* fall through */
+ case CONTROL:
+ rtc->reg[r] = val;
+ aspeed_rtc_calc_offset(rtc);
+ break;
+ case ALARM:
+ case ALARM_STATUS:
+ default:
+ qemu_log_mask(LOG_UNIMP, "%s: 0x%" HWADDR_PRIx "\n", __func__, addr);
+ break;
+ }
+ trace_aspeed_rtc_write(addr, val);
+}
+
+static void aspeed_rtc_reset(DeviceState *d)
+{
+ AspeedRtcState *rtc = ASPEED_RTC(d);
+
+ rtc->offset = 0;
+ memset(rtc->reg, 0, sizeof(rtc->reg));
+}
+
+static const MemoryRegionOps aspeed_rtc_ops = {
+ .read = aspeed_rtc_read,
+ .write = aspeed_rtc_write,
+ .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static const VMStateDescription vmstate_aspeed_rtc = {
+ .name = TYPE_ASPEED_RTC,
+ .version_id = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT32_ARRAY(reg, AspeedRtcState, 0x18),
+ VMSTATE_INT32(offset, AspeedRtcState),
+ VMSTATE_INT32(offset, AspeedRtcState),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static void aspeed_rtc_realize(DeviceState *dev, Error **errp)
+{
+ SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
+ AspeedRtcState *s = ASPEED_RTC(dev);
+
+ sysbus_init_irq(sbd, &s->irq);
+
+ memory_region_init_io(&s->iomem, OBJECT(s), &aspeed_rtc_ops, s,
+ "aspeed-rtc", 0x18ULL);
+ sysbus_init_mmio(sbd, &s->iomem);
+}
+
+static void aspeed_rtc_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ dc->realize = aspeed_rtc_realize;
+ dc->vmsd = &vmstate_aspeed_rtc;
+ dc->reset = aspeed_rtc_reset;
+}
+
+static const TypeInfo aspeed_rtc_info = {
+ .name = TYPE_ASPEED_RTC,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(AspeedRtcState),
+ .class_init = aspeed_rtc_class_init,
+};
+
+static void aspeed_rtc_register_types(void)
+{
+ type_register_static(&aspeed_rtc_info);
+}
+
+type_init(aspeed_rtc_register_types)
return t->start + delta_ns;
}
+static inline uint32_t calculate_match(struct AspeedTimer *t, int i)
+{
+ return t->match[i] < t->reload ? t->match[i] : 0;
+}
+
static uint64_t calculate_next(struct AspeedTimer *t)
{
- uint64_t next = 0;
- uint32_t rate = calculate_rate(t);
+ uint64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
+ uint64_t next;
- while (!next) {
- /* We don't know the relationship between the values in the match
- * registers, so sort using MAX/MIN/zero. We sort in that order as the
- * timer counts down to zero. */
- uint64_t seq[] = {
- calculate_time(t, MAX(t->match[0], t->match[1])),
- calculate_time(t, MIN(t->match[0], t->match[1])),
- calculate_time(t, 0),
- };
- uint64_t reload_ns;
- uint64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
-
- if (now < seq[0]) {
- next = seq[0];
- } else if (now < seq[1]) {
- next = seq[1];
- } else if (now < seq[2]) {
- next = seq[2];
- } else if (t->reload) {
- reload_ns = muldiv64(t->reload, NANOSECONDS_PER_SECOND, rate);
- t->start = now - ((now - t->start) % reload_ns);
- } else {
- /* no reload value, return 0 */
- break;
- }
+ /*
+ * We don't know the relationship between the values in the match
+ * registers, so sort using MAX/MIN/zero. We sort in that order as
+ * the timer counts down to zero.
+ */
+
+ next = calculate_time(t, MAX(calculate_match(t, 0), calculate_match(t, 1)));
+ if (now < next) {
+ return next;
+ }
+
+ next = calculate_time(t, MIN(calculate_match(t, 0), calculate_match(t, 1)));
+ if (now < next) {
+ return next;
}
- return next;
+ next = calculate_time(t, 0);
+ if (now < next) {
+ return next;
+ }
+
+ /* We've missed all deadlines, fire interrupt and try again */
+ timer_del(&t->timer);
+
+ if (timer_overflow_interrupt(t)) {
+ t->level = !t->level;
+ qemu_set_irq(t->irq, t->level);
+ }
+
+ next = MAX(MAX(calculate_match(t, 0), calculate_match(t, 1)), 0);
+ t->start = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
+
+ return calculate_time(t, next);
}
static void aspeed_timer_mod(AspeedTimer *t)
switch (reg) {
case TIMER_REG_STATUS:
- value = calculate_ticks(t, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL));
+ if (timer_enabled(t)) {
+ value = calculate_ticks(t, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL));
+ } else {
+ value = t->reload;
+ }
break;
case TIMER_REG_RELOAD:
value = t->reload;
int64_t delta = (int64_t) value - (int64_t) calculate_ticks(t, now);
uint32_t rate = calculate_rate(t);
- t->start += muldiv64(delta, NANOSECONDS_PER_SECOND, rate);
+ if (delta >= 0) {
+ t->start += muldiv64(delta, NANOSECONDS_PER_SECOND, rate);
+ } else {
+ t->start -= muldiv64(-delta, NANOSECONDS_PER_SECOND, rate);
+ }
aspeed_timer_mod(t);
}
break;
#include "sysemu/replay.h"
#include "hw/timer/mc146818rtc.h"
#include "qapi/error.h"
-#include "qapi/qapi-commands-target.h"
-#include "qapi/qapi-events-target.h"
+#include "qapi/qapi-commands-misc-target.h"
+#include "qapi/qapi-events-misc-target.h"
#include "qapi/visitor.h"
#include "exec/address-spaces.h"
cmsdk_apb_dualtimer_write(uint64_t offset, uint64_t data, unsigned size) "CMSDK APB dualtimer write: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u"
cmsdk_apb_dualtimer_reset(void) "CMSDK APB dualtimer: reset"
+# hw/timer/aspeed-rtc.c
+aspeed_rtc_read(uint64_t addr, uint64_t value) "addr 0x%02" PRIx64 " value 0x%08" PRIx64
+aspeed_rtc_write(uint64_t addr, uint64_t value) "addr 0x%02" PRIx64 " value 0x%08" PRIx64
+
# sun4v-rtc.c
sun4v_rtc_read(uint64_t addr, uint64_t value) "read: addr 0x%" PRIx64 " value 0x%" PRIx64
sun4v_rtc_write(uint64_t addr, uint64_t value) "write: addr 0x%" PRIx64 " value 0x%" PRIx64
* vfio based subchannel assignment support
*
* Copyright 2017 IBM Corp.
+ * Copyright 2019 Red Hat, Inc.
+ *
* Author(s): Dong Jia Shi <bjsdjshi@linux.vnet.ibm.com>
* Xiao Feng Ren <renxiaof@linux.vnet.ibm.com>
* Pierre Morel <pmorel@linux.vnet.ibm.com>
+ * Cornelia Huck <cohuck@redhat.com>
*
* This work is licensed under the terms of the GNU GPL, version 2 or (at
* your option) any later version. See the COPYING file in the top-level
uint64_t io_region_size;
uint64_t io_region_offset;
struct ccw_io_region *io_region;
+ uint64_t async_cmd_region_size;
+ uint64_t async_cmd_region_offset;
+ struct ccw_cmd_region *async_cmd_region;
EventNotifier io_notifier;
bool force_orb_pfch;
bool warned_orb_pfch;
}
}
+static int vfio_ccw_handle_clear(SubchDev *sch)
+{
+ S390CCWDevice *cdev = sch->driver_data;
+ VFIOCCWDevice *vcdev = DO_UPCAST(VFIOCCWDevice, cdev, cdev);
+ struct ccw_cmd_region *region = vcdev->async_cmd_region;
+ int ret;
+
+ if (!vcdev->async_cmd_region) {
+ /* Async command region not available, fall back to emulation */
+ return -ENOSYS;
+ }
+
+ memset(region, 0, sizeof(*region));
+ region->command = VFIO_CCW_ASYNC_CMD_CSCH;
+
+again:
+ ret = pwrite(vcdev->vdev.fd, region,
+ vcdev->async_cmd_region_size, vcdev->async_cmd_region_offset);
+ if (ret != vcdev->async_cmd_region_size) {
+ if (errno == EAGAIN) {
+ goto again;
+ }
+ error_report("vfio-ccw: write cmd region failed with errno=%d", errno);
+ ret = -errno;
+ } else {
+ ret = region->ret_code;
+ }
+ switch (ret) {
+ case 0:
+ case -ENODEV:
+ case -EACCES:
+ return 0;
+ case -EFAULT:
+ default:
+ sch_gen_unit_exception(sch);
+ css_inject_io_interrupt(sch);
+ return 0;
+ }
+}
+
+static int vfio_ccw_handle_halt(SubchDev *sch)
+{
+ S390CCWDevice *cdev = sch->driver_data;
+ VFIOCCWDevice *vcdev = DO_UPCAST(VFIOCCWDevice, cdev, cdev);
+ struct ccw_cmd_region *region = vcdev->async_cmd_region;
+ int ret;
+
+ if (!vcdev->async_cmd_region) {
+ /* Async command region not available, fall back to emulation */
+ return -ENOSYS;
+ }
+
+ memset(region, 0, sizeof(*region));
+ region->command = VFIO_CCW_ASYNC_CMD_HSCH;
+
+again:
+ ret = pwrite(vcdev->vdev.fd, region,
+ vcdev->async_cmd_region_size, vcdev->async_cmd_region_offset);
+ if (ret != vcdev->async_cmd_region_size) {
+ if (errno == EAGAIN) {
+ goto again;
+ }
+ error_report("vfio-ccw: write cmd region failed with errno=%d", errno);
+ ret = -errno;
+ } else {
+ ret = region->ret_code;
+ }
+ switch (ret) {
+ case 0:
+ case -EBUSY:
+ case -ENODEV:
+ case -EACCES:
+ return 0;
+ case -EFAULT:
+ default:
+ sch_gen_unit_exception(sch);
+ css_inject_io_interrupt(sch);
+ return 0;
+ }
+}
+
static void vfio_ccw_reset(DeviceState *dev)
{
CcwDevice *ccw_dev = DO_UPCAST(CcwDevice, parent_obj, dev);
{
VFIODevice *vdev = &vcdev->vdev;
struct vfio_irq_info *irq_info;
- struct vfio_irq_set *irq_set;
size_t argsz;
- int32_t *pfd;
+ int fd;
if (vdev->num_irqs < VFIO_CCW_IO_IRQ_INDEX + 1) {
error_setg(errp, "vfio: unexpected number of io irqs %u",
goto out_free_info;
}
- argsz = sizeof(*irq_set) + sizeof(*pfd);
- irq_set = g_malloc0(argsz);
- irq_set->argsz = argsz;
- irq_set->flags = VFIO_IRQ_SET_DATA_EVENTFD |
- VFIO_IRQ_SET_ACTION_TRIGGER;
- irq_set->index = VFIO_CCW_IO_IRQ_INDEX;
- irq_set->start = 0;
- irq_set->count = 1;
- pfd = (int32_t *) &irq_set->data;
-
- *pfd = event_notifier_get_fd(&vcdev->io_notifier);
- qemu_set_fd_handler(*pfd, vfio_ccw_io_notifier_handler, NULL, vcdev);
- if (ioctl(vdev->fd, VFIO_DEVICE_SET_IRQS, irq_set)) {
- error_setg(errp, "vfio: Failed to set up io notification");
- qemu_set_fd_handler(*pfd, NULL, NULL, vcdev);
+ fd = event_notifier_get_fd(&vcdev->io_notifier);
+ qemu_set_fd_handler(fd, vfio_ccw_io_notifier_handler, NULL, vcdev);
+
+ if (vfio_set_irq_signaling(vdev, VFIO_CCW_IO_IRQ_INDEX, 0,
+ VFIO_IRQ_SET_ACTION_TRIGGER, fd, errp)) {
+ qemu_set_fd_handler(fd, NULL, NULL, vcdev);
event_notifier_cleanup(&vcdev->io_notifier);
}
- g_free(irq_set);
-
out_free_info:
g_free(irq_info);
}
static void vfio_ccw_unregister_io_notifier(VFIOCCWDevice *vcdev)
{
- struct vfio_irq_set *irq_set;
- size_t argsz;
- int32_t *pfd;
-
- argsz = sizeof(*irq_set) + sizeof(*pfd);
- irq_set = g_malloc0(argsz);
- irq_set->argsz = argsz;
- irq_set->flags = VFIO_IRQ_SET_DATA_EVENTFD |
- VFIO_IRQ_SET_ACTION_TRIGGER;
- irq_set->index = VFIO_CCW_IO_IRQ_INDEX;
- irq_set->start = 0;
- irq_set->count = 1;
- pfd = (int32_t *) &irq_set->data;
- *pfd = -1;
+ Error *err = NULL;
- if (ioctl(vcdev->vdev.fd, VFIO_DEVICE_SET_IRQS, irq_set)) {
- error_report("vfio: Failed to de-assign device io fd: %m");
+ vfio_set_irq_signaling(&vcdev->vdev, VFIO_CCW_IO_IRQ_INDEX, 0,
+ VFIO_IRQ_SET_ACTION_TRIGGER, -1, &err);
+ if (err) {
+ error_reportf_err(err, VFIO_MSG_PREFIX, vcdev->vdev.name);
}
qemu_set_fd_handler(event_notifier_get_fd(&vcdev->io_notifier),
NULL, NULL, vcdev);
event_notifier_cleanup(&vcdev->io_notifier);
-
- g_free(irq_set);
}
static void vfio_ccw_get_region(VFIOCCWDevice *vcdev, Error **errp)
return;
}
+ /*
+ * We always expect at least the I/O region to be present. We also
+ * may have a variable number of regions governed by capabilities.
+ */
if (vdev->num_regions < VFIO_CCW_CONFIG_REGION_INDEX + 1) {
- error_setg(errp, "vfio: Unexpected number of the I/O region %u",
- vdev->num_regions);
+ error_setg(errp, "vfio: too few regions (%u), expected at least %u",
+ vdev->num_regions, VFIO_CCW_CONFIG_REGION_INDEX + 1);
return;
}
vcdev->io_region_offset = info->offset;
vcdev->io_region = g_malloc0(info->size);
+ /* check for the optional async command region */
+ ret = vfio_get_dev_region_info(vdev, VFIO_REGION_TYPE_CCW,
+ VFIO_REGION_SUBTYPE_CCW_ASYNC_CMD, &info);
+ if (!ret) {
+ vcdev->async_cmd_region_size = info->size;
+ if (sizeof(*vcdev->async_cmd_region) != vcdev->async_cmd_region_size) {
+ error_setg(errp, "vfio: Unexpected size of the async cmd region");
+ g_free(vcdev->io_region);
+ g_free(info);
+ return;
+ }
+ vcdev->async_cmd_region_offset = info->offset;
+ vcdev->async_cmd_region = g_malloc0(info->size);
+ }
+
g_free(info);
}
static void vfio_ccw_put_region(VFIOCCWDevice *vcdev)
{
+ g_free(vcdev->async_cmd_region);
g_free(vcdev->io_region);
}
dc->reset = vfio_ccw_reset;
cdc->handle_request = vfio_ccw_handle_request;
+ cdc->handle_halt = vfio_ccw_handle_halt;
+ cdc->handle_clear = vfio_ccw_handle_clear;
}
static const TypeInfo vfio_ccw_info = {
*/
if (vector->virq >= 0) {
int32_t fd = event_notifier_get_fd(&vector->interrupt);
+ Error *err = NULL;
- vfio_set_irq_signaling(&vdev->vbasedev, VFIO_PCI_MSIX_IRQ_INDEX, nr,
- VFIO_IRQ_SET_ACTION_TRIGGER, fd, NULL);
+ if (vfio_set_irq_signaling(&vdev->vbasedev, VFIO_PCI_MSIX_IRQ_INDEX, nr,
+ VFIO_IRQ_SET_ACTION_TRIGGER, fd, &err)) {
+ error_reportf_err(err, VFIO_MSG_PREFIX, vdev->vbasedev.name);
+ }
}
}
bool
default y
depends on VIRTIO
+
+config VIRTIO_PMEM_SUPPORTED
+ bool
+
+config VIRTIO_PMEM
+ bool
+ default y
+ depends on VIRTIO
+ depends on VIRTIO_PMEM_SUPPORTED
+ select MEM_DEVICE
obj-$(CONFIG_VIRTIO_BALLOON) += virtio-balloon.o
obj-$(CONFIG_VIRTIO_CRYPTO) += virtio-crypto.o
obj-$(call land,$(CONFIG_VIRTIO_CRYPTO),$(CONFIG_VIRTIO_PCI)) += virtio-crypto-pci.o
+obj-$(CONFIG_VIRTIO_PMEM) += virtio-pmem.o
+common-obj-$(call land,$(CONFIG_VIRTIO_PMEM),$(CONFIG_VIRTIO_PCI)) += virtio-pmem-pci.o
obj-$(CONFIG_VHOST_VSOCK) += vhost-vsock.o
ifeq ($(CONFIG_VIRTIO_PCI),y)
dc->props = virtio_pci_generic_properties;
}
-/* Used when the generic type and the base type is the same */
-static void virtio_pci_generic_base_class_init(ObjectClass *klass, void *data)
-{
- virtio_pci_base_class_init(klass, data);
- virtio_pci_generic_class_init(klass, NULL);
-}
-
static void virtio_pci_transitional_instance_init(Object *obj)
{
VirtIOPCIProxy *proxy = VIRTIO_PCI(obj);
void virtio_pci_types_register(const VirtioPCIDeviceTypeInfo *t)
{
+ char *base_name = NULL;
TypeInfo base_type_info = {
.name = t->base_name,
.parent = t->parent ? t->parent : TYPE_VIRTIO_PCI,
.instance_size = t->instance_size,
.instance_init = t->instance_init,
.class_size = t->class_size,
- .class_init = virtio_pci_base_class_init,
- .class_data = (void *)t,
.abstract = true,
+ .interfaces = t->interfaces,
};
TypeInfo generic_type_info = {
.name = t->generic_name,
if (!base_type_info.name) {
/* No base type -> register a single generic device type */
- base_type_info.name = t->generic_name;
- base_type_info.class_init = virtio_pci_generic_base_class_init;
- base_type_info.interfaces = generic_type_info.interfaces;
- base_type_info.abstract = false;
- generic_type_info.name = NULL;
+ /* use intermediate %s-base-type to add generic device props */
+ base_name = g_strdup_printf("%s-base-type", t->generic_name);
+ base_type_info.name = base_name;
+ base_type_info.class_init = virtio_pci_generic_class_init;
+
+ generic_type_info.parent = base_name;
+ generic_type_info.class_init = virtio_pci_base_class_init;
+ generic_type_info.class_data = (void *)t;
+
assert(!t->non_transitional_name);
assert(!t->transitional_name);
+ } else {
+ base_type_info.class_init = virtio_pci_base_class_init;
+ base_type_info.class_data = (void *)t;
}
type_register(&base_type_info);
};
type_register(&transitional_type_info);
}
+ g_free(base_name);
}
/* virtio-pci-bus */
size_t class_size;
void (*instance_init)(Object *obj);
void (*class_init)(ObjectClass *klass, void *data);
+ InterfaceInfo *interfaces;
} VirtioPCIDeviceTypeInfo;
/* Register virtio-pci type(s). @t must be static. */
--- /dev/null
+/*
+ * Virtio PMEM PCI device
+ *
+ * Copyright (C) 2018-2019 Red Hat, Inc.
+ *
+ * Authors:
+ * Pankaj Gupta <pagupta@redhat.com>
+ * David Hildenbrand <david@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include "qemu/osdep.h"
+
+#include "virtio-pmem-pci.h"
+#include "hw/mem/memory-device.h"
+#include "qapi/error.h"
+
+static void virtio_pmem_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
+{
+ VirtIOPMEMPCI *pmem_pci = VIRTIO_PMEM_PCI(vpci_dev);
+ DeviceState *vdev = DEVICE(&pmem_pci->vdev);
+
+ qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
+ object_property_set_bool(OBJECT(vdev), true, "realized", errp);
+}
+
+static void virtio_pmem_pci_set_addr(MemoryDeviceState *md, uint64_t addr,
+ Error **errp)
+{
+ object_property_set_uint(OBJECT(md), addr, VIRTIO_PMEM_ADDR_PROP, errp);
+}
+
+static uint64_t virtio_pmem_pci_get_addr(const MemoryDeviceState *md)
+{
+ return object_property_get_uint(OBJECT(md), VIRTIO_PMEM_ADDR_PROP,
+ &error_abort);
+}
+
+static MemoryRegion *virtio_pmem_pci_get_memory_region(MemoryDeviceState *md,
+ Error **errp)
+{
+ VirtIOPMEMPCI *pci_pmem = VIRTIO_PMEM_PCI(md);
+ VirtIOPMEM *pmem = VIRTIO_PMEM(&pci_pmem->vdev);
+ VirtIOPMEMClass *vpc = VIRTIO_PMEM_GET_CLASS(pmem);
+
+ return vpc->get_memory_region(pmem, errp);
+}
+
+static uint64_t virtio_pmem_pci_get_plugged_size(const MemoryDeviceState *md,
+ Error **errp)
+{
+ VirtIOPMEMPCI *pci_pmem = VIRTIO_PMEM_PCI(md);
+ VirtIOPMEM *pmem = VIRTIO_PMEM(&pci_pmem->vdev);
+ VirtIOPMEMClass *vpc = VIRTIO_PMEM_GET_CLASS(pmem);
+ MemoryRegion *mr = vpc->get_memory_region(pmem, errp);
+
+ /* the plugged size corresponds to the region size */
+ return mr ? 0 : memory_region_size(mr);
+}
+
+static void virtio_pmem_pci_fill_device_info(const MemoryDeviceState *md,
+ MemoryDeviceInfo *info)
+{
+ VirtioPMEMDeviceInfo *vi = g_new0(VirtioPMEMDeviceInfo, 1);
+ VirtIOPMEMPCI *pci_pmem = VIRTIO_PMEM_PCI(md);
+ VirtIOPMEM *pmem = VIRTIO_PMEM(&pci_pmem->vdev);
+ VirtIOPMEMClass *vpc = VIRTIO_PMEM_GET_CLASS(pmem);
+ DeviceState *dev = DEVICE(md);
+
+ if (dev->id) {
+ vi->has_id = true;
+ vi->id = g_strdup(dev->id);
+ }
+
+ /* let the real device handle everything else */
+ vpc->fill_device_info(pmem, vi);
+
+ info->u.virtio_pmem.data = vi;
+ info->type = MEMORY_DEVICE_INFO_KIND_VIRTIO_PMEM;
+}
+
+static void virtio_pmem_pci_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
+ PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
+ MemoryDeviceClass *mdc = MEMORY_DEVICE_CLASS(klass);
+
+ k->realize = virtio_pmem_pci_realize;
+ set_bit(DEVICE_CATEGORY_MISC, dc->categories);
+ pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
+ pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_PMEM;
+ pcidev_k->revision = VIRTIO_PCI_ABI_VERSION;
+ pcidev_k->class_id = PCI_CLASS_OTHERS;
+
+ mdc->get_addr = virtio_pmem_pci_get_addr;
+ mdc->set_addr = virtio_pmem_pci_set_addr;
+ mdc->get_plugged_size = virtio_pmem_pci_get_plugged_size;
+ mdc->get_memory_region = virtio_pmem_pci_get_memory_region;
+ mdc->fill_device_info = virtio_pmem_pci_fill_device_info;
+}
+
+static void virtio_pmem_pci_instance_init(Object *obj)
+{
+ VirtIOPMEMPCI *dev = VIRTIO_PMEM_PCI(obj);
+
+ virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
+ TYPE_VIRTIO_PMEM);
+}
+
+static const VirtioPCIDeviceTypeInfo virtio_pmem_pci_info = {
+ .base_name = TYPE_VIRTIO_PMEM_PCI,
+ .generic_name = "virtio-pmem-pci",
+ .transitional_name = "virtio-pmem-pci-transitional",
+ .non_transitional_name = "virtio-pmem-pci-non-transitional",
+ .instance_size = sizeof(VirtIOPMEMPCI),
+ .instance_init = virtio_pmem_pci_instance_init,
+ .class_init = virtio_pmem_pci_class_init,
+ .interfaces = (InterfaceInfo[]) {
+ { TYPE_MEMORY_DEVICE },
+ { }
+ },
+};
+
+static void virtio_pmem_pci_register_types(void)
+{
+ virtio_pci_types_register(&virtio_pmem_pci_info);
+}
+type_init(virtio_pmem_pci_register_types)
--- /dev/null
+/*
+ * Virtio PMEM PCI device
+ *
+ * Copyright (C) 2018-2019 Red Hat, Inc.
+ *
+ * Authors:
+ * Pankaj Gupta <pagupta@redhat.com>
+ * David Hildenbrand <david@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.
+ * See the COPYING file in the top-level directory.
+ */
+
+#ifndef QEMU_VIRTIO_PMEM_PCI_H
+#define QEMU_VIRTIO_PMEM_PCI_H
+
+#include "hw/virtio/virtio-pci.h"
+#include "hw/virtio/virtio-pmem.h"
+
+typedef struct VirtIOPMEMPCI VirtIOPMEMPCI;
+
+/*
+ * virtio-pmem-pci: This extends VirtioPCIProxy.
+ */
+#define TYPE_VIRTIO_PMEM_PCI "virtio-pmem-pci-base"
+#define VIRTIO_PMEM_PCI(obj) \
+ OBJECT_CHECK(VirtIOPMEMPCI, (obj), TYPE_VIRTIO_PMEM_PCI)
+
+struct VirtIOPMEMPCI {
+ VirtIOPCIProxy parent_obj;
+ VirtIOPMEM vdev;
+};
+
+#endif /* QEMU_VIRTIO_PMEM_PCI_H */
--- /dev/null
+/*
+ * Virtio PMEM device
+ *
+ * Copyright (C) 2018-2019 Red Hat, Inc.
+ *
+ * Authors:
+ * Pankaj Gupta <pagupta@redhat.com>
+ * David Hildenbrand <david@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include "qemu/osdep.h"
+#include "qapi/error.h"
+#include "qemu-common.h"
+#include "qemu/error-report.h"
+#include "hw/virtio/virtio-pmem.h"
+#include "hw/virtio/virtio-access.h"
+#include "standard-headers/linux/virtio_ids.h"
+#include "standard-headers/linux/virtio_pmem.h"
+#include "block/aio.h"
+#include "block/thread-pool.h"
+
+typedef struct VirtIODeviceRequest {
+ VirtQueueElement elem;
+ int fd;
+ VirtIOPMEM *pmem;
+ VirtIODevice *vdev;
+ struct virtio_pmem_req req;
+ struct virtio_pmem_resp resp;
+} VirtIODeviceRequest;
+
+static int worker_cb(void *opaque)
+{
+ VirtIODeviceRequest *req_data = opaque;
+ int err = 0;
+
+ /* flush raw backing image */
+ err = fsync(req_data->fd);
+ if (err != 0) {
+ err = 1;
+ }
+
+ virtio_stw_p(req_data->vdev, &req_data->resp.ret, err);
+
+ return 0;
+}
+
+static void done_cb(void *opaque, int ret)
+{
+ VirtIODeviceRequest *req_data = opaque;
+ int len = iov_from_buf(req_data->elem.in_sg, req_data->elem.in_num, 0,
+ &req_data->resp, sizeof(struct virtio_pmem_resp));
+
+ /* Callbacks are serialized, so no need to use atomic ops. */
+ virtqueue_push(req_data->pmem->rq_vq, &req_data->elem, len);
+ virtio_notify((VirtIODevice *)req_data->pmem, req_data->pmem->rq_vq);
+ g_free(req_data);
+}
+
+static void virtio_pmem_flush(VirtIODevice *vdev, VirtQueue *vq)
+{
+ VirtIODeviceRequest *req_data;
+ VirtIOPMEM *pmem = VIRTIO_PMEM(vdev);
+ HostMemoryBackend *backend = MEMORY_BACKEND(pmem->memdev);
+ ThreadPool *pool = aio_get_thread_pool(qemu_get_aio_context());
+
+ req_data = virtqueue_pop(vq, sizeof(VirtIODeviceRequest));
+ if (!req_data) {
+ virtio_error(vdev, "virtio-pmem missing request data");
+ return;
+ }
+
+ if (req_data->elem.out_num < 1 || req_data->elem.in_num < 1) {
+ virtio_error(vdev, "virtio-pmem request not proper");
+ g_free(req_data);
+ return;
+ }
+ req_data->fd = memory_region_get_fd(&backend->mr);
+ req_data->pmem = pmem;
+ req_data->vdev = vdev;
+ thread_pool_submit_aio(pool, worker_cb, req_data, done_cb, req_data);
+}
+
+static void virtio_pmem_get_config(VirtIODevice *vdev, uint8_t *config)
+{
+ VirtIOPMEM *pmem = VIRTIO_PMEM(vdev);
+ struct virtio_pmem_config *pmemcfg = (struct virtio_pmem_config *) config;
+
+ virtio_stq_p(vdev, &pmemcfg->start, pmem->start);
+ virtio_stq_p(vdev, &pmemcfg->size, memory_region_size(&pmem->memdev->mr));
+}
+
+static uint64_t virtio_pmem_get_features(VirtIODevice *vdev, uint64_t features,
+ Error **errp)
+{
+ return features;
+}
+
+static void virtio_pmem_realize(DeviceState *dev, Error **errp)
+{
+ VirtIODevice *vdev = VIRTIO_DEVICE(dev);
+ VirtIOPMEM *pmem = VIRTIO_PMEM(dev);
+
+ if (!pmem->memdev) {
+ error_setg(errp, "virtio-pmem memdev not set");
+ return;
+ }
+
+ if (host_memory_backend_is_mapped(pmem->memdev)) {
+ char *path = object_get_canonical_path_component(OBJECT(pmem->memdev));
+ error_setg(errp, "can't use already busy memdev: %s", path);
+ g_free(path);
+ return;
+ }
+
+ host_memory_backend_set_mapped(pmem->memdev, true);
+ virtio_init(vdev, TYPE_VIRTIO_PMEM, VIRTIO_ID_PMEM,
+ sizeof(struct virtio_pmem_config));
+ pmem->rq_vq = virtio_add_queue(vdev, 128, virtio_pmem_flush);
+}
+
+static void virtio_pmem_unrealize(DeviceState *dev, Error **errp)
+{
+ VirtIODevice *vdev = VIRTIO_DEVICE(dev);
+ VirtIOPMEM *pmem = VIRTIO_PMEM(dev);
+
+ host_memory_backend_set_mapped(pmem->memdev, false);
+ virtio_cleanup(vdev);
+}
+
+static void virtio_pmem_fill_device_info(const VirtIOPMEM *pmem,
+ VirtioPMEMDeviceInfo *vi)
+{
+ vi->memaddr = pmem->start;
+ vi->size = pmem->memdev ? memory_region_size(&pmem->memdev->mr) : 0;
+ vi->memdev = object_get_canonical_path(OBJECT(pmem->memdev));
+}
+
+static MemoryRegion *virtio_pmem_get_memory_region(VirtIOPMEM *pmem,
+ Error **errp)
+{
+ if (!pmem->memdev) {
+ error_setg(errp, "'%s' property must be set", VIRTIO_PMEM_MEMDEV_PROP);
+ return NULL;
+ }
+
+ return &pmem->memdev->mr;
+}
+
+static Property virtio_pmem_properties[] = {
+ DEFINE_PROP_UINT64(VIRTIO_PMEM_ADDR_PROP, VirtIOPMEM, start, 0),
+ DEFINE_PROP_LINK(VIRTIO_PMEM_MEMDEV_PROP, VirtIOPMEM, memdev,
+ TYPE_MEMORY_BACKEND, HostMemoryBackend *),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void virtio_pmem_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
+ VirtIOPMEMClass *vpc = VIRTIO_PMEM_CLASS(klass);
+
+ dc->props = virtio_pmem_properties;
+
+ vdc->realize = virtio_pmem_realize;
+ vdc->unrealize = virtio_pmem_unrealize;
+ vdc->get_config = virtio_pmem_get_config;
+ vdc->get_features = virtio_pmem_get_features;
+
+ vpc->fill_device_info = virtio_pmem_fill_device_info;
+ vpc->get_memory_region = virtio_pmem_get_memory_region;
+}
+
+static TypeInfo virtio_pmem_info = {
+ .name = TYPE_VIRTIO_PMEM,
+ .parent = TYPE_VIRTIO_DEVICE,
+ .class_size = sizeof(VirtIOPMEMClass),
+ .class_init = virtio_pmem_class_init,
+ .instance_size = sizeof(VirtIOPMEM),
+};
+
+static void virtio_register_types(void)
+{
+ type_register_static(&virtio_pmem_info);
+}
+
+type_init(virtio_register_types)
}
}
}
- vdev->started = val & VIRTIO_CONFIG_S_DRIVER_OK;
- if (unlikely(vdev->start_on_kick && vdev->started)) {
- vdev->start_on_kick = false;
+
+ if ((vdev->status & VIRTIO_CONFIG_S_DRIVER_OK) !=
+ (val & VIRTIO_CONFIG_S_DRIVER_OK)) {
+ virtio_set_started(vdev, val & VIRTIO_CONFIG_S_DRIVER_OK);
}
if (k->set_status) {
k->reset(vdev);
}
- vdev->start_on_kick = (virtio_host_has_feature(vdev, VIRTIO_F_VERSION_1) &&
- !virtio_vdev_has_feature(vdev, VIRTIO_F_VERSION_1));
+ vdev->start_on_kick = false;
vdev->started = false;
vdev->broken = false;
vdev->guest_features = 0;
ret = vq->handle_aio_output(vdev, vq);
if (unlikely(vdev->start_on_kick)) {
- vdev->started = true;
- vdev->start_on_kick = false;
+ virtio_set_started(vdev, true);
}
}
vq->handle_output(vdev, vq);
if (unlikely(vdev->start_on_kick)) {
- vdev->started = true;
- vdev->start_on_kick = false;
+ virtio_set_started(vdev, true);
}
}
}
event_notifier_set(&vq->host_notifier);
} else if (vq->handle_output) {
vq->handle_output(vdev, vq);
- }
- if (unlikely(vdev->start_on_kick)) {
- vdev->started = true;
- vdev->start_on_kick = false;
+ if (unlikely(vdev->start_on_kick)) {
+ virtio_set_started(vdev, true);
+ }
}
}
return -EINVAL;
}
ret = virtio_set_features_nocheck(vdev, val);
- if (!ret && virtio_vdev_has_feature(vdev, VIRTIO_RING_F_EVENT_IDX)) {
- /* VIRTIO_RING_F_EVENT_IDX changes the size of the caches. */
- int i;
- for (i = 0; i < VIRTIO_QUEUE_MAX; i++) {
- if (vdev->vq[i].vring.num != 0) {
- virtio_init_region_cache(vdev, i);
+ if (!ret) {
+ if (virtio_vdev_has_feature(vdev, VIRTIO_RING_F_EVENT_IDX)) {
+ /* VIRTIO_RING_F_EVENT_IDX changes the size of the caches. */
+ int i;
+ for (i = 0; i < VIRTIO_QUEUE_MAX; i++) {
+ if (vdev->vq[i].vring.num != 0) {
+ virtio_init_region_cache(vdev, i);
+ }
}
}
+
+ if (!virtio_device_started(vdev, vdev->status) &&
+ !virtio_vdev_has_feature(vdev, VIRTIO_F_VERSION_1)) {
+ vdev->start_on_kick = true;
+ }
}
return ret;
}
}
}
+ if (!virtio_device_started(vdev, vdev->status) &&
+ !virtio_vdev_has_feature(vdev, VIRTIO_F_VERSION_1)) {
+ vdev->start_on_kick = true;
+ }
+
rcu_read_lock();
for (i = 0; i < num; i++) {
if (vdev->vq[i].vring.desc) {
VirtIODevice *vdev = opaque;
BusState *qbus = qdev_get_parent_bus(DEVICE(vdev));
VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus);
- bool backend_run = running && vdev->started;
+ bool backend_run = running && virtio_device_started(vdev, vdev->status);
vdev->vm_running = running;
if (backend_run) {
g_malloc0(sizeof(*vdev->vector_queues) * nvectors);
}
- vdev->start_on_kick = (virtio_host_has_feature(vdev, VIRTIO_F_VERSION_1) &&
- !virtio_vdev_has_feature(vdev, VIRTIO_F_VERSION_1));
+ vdev->start_on_kick = false;
vdev->started = false;
vdev->device_id = device_id;
vdev->status = 0;
static Property virtio_properties[] = {
DEFINE_VIRTIO_COMMON_FEATURES(VirtIODevice, host_features),
+ DEFINE_PROP_BOOL("use-started", VirtIODevice, use_started, true),
DEFINE_PROP_END_OF_LIST(),
};
#define WDT_RESTART_MAGIC 0x4755
+#define SCU_RESET_CONTROL1 (0x04 / 4)
+#define SCU_RESET_SDRAM BIT(0)
+
static bool aspeed_wdt_is_enabled(const AspeedWDTState *s)
{
return s->regs[WDT_CTRL] & WDT_CTRL_ENABLE;
{
AspeedWDTState *s = ASPEED_WDT(dev);
+ /* Do not reset on SDRAM controller reset */
+ if (s->scu->regs[SCU_RESET_CONTROL1] & SCU_RESET_SDRAM) {
+ timer_del(s->timer);
+ s->regs[WDT_CTRL] = 0;
+ return;
+ }
+
qemu_log_mask(CPU_LOG_RESET, "Watchdog timer expired.\n");
watchdog_perform_action();
timer_del(s->timer);
{
SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
AspeedWDTState *s = ASPEED_WDT(dev);
+ Error *err = NULL;
+ Object *obj;
+
+ obj = object_property_get_link(OBJECT(dev), "scu", &err);
+ if (!obj) {
+ error_propagate(errp, err);
+ error_prepend(errp, "required link 'scu' not found: ");
+ return;
+ }
+ s->scu = ASPEED_SCU(obj);
if (!is_supported_silicon_rev(s->silicon_rev)) {
error_setg(errp, "Unknown silicon revision: 0x%" PRIx32,
int bdrv_is_allocated(BlockDriverState *bs, int64_t offset, int64_t bytes,
int64_t *pnum);
int bdrv_is_allocated_above(BlockDriverState *top, BlockDriverState *base,
- int64_t offset, int64_t bytes, int64_t *pnum);
+ bool include_base, int64_t offset, int64_t bytes,
+ int64_t *pnum);
bool bdrv_is_read_only(BlockDriverState *bs);
int bdrv_can_set_read_only(BlockDriverState *bs, bool read_only,
*/
void address_space_destroy(AddressSpace *as);
+/**
+ * address_space_remove_listeners: unregister all listeners of an address space
+ *
+ * Removes all callbacks previously registered with memory_listener_register()
+ * for @as.
+ *
+ * @as: an initialized #AddressSpace
+ */
+void address_space_remove_listeners(AddressSpace *as);
+
/**
* address_space_rw: read from or write to an address space.
*
#include "hw/intc/aspeed_vic.h"
#include "hw/misc/aspeed_scu.h"
#include "hw/misc/aspeed_sdmc.h"
+#include "hw/misc/aspeed_xdma.h"
#include "hw/timer/aspeed_timer.h"
+#include "hw/timer/aspeed_rtc.h"
#include "hw/i2c/aspeed_i2c.h"
#include "hw/ssi/aspeed_smc.h"
#include "hw/watchdog/wdt_aspeed.h"
#define ASPEED_SPIS_NUM 2
#define ASPEED_WDTS_NUM 3
+#define ASPEED_CPUS_NUM 2
+#define ASPEED_MACS_NUM 2
typedef struct AspeedSoCState {
/*< private >*/
DeviceState parent;
/*< public >*/
- ARMCPU cpu;
+ ARMCPU cpu[ASPEED_CPUS_NUM];
+ uint32_t num_cpus;
MemoryRegion sram;
AspeedVICState vic;
+ AspeedRtcState rtc;
AspeedTimerCtrlState timerctrl;
AspeedI2CState i2c;
AspeedSCUState scu;
+ AspeedXDMAState xdma;
AspeedSMCState fmc;
AspeedSMCState spi[ASPEED_SPIS_NUM];
AspeedSDMCState sdmc;
AspeedWDTState wdt[ASPEED_WDTS_NUM];
- FTGMAC100State ftgmac100;
+ FTGMAC100State ftgmac100[ASPEED_MACS_NUM];
} AspeedSoCState;
#define TYPE_ASPEED_SOC "aspeed-soc"
const char *name;
const char *cpu_type;
uint32_t silicon_rev;
- hwaddr sdram_base;
uint64_t sram_size;
int spis_num;
- const hwaddr *spi_bases;
const char *fmc_typename;
const char **spi_typename;
int wdts_num;
+ const int *irqmap;
+ const hwaddr *memmap;
+ uint32_t num_cpus;
} AspeedSoCInfo;
typedef struct AspeedSoCClass {
#define ASPEED_SOC_GET_CLASS(obj) \
OBJECT_GET_CLASS(AspeedSoCClass, (obj), TYPE_ASPEED_SOC)
+enum {
+ ASPEED_IOMEM,
+ ASPEED_UART1,
+ ASPEED_UART2,
+ ASPEED_UART3,
+ ASPEED_UART4,
+ ASPEED_UART5,
+ ASPEED_VUART,
+ ASPEED_FMC,
+ ASPEED_SPI1,
+ ASPEED_SPI2,
+ ASPEED_VIC,
+ ASPEED_SDMC,
+ ASPEED_SCU,
+ ASPEED_ADC,
+ ASPEED_SRAM,
+ ASPEED_GPIO,
+ ASPEED_RTC,
+ ASPEED_TIMER1,
+ ASPEED_TIMER2,
+ ASPEED_TIMER3,
+ ASPEED_TIMER4,
+ ASPEED_TIMER5,
+ ASPEED_TIMER6,
+ ASPEED_TIMER7,
+ ASPEED_TIMER8,
+ ASPEED_WDT,
+ ASPEED_PWM,
+ ASPEED_LPC,
+ ASPEED_IBT,
+ ASPEED_I2C,
+ ASPEED_ETH1,
+ ASPEED_ETH2,
+ ASPEED_SDRAM,
+ ASPEED_XDMA,
+};
+
#endif /* ASPEED_SOC_H */
FSL_IMX7_ADC2_ADDR = 0x30620000,
FSL_IMX7_ADCn_SIZE = 0x1000,
+ FSL_IMX7_PCIE_PHY_ADDR = 0x306D0000,
+ FSL_IMX7_PCIE_PHY_SIZE = 0x10000,
+
FSL_IMX7_GPC_ADDR = 0x303A0000,
FSL_IMX7_I2C1_ADDR = 0x30A20000,
FSL_IMX7_PCIE_REG_SIZE = 16 * 1024,
FSL_IMX7_GPR_ADDR = 0x30340000,
+
+ FSL_IMX7_DMA_APBH_ADDR = 0x33000000,
+ FSL_IMX7_DMA_APBH_SIZE = 0x2000,
};
enum FslIMX7IRQs {
FSL_IMX7_USB2_IRQ = 42,
FSL_IMX7_USB3_IRQ = 40,
- FSL_IMX7_PCI_INTA_IRQ = 122,
- FSL_IMX7_PCI_INTB_IRQ = 123,
- FSL_IMX7_PCI_INTC_IRQ = 124,
- FSL_IMX7_PCI_INTD_IRQ = 125,
+ FSL_IMX7_PCI_INTA_IRQ = 125,
+ FSL_IMX7_PCI_INTB_IRQ = 124,
+ FSL_IMX7_PCI_INTC_IRQ = 123,
+ FSL_IMX7_PCI_INTD_IRQ = 122,
FSL_IMX7_UART7_IRQ = 126,
#include "sysemu/blockdev.h"
#include "sysemu/accel.h"
#include "hw/qdev.h"
+#include "qapi/qapi-types-machine.h"
#include "qemu/module.h"
#include "qom/object.h"
#include "qom/cpu.h"
--- /dev/null
+#ifndef BITBANG_I2C_H
+#define BITBANG_I2C_H
+
+#include "hw/i2c/i2c.h"
+
+typedef struct bitbang_i2c_interface bitbang_i2c_interface;
+
+#define BITBANG_I2C_SDA 0
+#define BITBANG_I2C_SCL 1
+
+typedef enum bitbang_i2c_state {
+ STOPPED = 0,
+ SENDING_BIT7,
+ SENDING_BIT6,
+ SENDING_BIT5,
+ SENDING_BIT4,
+ SENDING_BIT3,
+ SENDING_BIT2,
+ SENDING_BIT1,
+ SENDING_BIT0,
+ WAITING_FOR_ACK,
+ RECEIVING_BIT7,
+ RECEIVING_BIT6,
+ RECEIVING_BIT5,
+ RECEIVING_BIT4,
+ RECEIVING_BIT3,
+ RECEIVING_BIT2,
+ RECEIVING_BIT1,
+ RECEIVING_BIT0,
+ SENDING_ACK,
+ SENT_NACK
+} bitbang_i2c_state;
+
+struct bitbang_i2c_interface {
+ I2CBus *bus;
+ bitbang_i2c_state state;
+ int last_data;
+ int last_clock;
+ int device_out;
+ uint8_t buffer;
+ int current_addr;
+};
+
+/**
+ * bitbang_i2c_init: in-place initialize the bitbang_i2c_interface struct
+ */
+void bitbang_i2c_init(bitbang_i2c_interface *s, I2CBus *bus);
+int bitbang_i2c_set(bitbang_i2c_interface *i2c, int line, int level);
+
+#endif
DeviceState *i2c_create_slave(I2CBus *bus, const char *name, uint8_t addr);
-typedef struct bitbang_i2c_interface bitbang_i2c_interface;
-
/* lm832x.c */
void lm832x_key_event(DeviceState *dev, int key, int state);
#define PPC4XX_I2C_H
#include "hw/sysbus.h"
-#include "hw/i2c/i2c.h"
+#include "hw/i2c/bitbang_i2c.h"
#define TYPE_PPC4xx_I2C "ppc4xx-i2c"
#define PPC4xx_I2C(obj) OBJECT_CHECK(PPC4xxI2CState, (obj), TYPE_PPC4xx_I2C)
I2CBus *bus;
qemu_irq irq;
MemoryRegion iomem;
- bitbang_i2c_interface *bitbang;
+ bitbang_i2c_interface bitbang;
int mdidx;
uint8_t mdata[4];
uint8_t lmadr;
/* use PVH to load kernels that support this feature */
bool pvh_enabled;
+
+ /* Enables contiguous-apic-ID mode */
+ bool compat_apic_id_mode;
} PCMachineClass;
#define TYPE_PC_MACHINE "generic-pc-machine"
--- /dev/null
+/*
+ * ASPEED XDMA Controller
+ * Eddie James <eajames@linux.ibm.com>
+ *
+ * Copyright (C) 2019 IBM Corp.
+ * SPDX-License-Identifer: GPL-2.0-or-later
+ */
+
+#ifndef ASPEED_XDMA_H
+#define ASPEED_XDMA_H
+
+#include "hw/sysbus.h"
+
+#define TYPE_ASPEED_XDMA "aspeed.xdma"
+#define ASPEED_XDMA(obj) OBJECT_CHECK(AspeedXDMAState, (obj), TYPE_ASPEED_XDMA)
+
+#define ASPEED_XDMA_NUM_REGS (ASPEED_XDMA_REG_SIZE / sizeof(uint32_t))
+#define ASPEED_XDMA_REG_SIZE 0x7C
+
+typedef struct AspeedXDMAState {
+ SysBusDevice parent;
+
+ MemoryRegion iomem;
+ qemu_irq irq;
+
+ char bmc_cmdq_readp_set;
+ uint32_t regs[ASPEED_XDMA_NUM_REGS];
+} AspeedXDMAState;
+
+#endif /* ASPEED_XDMA_H */
#define PCI_DEVICE_ID_VIRTIO_RNG 0x1005
#define PCI_DEVICE_ID_VIRTIO_9P 0x1009
#define PCI_DEVICE_ID_VIRTIO_VSOCK 0x1012
+#define PCI_DEVICE_ID_VIRTIO_PMEM 0x1013
#define PCI_VENDOR_ID_REDHAT 0x1b36
#define PCI_DEVICE_ID_REDHAT_BRIDGE 0x0001
void pcie_cap_slot_init(PCIDevice *dev, uint16_t slot);
void pcie_cap_slot_reset(PCIDevice *dev);
+void pcie_cap_slot_get(PCIDevice *dev, uint16_t *slot_ctl, uint16_t *slt_sta);
void pcie_cap_slot_write_config(PCIDevice *dev,
+ uint16_t old_slot_ctl, uint16_t old_slt_sta,
uint32_t addr, uint32_t val, int len);
int pcie_cap_slot_post_load(void *opaque, int version_id);
void pcie_cap_slot_push_attention_button(PCIDevice *dev);
uint64_t cores_mask;
void *cores;
- hwaddr xscom_base;
MemoryRegion xscom_mmio;
MemoryRegion xscom;
AddressSpace xscom_as;
uint64_t chip_cfam_id;
uint64_t cores_mask;
- hwaddr xscom_base;
-
DeviceRealize parent_realize;
uint32_t (*core_pir)(PnvChip *chip, uint32_t core_id);
*/
#define PNV_XSCOM_SIZE 0x800000000ull
#define PNV_XSCOM_BASE(chip) \
- (chip->xscom_base + ((uint64_t)(chip)->chip_id) * PNV_XSCOM_SIZE)
+ (0x0003fc0000000000ull + ((uint64_t)(chip)->chip_id) * PNV_XSCOM_SIZE)
/*
* XSCOM 0x20109CA defines the ICP BAR:
#define PNV9_PSIHB_ESB_SIZE 0x0000000000010000ull
#define PNV9_PSIHB_ESB_BASE(chip) PNV9_CHIP_BASE(chip, 0x00060302031c0000ull)
+#define PNV9_XSCOM_SIZE 0x0000000400000000ull
+#define PNV9_XSCOM_BASE(chip) PNV9_CHIP_BASE(chip, 0x00603fc00000000ull)
+
#endif /* PPC_PNV_H */
#define PNV9_XSCOM_XIVE_BASE 0x5013000
#define PNV9_XSCOM_XIVE_SIZE 0x300
-extern void pnv_xscom_realize(PnvChip *chip, Error **errp);
+extern void pnv_xscom_realize(PnvChip *chip, uint64_t size, Error **errp);
extern int pnv_dt_xscom(PnvChip *chip, void *fdt, int offset);
extern void pnv_xscom_add_subregion(PnvChip *chip, hwaddr offset,
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);
-static inline void spapr_rtas_unregister(int token)
-{
- spapr_rtas_register(token, NULL, NULL);
-}
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 (*reset)(SpaprMachineState *spapr, Error **errp);
void (*set_irq)(void *opaque, int srcno, int val);
const char *(*get_nodename)(SpaprMachineState *spapr);
- void (*init_emu)(SpaprMachineState *spapr, Error **errp);
void (*init_kvm)(SpaprMachineState *spapr, Error **errp);
} SpaprIrq;
/* KVM support */
int fd;
void *tm_mmap;
+ MemoryRegion tm_mmio_kvm;
VMChangeStateEntry *change;
} SpaprXive;
int spapr_xive_end_to_target(uint8_t end_blk, uint32_t end_idx,
uint32_t *out_server, uint8_t *out_prio);
-void spapr_xive_init(SpaprXive *xive, Error **errp);
/*
* KVM XIVE device helpers
uint32_t offset;
ICSIRQState *irqs;
XICSFabric *xics;
- bool init; /* sPAPR ICS device initialized */
};
#define ICS_PROP_XICS "xics"
/* KVM */
void icp_get_kvm_state(ICPState *icp);
-int icp_set_kvm_state(ICPState *icp);
+int icp_set_kvm_state(ICPState *icp, Error **errp);
void icp_synchronize_state(ICPState *icp);
void icp_kvm_realize(DeviceState *dev, Error **errp);
void ics_get_kvm_state(ICSState *ics);
-int ics_set_kvm_state_one(ICSState *ics, int srcno);
-int ics_set_kvm_state(ICSState *ics);
+int ics_set_kvm_state_one(ICSState *ics, int srcno, Error **errp);
+int ics_set_kvm_state(ICSState *ics, Error **errp);
void ics_synchronize_state(ICSState *ics);
void ics_kvm_set_irq(ICSState *ics, int srcno, int val);
void spapr_dt_xics(SpaprMachineState *spapr, uint32_t nr_servers, void *fdt,
uint32_t phandle);
-int xics_kvm_init(SpaprMachineState *spapr, Error **errp);
+int xics_kvm_connect(SpaprMachineState *spapr, Error **errp);
void xics_kvm_disconnect(SpaprMachineState *spapr, Error **errp);
+bool xics_kvm_has_broken_disconnect(SpaprMachineState *spapr);
void xics_spapr_init(SpaprMachineState *spapr);
#endif /* XICS_SPAPR_H */
/* KVM support */
void *esb_mmap;
+ MemoryRegion esb_mmio_kvm;
XiveNotifier *xive;
} XiveSource;
--- /dev/null
+/*
+ * QEMU RISC-V Boot Helper
+ *
+ * Copyright (c) 2017 SiFive, Inc.
+ * Copyright (c) 2019 Alistair Francis <alistair.francis@wdc.com>
+ *
+ * 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/>.
+ */
+
+#ifndef RISCV_BOOT_H
+#define RISCV_BOOT_H
+
+target_ulong riscv_load_firmware(const char *firmware_filename,
+ hwaddr firmware_load_addr);
+target_ulong riscv_load_kernel(const char *kernel_filename);
+hwaddr riscv_load_initrd(const char *filename, uint64_t mem_size,
+ uint64_t kernel_entry, hwaddr *start);
+
+#endif /* RISCV_BOOT_H */
RISCVHartArrayState cpus;
DeviceState *plic;
SIFIVEGPIOState gpio;
+ MemoryRegion xip_mem;
+ MemoryRegion mask_rom;
} SiFiveESoCState;
typedef struct SiFiveEState {
#ifndef HW_SIFIVE_PRCI_H
#define HW_SIFIVE_PRCI_H
+enum {
+ SIFIVE_PRCI_HFROSCCFG = 0x0,
+ SIFIVE_PRCI_HFXOSCCFG = 0x4,
+ SIFIVE_PRCI_PLLCFG = 0x8,
+ SIFIVE_PRCI_PLLOUTDIV = 0xC
+};
+
+enum {
+ SIFIVE_PRCI_HFROSCCFG_RDY = (1 << 31),
+ SIFIVE_PRCI_HFROSCCFG_EN = (1 << 30)
+};
+
+enum {
+ SIFIVE_PRCI_HFXOSCCFG_RDY = (1 << 31),
+ SIFIVE_PRCI_HFXOSCCFG_EN = (1 << 30)
+};
+
+enum {
+ SIFIVE_PRCI_PLLCFG_PLLSEL = (1 << 16),
+ SIFIVE_PRCI_PLLCFG_REFSEL = (1 << 17),
+ SIFIVE_PRCI_PLLCFG_BYPASS = (1 << 18),
+ SIFIVE_PRCI_PLLCFG_LOCK = (1 << 31)
+};
+
+enum {
+ SIFIVE_PRCI_PLLOUTDIV_DIV1 = (1 << 8)
+};
+
#define TYPE_SIFIVE_PRCI "riscv.sifive.prci"
#define SIFIVE_PRCI(obj) \
/*< public >*/
MemoryRegion mmio;
+ uint32_t hfrosccfg;
+ uint32_t hfxosccfg;
+ uint32_t pllcfg;
+ uint32_t plloutdiv;
} SiFivePRCIState;
DeviceState *sifive_prci_create(hwaddr addr);
IOInstEnding do_subchannel_work_virtual(SubchDev *sub);
IOInstEnding do_subchannel_work_passthrough(SubchDev *sub);
+int s390_ccw_halt(SubchDev *sch);
+int s390_ccw_clear(SubchDev *sch);
+
typedef enum {
CSS_IO_ADAPTER_VIRTIO = 0,
CSS_IO_ADAPTER_PCI = 1,
void (*realize)(S390CCWDevice *dev, char *sysfsdev, Error **errp);
void (*unrealize)(S390CCWDevice *dev, Error **errp);
IOInstEnding (*handle_request) (SubchDev *sch);
+ int (*handle_halt) (SubchDev *sch);
+ int (*handle_clear) (SubchDev *sch);
} S390CCWDeviceClass;
#endif
uint8_t r_timings;
uint8_t conf_enable_w0;
+ /* for DMA support */
+ uint64_t sdram_base;
+
AspeedSMCFlash *flashes;
uint8_t snoop_index;
--- /dev/null
+/*
+ * ASPEED Real Time Clock
+ * Joel Stanley <joel@jms.id.au>
+ *
+ * Copyright 2019 IBM Corp
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+#ifndef ASPEED_RTC_H
+#define ASPEED_RTC_H
+
+#include <stdint.h>
+
+#include "hw/hw.h"
+#include "hw/irq.h"
+#include "hw/sysbus.h"
+
+typedef struct AspeedRtcState {
+ SysBusDevice parent_obj;
+
+ MemoryRegion iomem;
+ qemu_irq irq;
+
+ uint32_t reg[0x18];
+ int offset;
+
+} AspeedRtcState;
+
+#define TYPE_ASPEED_RTC "aspeed.rtc"
+#define ASPEED_RTC(obj) OBJECT_CHECK(AspeedRtcState, (obj), TYPE_ASPEED_RTC)
+
+#endif /* ASPEED_RTC_H */
int error;
bool initialized;
unsigned long pgsizes;
- /*
- * This assumes the host IOMMU can support only a single
- * contiguous IOVA window. We may need to generalize that in
- * future
- */
QLIST_HEAD(, VFIOGuestIOMMU) giommu_list;
QLIST_HEAD(, VFIOHostDMAWindow) hostwin_list;
QLIST_HEAD(, VFIOGroup) group_list;
--- /dev/null
+/*
+ * Virtio PMEM device
+ *
+ * Copyright (C) 2018-2019 Red Hat, Inc.
+ *
+ * Authors:
+ * Pankaj Gupta <pagupta@redhat.com>
+ * David Hildenbrand <david@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.
+ * See the COPYING file in the top-level directory.
+ */
+
+#ifndef HW_VIRTIO_PMEM_H
+#define HW_VIRTIO_PMEM_H
+
+#include "hw/virtio/virtio.h"
+#include "sysemu/hostmem.h"
+
+#define TYPE_VIRTIO_PMEM "virtio-pmem"
+
+#define VIRTIO_PMEM(obj) \
+ OBJECT_CHECK(VirtIOPMEM, (obj), TYPE_VIRTIO_PMEM)
+#define VIRTIO_PMEM_CLASS(oc) \
+ OBJECT_CLASS_CHECK(VirtIOPMEMClass, (oc), TYPE_VIRTIO_PMEM)
+#define VIRTIO_PMEM_GET_CLASS(obj) \
+ OBJECT_GET_CLASS(VirtIOPMEMClass, (obj), TYPE_VIRTIO_PMEM)
+
+#define VIRTIO_PMEM_ADDR_PROP "memaddr"
+#define VIRTIO_PMEM_MEMDEV_PROP "memdev"
+
+typedef struct VirtIOPMEM {
+ VirtIODevice parent_obj;
+
+ VirtQueue *rq_vq;
+ uint64_t start;
+ HostMemoryBackend *memdev;
+} VirtIOPMEM;
+
+typedef struct VirtIOPMEMClass {
+ /* private */
+ VirtIODevice parent;
+
+ /* public */
+ void (*fill_device_info)(const VirtIOPMEM *pmem, VirtioPMEMDeviceInfo *vi);
+ MemoryRegion *(*get_memory_region)(VirtIOPMEM *pmem, Error **errp);
+} VirtIOPMEMClass;
+
+#endif
uint16_t device_id;
bool vm_running;
bool broken; /* device in invalid state, needs reset */
+ bool use_started;
bool started;
- bool start_on_kick; /* virtio 1.0 transitional devices support that */
+ bool start_on_kick; /* when virtio 1.0 feature has not been negotiated */
VMChangeStateEntry *vmstate;
char *bus_name;
uint8_t device_endian;
/* Devices conforming to VIRTIO 1.0 or later are always LE. */
return false;
}
+
+static inline bool virtio_device_started(VirtIODevice *vdev, uint8_t status)
+{
+ if (vdev->use_started) {
+ return vdev->started;
+ }
+
+ return status & VIRTIO_CONFIG_S_DRIVER_OK;
+}
+
+static inline void virtio_set_started(VirtIODevice *vdev, bool started)
+{
+ if (started) {
+ vdev->start_on_kick = false;
+ }
+
+ if (vdev->use_started) {
+ vdev->started = started;
+ }
+}
#endif
MemoryRegion iomem;
uint32_t regs[ASPEED_WDT_REGS_MAX];
+ AspeedSCUState *scu;
uint32_t pclk_freq;
uint32_t silicon_rev;
uint32_t ext_pulse_width_mask;
--- /dev/null
+/*
+ * Human Monitor Interface
+ *
+ * Copyright IBM, Corp. 2011
+ *
+ * Authors:
+ * Anthony Liguori <aliguori@us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2. See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+#ifndef HMP_H
+#define HMP_H
+
+#include "qemu/readline.h"
+
+void hmp_handle_error(Monitor *mon, Error **errp);
+
+void hmp_info_name(Monitor *mon, const QDict *qdict);
+void hmp_info_version(Monitor *mon, const QDict *qdict);
+void hmp_info_kvm(Monitor *mon, const QDict *qdict);
+void hmp_info_status(Monitor *mon, const QDict *qdict);
+void hmp_info_uuid(Monitor *mon, const QDict *qdict);
+void hmp_info_chardev(Monitor *mon, const QDict *qdict);
+void hmp_info_mice(Monitor *mon, const QDict *qdict);
+void hmp_info_migrate(Monitor *mon, const QDict *qdict);
+void hmp_info_migrate_capabilities(Monitor *mon, const QDict *qdict);
+void hmp_info_migrate_parameters(Monitor *mon, const QDict *qdict);
+void hmp_info_migrate_cache_size(Monitor *mon, const QDict *qdict);
+void hmp_info_cpus(Monitor *mon, const QDict *qdict);
+void hmp_info_block(Monitor *mon, const QDict *qdict);
+void hmp_info_blockstats(Monitor *mon, const QDict *qdict);
+void hmp_info_vnc(Monitor *mon, const QDict *qdict);
+void hmp_info_spice(Monitor *mon, const QDict *qdict);
+void hmp_info_balloon(Monitor *mon, const QDict *qdict);
+void hmp_info_irq(Monitor *mon, const QDict *qdict);
+void hmp_info_pic(Monitor *mon, const QDict *qdict);
+void hmp_info_rdma(Monitor *mon, const QDict *qdict);
+void hmp_info_pci(Monitor *mon, const QDict *qdict);
+void hmp_info_block_jobs(Monitor *mon, const QDict *qdict);
+void hmp_info_tpm(Monitor *mon, const QDict *qdict);
+void hmp_info_iothreads(Monitor *mon, const QDict *qdict);
+void hmp_quit(Monitor *mon, const QDict *qdict);
+void hmp_stop(Monitor *mon, const QDict *qdict);
+void hmp_sync_profile(Monitor *mon, const QDict *qdict);
+void hmp_system_reset(Monitor *mon, const QDict *qdict);
+void hmp_system_powerdown(Monitor *mon, const QDict *qdict);
+void hmp_exit_preconfig(Monitor *mon, const QDict *qdict);
+void hmp_announce_self(Monitor *mon, const QDict *qdict);
+void hmp_cpu(Monitor *mon, const QDict *qdict);
+void hmp_memsave(Monitor *mon, const QDict *qdict);
+void hmp_pmemsave(Monitor *mon, const QDict *qdict);
+void hmp_ringbuf_write(Monitor *mon, const QDict *qdict);
+void hmp_ringbuf_read(Monitor *mon, const QDict *qdict);
+void hmp_cont(Monitor *mon, const QDict *qdict);
+void hmp_system_wakeup(Monitor *mon, const QDict *qdict);
+void hmp_nmi(Monitor *mon, const QDict *qdict);
+void hmp_set_link(Monitor *mon, const QDict *qdict);
+void hmp_block_passwd(Monitor *mon, const QDict *qdict);
+void hmp_balloon(Monitor *mon, const QDict *qdict);
+void hmp_block_resize(Monitor *mon, const QDict *qdict);
+void hmp_snapshot_blkdev(Monitor *mon, const QDict *qdict);
+void hmp_snapshot_blkdev_internal(Monitor *mon, const QDict *qdict);
+void hmp_snapshot_delete_blkdev_internal(Monitor *mon, const QDict *qdict);
+void hmp_drive_mirror(Monitor *mon, const QDict *qdict);
+void hmp_drive_backup(Monitor *mon, const QDict *qdict);
+void hmp_loadvm(Monitor *mon, const QDict *qdict);
+void hmp_savevm(Monitor *mon, const QDict *qdict);
+void hmp_delvm(Monitor *mon, const QDict *qdict);
+void hmp_info_snapshots(Monitor *mon, const QDict *qdict);
+void hmp_migrate_cancel(Monitor *mon, const QDict *qdict);
+void hmp_migrate_continue(Monitor *mon, const QDict *qdict);
+void hmp_migrate_incoming(Monitor *mon, const QDict *qdict);
+void hmp_migrate_recover(Monitor *mon, const QDict *qdict);
+void hmp_migrate_pause(Monitor *mon, const QDict *qdict);
+void hmp_migrate_set_downtime(Monitor *mon, const QDict *qdict);
+void hmp_migrate_set_speed(Monitor *mon, const QDict *qdict);
+void hmp_migrate_set_capability(Monitor *mon, const QDict *qdict);
+void hmp_migrate_set_parameter(Monitor *mon, const QDict *qdict);
+void hmp_migrate_set_cache_size(Monitor *mon, const QDict *qdict);
+void hmp_client_migrate_info(Monitor *mon, const QDict *qdict);
+void hmp_migrate_start_postcopy(Monitor *mon, const QDict *qdict);
+void hmp_x_colo_lost_heartbeat(Monitor *mon, const QDict *qdict);
+void hmp_set_password(Monitor *mon, const QDict *qdict);
+void hmp_expire_password(Monitor *mon, const QDict *qdict);
+void hmp_eject(Monitor *mon, const QDict *qdict);
+void hmp_change(Monitor *mon, const QDict *qdict);
+void hmp_block_set_io_throttle(Monitor *mon, const QDict *qdict);
+void hmp_block_stream(Monitor *mon, const QDict *qdict);
+void hmp_block_job_set_speed(Monitor *mon, const QDict *qdict);
+void hmp_block_job_cancel(Monitor *mon, const QDict *qdict);
+void hmp_block_job_pause(Monitor *mon, const QDict *qdict);
+void hmp_block_job_resume(Monitor *mon, const QDict *qdict);
+void hmp_block_job_complete(Monitor *mon, const QDict *qdict);
+void hmp_migrate(Monitor *mon, const QDict *qdict);
+void hmp_device_add(Monitor *mon, const QDict *qdict);
+void hmp_device_del(Monitor *mon, const QDict *qdict);
+void hmp_dump_guest_memory(Monitor *mon, const QDict *qdict);
+void hmp_netdev_add(Monitor *mon, const QDict *qdict);
+void hmp_netdev_del(Monitor *mon, const QDict *qdict);
+void hmp_getfd(Monitor *mon, const QDict *qdict);
+void hmp_closefd(Monitor *mon, const QDict *qdict);
+void hmp_sendkey(Monitor *mon, const QDict *qdict);
+void hmp_screendump(Monitor *mon, const QDict *qdict);
+void hmp_nbd_server_start(Monitor *mon, const QDict *qdict);
+void hmp_nbd_server_add(Monitor *mon, const QDict *qdict);
+void hmp_nbd_server_remove(Monitor *mon, const QDict *qdict);
+void hmp_nbd_server_stop(Monitor *mon, const QDict *qdict);
+void hmp_chardev_add(Monitor *mon, const QDict *qdict);
+void hmp_chardev_change(Monitor *mon, const QDict *qdict);
+void hmp_chardev_remove(Monitor *mon, const QDict *qdict);
+void hmp_chardev_send_break(Monitor *mon, const QDict *qdict);
+void hmp_qemu_io(Monitor *mon, const QDict *qdict);
+void hmp_cpu_add(Monitor *mon, const QDict *qdict);
+void hmp_object_add(Monitor *mon, const QDict *qdict);
+void hmp_object_del(Monitor *mon, const QDict *qdict);
+void hmp_info_memdev(Monitor *mon, const QDict *qdict);
+void hmp_info_numa(Monitor *mon, const QDict *qdict);
+void hmp_info_memory_devices(Monitor *mon, const QDict *qdict);
+void hmp_qom_list(Monitor *mon, const QDict *qdict);
+void hmp_qom_set(Monitor *mon, const QDict *qdict);
+void hmp_info_qom_tree(Monitor *mon, const QDict *dict);
+void object_add_completion(ReadLineState *rs, int nb_args, const char *str);
+void object_del_completion(ReadLineState *rs, int nb_args, const char *str);
+void device_add_completion(ReadLineState *rs, int nb_args, const char *str);
+void device_del_completion(ReadLineState *rs, int nb_args, const char *str);
+void sendkey_completion(ReadLineState *rs, int nb_args, const char *str);
+void chardev_remove_completion(ReadLineState *rs, int nb_args, const char *str);
+void chardev_add_completion(ReadLineState *rs, int nb_args, const char *str);
+void set_link_completion(ReadLineState *rs, int nb_args, const char *str);
+void netdev_add_completion(ReadLineState *rs, int nb_args, const char *str);
+void netdev_del_completion(ReadLineState *rs, int nb_args, const char *str);
+void ringbuf_write_completion(ReadLineState *rs, int nb_args, const char *str);
+void info_trace_events_completion(ReadLineState *rs, int nb_args, const char *str);
+void trace_event_completion(ReadLineState *rs, int nb_args, const char *str);
+void watchdog_action_completion(ReadLineState *rs, int nb_args,
+ const char *str);
+void migrate_set_capability_completion(ReadLineState *rs, int nb_args,
+ const char *str);
+void migrate_set_parameter_completion(ReadLineState *rs, int nb_args,
+ const char *str);
+void delvm_completion(ReadLineState *rs, int nb_args, const char *str);
+void loadvm_completion(ReadLineState *rs, int nb_args, const char *str);
+void hmp_rocker(Monitor *mon, const QDict *qdict);
+void hmp_rocker_ports(Monitor *mon, const QDict *qdict);
+void hmp_rocker_of_dpa_flows(Monitor *mon, const QDict *qdict);
+void hmp_rocker_of_dpa_groups(Monitor *mon, const QDict *qdict);
+void hmp_info_dump(Monitor *mon, const QDict *qdict);
+void hmp_info_ramblock(Monitor *mon, const QDict *qdict);
+void hmp_hotpluggable_cpus(Monitor *mon, const QDict *qdict);
+void hmp_info_vm_generation_id(Monitor *mon, const QDict *qdict);
+void hmp_info_memory_size_summary(Monitor *mon, const QDict *qdict);
+void hmp_info_sev(Monitor *mon, const QDict *qdict);
+
+#endif
void hmp_info_qtree(Monitor *mon, const QDict *qdict);
void hmp_info_qdm(Monitor *mon, const QDict *qdict);
-void hmp_info_qom_tree(Monitor *mon, const QDict *dict);
void qmp_device_add(QDict *qdict, QObject **ret_data, Error **errp);
int qdev_device_help(QemuOpts *opts);
/* Returns: update the timer to the next time point */
int64_t qemu_announce_timer_step(AnnounceTimer *timer);
-/* Delete the underlying timer */
-void qemu_announce_timer_del(AnnounceTimer *timer);
+/*
+ * Delete the underlying timer and other data
+ * If 'free_named' true and the timer is a named timer, then remove
+ * it from the list of named timers and free the AnnounceTimer itself.
+ */
+void qemu_announce_timer_del(AnnounceTimer *timer, bool free_named);
/*
* Under BQL/main thread
#define VIRTIO_ID_INPUT 18 /* virtio input */
#define VIRTIO_ID_VSOCK 19 /* virtio vsock transport */
#define VIRTIO_ID_CRYPTO 20 /* virtio crypto */
+#define VIRTIO_ID_PMEM 27 /* virtio pmem */
#endif /* _LINUX_VIRTIO_IDS_H */
--- /dev/null
+/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
+/*
+ * Definitions for virtio-pmem devices.
+ *
+ * Copyright (C) 2019 Red Hat, Inc.
+ *
+ * Author(s): Pankaj Gupta <pagupta@redhat.com>
+ */
+
+#ifndef _UAPI_LINUX_VIRTIO_PMEM_H
+#define _UAPI_LINUX_VIRTIO_PMEM_H
+
+#include "standard-headers/linux/types.h"
+#include "standard-headers/linux/virtio_ids.h"
+#include "standard-headers/linux/virtio_config.h"
+
+struct virtio_pmem_config {
+ uint64_t start;
+ uint64_t size;
+};
+
+#define VIRTIO_PMEM_REQ_TYPE_FLUSH 0
+
+struct virtio_pmem_resp {
+ /* Host return status corresponding to flush request */
+ uint32_t ret;
+};
+
+struct virtio_pmem_req {
+ /* command type */
+ uint32_t type;
+};
+
+#endif
#ifndef DUMP_H
#define DUMP_H
-#include "qapi/qapi-types-misc.h"
+#include "qapi/qapi-types-dump.h"
#define MAKEDUMPFILE_SIGNATURE "makedumpfile"
#define MAX_SIZE_MDF_HEADER (4096) /* max size of makedumpfile_header */
#define SYSEMU_HOSTMEM_H
#include "sysemu/sysemu.h" /* for MAX_NODES */
-#include "qapi/qapi-types-misc.h"
+#include "qapi/qapi-types-machine.h"
#include "qom/object.h"
#include "exec/memory.h"
#include "qemu/bitmap.h"
};
extern NodeInfo numa_info[MAX_NODES];
+
+void set_numa_options(MachineState *ms, NumaOptions *object, Error **errp);
void parse_numa_opts(MachineState *ms);
void numa_complete_configuration(MachineState *ms);
void query_numa_node_mem(NumaNodeMem node_mem[]);
case QEMU_IFLA_BR_ROOT_ID:
case QEMU_IFLA_BR_BRIDGE_ID:
break;
+ /* br_boolopt_multi { uint32_t, uint32_t } */
+ case QEMU_IFLA_BR_MULTI_BOOLOPT:
+ u32 = NLA_DATA(nlattr);
+ u32[0] = tswap32(u32[0]); /* optval */
+ u32[1] = tswap32(u32[1]); /* optmask */
+ break;
default:
gemu_log("Unknown QEMU_IFLA_BR type %d\n", nlattr->nla_type);
break;
case QEMU_IFLA_BRPORT_ROOT_ID:
case QEMU_IFLA_BRPORT_BRIDGE_ID:
break;
- /* br_boolopt_multi { uint32_t, uint32_t } */
- case QEMU_IFLA_BR_MULTI_BOOLOPT:
- u32 = NLA_DATA(nlattr);
- u32[0] = tswap32(u32[0]); /* optval */
- u32[1] = tswap32(u32[1]); /* optmask */
- break;
default:
gemu_log("Unknown QEMU_IFLA_BRPORT type %d\n", nlattr->nla_type);
break;
#define TARGET_F_SHLCK 8
#endif
+#ifndef TARGET_HAVE_ARCH_STRUCT_FLOCK
#ifndef TARGET_ARCH_FLOCK_PAD
#define TARGET_ARCH_FLOCK_PAD
#endif
short l_whence;
abi_long l_start;
abi_long l_len;
-#if defined(TARGET_MIPS)
- abi_long l_sysid;
-#endif
int l_pid;
TARGET_ARCH_FLOCK_PAD
};
+#endif
+#ifndef TARGET_HAVE_ARCH_STRUCT_FLOCK64
#ifndef TARGET_ARCH_FLOCK64_PAD
#define TARGET_ARCH_FLOCK64_PAD
#endif
TARGET_ARCH_FLOCK64_PAD
};
#endif
+
+#endif
info.si_code = TARGET_ILL_ILLOPC;
queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
break;
+ case EXCP_FPE:
+ info.si_signo = TARGET_SIGFPE;
+ info.si_errno = 0;
+ info.si_code = TARGET_FPE_FLTUNK;
+ if (GET_FP_CAUSE(env->active_fpu.fcr31) & FP_INVALID) {
+ info.si_code = TARGET_FPE_FLTINV;
+ } else if (GET_FP_CAUSE(env->active_fpu.fcr31) & FP_DIV0) {
+ info.si_code = TARGET_FPE_FLTDIV;
+ } else if (GET_FP_CAUSE(env->active_fpu.fcr31) & FP_OVERFLOW) {
+ info.si_code = TARGET_FPE_FLTOVF;
+ } else if (GET_FP_CAUSE(env->active_fpu.fcr31) & FP_UNDERFLOW) {
+ info.si_code = TARGET_FPE_FLTUND;
+ } else if (GET_FP_CAUSE(env->active_fpu.fcr31) & FP_INEXACT) {
+ info.si_code = TARGET_FPE_FLTRES;
+ }
+ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
+ break;
/* The code below was inspired by the MIPS Linux kernel trap
* handling code in arch/mips/kernel/traps.c.
*/
#define TARGET_F_SETOWN 24 /* for sockets. */
#define TARGET_F_GETOWN 23 /* for sockets. */
-#define TARGET_ARCH_FLOCK_PAD abi_long pad[4];
-#define TARGET_ARCH_FLOCK64_PAD
+#if (TARGET_ABI_BITS == 32)
+
+struct target_flock {
+ short l_type;
+ short l_whence;
+ abi_long l_start;
+ abi_long l_len;
+ abi_long l_sysid;
+ int l_pid;
+ abi_long pad[4];
+};
+
+#define TARGET_HAVE_ARCH_STRUCT_FLOCK
+
+#endif
#define TARGET_F_GETLK64 33 /* using 'struct flock64' */
#define TARGET_F_SETLK64 34
#define TARGET_NR_pipe2 59
#define TARGET_NR_quotactl 60
#define TARGET_NR_getdents64 61
+#ifdef TARGET_RISCV32
+#define TARGET_NR__llseek 62
+#else
#define TARGET_NR_lseek 62
+#endif
#define TARGET_NR_read 63
#define TARGET_NR_write 64
#define TARGET_NR_readv 65
#define TARGET_NR_membarrier 283
#define TARGET_NR_mlock2 284
#define TARGET_NR_copy_file_range 285
+#define TARGET_NR_preadv2 286
+#define TARGET_NR_pwritev2 287
+#define TARGET_NR_pkey_mprotect 288
+#define TARGET_NR_pkey_alloc 289
+#define TARGET_NR_pkey_free 290
+#define TARGET_NR_statx 291
+#define TARGET_NR_io_pgetevents 292
+#define TARGET_NR_rseq 293
+#define TARGET_NR_kexec_file_load 294
-#define TARGET_NR_syscalls (TARGET_NR_copy_file_range + 1)
+#define TARGET_NR_syscalls (TARGET_NR_kexec_file_load + 1)
#endif
FLAG_END,
};
+UNUSED static struct flags statx_flags[] = {
+#ifdef AT_EMPTY_PATH
+ FLAG_GENERIC(AT_EMPTY_PATH),
+#endif
+#ifdef AT_NO_AUTOMOUNT
+ FLAG_GENERIC(AT_NO_AUTOMOUNT),
+#endif
+#ifdef AT_SYMLINK_NOFOLLOW
+ FLAG_GENERIC(AT_SYMLINK_NOFOLLOW),
+#endif
+#ifdef AT_STATX_SYNC_AS_STAT
+ FLAG_GENERIC(AT_STATX_SYNC_AS_STAT),
+#endif
+#ifdef AT_STATX_FORCE_SYNC
+ FLAG_GENERIC(AT_STATX_FORCE_SYNC),
+#endif
+#ifdef AT_STATX_DONT_SYNC
+ FLAG_GENERIC(AT_STATX_DONT_SYNC),
+#endif
+ FLAG_END,
+};
+
+UNUSED static struct flags statx_mask[] = {
+/* This must come first, because it includes everything. */
+#ifdef STATX_ALL
+ FLAG_GENERIC(STATX_ALL),
+#endif
+/* This must come second; it includes everything except STATX_BTIME. */
+#ifdef STATX_BASIC_STATS
+ FLAG_GENERIC(STATX_BASIC_STATS),
+#endif
+#ifdef STATX_TYPE
+ FLAG_GENERIC(STATX_TYPE),
+#endif
+#ifdef STATX_MODE
+ FLAG_GENERIC(STATX_MODE),
+#endif
+#ifdef STATX_NLINK
+ FLAG_GENERIC(STATX_NLINK),
+#endif
+#ifdef STATX_UID
+ FLAG_GENERIC(STATX_UID),
+#endif
+#ifdef STATX_GID
+ FLAG_GENERIC(STATX_GID),
+#endif
+#ifdef STATX_ATIME
+ FLAG_GENERIC(STATX_ATIME),
+#endif
+#ifdef STATX_MTIME
+ FLAG_GENERIC(STATX_MTIME),
+#endif
+#ifdef STATX_CTIME
+ FLAG_GENERIC(STATX_CTIME),
+#endif
+#ifdef STATX_INO
+ FLAG_GENERIC(STATX_INO),
+#endif
+#ifdef STATX_SIZE
+ FLAG_GENERIC(STATX_SIZE),
+#endif
+#ifdef STATX_BLOCKS
+ FLAG_GENERIC(STATX_BLOCKS),
+#endif
+#ifdef STATX_BTIME
+ FLAG_GENERIC(STATX_BTIME),
+#endif
+ FLAG_END,
+};
+
/*
* print_xxx utility functions. These are used to print syscall
* parameters in certain format. All of these have parameter
}
#endif
+#ifdef TARGET_NR_statx
+static void
+print_statx(const struct syscallname *name,
+ abi_long arg0, abi_long arg1, abi_long arg2,
+ abi_long arg3, abi_long arg4, abi_long arg5)
+{
+ print_syscall_prologue(name);
+ print_at_dirfd(arg0, 0);
+ print_string(arg1, 0);
+ print_flags(statx_flags, arg2, 0);
+ print_flags(statx_mask, arg3, 0);
+ print_pointer(arg4, 1);
+ print_syscall_epilogue(name);
+}
+#endif
+
/*
* An array of all of the syscalls we know about
*/
#ifdef TARGET_NR_atomic_barrier
{ TARGET_NR_atomic_barrier, "atomic_barrier", NULL, NULL, NULL },
#endif
+#ifdef TARGET_NR_statx
+{ TARGET_NR_statx, "statx", NULL, print_statx, NULL },
+#endif
#define __NR_sys_inotify_init __NR_inotify_init
#define __NR_sys_inotify_add_watch __NR_inotify_add_watch
#define __NR_sys_inotify_rm_watch __NR_inotify_rm_watch
+#define __NR_sys_statx __NR_statx
#if defined(__alpha__) || defined(__x86_64__) || defined(__s390x__)
#define __NR__llseek __NR_lseek
unsigned long, idx1, unsigned long, idx2)
#endif
+/*
+ * It is assumed that struct statx is architecture independent.
+ */
+#if defined(TARGET_NR_statx) && defined(__NR_statx)
+_syscall5(int, sys_statx, int, dirfd, const char *, pathname, int, flags,
+ unsigned int, mask, struct target_statx *, statxbuf)
+#endif
+
static bitmask_transtbl fcntl_flags_tbl[] = {
{ TARGET_O_ACCMODE, TARGET_O_WRONLY, O_ACCMODE, O_WRONLY, },
{ TARGET_O_ACCMODE, TARGET_O_RDWR, O_ACCMODE, O_RDWR, },
}
#endif
+#if defined(TARGET_NR_statx) && defined(__NR_statx)
+static inline abi_long host_to_target_statx(struct target_statx *host_stx,
+ abi_ulong target_addr)
+{
+ struct target_statx *target_stx;
+
+ if (!lock_user_struct(VERIFY_WRITE, target_stx, target_addr, 0)) {
+ return -TARGET_EFAULT;
+ }
+ memset(target_stx, 0, sizeof(*target_stx));
+
+ __put_user(host_stx->stx_mask, &target_stx->stx_mask);
+ __put_user(host_stx->stx_blksize, &target_stx->stx_blksize);
+ __put_user(host_stx->stx_attributes, &target_stx->stx_attributes);
+ __put_user(host_stx->stx_nlink, &target_stx->stx_nlink);
+ __put_user(host_stx->stx_uid, &target_stx->stx_uid);
+ __put_user(host_stx->stx_gid, &target_stx->stx_gid);
+ __put_user(host_stx->stx_mode, &target_stx->stx_mode);
+ __put_user(host_stx->stx_ino, &target_stx->stx_ino);
+ __put_user(host_stx->stx_size, &target_stx->stx_size);
+ __put_user(host_stx->stx_blocks, &target_stx->stx_blocks);
+ __put_user(host_stx->stx_attributes_mask, &target_stx->stx_attributes_mask);
+ __put_user(host_stx->stx_atime.tv_sec, &target_stx->stx_atime.tv_sec);
+ __put_user(host_stx->stx_atime.tv_nsec, &target_stx->stx_atime.tv_nsec);
+ __put_user(host_stx->stx_btime.tv_sec, &target_stx->stx_atime.tv_sec);
+ __put_user(host_stx->stx_btime.tv_nsec, &target_stx->stx_atime.tv_nsec);
+ __put_user(host_stx->stx_ctime.tv_sec, &target_stx->stx_atime.tv_sec);
+ __put_user(host_stx->stx_ctime.tv_nsec, &target_stx->stx_atime.tv_nsec);
+ __put_user(host_stx->stx_mtime.tv_sec, &target_stx->stx_atime.tv_sec);
+ __put_user(host_stx->stx_mtime.tv_nsec, &target_stx->stx_atime.tv_nsec);
+ __put_user(host_stx->stx_rdev_major, &target_stx->stx_rdev_major);
+ __put_user(host_stx->stx_rdev_minor, &target_stx->stx_rdev_minor);
+ __put_user(host_stx->stx_dev_major, &target_stx->stx_dev_major);
+ __put_user(host_stx->stx_dev_minor, &target_stx->stx_dev_minor);
+
+ unlock_user_struct(target_stx, target_addr, 1);
+
+ return 0;
+}
+#endif
+
+
/* ??? Using host futex calls even when target atomic operations
are not really atomic probably breaks things. However implementing
futexes locally would make futexes shared between multiple processes
abi_long ret;
#if defined(TARGET_NR_stat) || defined(TARGET_NR_stat64) \
|| defined(TARGET_NR_lstat) || defined(TARGET_NR_lstat64) \
- || defined(TARGET_NR_fstat) || defined(TARGET_NR_fstat64)
+ || defined(TARGET_NR_fstat) || defined(TARGET_NR_fstat64) \
+ || defined(TARGET_NR_statx)
struct stat st;
#endif
#if defined(TARGET_NR_statfs) || defined(TARGET_NR_statfs64) \
ret = host_to_target_stat64(cpu_env, arg3, &st);
return ret;
#endif
+#if defined(TARGET_NR_statx)
+ case TARGET_NR_statx:
+ {
+ struct target_statx *target_stx;
+ int dirfd = arg1;
+ int flags = arg3;
+
+ p = lock_user_string(arg2);
+ if (p == NULL) {
+ return -TARGET_EFAULT;
+ }
+#if defined(__NR_statx)
+ {
+ /*
+ * It is assumed that struct statx is architecture independent.
+ */
+ struct target_statx host_stx;
+ int mask = arg4;
+
+ ret = get_errno(sys_statx(dirfd, p, flags, mask, &host_stx));
+ if (!is_error(ret)) {
+ if (host_to_target_statx(&host_stx, arg5) != 0) {
+ unlock_user(p, arg2, 0);
+ return -TARGET_EFAULT;
+ }
+ }
+
+ if (ret != -TARGET_ENOSYS) {
+ unlock_user(p, arg2, 0);
+ return ret;
+ }
+ }
+#endif
+ ret = get_errno(fstatat(dirfd, path(p), &st, flags));
+ unlock_user(p, arg2, 0);
+
+ if (!is_error(ret)) {
+ if (!lock_user_struct(VERIFY_WRITE, target_stx, arg5, 0)) {
+ return -TARGET_EFAULT;
+ }
+ memset(target_stx, 0, sizeof(*target_stx));
+ __put_user(major(st.st_dev), &target_stx->stx_dev_major);
+ __put_user(minor(st.st_dev), &target_stx->stx_dev_minor);
+ __put_user(st.st_ino, &target_stx->stx_ino);
+ __put_user(st.st_mode, &target_stx->stx_mode);
+ __put_user(st.st_uid, &target_stx->stx_uid);
+ __put_user(st.st_gid, &target_stx->stx_gid);
+ __put_user(st.st_nlink, &target_stx->stx_nlink);
+ __put_user(major(st.st_rdev), &target_stx->stx_rdev_major);
+ __put_user(minor(st.st_rdev), &target_stx->stx_rdev_minor);
+ __put_user(st.st_size, &target_stx->stx_size);
+ __put_user(st.st_blksize, &target_stx->stx_blksize);
+ __put_user(st.st_blocks, &target_stx->stx_blocks);
+ __put_user(st.st_atime, &target_stx->stx_atime.tv_sec);
+ __put_user(st.st_mtime, &target_stx->stx_mtime.tv_sec);
+ __put_user(st.st_ctime, &target_stx->stx_ctime.tv_sec);
+ unlock_user_struct(target_stx, arg5, 1);
+ }
+ }
+ return ret;
+#endif
#ifdef TARGET_NR_lchown
case TARGET_NR_lchown:
if (!(p = lock_user_string(arg1)))
/* Return size of the log buffer */
#define TARGET_SYSLOG_ACTION_SIZE_BUFFER 10
+struct target_statx_timestamp {
+ int64_t tv_sec;
+ uint32_t tv_nsec;
+ int32_t __reserved;
+};
+
+struct target_statx {
+ /* 0x00 */
+ uint32_t stx_mask; /* What results were written [uncond] */
+ uint32_t stx_blksize; /* Preferred general I/O size [uncond] */
+ uint64_t stx_attributes; /* Flags conveying information about the file */
+ /* 0x10 */
+ uint32_t stx_nlink; /* Number of hard links */
+ uint32_t stx_uid; /* User ID of owner */
+ uint32_t stx_gid; /* Group ID of owner */
+ uint16_t stx_mode; /* File mode */
+ uint16_t __spare0[1];
+ /* 0x20 */
+ uint64_t stx_ino; /* Inode number */
+ uint64_t stx_size; /* File size */
+ uint64_t stx_blocks; /* Number of 512-byte blocks allocated */
+ uint64_t stx_attributes_mask; /* Mask to show what is supported */
+ /* 0x40 */
+ struct target_statx_timestamp stx_atime; /* Last access time */
+ struct target_statx_timestamp stx_btime; /* File creation time */
+ struct target_statx_timestamp stx_ctime; /* Last attribute change time */
+ struct target_statx_timestamp stx_mtime; /* Last data modification time */
+ /* 0x80 */
+ uint32_t stx_rdev_major; /* Device ID of special file [if bdev/cdev] */
+ uint32_t stx_rdev_minor;
+ uint32_t stx_dev_major; /* ID of device containing file [uncond] */
+ uint32_t stx_dev_minor;
+ /* 0x90 */
+ uint64_t __spare2[14]; /* Spare space for future expansion */
+ /* 0x100 */
+};
+
#endif
listener->address_space = NULL;
}
+void address_space_remove_listeners(AddressSpace *as)
+{
+ while (!QTAILQ_EMPTY(&as->listeners)) {
+ memory_listener_unregister(QTAILQ_FIRST(&as->listeners));
+ }
+}
+
void address_space_init(AddressSpace *as, MemoryRegion *root, const char *name)
{
memory_region_ref(root);
void qmp_xen_colo_do_checkpoint(Error **errp)
{
replication_do_checkpoint_all(errp);
+ /* Notify all filters of all NIC to do checkpoint */
+ colo_notify_filters_event(COLO_EVENT_CHECKPOINT, errp);
}
#endif
*/
static int qemu_rdma_broken_ipv6_kernel(struct ibv_context *verbs, Error **errp)
{
- struct ibv_port_attr port_attr;
-
/* This bug only exists in linux, to our knowledge. */
#ifdef CONFIG_LINUX
+ struct ibv_port_attr port_attr;
/*
* Verbs are only NULL if management has bound to '[::]'.
*/
#include "qemu/osdep.h"
-#include "hmp.h"
+#include "monitor/hmp.h"
#include "net/net.h"
#include "net/eth.h"
#include "chardev/char.h"
#include "monitor/monitor-internal.h"
#include "monitor/qdev.h"
#include "qapi/error.h"
+#include "qapi/clone-visitor.h"
#include "qapi/opts-visitor.h"
#include "qapi/qapi-builtin-visit.h"
#include "qapi/qapi-commands-block.h"
#include "qapi/qapi-commands-migration.h"
#include "qapi/qapi-commands-misc.h"
#include "qapi/qapi-commands-net.h"
+#include "qapi/qapi-commands-qdev.h"
#include "qapi/qapi-commands-rocker.h"
#include "qapi/qapi-commands-run-state.h"
#include "qapi/qapi-commands-tpm.h"
#include "qapi/qapi-commands-ui.h"
+#include "qapi/qapi-visit-net.h"
#include "qapi/qmp/qdict.h"
#include "qapi/qmp/qerror.h"
#include "qapi/string-input-visitor.h"
#include <spice/enums.h>
#endif
-static void hmp_handle_error(Monitor *mon, Error **errp)
+void hmp_handle_error(Monitor *mon, Error **errp)
{
assert(errp);
if (*errp) {
}
}
+/*
+ * Produce a strList from a comma separated list.
+ * A NULL or empty input string return NULL.
+ */
+static strList *strList_from_comma_list(const char *in)
+{
+ strList *res = NULL;
+ strList **hook = &res;
+
+ while (in && in[0]) {
+ char *comma = strchr(in, ',');
+ *hook = g_new0(strList, 1);
+
+ if (comma) {
+ (*hook)->value = g_strndup(in, comma - in);
+ in = comma + 1; /* skip the , */
+ } else {
+ (*hook)->value = g_strdup(in);
+ in = NULL;
+ }
+ hook = &(*hook)->next;
+ }
+
+ return res;
+}
+
void hmp_info_name(Monitor *mon, const QDict *qdict)
{
NameInfo *info;
qmp_query_migrate_cache_size(NULL) >> 10);
}
-void hmp_info_cpus(Monitor *mon, const QDict *qdict)
-{
- CpuInfoFastList *cpu_list, *cpu;
-
- cpu_list = qmp_query_cpus_fast(NULL);
-
- for (cpu = cpu_list; cpu; cpu = cpu->next) {
- int active = ' ';
-
- if (cpu->value->cpu_index == monitor_get_cpu_index()) {
- active = '*';
- }
-
- monitor_printf(mon, "%c CPU #%" PRId64 ":", active,
- cpu->value->cpu_index);
- monitor_printf(mon, " thread_id=%" PRId64 "\n", cpu->value->thread_id);
- }
-
- qapi_free_CpuInfoFastList(cpu_list);
-}
-
static void print_block_info(Monitor *mon, BlockInfo *info,
BlockDeviceInfo *inserted, bool verbose)
{
void hmp_announce_self(Monitor *mon, const QDict *qdict)
{
- qmp_announce_self(migrate_announce_params(), NULL);
+ const char *interfaces_str = qdict_get_try_str(qdict, "interfaces");
+ const char *id = qdict_get_try_str(qdict, "id");
+ AnnounceParameters *params = QAPI_CLONE(AnnounceParameters,
+ migrate_announce_params());
+
+ qapi_free_strList(params->interfaces);
+ params->interfaces = strList_from_comma_list(interfaces_str);
+ params->has_interfaces = params->interfaces != NULL;
+ params->id = g_strdup(id);
+ params->has_id = !!params->id;
+ qmp_announce_self(params, NULL);
+ qapi_free_AnnounceParameters(params);
}
void hmp_migrate_cancel(Monitor *mon, const QDict *qdict)
hmp_handle_error(mon, &err);
}
-void hmp_dump_guest_memory(Monitor *mon, const QDict *qdict)
-{
- Error *err = NULL;
- bool win_dmp = qdict_get_try_bool(qdict, "windmp", false);
- bool paging = qdict_get_try_bool(qdict, "paging", false);
- bool zlib = qdict_get_try_bool(qdict, "zlib", false);
- bool lzo = qdict_get_try_bool(qdict, "lzo", false);
- bool snappy = qdict_get_try_bool(qdict, "snappy", false);
- const char *file = qdict_get_str(qdict, "filename");
- bool has_begin = qdict_haskey(qdict, "begin");
- bool has_length = qdict_haskey(qdict, "length");
- bool has_detach = qdict_haskey(qdict, "detach");
- int64_t begin = 0;
- int64_t length = 0;
- bool detach = false;
- enum DumpGuestMemoryFormat dump_format = DUMP_GUEST_MEMORY_FORMAT_ELF;
- char *prot;
-
- if (zlib + lzo + snappy + win_dmp > 1) {
- error_setg(&err, "only one of '-z|-l|-s|-w' can be set");
- hmp_handle_error(mon, &err);
- return;
- }
-
- if (win_dmp) {
- dump_format = DUMP_GUEST_MEMORY_FORMAT_WIN_DMP;
- }
-
- if (zlib) {
- dump_format = DUMP_GUEST_MEMORY_FORMAT_KDUMP_ZLIB;
- }
-
- if (lzo) {
- dump_format = DUMP_GUEST_MEMORY_FORMAT_KDUMP_LZO;
- }
-
- if (snappy) {
- dump_format = DUMP_GUEST_MEMORY_FORMAT_KDUMP_SNAPPY;
- }
-
- if (has_begin) {
- begin = qdict_get_int(qdict, "begin");
- }
- if (has_length) {
- length = qdict_get_int(qdict, "length");
- }
- if (has_detach) {
- detach = qdict_get_bool(qdict, "detach");
- }
-
- prot = g_strconcat("file:", file, NULL);
-
- qmp_dump_guest_memory(paging, prot, true, detach, has_begin, begin,
- has_length, length, true, dump_format, &err);
- hmp_handle_error(mon, &err);
- g_free(prot);
-}
-
void hmp_netdev_add(Monitor *mon, const QDict *qdict)
{
Error *err = NULL;
hmp_handle_error(mon, &err);
}
-void hmp_cpu_add(Monitor *mon, const QDict *qdict)
-{
- int cpuid;
- Error *err = NULL;
-
- error_report("cpu_add is deprecated, please use device_add instead");
-
- cpuid = qdict_get_int(qdict, "id");
- qmp_cpu_add(cpuid, &err);
- hmp_handle_error(mon, &err);
-}
-
void hmp_chardev_add(Monitor *mon, const QDict *qdict)
{
const char *args = qdict_get_str(qdict, "args");
hmp_handle_error(mon, &err);
}
-void hmp_info_memdev(Monitor *mon, const QDict *qdict)
-{
- Error *err = NULL;
- MemdevList *memdev_list = qmp_query_memdev(&err);
- MemdevList *m = memdev_list;
- Visitor *v;
- char *str;
-
- while (m) {
- v = string_output_visitor_new(false, &str);
- visit_type_uint16List(v, NULL, &m->value->host_nodes, NULL);
- monitor_printf(mon, "memory backend: %s\n", m->value->id);
- monitor_printf(mon, " size: %" PRId64 "\n", m->value->size);
- monitor_printf(mon, " merge: %s\n",
- m->value->merge ? "true" : "false");
- monitor_printf(mon, " dump: %s\n",
- m->value->dump ? "true" : "false");
- monitor_printf(mon, " prealloc: %s\n",
- m->value->prealloc ? "true" : "false");
- monitor_printf(mon, " policy: %s\n",
- HostMemPolicy_str(m->value->policy));
- visit_complete(v, &str);
- monitor_printf(mon, " host nodes: %s\n", str);
-
- g_free(str);
- visit_free(v);
- m = m->next;
- }
-
- monitor_printf(mon, "\n");
-
- qapi_free_MemdevList(memdev_list);
- hmp_handle_error(mon, &err);
-}
-
void hmp_info_memory_devices(Monitor *mon, const QDict *qdict)
{
Error *err = NULL;
MemoryDeviceInfoList *info_list = qmp_query_memory_devices(&err);
MemoryDeviceInfoList *info;
+ VirtioPMEMDeviceInfo *vpi;
MemoryDeviceInfo *value;
PCDIMMDeviceInfo *di;
if (value) {
switch (value->type) {
case MEMORY_DEVICE_INFO_KIND_DIMM:
- di = value->u.dimm.data;
- break;
-
case MEMORY_DEVICE_INFO_KIND_NVDIMM:
- di = value->u.nvdimm.data;
- break;
-
- default:
- di = NULL;
- break;
- }
-
- if (di) {
+ di = value->type == MEMORY_DEVICE_INFO_KIND_DIMM ?
+ value->u.dimm.data : value->u.nvdimm.data;
monitor_printf(mon, "Memory device [%s]: \"%s\"\n",
MemoryDeviceInfoKind_str(value->type),
di->id ? di->id : "");
di->hotplugged ? "true" : "false");
monitor_printf(mon, " hotpluggable: %s\n",
di->hotpluggable ? "true" : "false");
+ break;
+ case MEMORY_DEVICE_INFO_KIND_VIRTIO_PMEM:
+ vpi = value->u.virtio_pmem.data;
+ monitor_printf(mon, "Memory device [%s]: \"%s\"\n",
+ MemoryDeviceInfoKind_str(value->type),
+ vpi->id ? vpi->id : "");
+ monitor_printf(mon, " memaddr: 0x%" PRIx64 "\n", vpi->memaddr);
+ monitor_printf(mon, " size: %" PRIu64 "\n", vpi->size);
+ monitor_printf(mon, " memdev: %s\n", vpi->memdev);
+ break;
+ default:
+ g_assert_not_reached();
}
}
}
qapi_free_IOThreadInfoList(info_list);
}
-void hmp_qom_list(Monitor *mon, const QDict *qdict)
-{
- const char *path = qdict_get_try_str(qdict, "path");
- ObjectPropertyInfoList *list;
- Error *err = NULL;
-
- if (path == NULL) {
- monitor_printf(mon, "/\n");
- return;
- }
-
- list = qmp_qom_list(path, &err);
- if (err == NULL) {
- ObjectPropertyInfoList *start = list;
- while (list != NULL) {
- ObjectPropertyInfo *value = list->value;
-
- monitor_printf(mon, "%s (%s)\n",
- value->name, value->type);
- list = list->next;
- }
- qapi_free_ObjectPropertyInfoList(start);
- }
- hmp_handle_error(mon, &err);
-}
-
-void hmp_qom_set(Monitor *mon, const QDict *qdict)
-{
- const char *path = qdict_get_str(qdict, "path");
- const char *property = qdict_get_str(qdict, "property");
- const char *value = qdict_get_str(qdict, "value");
- Error *err = NULL;
- bool ambiguous = false;
- Object *obj;
-
- obj = object_resolve_path(path, &ambiguous);
- if (obj == NULL) {
- error_set(&err, ERROR_CLASS_DEVICE_NOT_FOUND,
- "Device '%s' not found", path);
- } else {
- if (ambiguous) {
- monitor_printf(mon, "Warning: Path '%s' is ambiguous\n", path);
- }
- object_property_parse(obj, value, property, &err);
- }
- hmp_handle_error(mon, &err);
-}
-
void hmp_rocker(Monitor *mon, const QDict *qdict)
{
const char *name = qdict_get_str(qdict, "name");
qapi_free_RockerOfDpaGroupList(list);
}
-void hmp_info_dump(Monitor *mon, const QDict *qdict)
-{
- DumpQueryResult *result = qmp_query_dump(NULL);
-
- assert(result && result->status < DUMP_STATUS__MAX);
- monitor_printf(mon, "Status: %s\n", DumpStatus_str(result->status));
-
- if (result->status == DUMP_STATUS_ACTIVE) {
- float percent = 0;
- assert(result->total != 0);
- percent = 100.0 * result->completed / result->total;
- monitor_printf(mon, "Finished: %.2f %%\n", percent);
- }
-
- qapi_free_DumpQueryResult(result);
-}
-
void hmp_info_ramblock(Monitor *mon, const QDict *qdict)
{
ram_block_dump(mon);
}
-void hmp_hotpluggable_cpus(Monitor *mon, const QDict *qdict)
-{
- Error *err = NULL;
- HotpluggableCPUList *l = qmp_query_hotpluggable_cpus(&err);
- HotpluggableCPUList *saved = l;
- CpuInstanceProperties *c;
-
- if (err != NULL) {
- hmp_handle_error(mon, &err);
- return;
- }
-
- monitor_printf(mon, "Hotpluggable CPUs:\n");
- while (l) {
- monitor_printf(mon, " type: \"%s\"\n", l->value->type);
- monitor_printf(mon, " vcpus_count: \"%" PRIu64 "\"\n",
- l->value->vcpus_count);
- if (l->value->has_qom_path) {
- monitor_printf(mon, " qom_path: \"%s\"\n", l->value->qom_path);
- }
-
- c = l->value->props;
- monitor_printf(mon, " CPUInstance Properties:\n");
- if (c->has_node_id) {
- monitor_printf(mon, " node-id: \"%" PRIu64 "\"\n", c->node_id);
- }
- if (c->has_socket_id) {
- monitor_printf(mon, " socket-id: \"%" PRIu64 "\"\n", c->socket_id);
- }
- if (c->has_core_id) {
- monitor_printf(mon, " core-id: \"%" PRIu64 "\"\n", c->core_id);
- }
- if (c->has_thread_id) {
- monitor_printf(mon, " thread-id: \"%" PRIu64 "\"\n", c->thread_id);
- }
-
- l = l->next;
- }
-
- qapi_free_HotpluggableCPUList(saved);
-}
-
void hmp_info_vm_generation_id(Monitor *mon, const QDict *qdict)
{
Error *err = NULL;
#include "net/slirp.h"
#include "chardev/char-mux.h"
#include "ui/qemu-spice.h"
-#include "sysemu/numa.h"
#include "qemu/config-file.h"
#include "qemu/ctype.h"
#include "ui/console.h"
#include "sysemu/hw_accel.h"
#include "authz/list.h"
#include "qapi/util.h"
+#include "sysemu/blockdev.h"
+#include "sysemu/sysemu.h"
#include "sysemu/tcg.h"
#include "sysemu/tpm.h"
#include "qapi/qmp/qdict.h"
#include "qom/object_interfaces.h"
#include "trace/control.h"
#include "monitor/hmp-target.h"
+#include "monitor/hmp.h"
#ifdef CONFIG_TRACE_SIMPLE
#include "trace/simple.h"
#endif
#include "exec/memory.h"
#include "exec/exec-all.h"
#include "qemu/option.h"
-#include "hmp.h"
#include "qemu/thread.h"
#include "block/qapi.h"
#include "qapi/qapi-commands.h"
mtree_info(flatview, dispatch_tree, owner);
}
-static void hmp_info_numa(Monitor *mon, const QDict *qdict)
-{
- int i;
- NumaNodeMem *node_mem;
- CpuInfoList *cpu_list, *cpu;
-
- cpu_list = qmp_query_cpus(&error_abort);
- node_mem = g_new0(NumaNodeMem, nb_numa_nodes);
-
- query_numa_node_mem(node_mem);
- monitor_printf(mon, "%d nodes\n", nb_numa_nodes);
- for (i = 0; i < nb_numa_nodes; i++) {
- monitor_printf(mon, "node %d cpus:", i);
- for (cpu = cpu_list; cpu; cpu = cpu->next) {
- if (cpu->value->has_props && cpu->value->props->has_node_id &&
- cpu->value->props->node_id == i) {
- monitor_printf(mon, " %" PRIi64, cpu->value->CPU);
- }
- }
- monitor_printf(mon, "\n");
- monitor_printf(mon, "node %d size: %" PRId64 " MB\n", i,
- node_mem[i].node_mem >> 20);
- monitor_printf(mon, "node %d plugged: %" PRId64 " MB\n", i,
- node_mem[i].node_plugged_mem >> 20);
- }
- qapi_free_CpuInfoList(cpu_list);
- g_free(node_mem);
-}
-
#ifdef CONFIG_PROFILER
int64_t dev_time;
sortcmdlist();
qemu_mutex_init(&mon_fdsets_lock);
}
-
-HotpluggableCPUList *qmp_query_hotpluggable_cpus(Error **errp)
-{
- MachineState *ms = MACHINE(qdev_get_machine());
- MachineClass *mc = MACHINE_GET_CLASS(ms);
-
- if (!mc->has_hotpluggable_cpus) {
- error_setg(errp, QERR_FEATURE_DISABLED, "query-hotpluggable-cpus");
- return NULL;
- }
-
- return machine_query_hotpluggable_cpus(ms);
-}
#include "ui/vnc.h"
#include "sysemu/kvm.h"
#include "sysemu/arch_init.h"
-#include "hw/qdev.h"
#include "sysemu/blockdev.h"
#include "sysemu/block-backend.h"
-#include "qom/qom-qobject.h"
#include "qapi/error.h"
#include "qapi/qapi-commands-block-core.h"
+#include "qapi/qapi-commands-machine.h"
#include "qapi/qapi-commands-misc.h"
#include "qapi/qapi-commands-ui.h"
-#include "qapi/qmp/qdict.h"
#include "qapi/qmp/qerror.h"
-#include "qapi/qobject-input-visitor.h"
#include "hw/boards.h"
-#include "qom/object_interfaces.h"
#include "hw/mem/memory-device.h"
#include "hw/acpi/acpi_dev_interface.h"
qemu_system_powerdown_request();
}
-void qmp_cpu_add(int64_t id, Error **errp)
-{
- MachineClass *mc;
-
- mc = MACHINE_GET_CLASS(current_machine);
- if (mc->hot_add_cpu) {
- mc->hot_add_cpu(id, errp);
- } else {
- error_setg(errp, "Not supported");
- }
-}
-
void qmp_x_exit_preconfig(Error **errp)
{
if (!runstate_check(RUN_STATE_PRECONFIG)) {
qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER, errp);
}
-ObjectPropertyInfoList *qmp_qom_list(const char *path, Error **errp)
-{
- Object *obj;
- bool ambiguous = false;
- ObjectPropertyInfoList *props = NULL;
- ObjectProperty *prop;
- ObjectPropertyIterator iter;
-
- obj = object_resolve_path(path, &ambiguous);
- if (obj == NULL) {
- if (ambiguous) {
- error_setg(errp, "Path '%s' is ambiguous", path);
- } else {
- error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
- "Device '%s' not found", path);
- }
- return NULL;
- }
-
- object_property_iter_init(&iter, obj);
- while ((prop = object_property_iter_next(&iter))) {
- ObjectPropertyInfoList *entry = g_malloc0(sizeof(*entry));
-
- entry->value = g_malloc0(sizeof(ObjectPropertyInfo));
- entry->next = props;
- props = entry;
-
- entry->value->name = g_strdup(prop->name);
- entry->value->type = g_strdup(prop->type);
- }
-
- return props;
-}
-
-void qmp_qom_set(const char *path, const char *property, QObject *value,
- Error **errp)
-{
- Object *obj;
-
- obj = object_resolve_path(path, NULL);
- if (!obj) {
- error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
- "Device '%s' not found", path);
- return;
- }
-
- object_property_set_qobject(obj, value, property, errp);
-}
-
-QObject *qmp_qom_get(const char *path, const char *property, Error **errp)
-{
- Object *obj;
-
- obj = object_resolve_path(path, NULL);
- if (!obj) {
- error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
- "Device '%s' not found", path);
- return NULL;
- }
-
- return object_property_get_qobject(obj, property, errp);
-}
-
void qmp_set_password(const char *protocol, const char *password,
bool has_connected, const char *connected, Error **errp)
{
}
}
-static void qom_list_types_tramp(ObjectClass *klass, void *data)
-{
- ObjectTypeInfoList *e, **pret = data;
- ObjectTypeInfo *info;
- ObjectClass *parent = object_class_get_parent(klass);
-
- info = g_malloc0(sizeof(*info));
- info->name = g_strdup(object_class_get_name(klass));
- info->has_abstract = info->abstract = object_class_is_abstract(klass);
- if (parent) {
- info->has_parent = true;
- info->parent = g_strdup(object_class_get_name(parent));
- }
-
- e = g_malloc0(sizeof(*e));
- e->value = info;
- e->next = *pret;
- *pret = e;
-}
-
-ObjectTypeInfoList *qmp_qom_list_types(bool has_implements,
- const char *implements,
- bool has_abstract,
- bool abstract,
- Error **errp)
-{
- ObjectTypeInfoList *ret = NULL;
-
- object_class_foreach(qom_list_types_tramp, implements, abstract, &ret);
-
- return ret;
-}
-
-/* Return a DevicePropertyInfo for a qdev property.
- *
- * If a qdev property with the given name does not exist, use the given default
- * type. If the qdev property info should not be shown, return NULL.
- *
- * The caller must free the return value.
- */
-static ObjectPropertyInfo *make_device_property_info(ObjectClass *klass,
- const char *name,
- const char *default_type,
- const char *description)
-{
- ObjectPropertyInfo *info;
- Property *prop;
-
- do {
- for (prop = DEVICE_CLASS(klass)->props; prop && prop->name; prop++) {
- if (strcmp(name, prop->name) != 0) {
- continue;
- }
-
- /*
- * TODO Properties without a parser are just for dirty hacks.
- * qdev_prop_ptr is the only such PropertyInfo. It's marked
- * for removal. This conditional should be removed along with
- * it.
- */
- if (!prop->info->set && !prop->info->create) {
- return NULL; /* no way to set it, don't show */
- }
-
- info = g_malloc0(sizeof(*info));
- info->name = g_strdup(prop->name);
- info->type = default_type ? g_strdup(default_type)
- : g_strdup(prop->info->name);
- info->has_description = !!prop->info->description;
- info->description = g_strdup(prop->info->description);
- return info;
- }
- klass = object_class_get_parent(klass);
- } while (klass != object_class_by_name(TYPE_DEVICE));
-
- /* Not a qdev property, use the default type */
- info = g_malloc0(sizeof(*info));
- info->name = g_strdup(name);
- info->type = g_strdup(default_type);
- info->has_description = !!description;
- info->description = g_strdup(description);
-
- return info;
-}
-
-ObjectPropertyInfoList *qmp_device_list_properties(const char *typename,
- Error **errp)
-{
- ObjectClass *klass;
- Object *obj;
- ObjectProperty *prop;
- ObjectPropertyIterator iter;
- ObjectPropertyInfoList *prop_list = NULL;
-
- klass = object_class_by_name(typename);
- if (klass == NULL) {
- error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
- "Device '%s' not found", typename);
- return NULL;
- }
-
- klass = object_class_dynamic_cast(klass, TYPE_DEVICE);
- if (klass == NULL) {
- error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "typename", TYPE_DEVICE);
- return NULL;
- }
-
- if (object_class_is_abstract(klass)) {
- error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "typename",
- "non-abstract device type");
- return NULL;
- }
-
- obj = object_new(typename);
-
- object_property_iter_init(&iter, obj);
- while ((prop = object_property_iter_next(&iter))) {
- ObjectPropertyInfo *info;
- ObjectPropertyInfoList *entry;
-
- /* Skip Object and DeviceState properties */
- if (strcmp(prop->name, "type") == 0 ||
- strcmp(prop->name, "realized") == 0 ||
- strcmp(prop->name, "hotpluggable") == 0 ||
- strcmp(prop->name, "hotplugged") == 0 ||
- strcmp(prop->name, "parent_bus") == 0) {
- continue;
- }
-
- /* Skip legacy properties since they are just string versions of
- * properties that we already list.
- */
- if (strstart(prop->name, "legacy-", NULL)) {
- continue;
- }
-
- info = make_device_property_info(klass, prop->name, prop->type,
- prop->description);
- if (!info) {
- continue;
- }
-
- entry = g_malloc0(sizeof(*entry));
- entry->value = info;
- entry->next = prop_list;
- prop_list = entry;
- }
-
- object_unref(obj);
-
- return prop_list;
-}
-
-ObjectPropertyInfoList *qmp_qom_list_properties(const char *typename,
- Error **errp)
-{
- ObjectClass *klass;
- Object *obj = NULL;
- ObjectProperty *prop;
- ObjectPropertyIterator iter;
- ObjectPropertyInfoList *prop_list = NULL;
-
- klass = object_class_by_name(typename);
- if (klass == NULL) {
- error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
- "Class '%s' not found", typename);
- return NULL;
- }
-
- klass = object_class_dynamic_cast(klass, TYPE_OBJECT);
- if (klass == NULL) {
- error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "typename", TYPE_OBJECT);
- return NULL;
- }
-
- if (object_class_is_abstract(klass)) {
- object_class_property_iter_init(&iter, klass);
- } else {
- obj = object_new(typename);
- object_property_iter_init(&iter, obj);
- }
- while ((prop = object_property_iter_next(&iter))) {
- ObjectPropertyInfo *info;
- ObjectPropertyInfoList *entry;
-
- info = g_malloc0(sizeof(*info));
- info->name = g_strdup(prop->name);
- info->type = g_strdup(prop->type);
- info->has_description = !!prop->description;
- info->description = g_strdup(prop->description);
-
- entry = g_malloc0(sizeof(*entry));
- entry->value = info;
- entry->next = prop_list;
- prop_list = entry;
- }
-
- object_unref(obj);
-
- return prop_list;
-}
-
void qmp_add_client(const char *protocol, const char *fdname,
bool has_skipauth, bool skipauth, bool has_tls, bool tls,
Error **errp)
}
-void qmp_object_add(const char *type, const char *id,
- bool has_props, QObject *props, Error **errp)
-{
- QDict *pdict;
- Visitor *v;
- Object *obj;
-
- if (props) {
- pdict = qobject_to(QDict, props);
- if (!pdict) {
- error_setg(errp, QERR_INVALID_PARAMETER_TYPE, "props", "dict");
- return;
- }
- qobject_ref(pdict);
- } else {
- pdict = qdict_new();
- }
-
- v = qobject_input_visitor_new(QOBJECT(pdict));
- obj = user_creatable_add_type(type, id, pdict, v, errp);
- visit_free(v);
- if (obj) {
- object_unref(obj);
- }
- qobject_unref(pdict);
-}
-
-void qmp_object_del(const char *id, Error **errp)
-{
- user_creatable_del(id, errp);
-}
-
MemoryDeviceInfoList *qmp_query_memory_devices(Error **errp)
{
return qmp_memory_device_list();
#include "qapi/qapi-commands-net.h"
#include "trace.h"
+static GData *named_timers;
+
int64_t qemu_announce_timer_step(AnnounceTimer *timer)
{
int64_t step;
return step;
}
-void qemu_announce_timer_del(AnnounceTimer *timer)
+/*
+ * If 'free_named' is true, then remove the timer from the list
+ * and free the timer itself.
+ */
+void qemu_announce_timer_del(AnnounceTimer *timer, bool free_named)
{
+ bool free_timer = false;
if (timer->tm) {
timer_del(timer->tm);
timer_free(timer->tm);
timer->tm = NULL;
}
+ qapi_free_strList(timer->params.interfaces);
+ timer->params.interfaces = NULL;
+ if (free_named && timer->params.has_id) {
+ AnnounceTimer *list_timer;
+ /*
+ * Sanity check: There should only be one timer on the list with
+ * the id.
+ */
+ list_timer = g_datalist_get_data(&named_timers, timer->params.id);
+ assert(timer == list_timer);
+ free_timer = true;
+ g_datalist_remove_data(&named_timers, timer->params.id);
+ }
+ trace_qemu_announce_timer_del(free_named, free_timer, timer->params.id);
+ g_free(timer->params.id);
+ timer->params.id = NULL;
+
+ if (free_timer) {
+ g_free(timer);
+ }
}
/*
* We're under the BQL, so the current timer can't
* be firing, so we should be able to delete it.
*/
- qemu_announce_timer_del(timer);
+ qemu_announce_timer_del(timer, false);
QAPI_CLONE_MEMBERS(AnnounceParameters, &timer->params, params);
timer->round = params->rounds;
static void qemu_announce_self_iter(NICState *nic, void *opaque)
{
+ AnnounceTimer *timer = opaque;
uint8_t buf[60];
int len;
+ bool skip;
+
+ if (timer->params.has_interfaces) {
+ strList *entry = timer->params.interfaces;
+ /* Skip unless we find our name in the requested list */
+ skip = true;
+
+ while (entry) {
+ if (!strcmp(entry->value, nic->ncs->name)) {
+ /* Found us */
+ skip = false;
+ break;
+ }
+ entry = entry->next;
+ }
+ } else {
+ skip = false;
+ }
+
+ trace_qemu_announce_self_iter(timer->params.has_id ? timer->params.id : "_",
+ nic->ncs->name,
+ qemu_ether_ntoa(&nic->conf->macaddr), skip);
- trace_qemu_announce_self_iter(qemu_ether_ntoa(&nic->conf->macaddr));
- len = announce_self_create(buf, nic->conf->macaddr.a);
+ if (!skip) {
+ len = announce_self_create(buf, nic->conf->macaddr.a);
- qemu_send_packet_raw(qemu_get_queue(nic), buf, len);
+ qemu_send_packet_raw(qemu_get_queue(nic), buf, len);
- /* if the NIC provides it's own announcement support, use it as well */
- if (nic->ncs->info->announce) {
- nic->ncs->info->announce(nic->ncs);
+ /* if the NIC provides it's own announcement support, use it as well */
+ if (nic->ncs->info->announce) {
+ nic->ncs->info->announce(nic->ncs);
+ }
}
}
static void qemu_announce_self_once(void *opaque)
{
AnnounceTimer *timer = (AnnounceTimer *)opaque;
- qemu_foreach_nic(qemu_announce_self_iter, NULL);
+ qemu_foreach_nic(qemu_announce_self_iter, timer);
if (--timer->round) {
qemu_announce_timer_step(timer);
} else {
- qemu_announce_timer_del(timer);
+ qemu_announce_timer_del(timer, true);
}
}
if (params->rounds) {
qemu_announce_self_once(timer);
} else {
- qemu_announce_timer_del(timer);
+ qemu_announce_timer_del(timer, true);
}
}
void qmp_announce_self(AnnounceParameters *params, Error **errp)
{
- static AnnounceTimer announce_timer;
- qemu_announce_self(&announce_timer, params);
+ AnnounceTimer *named_timer;
+ if (!params->has_id) {
+ params->id = g_strdup("");
+ params->has_id = true;
+ }
+
+ named_timer = g_datalist_get_data(&named_timers, params->id);
+
+ if (!named_timer) {
+ named_timer = g_new0(AnnounceTimer, 1);
+ g_datalist_set_data(&named_timers, params->id, named_timer);
+ }
+
+ qemu_announce_self(named_timer, params);
}
char *pri_indev;
char *sec_indev;
char *outdev;
+ char *notify_dev;
CharBackend chr_pri_in;
CharBackend chr_sec_in;
CharBackend chr_out;
+ CharBackend chr_notify_dev;
SocketReadState pri_rs;
SocketReadState sec_rs;
+ SocketReadState notify_rs;
bool vnet_hdr;
/*
SECONDARY_IN,
};
-static void colo_compare_inconsistency_notify(void)
-{
- notifier_list_notify(&colo_compare_notifiers,
- migrate_get_current());
-}
static int compare_chr_send(CompareState *s,
const uint8_t *buf,
uint32_t size,
- uint32_t vnet_hdr_len);
+ uint32_t vnet_hdr_len,
+ bool notify_remote_frame);
+
+static void notify_remote_frame(CompareState *s)
+{
+ char msg[] = "DO_CHECKPOINT";
+ int ret = 0;
+
+ ret = compare_chr_send(s, (uint8_t *)msg, strlen(msg), 0, true);
+ if (ret < 0) {
+ error_report("Notify Xen COLO-frame failed");
+ }
+}
+
+static void colo_compare_inconsistency_notify(CompareState *s)
+{
+ if (s->notify_dev) {
+ notify_remote_frame(s);
+ } else {
+ notifier_list_notify(&colo_compare_notifiers,
+ migrate_get_current());
+ }
+}
static gint seq_sorter(Packet *a, Packet *b, gpointer data)
{
ret = compare_chr_send(s,
pkt->data,
pkt->size,
- pkt->vnet_hdr_len);
+ pkt->vnet_hdr_len,
+ false);
if (ret < 0) {
error_report("colo send primary packet failed");
}
qemu_hexdump((char *)spkt->data, stderr,
"colo-compare spkt", spkt->size);
- colo_compare_inconsistency_notify();
+ colo_compare_inconsistency_notify(s);
}
}
}
static int colo_old_packet_check_one_conn(Connection *conn,
- void *user_data)
+ CompareState *s)
{
GList *result = NULL;
int64_t check_time = REGULAR_PACKET_CHECK_MS;
if (result) {
/* Do checkpoint will flush old packet */
- colo_compare_inconsistency_notify();
+ colo_compare_inconsistency_notify(s);
return 0;
}
* If we find one old packet, stop finding job and notify
* COLO frame do checkpoint.
*/
- g_queue_find_custom(&s->conn_list, NULL,
+ g_queue_find_custom(&s->conn_list, s,
(GCompareFunc)colo_old_packet_check_one_conn);
}
*/
trace_colo_compare_main("packet different");
g_queue_push_head(&conn->primary_list, pkt);
- colo_compare_inconsistency_notify();
+
+ colo_compare_inconsistency_notify(s);
break;
}
}
static int compare_chr_send(CompareState *s,
const uint8_t *buf,
uint32_t size,
- uint32_t vnet_hdr_len)
+ uint32_t vnet_hdr_len,
+ bool notify_remote_frame)
{
int ret = 0;
uint32_t len = htonl(size);
return 0;
}
- ret = qemu_chr_fe_write_all(&s->chr_out, (uint8_t *)&len, sizeof(len));
+ if (notify_remote_frame) {
+ ret = qemu_chr_fe_write_all(&s->chr_notify_dev,
+ (uint8_t *)&len,
+ sizeof(len));
+ } else {
+ ret = qemu_chr_fe_write_all(&s->chr_out, (uint8_t *)&len, sizeof(len));
+ }
+
if (ret != sizeof(len)) {
goto err;
}
* know how to parse net packet correctly.
*/
len = htonl(vnet_hdr_len);
- ret = qemu_chr_fe_write_all(&s->chr_out, (uint8_t *)&len, sizeof(len));
+
+ if (!notify_remote_frame) {
+ ret = qemu_chr_fe_write_all(&s->chr_out,
+ (uint8_t *)&len,
+ sizeof(len));
+ }
+
if (ret != sizeof(len)) {
goto err;
}
}
- ret = qemu_chr_fe_write_all(&s->chr_out, (uint8_t *)buf, size);
+ if (notify_remote_frame) {
+ ret = qemu_chr_fe_write_all(&s->chr_notify_dev,
+ (uint8_t *)buf,
+ size);
+ } else {
+ ret = qemu_chr_fe_write_all(&s->chr_out, (uint8_t *)buf, size);
+ }
+
if (ret != size) {
goto err;
}
}
}
+static void compare_notify_chr(void *opaque, const uint8_t *buf, int size)
+{
+ CompareState *s = COLO_COMPARE(opaque);
+ int ret;
+
+ ret = net_fill_rstate(&s->notify_rs, buf, size);
+ if (ret == -1) {
+ qemu_chr_fe_set_handlers(&s->chr_notify_dev, NULL, NULL, NULL, NULL,
+ NULL, NULL, true);
+ error_report("colo-compare notify_dev error");
+ }
+}
+
/*
* Check old packet regularly so it can watch for any packets
* that the secondary hasn't produced equivalents of.
qemu_chr_fe_set_handlers(&s->chr_sec_in, compare_chr_can_read,
compare_sec_chr_in, NULL, NULL,
s, s->worker_context, true);
+ if (s->notify_dev) {
+ qemu_chr_fe_set_handlers(&s->chr_notify_dev, compare_chr_can_read,
+ compare_notify_chr, NULL, NULL,
+ s, s->worker_context, true);
+ }
colo_compare_timer_init(s);
s->event_bh = qemu_bh_new(colo_compare_handle_event, s);
s->vnet_hdr = value;
}
+static char *compare_get_notify_dev(Object *obj, Error **errp)
+{
+ CompareState *s = COLO_COMPARE(obj);
+
+ return g_strdup(s->notify_dev);
+}
+
+static void compare_set_notify_dev(Object *obj, const char *value, Error **errp)
+{
+ CompareState *s = COLO_COMPARE(obj);
+
+ g_free(s->notify_dev);
+ s->notify_dev = g_strdup(value);
+}
+
static void compare_pri_rs_finalize(SocketReadState *pri_rs)
{
CompareState *s = container_of(pri_rs, CompareState, pri_rs);
compare_chr_send(s,
pri_rs->buf,
pri_rs->packet_len,
- pri_rs->vnet_hdr_len);
+ pri_rs->vnet_hdr_len,
+ false);
} else {
/* compare packet in the specified connection */
colo_compare_connection(conn, s);
}
}
+static void compare_notify_rs_finalize(SocketReadState *notify_rs)
+{
+ CompareState *s = container_of(notify_rs, CompareState, notify_rs);
+
+ /* Get Xen colo-frame's notify and handle the message */
+ char *data = g_memdup(notify_rs->buf, notify_rs->packet_len);
+ char msg[] = "COLO_COMPARE_GET_XEN_INIT";
+ int ret;
+
+ if (!strcmp(data, "COLO_USERSPACE_PROXY_INIT")) {
+ ret = compare_chr_send(s, (uint8_t *)msg, strlen(msg), 0, true);
+ if (ret < 0) {
+ error_report("Notify Xen COLO-frame INIT failed");
+ }
+ }
+
+ if (!strcmp(data, "COLO_CHECKPOINT")) {
+ /* colo-compare do checkpoint, flush pri packet and remove sec packet */
+ g_queue_foreach(&s->conn_list, colo_flush_packets, s);
+ }
+}
/*
* Return 0 is success.
net_socket_rs_init(&s->pri_rs, compare_pri_rs_finalize, s->vnet_hdr);
net_socket_rs_init(&s->sec_rs, compare_sec_rs_finalize, s->vnet_hdr);
+ /* Try to enable remote notify chardev, currently just for Xen COLO */
+ if (s->notify_dev) {
+ if (find_and_check_chardev(&chr, s->notify_dev, errp) ||
+ !qemu_chr_fe_init(&s->chr_notify_dev, chr, errp)) {
+ return;
+ }
+
+ net_socket_rs_init(&s->notify_rs, compare_notify_rs_finalize,
+ s->vnet_hdr);
+ }
+
QTAILQ_INSERT_TAIL(&net_compares, s, next);
g_queue_init(&s->conn_list);
compare_chr_send(s,
pkt->data,
pkt->size,
- pkt->vnet_hdr_len);
+ pkt->vnet_hdr_len,
+ false);
packet_destroy(pkt, NULL);
}
while (!g_queue_is_empty(&conn->secondary_list)) {
(Object **)&s->iothread,
object_property_allow_set_link,
OBJ_PROP_LINK_STRONG, NULL);
+ /* This parameter just for Xen COLO */
+ object_property_add_str(obj, "notify_dev",
+ compare_get_notify_dev, compare_set_notify_dev,
+ NULL);
s->vnet_hdr = false;
object_property_add_bool(obj, "vnet_hdr_support", compare_get_vnet_hdr,
qemu_chr_fe_deinit(&s->chr_pri_in, false);
qemu_chr_fe_deinit(&s->chr_sec_in, false);
qemu_chr_fe_deinit(&s->chr_out, false);
+ if (s->notify_dev) {
+ qemu_chr_fe_deinit(&s->chr_notify_dev, false);
+ }
+
if (s->iothread) {
colo_compare_timer_del(s);
}
g_free(s->pri_indev);
g_free(s->sec_indev);
g_free(s->outdev);
+ g_free(s->notify_dev);
}
static const TypeInfo colo_compare_info = {
/***********************************************************/
/* network device redirectors */
-static int get_str_sep(char *buf, int buf_size, const char **pp, int sep)
-{
- const char *p, *p1;
- int len;
- p = *pp;
- p1 = strchr(p, sep);
- if (!p1)
- return -1;
- len = p1 - p;
- p1++;
- if (buf_size > 0) {
- if (len > buf_size - 1)
- len = buf_size - 1;
- memcpy(buf, p, len);
- buf[len] = '\0';
- }
- *pp = p1;
- return 0;
-}
-
int parse_host_port(struct sockaddr_in *saddr, const char *str,
Error **errp)
{
- char buf[512];
+ gchar **substrings;
struct hostent *he;
- const char *p, *r;
- int port;
+ const char *addr, *p, *r;
+ int port, ret = 0;
- p = str;
- if (get_str_sep(buf, sizeof(buf), &p, ':') < 0) {
+ substrings = g_strsplit(str, ":", 2);
+ if (!substrings || !substrings[0] || !substrings[1]) {
error_setg(errp, "host address '%s' doesn't contain ':' "
"separating host from port", str);
- return -1;
+ ret = -1;
+ goto out;
}
+
+ addr = substrings[0];
+ p = substrings[1];
+
saddr->sin_family = AF_INET;
- if (buf[0] == '\0') {
+ if (addr[0] == '\0') {
saddr->sin_addr.s_addr = 0;
} else {
- if (qemu_isdigit(buf[0])) {
- if (!inet_aton(buf, &saddr->sin_addr)) {
+ if (qemu_isdigit(addr[0])) {
+ if (!inet_aton(addr, &saddr->sin_addr)) {
error_setg(errp, "host address '%s' is not a valid "
- "IPv4 address", buf);
- return -1;
+ "IPv4 address", addr);
+ ret = -1;
+ goto out;
}
} else {
- he = gethostbyname(buf);
+ he = gethostbyname(addr);
if (he == NULL) {
- error_setg(errp, "can't resolve host address '%s'", buf);
- return - 1;
+ error_setg(errp, "can't resolve host address '%s'", addr);
+ ret = -1;
+ goto out;
}
saddr->sin_addr = *(struct in_addr *)he->h_addr;
}
port = strtol(p, (char **)&r, 0);
if (r == p) {
error_setg(errp, "port number '%s' is invalid", p);
- return -1;
+ ret = -1;
+ goto out;
}
saddr->sin_port = htons(port);
- return 0;
+
+out:
+ g_strfreev(substrings);
+ return ret;
}
char *qemu_mac_strdup_printf(const uint8_t *macaddr)
static int net_client_init(QemuOpts *opts, bool is_netdev, Error **errp)
{
+ gchar **substrings = NULL;
void *object = NULL;
Error *err = NULL;
int ret = -1;
const char *ip6_net = qemu_opt_get(opts, "ipv6-net");
if (ip6_net) {
- char buf[strlen(ip6_net) + 1];
+ char *prefix_addr;
+ unsigned long prefix_len = 64; /* Default 64bit prefix length. */
+
+ substrings = g_strsplit(ip6_net, "/", 2);
+ if (!substrings || !substrings[0]) {
+ error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "ipv6-net",
+ "a valid IPv6 prefix");
+ goto out;
+ }
- if (get_str_sep(buf, sizeof(buf), &ip6_net, '/') < 0) {
- /* Default 64bit prefix length. */
- qemu_opt_set(opts, "ipv6-prefix", ip6_net, &error_abort);
- qemu_opt_set_number(opts, "ipv6-prefixlen", 64, &error_abort);
- } else {
+ prefix_addr = substrings[0];
+
+ if (substrings[1]) {
/* User-specified prefix length. */
- unsigned long len;
int err;
- qemu_opt_set(opts, "ipv6-prefix", buf, &error_abort);
- err = qemu_strtoul(ip6_net, NULL, 10, &len);
-
+ err = qemu_strtoul(substrings[1], NULL, 10, &prefix_len);
if (err) {
error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
- "ipv6-prefix", "a number");
- } else {
- qemu_opt_set_number(opts, "ipv6-prefixlen", len,
- &error_abort);
+ "ipv6-prefixlen", "a number");
+ goto out;
}
}
+
+ qemu_opt_set(opts, "ipv6-prefix", prefix_addr, &error_abort);
+ qemu_opt_set_number(opts, "ipv6-prefixlen", prefix_len,
+ &error_abort);
qemu_opt_unset(opts, "ipv6-net");
}
}
qapi_free_NetLegacy(object);
}
+out:
error_propagate(errp, err);
+ g_strfreev(substrings);
visit_free(v);
return ret;
}
# See docs/devel/tracing.txt for syntax documentation.
# announce.c
-qemu_announce_self_iter(const char *mac) "%s"
+qemu_announce_self_iter(const char *id, const char *name, const char *mac, int skip) "%s:%s:%s skip: %d"
+qemu_announce_timer_del(bool free_named, bool free_timer, char *id) "free named: %d free timer: %d id: %s"
# vhost-user.c
vhost_user_event(const char *chr, int event) "chr: %s got event: %d"
+++ /dev/null
-/*
- * NUMA parameter parsing routines
- *
- * Copyright (c) 2014 Fujitsu Ltd.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-#include "qemu/osdep.h"
-#include "sysemu/numa.h"
-#include "exec/cpu-common.h"
-#include "exec/ramlist.h"
-#include "qemu/bitmap.h"
-#include "qom/cpu.h"
-#include "qemu/error-report.h"
-#include "qapi/error.h"
-#include "qapi/opts-visitor.h"
-#include "qapi/qapi-commands-misc.h"
-#include "qapi/qapi-visit-misc.h"
-#include "hw/boards.h"
-#include "sysemu/hostmem.h"
-#include "hw/mem/pc-dimm.h"
-#include "hw/mem/memory-device.h"
-#include "qemu/option.h"
-#include "qemu/config-file.h"
-#include "qemu/cutils.h"
-
-QemuOptsList qemu_numa_opts = {
- .name = "numa",
- .implied_opt_name = "type",
- .head = QTAILQ_HEAD_INITIALIZER(qemu_numa_opts.head),
- .desc = { { 0 } } /* validated with OptsVisitor */
-};
-
-static int have_memdevs = -1;
-static int max_numa_nodeid; /* Highest specified NUMA node ID, plus one.
- * For all nodes, nodeid < max_numa_nodeid
- */
-int nb_numa_nodes;
-bool have_numa_distance;
-NodeInfo numa_info[MAX_NODES];
-
-
-static void parse_numa_node(MachineState *ms, NumaNodeOptions *node,
- Error **errp)
-{
- Error *err = NULL;
- uint16_t nodenr;
- uint16List *cpus = NULL;
- MachineClass *mc = MACHINE_GET_CLASS(ms);
-
- if (node->has_nodeid) {
- nodenr = node->nodeid;
- } else {
- nodenr = nb_numa_nodes;
- }
-
- if (nodenr >= MAX_NODES) {
- error_setg(errp, "Max number of NUMA nodes reached: %"
- PRIu16 "", nodenr);
- return;
- }
-
- if (numa_info[nodenr].present) {
- error_setg(errp, "Duplicate NUMA nodeid: %" PRIu16, nodenr);
- return;
- }
-
- if (!mc->cpu_index_to_instance_props || !mc->get_default_cpu_node_id) {
- error_setg(errp, "NUMA is not supported by this machine-type");
- return;
- }
- for (cpus = node->cpus; cpus; cpus = cpus->next) {
- CpuInstanceProperties props;
- if (cpus->value >= max_cpus) {
- error_setg(errp,
- "CPU index (%" PRIu16 ")"
- " should be smaller than maxcpus (%d)",
- cpus->value, max_cpus);
- return;
- }
- props = mc->cpu_index_to_instance_props(ms, cpus->value);
- props.node_id = nodenr;
- props.has_node_id = true;
- machine_set_cpu_numa_node(ms, &props, &err);
- if (err) {
- error_propagate(errp, err);
- return;
- }
- }
-
- if (node->has_mem && node->has_memdev) {
- error_setg(errp, "cannot specify both mem= and memdev=");
- return;
- }
-
- if (have_memdevs == -1) {
- have_memdevs = node->has_memdev;
- }
- if (node->has_memdev != have_memdevs) {
- error_setg(errp, "memdev option must be specified for either "
- "all or no nodes");
- return;
- }
-
- if (node->has_mem) {
- numa_info[nodenr].node_mem = node->mem;
- }
- if (node->has_memdev) {
- Object *o;
- o = object_resolve_path_type(node->memdev, TYPE_MEMORY_BACKEND, NULL);
- if (!o) {
- error_setg(errp, "memdev=%s is ambiguous", node->memdev);
- return;
- }
-
- object_ref(o);
- numa_info[nodenr].node_mem = object_property_get_uint(o, "size", NULL);
- numa_info[nodenr].node_memdev = MEMORY_BACKEND(o);
- }
- numa_info[nodenr].present = true;
- max_numa_nodeid = MAX(max_numa_nodeid, nodenr + 1);
- nb_numa_nodes++;
-}
-
-static void parse_numa_distance(NumaDistOptions *dist, Error **errp)
-{
- uint16_t src = dist->src;
- uint16_t dst = dist->dst;
- uint8_t val = dist->val;
-
- if (src >= MAX_NODES || dst >= MAX_NODES) {
- error_setg(errp, "Parameter '%s' expects an integer between 0 and %d",
- src >= MAX_NODES ? "src" : "dst", MAX_NODES - 1);
- return;
- }
-
- if (!numa_info[src].present || !numa_info[dst].present) {
- error_setg(errp, "Source/Destination NUMA node is missing. "
- "Please use '-numa node' option to declare it first.");
- return;
- }
-
- if (val < NUMA_DISTANCE_MIN) {
- error_setg(errp, "NUMA distance (%" PRIu8 ") is invalid, "
- "it shouldn't be less than %d.",
- val, NUMA_DISTANCE_MIN);
- return;
- }
-
- if (src == dst && val != NUMA_DISTANCE_MIN) {
- error_setg(errp, "Local distance of node %d should be %d.",
- src, NUMA_DISTANCE_MIN);
- return;
- }
-
- numa_info[src].distance[dst] = val;
- have_numa_distance = true;
-}
-
-static
-void set_numa_options(MachineState *ms, NumaOptions *object, Error **errp)
-{
- Error *err = NULL;
-
- switch (object->type) {
- case NUMA_OPTIONS_TYPE_NODE:
- parse_numa_node(ms, &object->u.node, &err);
- if (err) {
- goto end;
- }
- break;
- case NUMA_OPTIONS_TYPE_DIST:
- parse_numa_distance(&object->u.dist, &err);
- if (err) {
- goto end;
- }
- break;
- case NUMA_OPTIONS_TYPE_CPU:
- if (!object->u.cpu.has_node_id) {
- error_setg(&err, "Missing mandatory node-id property");
- goto end;
- }
- if (!numa_info[object->u.cpu.node_id].present) {
- error_setg(&err, "Invalid node-id=%" PRId64 ", NUMA node must be "
- "defined with -numa node,nodeid=ID before it's used with "
- "-numa cpu,node-id=ID", object->u.cpu.node_id);
- goto end;
- }
-
- machine_set_cpu_numa_node(ms, qapi_NumaCpuOptions_base(&object->u.cpu),
- &err);
- break;
- default:
- abort();
- }
-
-end:
- error_propagate(errp, err);
-}
-
-static int parse_numa(void *opaque, QemuOpts *opts, Error **errp)
-{
- NumaOptions *object = NULL;
- MachineState *ms = MACHINE(opaque);
- Error *err = NULL;
- Visitor *v = opts_visitor_new(opts);
-
- visit_type_NumaOptions(v, NULL, &object, &err);
- visit_free(v);
- if (err) {
- goto end;
- }
-
- /* Fix up legacy suffix-less format */
- if ((object->type == NUMA_OPTIONS_TYPE_NODE) && object->u.node.has_mem) {
- const char *mem_str = qemu_opt_get(opts, "mem");
- qemu_strtosz_MiB(mem_str, NULL, &object->u.node.mem);
- }
-
- set_numa_options(ms, object, &err);
-
-end:
- qapi_free_NumaOptions(object);
- if (err) {
- error_propagate(errp, err);
- return -1;
- }
-
- return 0;
-}
-
-/* If all node pair distances are symmetric, then only distances
- * in one direction are enough. If there is even one asymmetric
- * pair, though, then all distances must be provided. The
- * distance from a node to itself is always NUMA_DISTANCE_MIN,
- * so providing it is never necessary.
- */
-static void validate_numa_distance(void)
-{
- int src, dst;
- bool is_asymmetrical = false;
-
- for (src = 0; src < nb_numa_nodes; src++) {
- for (dst = src; dst < nb_numa_nodes; dst++) {
- if (numa_info[src].distance[dst] == 0 &&
- numa_info[dst].distance[src] == 0) {
- if (src != dst) {
- error_report("The distance between node %d and %d is "
- "missing, at least one distance value "
- "between each nodes should be provided.",
- src, dst);
- exit(EXIT_FAILURE);
- }
- }
-
- if (numa_info[src].distance[dst] != 0 &&
- numa_info[dst].distance[src] != 0 &&
- numa_info[src].distance[dst] !=
- numa_info[dst].distance[src]) {
- is_asymmetrical = true;
- }
- }
- }
-
- if (is_asymmetrical) {
- for (src = 0; src < nb_numa_nodes; src++) {
- for (dst = 0; dst < nb_numa_nodes; dst++) {
- if (src != dst && numa_info[src].distance[dst] == 0) {
- error_report("At least one asymmetrical pair of "
- "distances is given, please provide distances "
- "for both directions of all node pairs.");
- exit(EXIT_FAILURE);
- }
- }
- }
- }
-}
-
-static void complete_init_numa_distance(void)
-{
- int src, dst;
-
- /* Fixup NUMA distance by symmetric policy because if it is an
- * asymmetric distance table, it should be a complete table and
- * there would not be any missing distance except local node, which
- * is verified by validate_numa_distance above.
- */
- for (src = 0; src < nb_numa_nodes; src++) {
- for (dst = 0; dst < nb_numa_nodes; dst++) {
- if (numa_info[src].distance[dst] == 0) {
- if (src == dst) {
- numa_info[src].distance[dst] = NUMA_DISTANCE_MIN;
- } else {
- numa_info[src].distance[dst] = numa_info[dst].distance[src];
- }
- }
- }
- }
-}
-
-void numa_legacy_auto_assign_ram(MachineClass *mc, NodeInfo *nodes,
- int nb_nodes, ram_addr_t size)
-{
- int i;
- uint64_t usedmem = 0;
-
- /* Align each node according to the alignment
- * requirements of the machine class
- */
-
- for (i = 0; i < nb_nodes - 1; i++) {
- nodes[i].node_mem = (size / nb_nodes) &
- ~((1 << mc->numa_mem_align_shift) - 1);
- usedmem += nodes[i].node_mem;
- }
- nodes[i].node_mem = size - usedmem;
-}
-
-void numa_default_auto_assign_ram(MachineClass *mc, NodeInfo *nodes,
- int nb_nodes, ram_addr_t size)
-{
- int i;
- uint64_t usedmem = 0, node_mem;
- uint64_t granularity = size / nb_nodes;
- uint64_t propagate = 0;
-
- for (i = 0; i < nb_nodes - 1; i++) {
- node_mem = (granularity + propagate) &
- ~((1 << mc->numa_mem_align_shift) - 1);
- propagate = granularity + propagate - node_mem;
- nodes[i].node_mem = node_mem;
- usedmem += node_mem;
- }
- nodes[i].node_mem = size - usedmem;
-}
-
-void numa_complete_configuration(MachineState *ms)
-{
- int i;
- MachineClass *mc = MACHINE_GET_CLASS(ms);
-
- /*
- * If memory hotplug is enabled (slots > 0) but without '-numa'
- * options explicitly on CLI, guestes will break.
- *
- * Windows: won't enable memory hotplug without SRAT table at all
- *
- * Linux: if QEMU is started with initial memory all below 4Gb
- * and no SRAT table present, guest kernel will use nommu DMA ops,
- * which breaks 32bit hw drivers when memory is hotplugged and
- * guest tries to use it with that drivers.
- *
- * Enable NUMA implicitly by adding a new NUMA node automatically.
- */
- if (ms->ram_slots > 0 && nb_numa_nodes == 0 &&
- mc->auto_enable_numa_with_memhp) {
- NumaNodeOptions node = { };
- parse_numa_node(ms, &node, &error_abort);
- }
-
- assert(max_numa_nodeid <= MAX_NODES);
-
- /* No support for sparse NUMA node IDs yet: */
- for (i = max_numa_nodeid - 1; i >= 0; i--) {
- /* Report large node IDs first, to make mistakes easier to spot */
- if (!numa_info[i].present) {
- error_report("numa: Node ID missing: %d", i);
- exit(1);
- }
- }
-
- /* This must be always true if all nodes are present: */
- assert(nb_numa_nodes == max_numa_nodeid);
-
- if (nb_numa_nodes > 0) {
- uint64_t numa_total;
-
- if (nb_numa_nodes > MAX_NODES) {
- nb_numa_nodes = MAX_NODES;
- }
-
- /* If no memory size is given for any node, assume the default case
- * and distribute the available memory equally across all nodes
- */
- for (i = 0; i < nb_numa_nodes; i++) {
- if (numa_info[i].node_mem != 0) {
- break;
- }
- }
- if (i == nb_numa_nodes) {
- assert(mc->numa_auto_assign_ram);
- mc->numa_auto_assign_ram(mc, numa_info, nb_numa_nodes, ram_size);
- }
-
- numa_total = 0;
- for (i = 0; i < nb_numa_nodes; i++) {
- numa_total += numa_info[i].node_mem;
- }
- if (numa_total != ram_size) {
- error_report("total memory for NUMA nodes (0x%" PRIx64 ")"
- " should equal RAM size (0x" RAM_ADDR_FMT ")",
- numa_total, ram_size);
- exit(1);
- }
-
- /* QEMU needs at least all unique node pair distances to build
- * the whole NUMA distance table. QEMU treats the distance table
- * as symmetric by default, i.e. distance A->B == distance B->A.
- * Thus, QEMU is able to complete the distance table
- * initialization even though only distance A->B is provided and
- * distance B->A is not. QEMU knows the distance of a node to
- * itself is always 10, so A->A distances may be omitted. When
- * the distances of two nodes of a pair differ, i.e. distance
- * A->B != distance B->A, then that means the distance table is
- * asymmetric. In this case, the distances for both directions
- * of all node pairs are required.
- */
- if (have_numa_distance) {
- /* Validate enough NUMA distance information was provided. */
- validate_numa_distance();
-
- /* Validation succeeded, now fill in any missing distances. */
- complete_init_numa_distance();
- }
- }
-}
-
-void parse_numa_opts(MachineState *ms)
-{
- qemu_opts_foreach(qemu_find_opts("numa"), parse_numa, ms, &error_fatal);
-}
-
-void qmp_set_numa_node(NumaOptions *cmd, Error **errp)
-{
- if (!runstate_check(RUN_STATE_PRECONFIG)) {
- error_setg(errp, "The command is permitted only in '%s' state",
- RunState_str(RUN_STATE_PRECONFIG));
- return;
- }
-
- set_numa_options(MACHINE(qdev_get_machine()), cmd, errp);
-}
-
-void numa_cpu_pre_plug(const CPUArchId *slot, DeviceState *dev, Error **errp)
-{
- int node_id = object_property_get_int(OBJECT(dev), "node-id", &error_abort);
-
- if (node_id == CPU_UNSET_NUMA_NODE_ID) {
- /* due to bug in libvirt, it doesn't pass node-id from props on
- * device_add as expected, so we have to fix it up here */
- if (slot->props.has_node_id) {
- object_property_set_int(OBJECT(dev), slot->props.node_id,
- "node-id", errp);
- }
- } else if (node_id != slot->props.node_id) {
- error_setg(errp, "invalid node-id, must be %"PRId64,
- slot->props.node_id);
- }
-}
-
-static void allocate_system_memory_nonnuma(MemoryRegion *mr, Object *owner,
- const char *name,
- uint64_t ram_size)
-{
- if (mem_path) {
-#ifdef __linux__
- Error *err = NULL;
- memory_region_init_ram_from_file(mr, owner, name, ram_size, 0, 0,
- mem_path, &err);
- if (err) {
- error_report_err(err);
- if (mem_prealloc) {
- exit(1);
- }
- error_report("falling back to regular RAM allocation.");
-
- /* Legacy behavior: if allocation failed, fall back to
- * regular RAM allocation.
- */
- mem_path = NULL;
- memory_region_init_ram_nomigrate(mr, owner, name, ram_size, &error_fatal);
- }
-#else
- fprintf(stderr, "-mem-path not supported on this host\n");
- exit(1);
-#endif
- } else {
- memory_region_init_ram_nomigrate(mr, owner, name, ram_size, &error_fatal);
- }
- vmstate_register_ram_global(mr);
-}
-
-void memory_region_allocate_system_memory(MemoryRegion *mr, Object *owner,
- const char *name,
- uint64_t ram_size)
-{
- uint64_t addr = 0;
- int i;
-
- if (nb_numa_nodes == 0 || !have_memdevs) {
- allocate_system_memory_nonnuma(mr, owner, name, ram_size);
- return;
- }
-
- memory_region_init(mr, owner, name, ram_size);
- for (i = 0; i < nb_numa_nodes; i++) {
- uint64_t size = numa_info[i].node_mem;
- HostMemoryBackend *backend = numa_info[i].node_memdev;
- if (!backend) {
- continue;
- }
- MemoryRegion *seg = host_memory_backend_get_memory(backend);
-
- if (memory_region_is_mapped(seg)) {
- char *path = object_get_canonical_path_component(OBJECT(backend));
- error_report("memory backend %s is used multiple times. Each "
- "-numa option must use a different memdev value.",
- path);
- g_free(path);
- exit(1);
- }
-
- host_memory_backend_set_mapped(backend, true);
- memory_region_add_subregion(mr, addr, seg);
- vmstate_register_ram_global(seg);
- addr += size;
- }
-}
-
-static void numa_stat_memory_devices(NumaNodeMem node_mem[])
-{
- MemoryDeviceInfoList *info_list = qmp_memory_device_list();
- MemoryDeviceInfoList *info;
- PCDIMMDeviceInfo *pcdimm_info;
-
- for (info = info_list; info; info = info->next) {
- MemoryDeviceInfo *value = info->value;
-
- if (value) {
- switch (value->type) {
- case MEMORY_DEVICE_INFO_KIND_DIMM:
- pcdimm_info = value->u.dimm.data;
- break;
-
- case MEMORY_DEVICE_INFO_KIND_NVDIMM:
- pcdimm_info = value->u.nvdimm.data;
- break;
-
- default:
- pcdimm_info = NULL;
- break;
- }
-
- if (pcdimm_info) {
- node_mem[pcdimm_info->node].node_mem += pcdimm_info->size;
- node_mem[pcdimm_info->node].node_plugged_mem +=
- pcdimm_info->size;
- }
- }
- }
- qapi_free_MemoryDeviceInfoList(info_list);
-}
-
-void query_numa_node_mem(NumaNodeMem node_mem[])
-{
- int i;
-
- if (nb_numa_nodes <= 0) {
- return;
- }
-
- numa_stat_memory_devices(node_mem);
- for (i = 0; i < nb_numa_nodes; i++) {
- node_mem[i].node_mem += numa_info[i].node_mem;
- }
-}
-
-static int query_memdev(Object *obj, void *opaque)
-{
- MemdevList **list = opaque;
- MemdevList *m = NULL;
-
- if (object_dynamic_cast(obj, TYPE_MEMORY_BACKEND)) {
- m = g_malloc0(sizeof(*m));
-
- m->value = g_malloc0(sizeof(*m->value));
-
- m->value->id = object_get_canonical_path_component(obj);
- m->value->has_id = !!m->value->id;
-
- m->value->size = object_property_get_uint(obj, "size",
- &error_abort);
- m->value->merge = object_property_get_bool(obj, "merge",
- &error_abort);
- m->value->dump = object_property_get_bool(obj, "dump",
- &error_abort);
- m->value->prealloc = object_property_get_bool(obj,
- "prealloc",
- &error_abort);
- m->value->policy = object_property_get_enum(obj,
- "policy",
- "HostMemPolicy",
- &error_abort);
- object_property_get_uint16List(obj, "host-nodes",
- &m->value->host_nodes,
- &error_abort);
-
- m->next = *list;
- *list = m;
- }
-
- return 0;
-}
-
-MemdevList *qmp_query_memdev(Error **errp)
-{
- Object *obj = object_get_objects_root();
- MemdevList *list = NULL;
-
- object_child_foreach(obj, query_memdev, &list);
- return list;
-}
-
-void ram_block_notifier_add(RAMBlockNotifier *n)
-{
- QLIST_INSERT_HEAD(&ram_list.ramblock_notifiers, n, next);
-}
-
-void ram_block_notifier_remove(RAMBlockNotifier *n)
-{
- QLIST_REMOVE(n, next);
-}
-
-void ram_block_notify_add(void *host, size_t size)
-{
- RAMBlockNotifier *notifier;
-
- QLIST_FOREACH(notifier, &ram_list.ramblock_notifiers, next) {
- notifier->ram_block_added(notifier, host, size);
- }
-}
-
-void ram_block_notify_remove(void *host, size_t size)
-{
- RAMBlockNotifier *notifier;
-
- QLIST_FOREACH(notifier, &ram_list.ramblock_notifiers, next) {
- notifier->ram_block_removed(notifier, host, size);
- }
-}
build-all: spapr-rtas.bin
+%.o: %.S
+ $(call quiet-command,$(CCAS) -mbig -c -o $@ $<,"CCAS","$(TARGET_DIR)$@")
+
%.img: %.o
- $(call quiet-command,$(CC) -nostdlib -o $@ $<,"Building","$(TARGET_DIR)$@")
+ $(call quiet-command,$(CC) -nostdlib -mbig -o $@ $<,"Building","$(TARGET_DIR)$@")
%.bin: %.img
$(call quiet-command,$(OBJCOPY) -O binary -j .text $< $@,"Building","$(TARGET_DIR)$@")
# Based on qmp.py.
#
-import errno
import logging
import os
-import subprocess
-import re
-import shutil
-import socket
-import tempfile
from . import qmp
-
+from . import machine
LOG = logging.getLogger(__name__)
if target_arch != ADDITIONAL_ARCHES.get(host_arch):
return False
return os.access("/dev/kvm", os.R_OK | os.W_OK)
-
-
-class QEMUMachineError(Exception):
- """
- Exception called when an error in QEMUMachine happens.
- """
-
-
-class QEMUMachineAddDeviceError(QEMUMachineError):
- """
- Exception raised when a request to add a device can not be fulfilled
-
- The failures are caused by limitations, lack of information or conflicting
- requests on the QEMUMachine methods. This exception does not represent
- failures reported by the QEMU binary itself.
- """
-
-class MonitorResponseError(qmp.QMPError):
- """
- Represents erroneous QMP monitor reply
- """
- def __init__(self, reply):
- try:
- desc = reply["error"]["desc"]
- except KeyError:
- desc = reply
- super(MonitorResponseError, self).__init__(desc)
- self.reply = reply
-
-
-class QEMUMachine(object):
- """
- A QEMU VM
-
- Use this object as a context manager to ensure the QEMU process terminates::
-
- with VM(binary) as vm:
- ...
- # vm is guaranteed to be shut down here
- """
-
- def __init__(self, binary, args=None, wrapper=None, name=None,
- test_dir="/var/tmp", monitor_address=None,
- socket_scm_helper=None):
- '''
- Initialize a QEMUMachine
-
- @param binary: path to the qemu binary
- @param args: list of extra arguments
- @param wrapper: list of arguments used as prefix to qemu binary
- @param name: prefix for socket and log file names (default: qemu-PID)
- @param test_dir: where to create socket and log file
- @param monitor_address: address for QMP monitor
- @param socket_scm_helper: helper program, required for send_fd_scm()
- @note: Qemu process is not started until launch() is used.
- '''
- if args is None:
- args = []
- if wrapper is None:
- wrapper = []
- if name is None:
- name = "qemu-%d" % os.getpid()
- self._name = name
- self._monitor_address = monitor_address
- self._vm_monitor = None
- self._qemu_log_path = None
- self._qemu_log_file = None
- self._popen = None
- self._binary = binary
- self._args = list(args) # Force copy args in case we modify them
- self._wrapper = wrapper
- self._events = []
- self._iolog = None
- self._socket_scm_helper = socket_scm_helper
- self._qmp = None
- self._qemu_full_args = None
- self._test_dir = test_dir
- self._temp_dir = None
- self._launched = False
- self._machine = None
- self._console_set = False
- self._console_device_type = None
- self._console_address = None
- self._console_socket = None
-
- # just in case logging wasn't configured by the main script:
- logging.basicConfig()
-
- def __enter__(self):
- return self
-
- def __exit__(self, exc_type, exc_val, exc_tb):
- self.shutdown()
- return False
-
- # This can be used to add an unused monitor instance.
- def add_monitor_null(self):
- self._args.append('-monitor')
- self._args.append('null')
-
- def add_fd(self, fd, fdset, opaque, opts=''):
- """
- Pass a file descriptor to the VM
- """
- options = ['fd=%d' % fd,
- 'set=%d' % fdset,
- 'opaque=%s' % opaque]
- if opts:
- options.append(opts)
-
- # This did not exist before 3.4, but since then it is
- # mandatory for our purpose
- if hasattr(os, 'set_inheritable'):
- os.set_inheritable(fd, True)
-
- self._args.append('-add-fd')
- self._args.append(','.join(options))
- return self
-
- # Exactly one of fd and file_path must be given.
- # (If it is file_path, the helper will open that file and pass its
- # own fd)
- def send_fd_scm(self, fd=None, file_path=None):
- # In iotest.py, the qmp should always use unix socket.
- assert self._qmp.is_scm_available()
- if self._socket_scm_helper is None:
- raise QEMUMachineError("No path to socket_scm_helper set")
- if not os.path.exists(self._socket_scm_helper):
- raise QEMUMachineError("%s does not exist" %
- self._socket_scm_helper)
-
- # This did not exist before 3.4, but since then it is
- # mandatory for our purpose
- if hasattr(os, 'set_inheritable'):
- os.set_inheritable(self._qmp.get_sock_fd(), True)
- if fd is not None:
- os.set_inheritable(fd, True)
-
- fd_param = ["%s" % self._socket_scm_helper,
- "%d" % self._qmp.get_sock_fd()]
-
- if file_path is not None:
- assert fd is None
- fd_param.append(file_path)
- else:
- assert fd is not None
- fd_param.append(str(fd))
-
- devnull = open(os.path.devnull, 'rb')
- proc = subprocess.Popen(fd_param, stdin=devnull, stdout=subprocess.PIPE,
- stderr=subprocess.STDOUT, close_fds=False)
- output = proc.communicate()[0]
- if output:
- LOG.debug(output)
-
- return proc.returncode
-
- @staticmethod
- def _remove_if_exists(path):
- """
- Remove file object at path if it exists
- """
- try:
- os.remove(path)
- except OSError as exception:
- if exception.errno == errno.ENOENT:
- return
- raise
-
- def is_running(self):
- return self._popen is not None and self._popen.poll() is None
-
- def exitcode(self):
- if self._popen is None:
- return None
- return self._popen.poll()
-
- def get_pid(self):
- if not self.is_running():
- return None
- return self._popen.pid
-
- def _load_io_log(self):
- if self._qemu_log_path is not None:
- with open(self._qemu_log_path, "r") as iolog:
- self._iolog = iolog.read()
-
- def _base_args(self):
- if isinstance(self._monitor_address, tuple):
- moncdev = "socket,id=mon,host=%s,port=%s" % (
- self._monitor_address[0],
- self._monitor_address[1])
- else:
- moncdev = 'socket,id=mon,path=%s' % self._vm_monitor
- args = ['-chardev', moncdev,
- '-mon', 'chardev=mon,mode=control',
- '-display', 'none', '-vga', 'none']
- if self._machine is not None:
- args.extend(['-machine', self._machine])
- if self._console_set:
- self._console_address = os.path.join(self._temp_dir,
- self._name + "-console.sock")
- chardev = ('socket,id=console,path=%s,server,nowait' %
- self._console_address)
- args.extend(['-chardev', chardev])
- if self._console_device_type is None:
- args.extend(['-serial', 'chardev:console'])
- else:
- device = '%s,chardev=console' % self._console_device_type
- args.extend(['-device', device])
- return args
-
- def _pre_launch(self):
- self._temp_dir = tempfile.mkdtemp(dir=self._test_dir)
- if self._monitor_address is not None:
- self._vm_monitor = self._monitor_address
- else:
- self._vm_monitor = os.path.join(self._temp_dir,
- self._name + "-monitor.sock")
- self._qemu_log_path = os.path.join(self._temp_dir, self._name + ".log")
- self._qemu_log_file = open(self._qemu_log_path, 'wb')
-
- self._qmp = qmp.QEMUMonitorProtocol(self._vm_monitor,
- server=True)
-
- def _post_launch(self):
- self._qmp.accept()
-
- def _post_shutdown(self):
- if self._qemu_log_file is not None:
- self._qemu_log_file.close()
- self._qemu_log_file = None
-
- self._qemu_log_path = None
-
- if self._console_socket is not None:
- self._console_socket.close()
- self._console_socket = None
-
- if self._temp_dir is not None:
- shutil.rmtree(self._temp_dir)
- self._temp_dir = None
-
- def launch(self):
- """
- Launch the VM and make sure we cleanup and expose the
- command line/output in case of exception
- """
-
- if self._launched:
- raise QEMUMachineError('VM already launched')
-
- self._iolog = None
- self._qemu_full_args = None
- try:
- self._launch()
- self._launched = True
- except:
- self.shutdown()
-
- LOG.debug('Error launching VM')
- if self._qemu_full_args:
- LOG.debug('Command: %r', ' '.join(self._qemu_full_args))
- if self._iolog:
- LOG.debug('Output: %r', self._iolog)
- raise
-
- def _launch(self):
- """
- Launch the VM and establish a QMP connection
- """
- devnull = open(os.path.devnull, 'rb')
- self._pre_launch()
- self._qemu_full_args = (self._wrapper + [self._binary] +
- self._base_args() + self._args)
- LOG.debug('VM launch command: %r', ' '.join(self._qemu_full_args))
- self._popen = subprocess.Popen(self._qemu_full_args,
- stdin=devnull,
- stdout=self._qemu_log_file,
- stderr=subprocess.STDOUT,
- shell=False,
- close_fds=False)
- self._post_launch()
-
- def wait(self):
- """
- Wait for the VM to power off
- """
- self._popen.wait()
- self._qmp.close()
- self._load_io_log()
- self._post_shutdown()
-
- def shutdown(self):
- """
- Terminate the VM and clean up
- """
- if self.is_running():
- try:
- self._qmp.cmd('quit')
- self._qmp.close()
- except:
- self._popen.kill()
- self._popen.wait()
-
- self._load_io_log()
- self._post_shutdown()
-
- exitcode = self.exitcode()
- if exitcode is not None and exitcode < 0:
- msg = 'qemu received signal %i: %s'
- if self._qemu_full_args:
- command = ' '.join(self._qemu_full_args)
- else:
- command = ''
- LOG.warn(msg, -exitcode, command)
-
- self._launched = False
-
- def qmp(self, cmd, conv_keys=True, **args):
- """
- Invoke a QMP command and return the response dict
- """
- qmp_args = dict()
- for key, value in args.items():
- if conv_keys:
- qmp_args[key.replace('_', '-')] = value
- else:
- qmp_args[key] = value
-
- return self._qmp.cmd(cmd, args=qmp_args)
-
- def command(self, cmd, conv_keys=True, **args):
- """
- Invoke a QMP command.
- On success return the response dict.
- On failure raise an exception.
- """
- reply = self.qmp(cmd, conv_keys, **args)
- if reply is None:
- raise qmp.QMPError("Monitor is closed")
- if "error" in reply:
- raise MonitorResponseError(reply)
- return reply["return"]
-
- def get_qmp_event(self, wait=False):
- """
- Poll for one queued QMP events and return it
- """
- if len(self._events) > 0:
- return self._events.pop(0)
- return self._qmp.pull_event(wait=wait)
-
- def get_qmp_events(self, wait=False):
- """
- Poll for queued QMP events and return a list of dicts
- """
- events = self._qmp.get_events(wait=wait)
- events.extend(self._events)
- del self._events[:]
- self._qmp.clear_events()
- return events
-
- @staticmethod
- def event_match(event, match=None):
- """
- Check if an event matches optional match criteria.
-
- The match criteria takes the form of a matching subdict. The event is
- checked to be a superset of the subdict, recursively, with matching
- values whenever the subdict values are not None.
-
- This has a limitation that you cannot explicitly check for None values.
-
- Examples, with the subdict queries on the left:
- - None matches any object.
- - {"foo": None} matches {"foo": {"bar": 1}}
- - {"foo": None} matches {"foo": 5}
- - {"foo": {"abc": None}} does not match {"foo": {"bar": 1}}
- - {"foo": {"rab": 2}} matches {"foo": {"bar": 1, "rab": 2}}
- """
- if match is None:
- return True
-
- try:
- for key in match:
- if key in event:
- if not QEMUMachine.event_match(event[key], match[key]):
- return False
- else:
- return False
- return True
- except TypeError:
- # either match or event wasn't iterable (not a dict)
- return match == event
-
- def event_wait(self, name, timeout=60.0, match=None):
- """
- event_wait waits for and returns a named event from QMP with a timeout.
-
- name: The event to wait for.
- timeout: QEMUMonitorProtocol.pull_event timeout parameter.
- match: Optional match criteria. See event_match for details.
- """
- return self.events_wait([(name, match)], timeout)
-
- def events_wait(self, events, timeout=60.0):
- """
- events_wait waits for and returns a named event from QMP with a timeout.
-
- events: a sequence of (name, match_criteria) tuples.
- The match criteria are optional and may be None.
- See event_match for details.
- timeout: QEMUMonitorProtocol.pull_event timeout parameter.
- """
- def _match(event):
- for name, match in events:
- if (event['event'] == name and
- self.event_match(event, match)):
- return True
- return False
-
- # Search cached events
- for event in self._events:
- if _match(event):
- self._events.remove(event)
- return event
-
- # Poll for new events
- while True:
- event = self._qmp.pull_event(wait=timeout)
- if _match(event):
- return event
- self._events.append(event)
-
- return None
-
- def get_log(self):
- """
- After self.shutdown or failed qemu execution, this returns the output
- of the qemu process.
- """
- return self._iolog
-
- def add_args(self, *args):
- """
- Adds to the list of extra arguments to be given to the QEMU binary
- """
- self._args.extend(args)
-
- def set_machine(self, machine_type):
- """
- Sets the machine type
-
- If set, the machine type will be added to the base arguments
- of the resulting QEMU command line.
- """
- self._machine = machine_type
-
- def set_console(self, device_type=None):
- """
- Sets the device type for a console device
-
- If set, the console device and a backing character device will
- be added to the base arguments of the resulting QEMU command
- line.
-
- This is a convenience method that will either use the provided
- device type, or default to a "-serial chardev:console" command
- line argument.
-
- The actual setting of command line arguments will be be done at
- machine launch time, as it depends on the temporary directory
- to be created.
-
- @param device_type: the device type, such as "isa-serial". If
- None is given (the default value) a "-serial
- chardev:console" command line argument will
- be used instead, resorting to the machine's
- default device type.
- """
- self._console_set = True
- self._console_device_type = device_type
-
- @property
- def console_socket(self):
- """
- Returns a socket connected to the console
- """
- if self._console_socket is None:
- self._console_socket = socket.socket(socket.AF_UNIX,
- socket.SOCK_STREAM)
- self._console_socket.connect(self._console_address)
- return self._console_socket
--- /dev/null
+"""
+QEMU machine module:
+
+The machine module primarily provides the QEMUMachine class,
+which provides facilities for managing the lifetime of a QEMU VM.
+"""
+
+# Copyright (C) 2015-2016 Red Hat Inc.
+# Copyright (C) 2012 IBM Corp.
+#
+# Authors:
+# Fam Zheng <famz@redhat.com>
+#
+# This work is licensed under the terms of the GNU GPL, version 2. See
+# the COPYING file in the top-level directory.
+#
+# Based on qmp.py.
+#
+
+import errno
+import logging
+import os
+import subprocess
+import shutil
+import socket
+import tempfile
+
+from . import qmp
+
+LOG = logging.getLogger(__name__)
+
+class QEMUMachineError(Exception):
+ """
+ Exception called when an error in QEMUMachine happens.
+ """
+
+
+class QEMUMachineAddDeviceError(QEMUMachineError):
+ """
+ Exception raised when a request to add a device can not be fulfilled
+
+ The failures are caused by limitations, lack of information or conflicting
+ requests on the QEMUMachine methods. This exception does not represent
+ failures reported by the QEMU binary itself.
+ """
+
+
+class MonitorResponseError(qmp.QMPError):
+ """
+ Represents erroneous QMP monitor reply
+ """
+ def __init__(self, reply):
+ try:
+ desc = reply["error"]["desc"]
+ except KeyError:
+ desc = reply
+ super(MonitorResponseError, self).__init__(desc)
+ self.reply = reply
+
+
+class QEMUMachine(object):
+ """
+ A QEMU VM
+
+ Use this object as a context manager to ensure the QEMU process terminates::
+
+ with VM(binary) as vm:
+ ...
+ # vm is guaranteed to be shut down here
+ """
+
+ def __init__(self, binary, args=None, wrapper=None, name=None,
+ test_dir="/var/tmp", monitor_address=None,
+ socket_scm_helper=None):
+ '''
+ Initialize a QEMUMachine
+
+ @param binary: path to the qemu binary
+ @param args: list of extra arguments
+ @param wrapper: list of arguments used as prefix to qemu binary
+ @param name: prefix for socket and log file names (default: qemu-PID)
+ @param test_dir: where to create socket and log file
+ @param monitor_address: address for QMP monitor
+ @param socket_scm_helper: helper program, required for send_fd_scm()
+ @note: Qemu process is not started until launch() is used.
+ '''
+ if args is None:
+ args = []
+ if wrapper is None:
+ wrapper = []
+ if name is None:
+ name = "qemu-%d" % os.getpid()
+ self._name = name
+ self._monitor_address = monitor_address
+ self._vm_monitor = None
+ self._qemu_log_path = None
+ self._qemu_log_file = None
+ self._popen = None
+ self._binary = binary
+ self._args = list(args) # Force copy args in case we modify them
+ self._wrapper = wrapper
+ self._events = []
+ self._iolog = None
+ self._socket_scm_helper = socket_scm_helper
+ self._qmp = None
+ self._qemu_full_args = None
+ self._test_dir = test_dir
+ self._temp_dir = None
+ self._launched = False
+ self._machine = None
+ self._console_set = False
+ self._console_device_type = None
+ self._console_address = None
+ self._console_socket = None
+
+ # just in case logging wasn't configured by the main script:
+ logging.basicConfig()
+
+ def __enter__(self):
+ return self
+
+ def __exit__(self, exc_type, exc_val, exc_tb):
+ self.shutdown()
+ return False
+
+ def add_monitor_null(self):
+ """
+ This can be used to add an unused monitor instance.
+ """
+ self._args.append('-monitor')
+ self._args.append('null')
+
+ def add_fd(self, fd, fdset, opaque, opts=''):
+ """
+ Pass a file descriptor to the VM
+ """
+ options = ['fd=%d' % fd,
+ 'set=%d' % fdset,
+ 'opaque=%s' % opaque]
+ if opts:
+ options.append(opts)
+
+ # This did not exist before 3.4, but since then it is
+ # mandatory for our purpose
+ if hasattr(os, 'set_inheritable'):
+ os.set_inheritable(fd, True)
+
+ self._args.append('-add-fd')
+ self._args.append(','.join(options))
+ return self
+
+ def send_fd_scm(self, fd=None, file_path=None):
+ """
+ Send an fd or file_path to socket_scm_helper.
+
+ Exactly one of fd and file_path must be given.
+ If it is file_path, the helper will open that file and pass its own fd.
+ """
+ # In iotest.py, the qmp should always use unix socket.
+ assert self._qmp.is_scm_available()
+ if self._socket_scm_helper is None:
+ raise QEMUMachineError("No path to socket_scm_helper set")
+ if not os.path.exists(self._socket_scm_helper):
+ raise QEMUMachineError("%s does not exist" %
+ self._socket_scm_helper)
+
+ # This did not exist before 3.4, but since then it is
+ # mandatory for our purpose
+ if hasattr(os, 'set_inheritable'):
+ os.set_inheritable(self._qmp.get_sock_fd(), True)
+ if fd is not None:
+ os.set_inheritable(fd, True)
+
+ fd_param = ["%s" % self._socket_scm_helper,
+ "%d" % self._qmp.get_sock_fd()]
+
+ if file_path is not None:
+ assert fd is None
+ fd_param.append(file_path)
+ else:
+ assert fd is not None
+ fd_param.append(str(fd))
+
+ devnull = open(os.path.devnull, 'rb')
+ proc = subprocess.Popen(fd_param, stdin=devnull, stdout=subprocess.PIPE,
+ stderr=subprocess.STDOUT, close_fds=False)
+ output = proc.communicate()[0]
+ if output:
+ LOG.debug(output)
+
+ return proc.returncode
+
+ @staticmethod
+ def _remove_if_exists(path):
+ """
+ Remove file object at path if it exists
+ """
+ try:
+ os.remove(path)
+ except OSError as exception:
+ if exception.errno == errno.ENOENT:
+ return
+ raise
+
+ def is_running(self):
+ """Returns true if the VM is running."""
+ return self._popen is not None and self._popen.poll() is None
+
+ def exitcode(self):
+ """Returns the exit code if possible, or None."""
+ if self._popen is None:
+ return None
+ return self._popen.poll()
+
+ def get_pid(self):
+ """Returns the PID of the running process, or None."""
+ if not self.is_running():
+ return None
+ return self._popen.pid
+
+ def _load_io_log(self):
+ if self._qemu_log_path is not None:
+ with open(self._qemu_log_path, "r") as iolog:
+ self._iolog = iolog.read()
+
+ def _base_args(self):
+ if isinstance(self._monitor_address, tuple):
+ moncdev = "socket,id=mon,host=%s,port=%s" % (
+ self._monitor_address[0],
+ self._monitor_address[1])
+ else:
+ moncdev = 'socket,id=mon,path=%s' % self._vm_monitor
+ args = ['-chardev', moncdev,
+ '-mon', 'chardev=mon,mode=control',
+ '-display', 'none', '-vga', 'none']
+ if self._machine is not None:
+ args.extend(['-machine', self._machine])
+ if self._console_set:
+ self._console_address = os.path.join(self._temp_dir,
+ self._name + "-console.sock")
+ chardev = ('socket,id=console,path=%s,server,nowait' %
+ self._console_address)
+ args.extend(['-chardev', chardev])
+ if self._console_device_type is None:
+ args.extend(['-serial', 'chardev:console'])
+ else:
+ device = '%s,chardev=console' % self._console_device_type
+ args.extend(['-device', device])
+ return args
+
+ def _pre_launch(self):
+ self._temp_dir = tempfile.mkdtemp(dir=self._test_dir)
+ if self._monitor_address is not None:
+ self._vm_monitor = self._monitor_address
+ else:
+ self._vm_monitor = os.path.join(self._temp_dir,
+ self._name + "-monitor.sock")
+ self._qemu_log_path = os.path.join(self._temp_dir, self._name + ".log")
+ self._qemu_log_file = open(self._qemu_log_path, 'wb')
+
+ self._qmp = qmp.QEMUMonitorProtocol(self._vm_monitor,
+ server=True)
+
+ def _post_launch(self):
+ self._qmp.accept()
+
+ def _post_shutdown(self):
+ if self._qemu_log_file is not None:
+ self._qemu_log_file.close()
+ self._qemu_log_file = None
+
+ self._qemu_log_path = None
+
+ if self._console_socket is not None:
+ self._console_socket.close()
+ self._console_socket = None
+
+ if self._temp_dir is not None:
+ shutil.rmtree(self._temp_dir)
+ self._temp_dir = None
+
+ def launch(self):
+ """
+ Launch the VM and make sure we cleanup and expose the
+ command line/output in case of exception
+ """
+
+ if self._launched:
+ raise QEMUMachineError('VM already launched')
+
+ self._iolog = None
+ self._qemu_full_args = None
+ try:
+ self._launch()
+ self._launched = True
+ except:
+ self.shutdown()
+
+ LOG.debug('Error launching VM')
+ if self._qemu_full_args:
+ LOG.debug('Command: %r', ' '.join(self._qemu_full_args))
+ if self._iolog:
+ LOG.debug('Output: %r', self._iolog)
+ raise
+
+ def _launch(self):
+ """
+ Launch the VM and establish a QMP connection
+ """
+ devnull = open(os.path.devnull, 'rb')
+ self._pre_launch()
+ self._qemu_full_args = (self._wrapper + [self._binary] +
+ self._base_args() + self._args)
+ LOG.debug('VM launch command: %r', ' '.join(self._qemu_full_args))
+ self._popen = subprocess.Popen(self._qemu_full_args,
+ stdin=devnull,
+ stdout=self._qemu_log_file,
+ stderr=subprocess.STDOUT,
+ shell=False,
+ close_fds=False)
+ self._post_launch()
+
+ def wait(self):
+ """
+ Wait for the VM to power off
+ """
+ self._popen.wait()
+ self._qmp.close()
+ self._load_io_log()
+ self._post_shutdown()
+
+ def shutdown(self):
+ """
+ Terminate the VM and clean up
+ """
+ if self.is_running():
+ try:
+ self._qmp.cmd('quit')
+ self._qmp.close()
+ except:
+ self._popen.kill()
+ self._popen.wait()
+
+ self._load_io_log()
+ self._post_shutdown()
+
+ exitcode = self.exitcode()
+ if exitcode is not None and exitcode < 0:
+ msg = 'qemu received signal %i: %s'
+ if self._qemu_full_args:
+ command = ' '.join(self._qemu_full_args)
+ else:
+ command = ''
+ LOG.warning(msg, -exitcode, command)
+
+ self._launched = False
+
+ def qmp(self, cmd, conv_keys=True, **args):
+ """
+ Invoke a QMP command and return the response dict
+ """
+ qmp_args = dict()
+ for key, value in args.items():
+ if conv_keys:
+ qmp_args[key.replace('_', '-')] = value
+ else:
+ qmp_args[key] = value
+
+ return self._qmp.cmd(cmd, args=qmp_args)
+
+ def command(self, cmd, conv_keys=True, **args):
+ """
+ Invoke a QMP command.
+ On success return the response dict.
+ On failure raise an exception.
+ """
+ reply = self.qmp(cmd, conv_keys, **args)
+ if reply is None:
+ raise qmp.QMPError("Monitor is closed")
+ if "error" in reply:
+ raise MonitorResponseError(reply)
+ return reply["return"]
+
+ def get_qmp_event(self, wait=False):
+ """
+ Poll for one queued QMP events and return it
+ """
+ if self._events:
+ return self._events.pop(0)
+ return self._qmp.pull_event(wait=wait)
+
+ def get_qmp_events(self, wait=False):
+ """
+ Poll for queued QMP events and return a list of dicts
+ """
+ events = self._qmp.get_events(wait=wait)
+ events.extend(self._events)
+ del self._events[:]
+ self._qmp.clear_events()
+ return events
+
+ @staticmethod
+ def event_match(event, match=None):
+ """
+ Check if an event matches optional match criteria.
+
+ The match criteria takes the form of a matching subdict. The event is
+ checked to be a superset of the subdict, recursively, with matching
+ values whenever the subdict values are not None.
+
+ This has a limitation that you cannot explicitly check for None values.
+
+ Examples, with the subdict queries on the left:
+ - None matches any object.
+ - {"foo": None} matches {"foo": {"bar": 1}}
+ - {"foo": None} matches {"foo": 5}
+ - {"foo": {"abc": None}} does not match {"foo": {"bar": 1}}
+ - {"foo": {"rab": 2}} matches {"foo": {"bar": 1, "rab": 2}}
+ """
+ if match is None:
+ return True
+
+ try:
+ for key in match:
+ if key in event:
+ if not QEMUMachine.event_match(event[key], match[key]):
+ return False
+ else:
+ return False
+ return True
+ except TypeError:
+ # either match or event wasn't iterable (not a dict)
+ return match == event
+
+ def event_wait(self, name, timeout=60.0, match=None):
+ """
+ event_wait waits for and returns a named event from QMP with a timeout.
+
+ name: The event to wait for.
+ timeout: QEMUMonitorProtocol.pull_event timeout parameter.
+ match: Optional match criteria. See event_match for details.
+ """
+ return self.events_wait([(name, match)], timeout)
+
+ def events_wait(self, events, timeout=60.0):
+ """
+ events_wait waits for and returns a named event from QMP with a timeout.
+
+ events: a sequence of (name, match_criteria) tuples.
+ The match criteria are optional and may be None.
+ See event_match for details.
+ timeout: QEMUMonitorProtocol.pull_event timeout parameter.
+ """
+ def _match(event):
+ for name, match in events:
+ if event['event'] == name and self.event_match(event, match):
+ return True
+ return False
+
+ # Search cached events
+ for event in self._events:
+ if _match(event):
+ self._events.remove(event)
+ return event
+
+ # Poll for new events
+ while True:
+ event = self._qmp.pull_event(wait=timeout)
+ if _match(event):
+ return event
+ self._events.append(event)
+
+ return None
+
+ def get_log(self):
+ """
+ After self.shutdown or failed qemu execution, this returns the output
+ of the qemu process.
+ """
+ return self._iolog
+
+ def add_args(self, *args):
+ """
+ Adds to the list of extra arguments to be given to the QEMU binary
+ """
+ self._args.extend(args)
+
+ def set_machine(self, machine_type):
+ """
+ Sets the machine type
+
+ If set, the machine type will be added to the base arguments
+ of the resulting QEMU command line.
+ """
+ self._machine = machine_type
+
+ def set_console(self, device_type=None):
+ """
+ Sets the device type for a console device
+
+ If set, the console device and a backing character device will
+ be added to the base arguments of the resulting QEMU command
+ line.
+
+ This is a convenience method that will either use the provided
+ device type, or default to a "-serial chardev:console" command
+ line argument.
+
+ The actual setting of command line arguments will be be done at
+ machine launch time, as it depends on the temporary directory
+ to be created.
+
+ @param device_type: the device type, such as "isa-serial". If
+ None is given (the default value) a "-serial
+ chardev:console" command line argument will
+ be used instead, resorting to the machine's
+ default device type.
+ """
+ self._console_set = True
+ self._console_device_type = device_type
+
+ @property
+ def console_socket(self):
+ """
+ Returns a socket connected to the console
+ """
+ if self._console_socket is None:
+ self._console_socket = socket.socket(socket.AF_UNIX,
+ socket.SOCK_STREAM)
+ self._console_socket.connect(self._console_address)
+ return self._console_socket
import socket
import os
-from . import QEMUMachine
+from .machine import QEMUMachine
class QEMUQtestProtocol(object):
util-obj-y += qapi-util.o
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_COMMON_MODULES += dump introspect job machine migration misc net
+QAPI_COMMON_MODULES += qdev qom rdma rocker run-state sockets tpm
+QAPI_COMMON_MODULES += trace transaction ui
+QAPI_TARGET_MODULES = machine-target misc-target
QAPI_MODULES = $(QAPI_COMMON_MODULES) $(QAPI_TARGET_MODULES)
util-obj-y += qapi-builtin-types.o
--- /dev/null
+# -*- Mode: Python -*-
+#
+# This work is licensed under the terms of the GNU GPL, version 2 or later.
+# See the COPYING file in the top-level directory.
+
+##
+# = Dump guest memory
+##
+
+##
+# @DumpGuestMemoryFormat:
+#
+# An enumeration of guest-memory-dump's format.
+#
+# @elf: elf format
+#
+# @kdump-zlib: kdump-compressed format with zlib-compressed
+#
+# @kdump-lzo: kdump-compressed format with lzo-compressed
+#
+# @kdump-snappy: kdump-compressed format with snappy-compressed
+#
+# @win-dmp: Windows full crashdump format,
+# can be used instead of ELF converting (since 2.13)
+#
+# Since: 2.0
+##
+{ 'enum': 'DumpGuestMemoryFormat',
+ 'data': [ 'elf', 'kdump-zlib', 'kdump-lzo', 'kdump-snappy', 'win-dmp' ] }
+
+##
+# @dump-guest-memory:
+#
+# Dump guest's memory to vmcore. It is a synchronous operation that can take
+# very long depending on the amount of guest memory.
+#
+# @paging: if true, do paging to get guest's memory mapping. This allows
+# using gdb to process the core file.
+#
+# IMPORTANT: this option can make QEMU allocate several gigabytes
+# of RAM. This can happen for a large guest, or a
+# malicious guest pretending to be large.
+#
+# Also, paging=true has the following limitations:
+#
+# 1. The guest may be in a catastrophic state or can have corrupted
+# memory, which cannot be trusted
+# 2. The guest can be in real-mode even if paging is enabled. For
+# example, the guest uses ACPI to sleep, and ACPI sleep state
+# goes in real-mode
+# 3. Currently only supported on i386 and x86_64.
+#
+# @protocol: the filename or file descriptor of the vmcore. The supported
+# protocols are:
+#
+# 1. file: the protocol starts with "file:", and the following
+# string is the file's path.
+# 2. fd: the protocol starts with "fd:", and the following string
+# is the fd's name.
+#
+# @detach: if true, QMP will return immediately rather than
+# waiting for the dump to finish. The user can track progress
+# using "query-dump". (since 2.6).
+#
+# @begin: if specified, the starting physical address.
+#
+# @length: if specified, the memory size, in bytes. If you don't
+# want to dump all guest's memory, please specify the start @begin
+# and @length
+#
+# @format: if specified, the format of guest memory dump. But non-elf
+# format is conflict with paging and filter, ie. @paging, @begin and
+# @length is not allowed to be specified with non-elf @format at the
+# same time (since 2.0)
+#
+# Note: All boolean arguments default to false
+#
+# Returns: nothing on success
+#
+# Since: 1.2
+#
+# Example:
+#
+# -> { "execute": "dump-guest-memory",
+# "arguments": { "protocol": "fd:dump" } }
+# <- { "return": {} }
+#
+##
+{ 'command': 'dump-guest-memory',
+ 'data': { 'paging': 'bool', 'protocol': 'str', '*detach': 'bool',
+ '*begin': 'int', '*length': 'int',
+ '*format': 'DumpGuestMemoryFormat'} }
+
+##
+# @DumpStatus:
+#
+# Describe the status of a long-running background guest memory dump.
+#
+# @none: no dump-guest-memory has started yet.
+#
+# @active: there is one dump running in background.
+#
+# @completed: the last dump has finished successfully.
+#
+# @failed: the last dump has failed.
+#
+# Since: 2.6
+##
+{ 'enum': 'DumpStatus',
+ 'data': [ 'none', 'active', 'completed', 'failed' ] }
+
+##
+# @DumpQueryResult:
+#
+# The result format for 'query-dump'.
+#
+# @status: enum of @DumpStatus, which shows current dump status
+#
+# @completed: bytes written in latest dump (uncompressed)
+#
+# @total: total bytes to be written in latest dump (uncompressed)
+#
+# Since: 2.6
+##
+{ 'struct': 'DumpQueryResult',
+ 'data': { 'status': 'DumpStatus',
+ 'completed': 'int',
+ 'total': 'int' } }
+
+##
+# @query-dump:
+#
+# Query latest dump status.
+#
+# Returns: A @DumpStatus object showing the dump status.
+#
+# Since: 2.6
+#
+# Example:
+#
+# -> { "execute": "query-dump" }
+# <- { "return": { "status": "active", "completed": 1024000,
+# "total": 2048000 } }
+#
+##
+{ 'command': 'query-dump', 'returns': 'DumpQueryResult' }
+
+##
+# @DUMP_COMPLETED:
+#
+# Emitted when background dump has completed
+#
+# @result: final dump status
+#
+# @error: human-readable error string that provides
+# hint on why dump failed. Only presents on failure. The
+# user should not try to interpret the error string.
+#
+# Since: 2.6
+#
+# Example:
+#
+# { "event": "DUMP_COMPLETED",
+# "data": {"result": {"total": 1090650112, "status": "completed",
+# "completed": 1090650112} } }
+#
+##
+{ 'event': 'DUMP_COMPLETED' ,
+ 'data': { 'result': 'DumpQueryResult', '*error': 'str' } }
+
+##
+# @DumpGuestMemoryCapability:
+#
+# A list of the available formats for dump-guest-memory
+#
+# Since: 2.0
+##
+{ 'struct': 'DumpGuestMemoryCapability',
+ 'data': {
+ 'formats': ['DumpGuestMemoryFormat'] } }
+
+##
+# @query-dump-guest-memory-capability:
+#
+# Returns the available formats for dump-guest-memory
+#
+# Returns: A @DumpGuestMemoryCapability object listing available formats for
+# dump-guest-memory
+#
+# Since: 2.0
+#
+# Example:
+#
+# -> { "execute": "query-dump-guest-memory-capability" }
+# <- { "return": { "formats":
+# ["elf", "kdump-zlib", "kdump-lzo", "kdump-snappy"] }
+#
+##
+{ 'command': 'query-dump-guest-memory-capability',
+ 'returns': 'DumpGuestMemoryCapability' }
--- /dev/null
+# -*- Mode: Python -*-
+#
+# This work is licensed under the terms of the GNU GPL, version 2 or later.
+# See the COPYING file in the top-level directory.
+
+##
+# @CpuModelInfo:
+#
+# Virtual CPU model.
+#
+# A CPU model consists of the name of a CPU definition, to which
+# delta changes are applied (e.g. features added/removed). Most magic values
+# that an architecture might require should be hidden behind the name.
+# However, if required, architectures can expose relevant properties.
+#
+# @name: the name of the CPU definition the model is based on
+# @props: a dictionary of QOM properties to be applied
+#
+# Since: 2.8.0
+##
+{ 'struct': 'CpuModelInfo',
+ 'data': { 'name': 'str',
+ '*props': 'any' } }
+
+##
+# @CpuModelExpansionType:
+#
+# An enumeration of CPU model expansion types.
+#
+# @static: Expand to a static CPU model, a combination of a static base
+# model name and property delta changes. As the static base model will
+# never change, the expanded CPU model will be the same, independent of
+# QEMU version, machine type, machine options, and accelerator options.
+# Therefore, the resulting model can be used by tooling without having
+# to specify a compatibility machine - e.g. when displaying the "host"
+# model. The @static CPU models are migration-safe.
+
+# @full: Expand all properties. The produced model is not guaranteed to be
+# migration-safe, but allows tooling to get an insight and work with
+# model details.
+#
+# Note: When a non-migration-safe CPU model is expanded in static mode, some
+# features enabled by the CPU model may be omitted, because they can't be
+# implemented by a static CPU model definition (e.g. cache info passthrough and
+# PMU passthrough in x86). If you need an accurate representation of the
+# features enabled by a non-migration-safe CPU model, use @full. If you need a
+# static representation that will keep ABI compatibility even when changing QEMU
+# version or machine-type, use @static (but keep in mind that some features may
+# be omitted).
+#
+# Since: 2.8.0
+##
+{ 'enum': 'CpuModelExpansionType',
+ 'data': [ 'static', 'full' ] }
+
+
+##
+# @CpuModelCompareResult:
+#
+# An enumeration of CPU model comparison results. The result is usually
+# calculated using e.g. CPU features or CPU generations.
+#
+# @incompatible: If model A is incompatible to model B, model A is not
+# guaranteed to run where model B runs and the other way around.
+#
+# @identical: If model A is identical to model B, model A is guaranteed to run
+# where model B runs and the other way around.
+#
+# @superset: If model A is a superset of model B, model B is guaranteed to run
+# where model A runs. There are no guarantees about the other way.
+#
+# @subset: If model A is a subset of model B, model A is guaranteed to run
+# where model B runs. There are no guarantees about the other way.
+#
+# Since: 2.8.0
+##
+{ 'enum': 'CpuModelCompareResult',
+ 'data': [ 'incompatible', 'identical', 'superset', 'subset' ] }
+
+##
+# @CpuModelBaselineInfo:
+#
+# The result of a CPU model baseline.
+#
+# @model: the baselined CpuModelInfo.
+#
+# Since: 2.8.0
+##
+{ 'struct': 'CpuModelBaselineInfo',
+ 'data': { 'model': 'CpuModelInfo' },
+ 'if': 'defined(TARGET_S390X)' }
+
+##
+# @CpuModelCompareInfo:
+#
+# The result of a CPU model comparison.
+#
+# @result: The result of the compare operation.
+# @responsible-properties: List of properties that led to the comparison result
+# not being identical.
+#
+# @responsible-properties is a list of QOM property names that led to
+# both CPUs not being detected as identical. For identical models, this
+# list is empty.
+# If a QOM property is read-only, that means there's no known way to make the
+# CPU models identical. If the special property name "type" is included, the
+# models are by definition not identical and cannot be made identical.
+#
+# Since: 2.8.0
+##
+{ 'struct': 'CpuModelCompareInfo',
+ 'data': { 'result': 'CpuModelCompareResult',
+ 'responsible-properties': ['str'] },
+ 'if': 'defined(TARGET_S390X)' }
+
+##
+# @query-cpu-model-comparison:
+#
+# Compares two CPU models, returning how they compare in a specific
+# configuration. The results indicates how both models compare regarding
+# runnability. This result can be used by tooling to make decisions if a
+# certain CPU model will run in a certain configuration or if a compatible
+# CPU model has to be created by baselining.
+#
+# Usually, a CPU model is compared against the maximum possible CPU model
+# of a certain configuration (e.g. the "host" model for KVM). If that CPU
+# model is identical or a subset, it will run in that configuration.
+#
+# The result returned by this command may be affected by:
+#
+# * QEMU version: CPU models may look different depending on the QEMU version.
+# (Except for CPU models reported as "static" in query-cpu-definitions.)
+# * machine-type: CPU model may look different depending on the machine-type.
+# (Except for CPU models reported as "static" in query-cpu-definitions.)
+# * machine options (including accelerator): in some architectures, CPU models
+# may look different depending on machine and accelerator options. (Except for
+# CPU models reported as "static" in query-cpu-definitions.)
+# * "-cpu" arguments and global properties: arguments to the -cpu option and
+# global properties may affect expansion of CPU models. Using
+# query-cpu-model-expansion while using these is not advised.
+#
+# Some architectures may not support comparing CPU models. s390x supports
+# comparing CPU models.
+#
+# Returns: a CpuModelBaselineInfo. Returns an error if comparing CPU models is
+# not supported, if a model cannot be used, if a model contains
+# an unknown cpu definition name, unknown properties or properties
+# with wrong types.
+#
+# Note: this command isn't specific to s390x, but is only implemented
+# on this architecture currently.
+#
+# Since: 2.8.0
+##
+{ 'command': 'query-cpu-model-comparison',
+ 'data': { 'modela': 'CpuModelInfo', 'modelb': 'CpuModelInfo' },
+ 'returns': 'CpuModelCompareInfo',
+ 'if': 'defined(TARGET_S390X)' }
+
+##
+# @query-cpu-model-baseline:
+#
+# Baseline two CPU models, creating a compatible third model. The created
+# model will always be a static, migration-safe CPU model (see "static"
+# CPU model expansion for details).
+#
+# This interface can be used by tooling to create a compatible CPU model out
+# two CPU models. The created CPU model will be identical to or a subset of
+# both CPU models when comparing them. Therefore, the created CPU model is
+# guaranteed to run where the given CPU models run.
+#
+# The result returned by this command may be affected by:
+#
+# * QEMU version: CPU models may look different depending on the QEMU version.
+# (Except for CPU models reported as "static" in query-cpu-definitions.)
+# * machine-type: CPU model may look different depending on the machine-type.
+# (Except for CPU models reported as "static" in query-cpu-definitions.)
+# * machine options (including accelerator): in some architectures, CPU models
+# may look different depending on machine and accelerator options. (Except for
+# CPU models reported as "static" in query-cpu-definitions.)
+# * "-cpu" arguments and global properties: arguments to the -cpu option and
+# global properties may affect expansion of CPU models. Using
+# query-cpu-model-expansion while using these is not advised.
+#
+# Some architectures may not support baselining CPU models. s390x supports
+# baselining CPU models.
+#
+# Returns: a CpuModelBaselineInfo. Returns an error if baselining CPU models is
+# not supported, if a model cannot be used, if a model contains
+# an unknown cpu definition name, unknown properties or properties
+# with wrong types.
+#
+# Note: this command isn't specific to s390x, but is only implemented
+# on this architecture currently.
+#
+# Since: 2.8.0
+##
+{ 'command': 'query-cpu-model-baseline',
+ 'data': { 'modela': 'CpuModelInfo',
+ 'modelb': 'CpuModelInfo' },
+ 'returns': 'CpuModelBaselineInfo',
+ 'if': 'defined(TARGET_S390X)' }
+
+##
+# @CpuModelExpansionInfo:
+#
+# The result of a cpu model expansion.
+#
+# @model: the expanded CpuModelInfo.
+#
+# Since: 2.8.0
+##
+{ 'struct': 'CpuModelExpansionInfo',
+ 'data': { 'model': 'CpuModelInfo' },
+ 'if': 'defined(TARGET_S390X) || defined(TARGET_I386)' }
+
+##
+# @query-cpu-model-expansion:
+#
+# Expands a given CPU model (or a combination of CPU model + additional options)
+# to different granularities, allowing tooling to get an understanding what a
+# specific CPU model looks like in QEMU under a certain configuration.
+#
+# This interface can be used to query the "host" CPU model.
+#
+# The data returned by this command may be affected by:
+#
+# * QEMU version: CPU models may look different depending on the QEMU version.
+# (Except for CPU models reported as "static" in query-cpu-definitions.)
+# * machine-type: CPU model may look different depending on the machine-type.
+# (Except for CPU models reported as "static" in query-cpu-definitions.)
+# * machine options (including accelerator): in some architectures, CPU models
+# may look different depending on machine and accelerator options. (Except for
+# CPU models reported as "static" in query-cpu-definitions.)
+# * "-cpu" arguments and global properties: arguments to the -cpu option and
+# global properties may affect expansion of CPU models. Using
+# query-cpu-model-expansion while using these is not advised.
+#
+# Some architectures may not support all expansion types. s390x supports
+# "full" and "static".
+#
+# Returns: a CpuModelExpansionInfo. Returns an error if expanding CPU models is
+# not supported, if the model cannot be expanded, if the model contains
+# an unknown CPU definition name, unknown properties or properties
+# with a wrong type. Also returns an error if an expansion type is
+# not supported.
+#
+# Since: 2.8.0
+##
+{ 'command': 'query-cpu-model-expansion',
+ 'data': { 'type': 'CpuModelExpansionType',
+ 'model': 'CpuModelInfo' },
+ 'returns': 'CpuModelExpansionInfo',
+ 'if': 'defined(TARGET_S390X) || defined(TARGET_I386)' }
+
+##
+# @CpuDefinitionInfo:
+#
+# Virtual CPU definition.
+#
+# @name: the name of the CPU definition
+#
+# @migration-safe: whether a CPU definition can be safely used for
+# migration in combination with a QEMU compatibility machine
+# when migrating between different QEMU versions and between
+# hosts with different sets of (hardware or software)
+# capabilities. If not provided, information is not available
+# and callers should not assume the CPU definition to be
+# migration-safe. (since 2.8)
+#
+# @static: whether a CPU definition is static and will not change depending on
+# QEMU version, machine type, machine options and accelerator options.
+# A static model is always migration-safe. (since 2.8)
+#
+# @unavailable-features: List of properties that prevent
+# the CPU model from running in the current
+# host. (since 2.8)
+# @typename: Type name that can be used as argument to @device-list-properties,
+# to introspect properties configurable using -cpu or -global.
+# (since 2.9)
+#
+# @unavailable-features is a list of QOM property names that
+# represent CPU model attributes that prevent the CPU from running.
+# If the QOM property is read-only, that means there's no known
+# way to make the CPU model run in the current host. Implementations
+# that choose not to provide specific information return the
+# property name "type".
+# If the property is read-write, it means that it MAY be possible
+# to run the CPU model in the current host if that property is
+# changed. Management software can use it as hints to suggest or
+# choose an alternative for the user, or just to generate meaningful
+# error messages explaining why the CPU model can't be used.
+# If @unavailable-features is an empty list, the CPU model is
+# runnable using the current host and machine-type.
+# If @unavailable-features is not present, runnability
+# information for the CPU is not available.
+#
+# Since: 1.2.0
+##
+{ 'struct': 'CpuDefinitionInfo',
+ 'data': { 'name': 'str',
+ '*migration-safe': 'bool',
+ 'static': 'bool',
+ '*unavailable-features': [ 'str' ],
+ 'typename': 'str' },
+ 'if': 'defined(TARGET_PPC) || defined(TARGET_ARM) || defined(TARGET_I386) || defined(TARGET_S390X) || defined(TARGET_MIPS)' }
+
+##
+# @query-cpu-definitions:
+#
+# Return a list of supported virtual CPU definitions
+#
+# Returns: a list of CpuDefInfo
+#
+# Since: 1.2.0
+##
+{ 'command': 'query-cpu-definitions', 'returns': ['CpuDefinitionInfo'],
+ 'if': 'defined(TARGET_PPC) || defined(TARGET_ARM) || defined(TARGET_I386) || defined(TARGET_S390X) || defined(TARGET_MIPS)' }
--- /dev/null
+# -*- Mode: Python -*-
+#
+# This work is licensed under the terms of the GNU GPL, version 2 or later.
+# See the COPYING file in the top-level directory.
+
+##
+# = Machines
+##
+
+{ 'include': 'common.json' }
+
+##
+# @CpuInfoArch:
+#
+# An enumeration of cpu types that enable additional information during
+# @query-cpus and @query-cpus-fast.
+#
+# @s390: since 2.12
+#
+# @riscv: since 2.12
+#
+# Since: 2.6
+##
+{ 'enum': 'CpuInfoArch',
+ 'data': ['x86', 'sparc', 'ppc', 'mips', 'tricore', 's390', 'riscv', 'other' ] }
+
+##
+# @CpuInfo:
+#
+# Information about a virtual CPU
+#
+# @CPU: the index of the virtual CPU
+#
+# @current: this only exists for backwards compatibility and should be ignored
+#
+# @halted: true if the virtual CPU is in the halt state. Halt usually refers
+# to a processor specific low power mode.
+#
+# @qom_path: path to the CPU object in the QOM tree (since 2.4)
+#
+# @thread_id: ID of the underlying host thread
+#
+# @props: properties describing to which node/socket/core/thread
+# virtual CPU belongs to, provided if supported by board (since 2.10)
+#
+# @arch: architecture of the cpu, which determines which additional fields
+# will be listed (since 2.6)
+#
+# Since: 0.14.0
+#
+# Notes: @halted is a transient state that changes frequently. By the time the
+# data is sent to the client, the guest may no longer be halted.
+##
+{ 'union': 'CpuInfo',
+ 'base': {'CPU': 'int', 'current': 'bool', 'halted': 'bool',
+ 'qom_path': 'str', 'thread_id': 'int',
+ '*props': 'CpuInstanceProperties', 'arch': 'CpuInfoArch' },
+ 'discriminator': 'arch',
+ 'data': { 'x86': 'CpuInfoX86',
+ 'sparc': 'CpuInfoSPARC',
+ 'ppc': 'CpuInfoPPC',
+ 'mips': 'CpuInfoMIPS',
+ 'tricore': 'CpuInfoTricore',
+ 's390': 'CpuInfoS390',
+ 'riscv': 'CpuInfoRISCV' } }
+
+##
+# @CpuInfoX86:
+#
+# Additional information about a virtual i386 or x86_64 CPU
+#
+# @pc: the 64-bit instruction pointer
+#
+# Since: 2.6
+##
+{ 'struct': 'CpuInfoX86', 'data': { 'pc': 'int' } }
+
+##
+# @CpuInfoSPARC:
+#
+# Additional information about a virtual SPARC CPU
+#
+# @pc: the PC component of the instruction pointer
+#
+# @npc: the NPC component of the instruction pointer
+#
+# Since: 2.6
+##
+{ 'struct': 'CpuInfoSPARC', 'data': { 'pc': 'int', 'npc': 'int' } }
+
+##
+# @CpuInfoPPC:
+#
+# Additional information about a virtual PPC CPU
+#
+# @nip: the instruction pointer
+#
+# Since: 2.6
+##
+{ 'struct': 'CpuInfoPPC', 'data': { 'nip': 'int' } }
+
+##
+# @CpuInfoMIPS:
+#
+# Additional information about a virtual MIPS CPU
+#
+# @PC: the instruction pointer
+#
+# Since: 2.6
+##
+{ 'struct': 'CpuInfoMIPS', 'data': { 'PC': 'int' } }
+
+##
+# @CpuInfoTricore:
+#
+# Additional information about a virtual Tricore CPU
+#
+# @PC: the instruction pointer
+#
+# Since: 2.6
+##
+{ 'struct': 'CpuInfoTricore', 'data': { 'PC': 'int' } }
+
+##
+# @CpuInfoRISCV:
+#
+# Additional information about a virtual RISCV CPU
+#
+# @pc: the instruction pointer
+#
+# Since 2.12
+##
+{ 'struct': 'CpuInfoRISCV', 'data': { 'pc': 'int' } }
+
+##
+# @CpuS390State:
+#
+# An enumeration of cpu states that can be assumed by a virtual
+# S390 CPU
+#
+# Since: 2.12
+##
+{ 'enum': 'CpuS390State',
+ 'prefix': 'S390_CPU_STATE',
+ 'data': [ 'uninitialized', 'stopped', 'check-stop', 'operating', 'load' ] }
+
+##
+# @CpuInfoS390:
+#
+# Additional information about a virtual S390 CPU
+#
+# @cpu-state: the virtual CPU's state
+#
+# Since: 2.12
+##
+{ 'struct': 'CpuInfoS390', 'data': { 'cpu-state': 'CpuS390State' } }
+
+##
+# @query-cpus:
+#
+# Returns a list of information about each virtual CPU.
+#
+# This command causes vCPU threads to exit to userspace, which causes
+# a small interruption to guest CPU execution. This will have a negative
+# impact on realtime guests and other latency sensitive guest workloads.
+# It is recommended to use @query-cpus-fast instead of this command to
+# avoid the vCPU interruption.
+#
+# Returns: a list of @CpuInfo for each virtual CPU
+#
+# Since: 0.14.0
+#
+# Example:
+#
+# -> { "execute": "query-cpus" }
+# <- { "return": [
+# {
+# "CPU":0,
+# "current":true,
+# "halted":false,
+# "qom_path":"/machine/unattached/device[0]",
+# "arch":"x86",
+# "pc":3227107138,
+# "thread_id":3134
+# },
+# {
+# "CPU":1,
+# "current":false,
+# "halted":true,
+# "qom_path":"/machine/unattached/device[2]",
+# "arch":"x86",
+# "pc":7108165,
+# "thread_id":3135
+# }
+# ]
+# }
+#
+# Notes: This interface is deprecated (since 2.12.0), and it is strongly
+# recommended that you avoid using it. Use @query-cpus-fast to
+# obtain information about virtual CPUs.
+#
+##
+{ 'command': 'query-cpus', 'returns': ['CpuInfo'] }
+
+##
+# @CpuInfoFast:
+#
+# Information about a virtual CPU
+#
+# @cpu-index: index of the virtual CPU
+#
+# @qom-path: path to the CPU object in the QOM tree
+#
+# @thread-id: ID of the underlying host thread
+#
+# @props: properties describing to which node/socket/core/thread
+# virtual CPU belongs to, provided if supported by board
+#
+# @arch: base architecture of the cpu; deprecated since 3.0.0 in favor
+# of @target
+#
+# @target: the QEMU system emulation target, which determines which
+# additional fields will be listed (since 3.0)
+#
+# Since: 2.12
+#
+##
+{ 'union' : 'CpuInfoFast',
+ 'base' : { 'cpu-index' : 'int',
+ 'qom-path' : 'str',
+ 'thread-id' : 'int',
+ '*props' : 'CpuInstanceProperties',
+ 'arch' : 'CpuInfoArch',
+ 'target' : 'SysEmuTarget' },
+ 'discriminator' : 'target',
+ 'data' : { 's390x' : 'CpuInfoS390' } }
+
+##
+# @query-cpus-fast:
+#
+# Returns information about all virtual CPUs. This command does not
+# incur a performance penalty and should be used in production
+# instead of query-cpus.
+#
+# Returns: list of @CpuInfoFast
+#
+# Since: 2.12
+#
+# Example:
+#
+# -> { "execute": "query-cpus-fast" }
+# <- { "return": [
+# {
+# "thread-id": 25627,
+# "props": {
+# "core-id": 0,
+# "thread-id": 0,
+# "socket-id": 0
+# },
+# "qom-path": "/machine/unattached/device[0]",
+# "arch":"x86",
+# "target":"x86_64",
+# "cpu-index": 0
+# },
+# {
+# "thread-id": 25628,
+# "props": {
+# "core-id": 0,
+# "thread-id": 0,
+# "socket-id": 1
+# },
+# "qom-path": "/machine/unattached/device[2]",
+# "arch":"x86",
+# "target":"x86_64",
+# "cpu-index": 1
+# }
+# ]
+# }
+##
+{ 'command': 'query-cpus-fast', 'returns': [ 'CpuInfoFast' ] }
+
+##
+# @cpu-add:
+#
+# Adds CPU with specified ID.
+#
+# @id: ID of CPU to be created, valid values [0..max_cpus)
+#
+# Returns: Nothing on success
+#
+# Since: 1.5
+#
+# Note: This command is deprecated. The `device_add` command should be
+# used instead. See the `query-hotpluggable-cpus` command for
+# details.
+#
+# Example:
+#
+# -> { "execute": "cpu-add", "arguments": { "id": 2 } }
+# <- { "return": {} }
+#
+##
+{ 'command': 'cpu-add', 'data': {'id': 'int'} }
+
+##
+# @MachineInfo:
+#
+# Information describing a machine.
+#
+# @name: the name of the machine
+#
+# @alias: an alias for the machine name
+#
+# @is-default: whether the machine is default
+#
+# @cpu-max: maximum number of CPUs supported by the machine type
+# (since 1.5.0)
+#
+# @hotpluggable-cpus: cpu hotplug via -device is supported (since 2.7.0)
+#
+# Since: 1.2.0
+##
+{ 'struct': 'MachineInfo',
+ 'data': { 'name': 'str', '*alias': 'str',
+ '*is-default': 'bool', 'cpu-max': 'int',
+ 'hotpluggable-cpus': 'bool'} }
+
+##
+# @query-machines:
+#
+# Return a list of supported machines
+#
+# Returns: a list of MachineInfo
+#
+# Since: 1.2.0
+##
+{ 'command': 'query-machines', 'returns': ['MachineInfo'] }
+
+##
+# @CurrentMachineParams:
+#
+# Information describing the running machine parameters.
+#
+# @wakeup-suspend-support: true if the machine supports wake up from
+# suspend
+#
+# Since: 4.0
+##
+{ 'struct': 'CurrentMachineParams',
+ 'data': { 'wakeup-suspend-support': 'bool'} }
+
+##
+# @query-current-machine:
+#
+# Return information on the current virtual machine.
+#
+# Returns: CurrentMachineParams
+#
+# Since: 4.0
+##
+{ 'command': 'query-current-machine', 'returns': 'CurrentMachineParams' }
+
+##
+# @NumaOptionsType:
+#
+# @node: NUMA nodes configuration
+#
+# @dist: NUMA distance configuration (since 2.10)
+#
+# @cpu: property based CPU(s) to node mapping (Since: 2.10)
+#
+# Since: 2.1
+##
+{ 'enum': 'NumaOptionsType',
+ 'data': [ 'node', 'dist', 'cpu' ] }
+
+##
+# @NumaOptions:
+#
+# A discriminated record of NUMA options. (for OptsVisitor)
+#
+# Since: 2.1
+##
+{ 'union': 'NumaOptions',
+ 'base': { 'type': 'NumaOptionsType' },
+ 'discriminator': 'type',
+ 'data': {
+ 'node': 'NumaNodeOptions',
+ 'dist': 'NumaDistOptions',
+ 'cpu': 'NumaCpuOptions' }}
+
+##
+# @NumaNodeOptions:
+#
+# Create a guest NUMA node. (for OptsVisitor)
+#
+# @nodeid: NUMA node ID (increase by 1 from 0 if omitted)
+#
+# @cpus: VCPUs belonging to this node (assign VCPUS round-robin
+# if omitted)
+#
+# @mem: memory size of this node; mutually exclusive with @memdev.
+# Equally divide total memory among nodes if both @mem and @memdev are
+# omitted.
+#
+# @memdev: memory backend object. If specified for one node,
+# it must be specified for all nodes.
+#
+# Since: 2.1
+##
+{ 'struct': 'NumaNodeOptions',
+ 'data': {
+ '*nodeid': 'uint16',
+ '*cpus': ['uint16'],
+ '*mem': 'size',
+ '*memdev': 'str' }}
+
+##
+# @NumaDistOptions:
+#
+# Set the distance between 2 NUMA nodes.
+#
+# @src: source NUMA node.
+#
+# @dst: destination NUMA node.
+#
+# @val: NUMA distance from source node to destination node.
+# When a node is unreachable from another node, set the distance
+# between them to 255.
+#
+# Since: 2.10
+##
+{ 'struct': 'NumaDistOptions',
+ 'data': {
+ 'src': 'uint16',
+ 'dst': 'uint16',
+ 'val': 'uint8' }}
+
+##
+# @X86CPURegister32:
+#
+# A X86 32-bit register
+#
+# Since: 1.5
+##
+{ 'enum': 'X86CPURegister32',
+ 'data': [ 'EAX', 'EBX', 'ECX', 'EDX', 'ESP', 'EBP', 'ESI', 'EDI' ] }
+
+##
+# @X86CPUFeatureWordInfo:
+#
+# Information about a X86 CPU feature word
+#
+# @cpuid-input-eax: Input EAX value for CPUID instruction for that feature word
+#
+# @cpuid-input-ecx: Input ECX value for CPUID instruction for that
+# feature word
+#
+# @cpuid-register: Output register containing the feature bits
+#
+# @features: value of output register, containing the feature bits
+#
+# Since: 1.5
+##
+{ 'struct': 'X86CPUFeatureWordInfo',
+ 'data': { 'cpuid-input-eax': 'int',
+ '*cpuid-input-ecx': 'int',
+ 'cpuid-register': 'X86CPURegister32',
+ 'features': 'int' } }
+
+##
+# @DummyForceArrays:
+#
+# Not used by QMP; hack to let us use X86CPUFeatureWordInfoList internally
+#
+# Since: 2.5
+##
+{ 'struct': 'DummyForceArrays',
+ 'data': { 'unused': ['X86CPUFeatureWordInfo'] } }
+
+##
+# @NumaCpuOptions:
+#
+# Option "-numa cpu" overrides default cpu to node mapping.
+# It accepts the same set of cpu properties as returned by
+# query-hotpluggable-cpus[].props, where node-id could be used to
+# override default node mapping.
+#
+# Since: 2.10
+##
+{ 'struct': 'NumaCpuOptions',
+ 'base': 'CpuInstanceProperties',
+ 'data' : {} }
+
+##
+# @HostMemPolicy:
+#
+# Host memory policy types
+#
+# @default: restore default policy, remove any nondefault policy
+#
+# @preferred: set the preferred host nodes for allocation
+#
+# @bind: a strict policy that restricts memory allocation to the
+# host nodes specified
+#
+# @interleave: memory allocations are interleaved across the set
+# of host nodes specified
+#
+# Since: 2.1
+##
+{ 'enum': 'HostMemPolicy',
+ 'data': [ 'default', 'preferred', 'bind', 'interleave' ] }
+
+##
+# @Memdev:
+#
+# Information about memory backend
+#
+# @id: backend's ID if backend has 'id' property (since 2.9)
+#
+# @size: memory backend size
+#
+# @merge: enables or disables memory merge support
+#
+# @dump: includes memory backend's memory in a core dump or not
+#
+# @prealloc: enables or disables memory preallocation
+#
+# @host-nodes: host nodes for its memory policy
+#
+# @policy: memory policy of memory backend
+#
+# Since: 2.1
+##
+{ 'struct': 'Memdev',
+ 'data': {
+ '*id': 'str',
+ 'size': 'size',
+ 'merge': 'bool',
+ 'dump': 'bool',
+ 'prealloc': 'bool',
+ 'host-nodes': ['uint16'],
+ 'policy': 'HostMemPolicy' }}
+
+##
+# @query-memdev:
+#
+# Returns information for all memory backends.
+#
+# Returns: a list of @Memdev.
+#
+# Since: 2.1
+#
+# Example:
+#
+# -> { "execute": "query-memdev" }
+# <- { "return": [
+# {
+# "id": "mem1",
+# "size": 536870912,
+# "merge": false,
+# "dump": true,
+# "prealloc": false,
+# "host-nodes": [0, 1],
+# "policy": "bind"
+# },
+# {
+# "size": 536870912,
+# "merge": false,
+# "dump": true,
+# "prealloc": true,
+# "host-nodes": [2, 3],
+# "policy": "preferred"
+# }
+# ]
+# }
+#
+##
+{ 'command': 'query-memdev', 'returns': ['Memdev'], 'allow-preconfig': true }
+
+##
+# @CpuInstanceProperties:
+#
+# List of properties to be used for hotplugging a CPU instance,
+# it should be passed by management with device_add command when
+# a CPU is being hotplugged.
+#
+# @node-id: NUMA node ID the CPU belongs to
+# @socket-id: socket number within node/board the CPU belongs to
+# @core-id: core number within socket the CPU belongs to
+# @thread-id: thread number within core the CPU belongs to
+#
+# Note: currently there are 4 properties that could be present
+# but management should be prepared to pass through other
+# properties with device_add command to allow for future
+# interface extension. This also requires the filed names to be kept in
+# sync with the properties passed to -device/device_add.
+#
+# Since: 2.7
+##
+{ 'struct': 'CpuInstanceProperties',
+ 'data': { '*node-id': 'int',
+ '*socket-id': 'int',
+ '*core-id': 'int',
+ '*thread-id': 'int'
+ }
+}
+
+##
+# @HotpluggableCPU:
+#
+# @type: CPU object type for usage with device_add command
+# @props: list of properties to be used for hotplugging CPU
+# @vcpus-count: number of logical VCPU threads @HotpluggableCPU provides
+# @qom-path: link to existing CPU object if CPU is present or
+# omitted if CPU is not present.
+#
+# Since: 2.7
+##
+{ 'struct': 'HotpluggableCPU',
+ 'data': { 'type': 'str',
+ 'vcpus-count': 'int',
+ 'props': 'CpuInstanceProperties',
+ '*qom-path': 'str'
+ }
+}
+
+##
+# @query-hotpluggable-cpus:
+#
+# TODO: Better documentation; currently there is none.
+#
+# Returns: a list of HotpluggableCPU objects.
+#
+# Since: 2.7
+#
+# Example:
+#
+# For pseries machine type started with -smp 2,cores=2,maxcpus=4 -cpu POWER8:
+#
+# -> { "execute": "query-hotpluggable-cpus" }
+# <- {"return": [
+# { "props": { "core": 8 }, "type": "POWER8-spapr-cpu-core",
+# "vcpus-count": 1 },
+# { "props": { "core": 0 }, "type": "POWER8-spapr-cpu-core",
+# "vcpus-count": 1, "qom-path": "/machine/unattached/device[0]"}
+# ]}'
+#
+# For pc machine type started with -smp 1,maxcpus=2:
+#
+# -> { "execute": "query-hotpluggable-cpus" }
+# <- {"return": [
+# {
+# "type": "qemu64-x86_64-cpu", "vcpus-count": 1,
+# "props": {"core-id": 0, "socket-id": 1, "thread-id": 0}
+# },
+# {
+# "qom-path": "/machine/unattached/device[0]",
+# "type": "qemu64-x86_64-cpu", "vcpus-count": 1,
+# "props": {"core-id": 0, "socket-id": 0, "thread-id": 0}
+# }
+# ]}
+#
+# For s390x-virtio-ccw machine type started with -smp 1,maxcpus=2 -cpu qemu
+# (Since: 2.11):
+#
+# -> { "execute": "query-hotpluggable-cpus" }
+# <- {"return": [
+# {
+# "type": "qemu-s390x-cpu", "vcpus-count": 1,
+# "props": { "core-id": 1 }
+# },
+# {
+# "qom-path": "/machine/unattached/device[0]",
+# "type": "qemu-s390x-cpu", "vcpus-count": 1,
+# "props": { "core-id": 0 }
+# }
+# ]}
+#
+##
+{ 'command': 'query-hotpluggable-cpus', 'returns': ['HotpluggableCPU'],
+ 'allow-preconfig': true }
+
+##
+# @set-numa-node:
+#
+# Runtime equivalent of '-numa' CLI option, available at
+# preconfigure stage to configure numa mapping before initializing
+# machine.
+#
+# Since 3.0
+##
+{ 'command': 'set-numa-node', 'boxed': true,
+ 'data': 'NumaOptions',
+ 'allow-preconfig': true
+}
--- /dev/null
+# -*- Mode: Python -*-
+#
+
+##
+# @RTC_CHANGE:
+#
+# Emitted when the guest changes the RTC time.
+#
+# @offset: offset between base RTC clock (as specified by -rtc base), and
+# new RTC clock value
+#
+# Note: This event is rate-limited.
+#
+# Since: 0.13.0
+#
+# Example:
+#
+# <- { "event": "RTC_CHANGE",
+# "data": { "offset": 78 },
+# "timestamp": { "seconds": 1267020223, "microseconds": 435656 } }
+#
+##
+{ 'event': 'RTC_CHANGE',
+ 'data': { 'offset': 'int' },
+ 'if': 'defined(TARGET_ALPHA) || defined(TARGET_ARM) || defined(TARGET_HPPA) || defined(TARGET_I386) || defined(TARGET_MIPS) || defined(TARGET_MIPS64) || defined(TARGET_MOXIE) || defined(TARGET_PPC) || defined(TARGET_PPC64) || defined(TARGET_S390X) || defined(TARGET_SH4) || defined(TARGET_SPARC)' }
+
+##
+# @rtc-reset-reinjection:
+#
+# This command will reset the RTC interrupt reinjection backlog.
+# Can be used if another mechanism to synchronize guest time
+# is in effect, for example QEMU guest agent's guest-set-time
+# command.
+#
+# Since: 2.1
+#
+# Example:
+#
+# -> { "execute": "rtc-reset-reinjection" }
+# <- { "return": {} }
+#
+##
+{ 'command': 'rtc-reset-reinjection',
+ 'if': 'defined(TARGET_I386)' }
+
+
+##
+# @SevState:
+#
+# An enumeration of SEV state information used during @query-sev.
+#
+# @uninit: The guest is uninitialized.
+#
+# @launch-update: The guest is currently being launched; plaintext data and
+# register state is being imported.
+#
+# @launch-secret: The guest is currently being launched; ciphertext data
+# is being imported.
+#
+# @running: The guest is fully launched or migrated in.
+#
+# @send-update: The guest is currently being migrated out to another machine.
+#
+# @receive-update: The guest is currently being migrated from another machine.
+#
+# Since: 2.12
+##
+{ 'enum': 'SevState',
+ 'data': ['uninit', 'launch-update', 'launch-secret', 'running',
+ 'send-update', 'receive-update' ],
+ 'if': 'defined(TARGET_I386)' }
+
+##
+# @SevInfo:
+#
+# Information about Secure Encrypted Virtualization (SEV) support
+#
+# @enabled: true if SEV is active
+#
+# @api-major: SEV API major version
+#
+# @api-minor: SEV API minor version
+#
+# @build-id: SEV FW build id
+#
+# @policy: SEV policy value
+#
+# @state: SEV guest state
+#
+# @handle: SEV firmware handle
+#
+# Since: 2.12
+##
+{ 'struct': 'SevInfo',
+ 'data': { 'enabled': 'bool',
+ 'api-major': 'uint8',
+ 'api-minor' : 'uint8',
+ 'build-id' : 'uint8',
+ 'policy' : 'uint32',
+ 'state' : 'SevState',
+ 'handle' : 'uint32'
+ },
+ 'if': 'defined(TARGET_I386)'
+}
+
+##
+# @query-sev:
+#
+# Returns information about SEV
+#
+# Returns: @SevInfo
+#
+# Since: 2.12
+#
+# Example:
+#
+# -> { "execute": "query-sev" }
+# <- { "return": { "enabled": true, "api-major" : 0, "api-minor" : 0,
+# "build-id" : 0, "policy" : 0, "state" : "running",
+# "handle" : 1 } }
+#
+##
+{ 'command': 'query-sev', 'returns': 'SevInfo',
+ 'if': 'defined(TARGET_I386)' }
+
+
+##
+# @SevLaunchMeasureInfo:
+#
+# SEV Guest Launch measurement information
+#
+# @data: the measurement value encoded in base64
+#
+# Since: 2.12
+#
+##
+{ 'struct': 'SevLaunchMeasureInfo', 'data': {'data': 'str'},
+ 'if': 'defined(TARGET_I386)' }
+
+##
+# @query-sev-launch-measure:
+#
+# Query the SEV guest launch information.
+#
+# Returns: The @SevLaunchMeasureInfo for the guest
+#
+# Since: 2.12
+#
+# Example:
+#
+# -> { "execute": "query-sev-launch-measure" }
+# <- { "return": { "data": "4l8LXeNlSPUDlXPJG5966/8%YZ" } }
+#
+##
+{ 'command': 'query-sev-launch-measure', 'returns': 'SevLaunchMeasureInfo',
+ 'if': 'defined(TARGET_I386)' }
+
+
+##
+# @SevCapability:
+#
+# The struct describes capability for a Secure Encrypted Virtualization
+# feature.
+#
+# @pdh: Platform Diffie-Hellman key (base64 encoded)
+#
+# @cert-chain: PDH certificate chain (base64 encoded)
+#
+# @cbitpos: C-bit location in page table entry
+#
+# @reduced-phys-bits: Number of physical Address bit reduction when SEV is
+# enabled
+#
+# Since: 2.12
+##
+{ 'struct': 'SevCapability',
+ 'data': { 'pdh': 'str',
+ 'cert-chain': 'str',
+ 'cbitpos': 'int',
+ 'reduced-phys-bits': 'int'},
+ 'if': 'defined(TARGET_I386)' }
+
+##
+# @query-sev-capabilities:
+#
+# This command is used to get the SEV capabilities, and is supported on AMD
+# X86 platforms only.
+#
+# Returns: SevCapability objects.
+#
+# Since: 2.12
+#
+# Example:
+#
+# -> { "execute": "query-sev-capabilities" }
+# <- { "return": { "pdh": "8CCDD8DDD", "cert-chain": "888CCCDDDEE",
+# "cbitpos": 47, "reduced-phys-bits": 5}}
+#
+##
+{ 'command': 'query-sev-capabilities', 'returns': 'SevCapability',
+ 'if': 'defined(TARGET_I386)' }
+
+##
+# @dump-skeys:
+#
+# Dump guest's storage keys
+#
+# @filename: the path to the file to dump to
+#
+# This command is only supported on s390 architecture.
+#
+# Since: 2.5
+#
+# Example:
+#
+# -> { "execute": "dump-skeys",
+# "arguments": { "filename": "/tmp/skeys" } }
+# <- { "return": {} }
+#
+##
+{ 'command': 'dump-skeys',
+ 'data': { 'filename': 'str' },
+ 'if': 'defined(TARGET_S390X)' }
+
+##
+# @GICCapability:
+#
+# The struct describes capability for a specific GIC (Generic
+# Interrupt Controller) version. These bits are not only decided by
+# QEMU/KVM software version, but also decided by the hardware that
+# the program is running upon.
+#
+# @version: version of GIC to be described. Currently, only 2 and 3
+# are supported.
+#
+# @emulated: whether current QEMU/hardware supports emulated GIC
+# device in user space.
+#
+# @kernel: whether current QEMU/hardware supports hardware
+# accelerated GIC device in kernel.
+#
+# Since: 2.6
+##
+{ 'struct': 'GICCapability',
+ 'data': { 'version': 'int',
+ 'emulated': 'bool',
+ 'kernel': 'bool' },
+ 'if': 'defined(TARGET_ARM)' }
+
+##
+# @query-gic-capabilities:
+#
+# This command is ARM-only. It will return a list of GICCapability
+# objects that describe its capability bits.
+#
+# Returns: a list of GICCapability objects.
+#
+# Since: 2.6
+#
+# Example:
+#
+# -> { "execute": "query-gic-capabilities" }
+# <- { "return": [{ "version": 2, "emulated": true, "kernel": false },
+# { "version": 3, "emulated": false, "kernel": true } ] }
+#
+##
+{ 'command': 'query-gic-capabilities', 'returns': ['GICCapability'],
+ 'if': 'defined(TARGET_ARM)' }
##
{ 'command': 'query-events', 'returns': ['EventInfo'] }
-##
-# @CpuInfoArch:
-#
-# An enumeration of cpu types that enable additional information during
-# @query-cpus and @query-cpus-fast.
-#
-# @s390: since 2.12
-#
-# @riscv: since 2.12
-#
-# Since: 2.6
-##
-{ 'enum': 'CpuInfoArch',
- 'data': ['x86', 'sparc', 'ppc', 'mips', 'tricore', 's390', 'riscv', 'other' ] }
-
-##
-# @CpuInfo:
-#
-# Information about a virtual CPU
-#
-# @CPU: the index of the virtual CPU
-#
-# @current: this only exists for backwards compatibility and should be ignored
-#
-# @halted: true if the virtual CPU is in the halt state. Halt usually refers
-# to a processor specific low power mode.
-#
-# @qom_path: path to the CPU object in the QOM tree (since 2.4)
-#
-# @thread_id: ID of the underlying host thread
-#
-# @props: properties describing to which node/socket/core/thread
-# virtual CPU belongs to, provided if supported by board (since 2.10)
-#
-# @arch: architecture of the cpu, which determines which additional fields
-# will be listed (since 2.6)
-#
-# Since: 0.14.0
-#
-# Notes: @halted is a transient state that changes frequently. By the time the
-# data is sent to the client, the guest may no longer be halted.
-##
-{ 'union': 'CpuInfo',
- 'base': {'CPU': 'int', 'current': 'bool', 'halted': 'bool',
- 'qom_path': 'str', 'thread_id': 'int',
- '*props': 'CpuInstanceProperties', 'arch': 'CpuInfoArch' },
- 'discriminator': 'arch',
- 'data': { 'x86': 'CpuInfoX86',
- 'sparc': 'CpuInfoSPARC',
- 'ppc': 'CpuInfoPPC',
- 'mips': 'CpuInfoMIPS',
- 'tricore': 'CpuInfoTricore',
- 's390': 'CpuInfoS390',
- 'riscv': 'CpuInfoRISCV' } }
-
-##
-# @CpuInfoX86:
-#
-# Additional information about a virtual i386 or x86_64 CPU
-#
-# @pc: the 64-bit instruction pointer
-#
-# Since: 2.6
-##
-{ 'struct': 'CpuInfoX86', 'data': { 'pc': 'int' } }
-
-##
-# @CpuInfoSPARC:
-#
-# Additional information about a virtual SPARC CPU
-#
-# @pc: the PC component of the instruction pointer
-#
-# @npc: the NPC component of the instruction pointer
-#
-# Since: 2.6
-##
-{ 'struct': 'CpuInfoSPARC', 'data': { 'pc': 'int', 'npc': 'int' } }
-
-##
-# @CpuInfoPPC:
-#
-# Additional information about a virtual PPC CPU
-#
-# @nip: the instruction pointer
-#
-# Since: 2.6
-##
-{ 'struct': 'CpuInfoPPC', 'data': { 'nip': 'int' } }
-
-##
-# @CpuInfoMIPS:
-#
-# Additional information about a virtual MIPS CPU
-#
-# @PC: the instruction pointer
-#
-# Since: 2.6
-##
-{ 'struct': 'CpuInfoMIPS', 'data': { 'PC': 'int' } }
-
-##
-# @CpuInfoTricore:
-#
-# Additional information about a virtual Tricore CPU
-#
-# @PC: the instruction pointer
-#
-# Since: 2.6
-##
-{ 'struct': 'CpuInfoTricore', 'data': { 'PC': 'int' } }
-
-##
-# @CpuInfoRISCV:
-#
-# Additional information about a virtual RISCV CPU
-#
-# @pc: the instruction pointer
-#
-# Since 2.12
-##
-{ 'struct': 'CpuInfoRISCV', 'data': { 'pc': 'int' } }
-
-##
-# @CpuS390State:
-#
-# An enumeration of cpu states that can be assumed by a virtual
-# S390 CPU
-#
-# Since: 2.12
-##
-{ 'enum': 'CpuS390State',
- 'prefix': 'S390_CPU_STATE',
- 'data': [ 'uninitialized', 'stopped', 'check-stop', 'operating', 'load' ] }
-
-##
-# @CpuInfoS390:
-#
-# Additional information about a virtual S390 CPU
-#
-# @cpu-state: the virtual CPU's state
-#
-# Since: 2.12
-##
-{ 'struct': 'CpuInfoS390', 'data': { 'cpu-state': 'CpuS390State' } }
-
-##
-# @query-cpus:
-#
-# Returns a list of information about each virtual CPU.
-#
-# This command causes vCPU threads to exit to userspace, which causes
-# a small interruption to guest CPU execution. This will have a negative
-# impact on realtime guests and other latency sensitive guest workloads.
-# It is recommended to use @query-cpus-fast instead of this command to
-# avoid the vCPU interruption.
-#
-# Returns: a list of @CpuInfo for each virtual CPU
-#
-# Since: 0.14.0
-#
-# Example:
-#
-# -> { "execute": "query-cpus" }
-# <- { "return": [
-# {
-# "CPU":0,
-# "current":true,
-# "halted":false,
-# "qom_path":"/machine/unattached/device[0]",
-# "arch":"x86",
-# "pc":3227107138,
-# "thread_id":3134
-# },
-# {
-# "CPU":1,
-# "current":false,
-# "halted":true,
-# "qom_path":"/machine/unattached/device[2]",
-# "arch":"x86",
-# "pc":7108165,
-# "thread_id":3135
-# }
-# ]
-# }
-#
-# Notes: This interface is deprecated (since 2.12.0), and it is strongly
-# recommended that you avoid using it. Use @query-cpus-fast to
-# obtain information about virtual CPUs.
-#
-##
-{ 'command': 'query-cpus', 'returns': ['CpuInfo'] }
-
-##
-# @CpuInfoFast:
-#
-# Information about a virtual CPU
-#
-# @cpu-index: index of the virtual CPU
-#
-# @qom-path: path to the CPU object in the QOM tree
-#
-# @thread-id: ID of the underlying host thread
-#
-# @props: properties describing to which node/socket/core/thread
-# virtual CPU belongs to, provided if supported by board
-#
-# @arch: base architecture of the cpu; deprecated since 3.0.0 in favor
-# of @target
-#
-# @target: the QEMU system emulation target, which determines which
-# additional fields will be listed (since 3.0)
-#
-# Since: 2.12
-#
-##
-{ 'union' : 'CpuInfoFast',
- 'base' : { 'cpu-index' : 'int',
- 'qom-path' : 'str',
- 'thread-id' : 'int',
- '*props' : 'CpuInstanceProperties',
- 'arch' : 'CpuInfoArch',
- 'target' : 'SysEmuTarget' },
- 'discriminator' : 'target',
- 'data' : { 's390x' : 'CpuInfoS390' } }
-
-##
-# @query-cpus-fast:
-#
-# Returns information about all virtual CPUs. This command does not
-# incur a performance penalty and should be used in production
-# instead of query-cpus.
-#
-# Returns: list of @CpuInfoFast
-#
-# Since: 2.12
-#
-# Example:
-#
-# -> { "execute": "query-cpus-fast" }
-# <- { "return": [
-# {
-# "thread-id": 25627,
-# "props": {
-# "core-id": 0,
-# "thread-id": 0,
-# "socket-id": 0
-# },
-# "qom-path": "/machine/unattached/device[0]",
-# "arch":"x86",
-# "target":"x86_64",
-# "cpu-index": 0
-# },
-# {
-# "thread-id": 25628,
-# "props": {
-# "core-id": 0,
-# "thread-id": 0,
-# "socket-id": 1
-# },
-# "qom-path": "/machine/unattached/device[2]",
-# "arch":"x86",
-# "target":"x86_64",
-# "cpu-index": 1
-# }
-# ]
-# }
-##
-{ 'command': 'query-cpus-fast', 'returns': [ 'CpuInfoFast' ] }
-
##
# @IOThreadInfo:
#
##
{ 'command': 'system_powerdown' }
-##
-# @cpu-add:
-#
-# Adds CPU with specified ID.
-#
-# @id: ID of CPU to be created, valid values [0..max_cpus)
-#
-# Returns: Nothing on success
-#
-# Since: 1.5
-#
-# Note: This command is deprecated. The `device_add` command should be
-# used instead. See the `query-hotpluggable-cpus` command for
-# details.
-#
-# Example:
-#
-# -> { "execute": "cpu-add", "arguments": { "id": 2 } }
-# <- { "return": {} }
-#
-##
-{ 'command': 'cpu-add', 'data': {'id': 'int'} }
-
##
# @memsave:
#
'data': {'command-line': 'str', '*cpu-index': 'int'},
'returns': 'str' }
-##
-# @ObjectPropertyInfo:
-#
-# @name: the name of the property
-#
-# @type: the type of the property. This will typically come in one of four
-# forms:
-#
-# 1) A primitive type such as 'u8', 'u16', 'bool', 'str', or 'double'.
-# These types are mapped to the appropriate JSON type.
-#
-# 2) A child type in the form 'child<subtype>' where subtype is a qdev
-# device type name. Child properties create the composition tree.
-#
-# 3) A link type in the form 'link<subtype>' where subtype is a qdev
-# device type name. Link properties form the device model graph.
-#
-# @description: if specified, the description of the property.
-#
-# Since: 1.2
-##
-{ 'struct': 'ObjectPropertyInfo',
- 'data': { 'name': 'str', 'type': 'str', '*description': 'str' } }
-
-##
-# @qom-list:
-#
-# This command will list any properties of a object given a path in the object
-# model.
-#
-# @path: the path within the object model. See @qom-get for a description of
-# this parameter.
-#
-# Returns: a list of @ObjectPropertyInfo that describe the properties of the
-# object.
-#
-# Since: 1.2
-#
-# Example:
-#
-# -> { "execute": "qom-list",
-# "arguments": { "path": "/chardevs" } }
-# <- { "return": [ { "name": "type", "type": "string" },
-# { "name": "parallel0", "type": "child<chardev-vc>" },
-# { "name": "serial0", "type": "child<chardev-vc>" },
-# { "name": "mon0", "type": "child<chardev-stdio>" } ] }
-#
-##
-{ 'command': 'qom-list',
- 'data': { 'path': 'str' },
- 'returns': [ 'ObjectPropertyInfo' ],
- 'allow-preconfig': true }
-
-##
-# @qom-get:
-#
-# This command will get a property from a object model path and return the
-# value.
-#
-# @path: The path within the object model. There are two forms of supported
-# paths--absolute and partial paths.
-#
-# Absolute paths are derived from the root object and can follow child<>
-# or link<> properties. Since they can follow link<> properties, they
-# can be arbitrarily long. Absolute paths look like absolute filenames
-# and are prefixed with a leading slash.
-#
-# Partial paths look like relative filenames. They do not begin
-# with a prefix. The matching rules for partial paths are subtle but
-# designed to make specifying objects easy. At each level of the
-# composition tree, the partial path is matched as an absolute path.
-# The first match is not returned. At least two matches are searched
-# for. A successful result is only returned if only one match is
-# found. If more than one match is found, a flag is return to
-# indicate that the match was ambiguous.
-#
-# @property: The property name to read
-#
-# Returns: The property value. The type depends on the property
-# type. child<> and link<> properties are returned as #str
-# pathnames. All integer property types (u8, u16, etc) are
-# returned as #int.
-#
-# Since: 1.2
-#
-# Example:
-#
-# 1. Use absolute path
-#
-# -> { "execute": "qom-get",
-# "arguments": { "path": "/machine/unattached/device[0]",
-# "property": "hotplugged" } }
-# <- { "return": false }
-#
-# 2. Use partial path
-#
-# -> { "execute": "qom-get",
-# "arguments": { "path": "unattached/sysbus",
-# "property": "type" } }
-# <- { "return": "System" }
-#
-##
-{ 'command': 'qom-get',
- 'data': { 'path': 'str', 'property': 'str' },
- 'returns': 'any',
- 'allow-preconfig': true }
-
-##
-# @qom-set:
-#
-# This command will set a property from a object model path.
-#
-# @path: see @qom-get for a description of this parameter
-#
-# @property: the property name to set
-#
-# @value: a value who's type is appropriate for the property type. See @qom-get
-# for a description of type mapping.
-#
-# Since: 1.2
-#
-# Example:
-#
-# -> { "execute": "qom-set",
-# "arguments": { "path": "/machine",
-# "property": "graphics",
-# "value": false } }
-# <- { "return": {} }
-#
-##
-{ 'command': 'qom-set',
- 'data': { 'path': 'str', 'property': 'str', 'value': 'any' },
- 'allow-preconfig': true }
-
##
# @change:
#
{ 'command': 'change',
'data': {'device': 'str', 'target': 'str', '*arg': 'str'} }
-##
-# @ObjectTypeInfo:
-#
-# This structure describes a search result from @qom-list-types
-#
-# @name: the type name found in the search
-#
-# @abstract: the type is abstract and can't be directly instantiated.
-# Omitted if false. (since 2.10)
-#
-# @parent: Name of parent type, if any (since 2.10)
-#
-# Since: 1.1
-##
-{ 'struct': 'ObjectTypeInfo',
- 'data': { 'name': 'str', '*abstract': 'bool', '*parent': 'str' } }
-
-##
-# @qom-list-types:
-#
-# This command will return a list of types given search parameters
-#
-# @implements: if specified, only return types that implement this type name
-#
-# @abstract: if true, include abstract types in the results
-#
-# Returns: a list of @ObjectTypeInfo or an empty list if no results are found
-#
-# Since: 1.1
-##
-{ 'command': 'qom-list-types',
- 'data': { '*implements': 'str', '*abstract': 'bool' },
- 'returns': [ 'ObjectTypeInfo' ],
- 'allow-preconfig': true }
-
-##
-# @device-list-properties:
-#
-# List properties associated with a device.
-#
-# @typename: the type name of a device
-#
-# Returns: a list of ObjectPropertyInfo describing a devices properties
-#
-# Note: objects can create properties at runtime, for example to describe
-# links between different devices and/or objects. These properties
-# are not included in the output of this command.
-#
-# Since: 1.2
-##
-{ 'command': 'device-list-properties',
- 'data': { 'typename': 'str'},
- 'returns': [ 'ObjectPropertyInfo' ] }
-
-##
-# @qom-list-properties:
-#
-# List properties associated with a QOM object.
-#
-# @typename: the type name of an object
-#
-# Note: objects can create properties at runtime, for example to describe
-# links between different devices and/or objects. These properties
-# are not included in the output of this command.
-#
-# Returns: a list of ObjectPropertyInfo describing object properties
-#
-# Since: 2.12
-##
-{ 'command': 'qom-list-properties',
- 'data': { 'typename': 'str'},
- 'returns': [ 'ObjectPropertyInfo' ],
- 'allow-preconfig': true }
-
##
# @xen-set-global-dirty-log:
#
{ 'command': 'xen-set-global-dirty-log', 'data': { 'enable': 'bool' } }
##
-# @device_add:
-#
-# @driver: the name of the new device's driver
+# @getfd:
#
-# @bus: the device's parent bus (device tree path)
+# Receive a file descriptor via SCM rights and assign it a name
#
-# @id: the device's ID, must be unique
+# @fdname: file descriptor name
#
-# Additional arguments depend on the type.
+# Returns: Nothing on success
#
-# Add a device.
+# Since: 0.14.0
#
-# Notes:
-# 1. For detailed information about this command, please refer to the
-# 'docs/qdev-device-use.txt' file.
+# Notes: If @fdname already exists, the file descriptor assigned to
+# it will be closed and replaced by the received file
+# descriptor.
#
-# 2. It's possible to list device properties by running QEMU with the
-# "-device DEVICE,help" command-line argument, where DEVICE is the
-# device's name
+# The 'closefd' command can be used to explicitly close the
+# file descriptor when it is no longer needed.
#
# Example:
#
-# -> { "execute": "device_add",
-# "arguments": { "driver": "e1000", "id": "net1",
-# "bus": "pci.0",
-# "mac": "52:54:00:12:34:56" } }
+# -> { "execute": "getfd", "arguments": { "fdname": "fd1" } }
# <- { "return": {} }
#
-# TODO: This command effectively bypasses QAPI completely due to its
-# "additional arguments" business. It shouldn't have been added to
-# the schema in this form. It should be qapified properly, or
-# replaced by a properly qapified command.
-#
-# Since: 0.13
##
-{ 'command': 'device_add',
- 'data': {'driver': 'str', '*bus': 'str', '*id': 'str'},
- 'gen': false } # so we can get the additional arguments
+{ 'command': 'getfd', 'data': {'fdname': 'str'} }
##
-# @device_del:
+# @closefd:
#
-# Remove a device from a guest
+# Close a file descriptor previously passed via SCM rights
#
-# @id: the device's ID or QOM path
+# @fdname: file descriptor name
#
# Returns: Nothing on success
-# If @id is not a valid device, DeviceNotFound
-#
-# Notes: When this command completes, the device may not be removed from the
-# guest. Hot removal is an operation that requires guest cooperation.
-# This command merely requests that the guest begin the hot removal
-# process. Completion of the device removal process is signaled with a
-# DEVICE_DELETED event. Guest reset will automatically complete removal
-# for all devices.
#
# Since: 0.14.0
#
# Example:
#
-# -> { "execute": "device_del",
-# "arguments": { "id": "net1" } }
-# <- { "return": {} }
-#
-# -> { "execute": "device_del",
-# "arguments": { "id": "/machine/peripheral-anon/device[0]" } }
+# -> { "execute": "closefd", "arguments": { "fdname": "fd1" } }
# <- { "return": {} }
#
##
-{ 'command': 'device_del', 'data': {'id': 'str'} }
+{ 'command': 'closefd', 'data': {'fdname': 'str'} }
##
-# @DEVICE_DELETED:
-#
-# Emitted whenever the device removal completion is acknowledged by the guest.
-# At this point, it's safe to reuse the specified device ID. Device removal can
-# be initiated by the guest or by HMP/QMP commands.
+# @MemoryInfo:
#
-# @device: device name
-#
-# @path: device path
-#
-# Since: 1.5
-#
-# Example:
-#
-# <- { "event": "DEVICE_DELETED",
-# "data": { "device": "virtio-net-pci-0",
-# "path": "/machine/peripheral/virtio-net-pci-0" },
-# "timestamp": { "seconds": 1265044230, "microseconds": 450486 } }
-#
-##
-{ 'event': 'DEVICE_DELETED',
- 'data': { '*device': 'str', 'path': 'str' } }
-
-##
-# @DumpGuestMemoryFormat:
-#
-# An enumeration of guest-memory-dump's format.
-#
-# @elf: elf format
-#
-# @kdump-zlib: kdump-compressed format with zlib-compressed
-#
-# @kdump-lzo: kdump-compressed format with lzo-compressed
-#
-# @kdump-snappy: kdump-compressed format with snappy-compressed
-#
-# @win-dmp: Windows full crashdump format,
-# can be used instead of ELF converting (since 2.13)
-#
-# Since: 2.0
-##
-{ 'enum': 'DumpGuestMemoryFormat',
- 'data': [ 'elf', 'kdump-zlib', 'kdump-lzo', 'kdump-snappy', 'win-dmp' ] }
-
-##
-# @dump-guest-memory:
-#
-# Dump guest's memory to vmcore. It is a synchronous operation that can take
-# very long depending on the amount of guest memory.
-#
-# @paging: if true, do paging to get guest's memory mapping. This allows
-# using gdb to process the core file.
-#
-# IMPORTANT: this option can make QEMU allocate several gigabytes
-# of RAM. This can happen for a large guest, or a
-# malicious guest pretending to be large.
-#
-# Also, paging=true has the following limitations:
-#
-# 1. The guest may be in a catastrophic state or can have corrupted
-# memory, which cannot be trusted
-# 2. The guest can be in real-mode even if paging is enabled. For
-# example, the guest uses ACPI to sleep, and ACPI sleep state
-# goes in real-mode
-# 3. Currently only supported on i386 and x86_64.
-#
-# @protocol: the filename or file descriptor of the vmcore. The supported
-# protocols are:
-#
-# 1. file: the protocol starts with "file:", and the following
-# string is the file's path.
-# 2. fd: the protocol starts with "fd:", and the following string
-# is the fd's name.
-#
-# @detach: if true, QMP will return immediately rather than
-# waiting for the dump to finish. The user can track progress
-# using "query-dump". (since 2.6).
-#
-# @begin: if specified, the starting physical address.
-#
-# @length: if specified, the memory size, in bytes. If you don't
-# want to dump all guest's memory, please specify the start @begin
-# and @length
-#
-# @format: if specified, the format of guest memory dump. But non-elf
-# format is conflict with paging and filter, ie. @paging, @begin and
-# @length is not allowed to be specified with non-elf @format at the
-# same time (since 2.0)
-#
-# Note: All boolean arguments default to false
-#
-# Returns: nothing on success
-#
-# Since: 1.2
-#
-# Example:
-#
-# -> { "execute": "dump-guest-memory",
-# "arguments": { "protocol": "fd:dump" } }
-# <- { "return": {} }
-#
-##
-{ 'command': 'dump-guest-memory',
- 'data': { 'paging': 'bool', 'protocol': 'str', '*detach': 'bool',
- '*begin': 'int', '*length': 'int',
- '*format': 'DumpGuestMemoryFormat'} }
-
-##
-# @DumpStatus:
-#
-# Describe the status of a long-running background guest memory dump.
-#
-# @none: no dump-guest-memory has started yet.
-#
-# @active: there is one dump running in background.
-#
-# @completed: the last dump has finished successfully.
-#
-# @failed: the last dump has failed.
-#
-# Since: 2.6
-##
-{ 'enum': 'DumpStatus',
- 'data': [ 'none', 'active', 'completed', 'failed' ] }
-
-##
-# @DumpQueryResult:
-#
-# The result format for 'query-dump'.
-#
-# @status: enum of @DumpStatus, which shows current dump status
-#
-# @completed: bytes written in latest dump (uncompressed)
-#
-# @total: total bytes to be written in latest dump (uncompressed)
-#
-# Since: 2.6
-##
-{ 'struct': 'DumpQueryResult',
- 'data': { 'status': 'DumpStatus',
- 'completed': 'int',
- 'total': 'int' } }
-
-##
-# @query-dump:
-#
-# Query latest dump status.
-#
-# Returns: A @DumpStatus object showing the dump status.
-#
-# Since: 2.6
-#
-# Example:
-#
-# -> { "execute": "query-dump" }
-# <- { "return": { "status": "active", "completed": 1024000,
-# "total": 2048000 } }
-#
-##
-{ 'command': 'query-dump', 'returns': 'DumpQueryResult' }
-
-##
-# @DUMP_COMPLETED:
-#
-# Emitted when background dump has completed
-#
-# @result: final dump status
-#
-# @error: human-readable error string that provides
-# hint on why dump failed. Only presents on failure. The
-# user should not try to interpret the error string.
-#
-# Since: 2.6
-#
-# Example:
-#
-# { "event": "DUMP_COMPLETED",
-# "data": {"result": {"total": 1090650112, "status": "completed",
-# "completed": 1090650112} } }
-#
-##
-{ 'event': 'DUMP_COMPLETED' ,
- 'data': { 'result': 'DumpQueryResult', '*error': 'str' } }
-
-##
-# @DumpGuestMemoryCapability:
-#
-# A list of the available formats for dump-guest-memory
-#
-# Since: 2.0
-##
-{ 'struct': 'DumpGuestMemoryCapability',
- 'data': {
- 'formats': ['DumpGuestMemoryFormat'] } }
-
-##
-# @query-dump-guest-memory-capability:
-#
-# Returns the available formats for dump-guest-memory
-#
-# Returns: A @DumpGuestMemoryCapability object listing available formats for
-# dump-guest-memory
-#
-# Since: 2.0
-#
-# Example:
-#
-# -> { "execute": "query-dump-guest-memory-capability" }
-# <- { "return": { "formats":
-# ["elf", "kdump-zlib", "kdump-lzo", "kdump-snappy"] }
-#
-##
-{ 'command': 'query-dump-guest-memory-capability',
- 'returns': 'DumpGuestMemoryCapability' }
-
-##
-# @object-add:
-#
-# Create a QOM object.
-#
-# @qom-type: the class name for the object to be created
-#
-# @id: the name of the new object
-#
-# @props: a dictionary of properties to be passed to the backend
-#
-# Returns: Nothing on success
-# Error if @qom-type is not a valid class name
-#
-# Since: 2.0
-#
-# Example:
-#
-# -> { "execute": "object-add",
-# "arguments": { "qom-type": "rng-random", "id": "rng1",
-# "props": { "filename": "/dev/hwrng" } } }
-# <- { "return": {} }
-#
-##
-{ 'command': 'object-add',
- 'data': {'qom-type': 'str', 'id': 'str', '*props': 'any'} }
-
-##
-# @object-del:
-#
-# Remove a QOM object.
-#
-# @id: the name of the QOM object to remove
-#
-# Returns: Nothing on success
-# Error if @id is not a valid id for a QOM object
-#
-# Since: 2.0
-#
-# Example:
-#
-# -> { "execute": "object-del", "arguments": { "id": "rng1" } }
-# <- { "return": {} }
-#
-##
-{ 'command': 'object-del', 'data': {'id': 'str'} }
-
-##
-# @getfd:
-#
-# Receive a file descriptor via SCM rights and assign it a name
-#
-# @fdname: file descriptor name
-#
-# Returns: Nothing on success
-#
-# Since: 0.14.0
-#
-# Notes: If @fdname already exists, the file descriptor assigned to
-# it will be closed and replaced by the received file
-# descriptor.
-#
-# The 'closefd' command can be used to explicitly close the
-# file descriptor when it is no longer needed.
-#
-# Example:
-#
-# -> { "execute": "getfd", "arguments": { "fdname": "fd1" } }
-# <- { "return": {} }
-#
-##
-{ 'command': 'getfd', 'data': {'fdname': 'str'} }
-
-##
-# @closefd:
-#
-# Close a file descriptor previously passed via SCM rights
-#
-# @fdname: file descriptor name
-#
-# Returns: Nothing on success
-#
-# Since: 0.14.0
-#
-# Example:
-#
-# -> { "execute": "closefd", "arguments": { "fdname": "fd1" } }
-# <- { "return": {} }
-#
-##
-{ 'command': 'closefd', 'data': {'fdname': 'str'} }
-
-##
-# @MachineInfo:
-#
-# Information describing a machine.
-#
-# @name: the name of the machine
-#
-# @alias: an alias for the machine name
-#
-# @is-default: whether the machine is default
-#
-# @cpu-max: maximum number of CPUs supported by the machine type
-# (since 1.5.0)
-#
-# @hotpluggable-cpus: cpu hotplug via -device is supported (since 2.7.0)
-#
-# Since: 1.2.0
-##
-{ 'struct': 'MachineInfo',
- 'data': { 'name': 'str', '*alias': 'str',
- '*is-default': 'bool', 'cpu-max': 'int',
- 'hotpluggable-cpus': 'bool'} }
-
-##
-# @query-machines:
-#
-# Return a list of supported machines
-#
-# Returns: a list of MachineInfo
-#
-# Since: 1.2.0
-##
-{ 'command': 'query-machines', 'returns': ['MachineInfo'] }
-
-##
-# @CurrentMachineParams:
-#
-# Information describing the running machine parameters.
-#
-# @wakeup-suspend-support: true if the machine supports wake up from
-# suspend
-#
-# Since: 4.0
-##
-{ 'struct': 'CurrentMachineParams',
- 'data': { 'wakeup-suspend-support': 'bool'} }
-
-##
-# @query-current-machine:
-#
-# Return information on the current virtual machine.
-#
-# Returns: CurrentMachineParams
-#
-# Since: 4.0
-##
-{ 'command': 'query-current-machine', 'returns': 'CurrentMachineParams' }
-
-##
-# @MemoryInfo:
-#
-# Actual memory information in bytes.
+# Actual memory information in bytes.
#
# @base-memory: size of "base" memory specified with command line
# option -m.
{ 'command': 'query-memory-size-summary', 'returns': 'MemoryInfo' }
-##
-# @CpuModelInfo:
-#
-# Virtual CPU model.
-#
-# A CPU model consists of the name of a CPU definition, to which
-# delta changes are applied (e.g. features added/removed). Most magic values
-# that an architecture might require should be hidden behind the name.
-# However, if required, architectures can expose relevant properties.
-#
-# @name: the name of the CPU definition the model is based on
-# @props: a dictionary of QOM properties to be applied
-#
-# Since: 2.8.0
-##
-{ 'struct': 'CpuModelInfo',
- 'data': { 'name': 'str',
- '*props': 'any' } }
-
-##
-# @CpuModelExpansionType:
-#
-# An enumeration of CPU model expansion types.
-#
-# @static: Expand to a static CPU model, a combination of a static base
-# model name and property delta changes. As the static base model will
-# never change, the expanded CPU model will be the same, independent of
-# QEMU version, machine type, machine options, and accelerator options.
-# Therefore, the resulting model can be used by tooling without having
-# to specify a compatibility machine - e.g. when displaying the "host"
-# model. The @static CPU models are migration-safe.
-
-# @full: Expand all properties. The produced model is not guaranteed to be
-# migration-safe, but allows tooling to get an insight and work with
-# model details.
-#
-# Note: When a non-migration-safe CPU model is expanded in static mode, some
-# features enabled by the CPU model may be omitted, because they can't be
-# implemented by a static CPU model definition (e.g. cache info passthrough and
-# PMU passthrough in x86). If you need an accurate representation of the
-# features enabled by a non-migration-safe CPU model, use @full. If you need a
-# static representation that will keep ABI compatibility even when changing QEMU
-# version or machine-type, use @static (but keep in mind that some features may
-# be omitted).
-#
-# Since: 2.8.0
-##
-{ 'enum': 'CpuModelExpansionType',
- 'data': [ 'static', 'full' ] }
-
-
-##
-# @CpuModelCompareResult:
-#
-# An enumeration of CPU model comparison results. The result is usually
-# calculated using e.g. CPU features or CPU generations.
-#
-# @incompatible: If model A is incompatible to model B, model A is not
-# guaranteed to run where model B runs and the other way around.
-#
-# @identical: If model A is identical to model B, model A is guaranteed to run
-# where model B runs and the other way around.
-#
-# @superset: If model A is a superset of model B, model B is guaranteed to run
-# where model A runs. There are no guarantees about the other way.
-#
-# @subset: If model A is a subset of model B, model A is guaranteed to run
-# where model B runs. There are no guarantees about the other way.
-#
-# Since: 2.8.0
-##
-{ 'enum': 'CpuModelCompareResult',
- 'data': [ 'incompatible', 'identical', 'superset', 'subset' ] }
-
##
# @AddfdInfo:
#
'returns': ['CommandLineOptionInfo'],
'allow-preconfig': true }
-##
-# @X86CPURegister32:
-#
-# A X86 32-bit register
-#
-# Since: 1.5
-##
-{ 'enum': 'X86CPURegister32',
- 'data': [ 'EAX', 'EBX', 'ECX', 'EDX', 'ESP', 'EBP', 'ESI', 'EDI' ] }
-
-##
-# @X86CPUFeatureWordInfo:
-#
-# Information about a X86 CPU feature word
-#
-# @cpuid-input-eax: Input EAX value for CPUID instruction for that feature word
-#
-# @cpuid-input-ecx: Input ECX value for CPUID instruction for that
-# feature word
-#
-# @cpuid-register: Output register containing the feature bits
-#
-# @features: value of output register, containing the feature bits
-#
-# Since: 1.5
-##
-{ 'struct': 'X86CPUFeatureWordInfo',
- 'data': { 'cpuid-input-eax': 'int',
- '*cpuid-input-ecx': 'int',
- 'cpuid-register': 'X86CPURegister32',
- 'features': 'int' } }
-
-##
-# @DummyForceArrays:
-#
-# Not used by QMP; hack to let us use X86CPUFeatureWordInfoList internally
-#
-# Since: 2.5
-##
-{ 'struct': 'DummyForceArrays',
- 'data': { 'unused': ['X86CPUFeatureWordInfo'] } }
-
-
-##
-# @NumaOptionsType:
-#
-# @node: NUMA nodes configuration
-#
-# @dist: NUMA distance configuration (since 2.10)
-#
-# @cpu: property based CPU(s) to node mapping (Since: 2.10)
-#
-# Since: 2.1
-##
-{ 'enum': 'NumaOptionsType',
- 'data': [ 'node', 'dist', 'cpu' ] }
-
-##
-# @NumaOptions:
-#
-# A discriminated record of NUMA options. (for OptsVisitor)
-#
-# Since: 2.1
-##
-{ 'union': 'NumaOptions',
- 'base': { 'type': 'NumaOptionsType' },
- 'discriminator': 'type',
- 'data': {
- 'node': 'NumaNodeOptions',
- 'dist': 'NumaDistOptions',
- 'cpu': 'NumaCpuOptions' }}
-
-##
-# @NumaNodeOptions:
-#
-# Create a guest NUMA node. (for OptsVisitor)
-#
-# @nodeid: NUMA node ID (increase by 1 from 0 if omitted)
-#
-# @cpus: VCPUs belonging to this node (assign VCPUS round-robin
-# if omitted)
-#
-# @mem: memory size of this node; mutually exclusive with @memdev.
-# Equally divide total memory among nodes if both @mem and @memdev are
-# omitted.
-#
-# @memdev: memory backend object. If specified for one node,
-# it must be specified for all nodes.
-#
-# Since: 2.1
-##
-{ 'struct': 'NumaNodeOptions',
- 'data': {
- '*nodeid': 'uint16',
- '*cpus': ['uint16'],
- '*mem': 'size',
- '*memdev': 'str' }}
-
-##
-# @NumaDistOptions:
-#
-# Set the distance between 2 NUMA nodes.
-#
-# @src: source NUMA node.
-#
-# @dst: destination NUMA node.
-#
-# @val: NUMA distance from source node to destination node.
-# When a node is unreachable from another node, set the distance
-# between them to 255.
-#
-# Since: 2.10
-##
-{ 'struct': 'NumaDistOptions',
- 'data': {
- 'src': 'uint16',
- 'dst': 'uint16',
- 'val': 'uint8' }}
-
-##
-# @NumaCpuOptions:
-#
-# Option "-numa cpu" overrides default cpu to node mapping.
-# It accepts the same set of cpu properties as returned by
-# query-hotpluggable-cpus[].props, where node-id could be used to
-# override default node mapping.
-#
-# Since: 2.10
-##
-{ 'struct': 'NumaCpuOptions',
- 'base': 'CpuInstanceProperties',
- 'data' : {} }
-
-##
-# @HostMemPolicy:
-#
-# Host memory policy types
-#
-# @default: restore default policy, remove any nondefault policy
-#
-# @preferred: set the preferred host nodes for allocation
-#
-# @bind: a strict policy that restricts memory allocation to the
-# host nodes specified
-#
-# @interleave: memory allocations are interleaved across the set
-# of host nodes specified
-#
-# Since: 2.1
-##
-{ 'enum': 'HostMemPolicy',
- 'data': [ 'default', 'preferred', 'bind', 'interleave' ] }
-
-##
-# @Memdev:
-#
-# Information about memory backend
-#
-# @id: backend's ID if backend has 'id' property (since 2.9)
-#
-# @size: memory backend size
-#
-# @merge: enables or disables memory merge support
-#
-# @dump: includes memory backend's memory in a core dump or not
-#
-# @prealloc: enables or disables memory preallocation
-#
-# @host-nodes: host nodes for its memory policy
-#
-# @policy: memory policy of memory backend
-#
-# Since: 2.1
-##
-{ 'struct': 'Memdev',
- 'data': {
- '*id': 'str',
- 'size': 'size',
- 'merge': 'bool',
- 'dump': 'bool',
- 'prealloc': 'bool',
- 'host-nodes': ['uint16'],
- 'policy': 'HostMemPolicy' }}
-
-##
-# @query-memdev:
-#
-# Returns information for all memory backends.
-#
-# Returns: a list of @Memdev.
-#
-# Since: 2.1
-#
-# Example:
-#
-# -> { "execute": "query-memdev" }
-# <- { "return": [
-# {
-# "id": "mem1",
-# "size": 536870912,
-# "merge": false,
-# "dump": true,
-# "prealloc": false,
-# "host-nodes": [0, 1],
-# "policy": "bind"
-# },
-# {
-# "size": 536870912,
-# "merge": false,
-# "dump": true,
-# "prealloc": true,
-# "host-nodes": [2, 3],
-# "policy": "preferred"
-# }
-# ]
-# }
-#
-##
-{ 'command': 'query-memdev', 'returns': ['Memdev'], 'allow-preconfig': true }
-
##
# @PCDIMMDeviceInfo:
#
}
}
+##
+# @VirtioPMEMDeviceInfo:
+#
+# VirtioPMEM state information
+#
+# @id: device's ID
+#
+# @memaddr: physical address in memory, where device is mapped
+#
+# @size: size of memory that the device provides
+#
+# @memdev: memory backend linked with device
+#
+# Since: 4.1
+##
+{ 'struct': 'VirtioPMEMDeviceInfo',
+ 'data': { '*id': 'str',
+ 'memaddr': 'size',
+ 'size': 'size',
+ 'memdev': 'str'
+ }
+}
+
##
# @MemoryDeviceInfo:
#
# Union containing information about a memory device
#
+# nvdimm is included since 2.12. virtio-pmem is included since 4.1.
+#
# Since: 2.1
##
{ 'union': 'MemoryDeviceInfo',
'data': { 'dimm': 'PCDIMMDeviceInfo',
- 'nvdimm': 'PCDIMMDeviceInfo'
+ 'nvdimm': 'PCDIMMDeviceInfo',
+ 'virtio-pmem': 'VirtioPMEMDeviceInfo'
}
}
##
{ 'command': 'xen-load-devices-state', 'data': {'filename': 'str'} }
-##
-# @CpuInstanceProperties:
-#
-# List of properties to be used for hotplugging a CPU instance,
-# it should be passed by management with device_add command when
-# a CPU is being hotplugged.
-#
-# @node-id: NUMA node ID the CPU belongs to
-# @socket-id: socket number within node/board the CPU belongs to
-# @core-id: core number within socket the CPU belongs to
-# @thread-id: thread number within core the CPU belongs to
-#
-# Note: currently there are 4 properties that could be present
-# but management should be prepared to pass through other
-# properties with device_add command to allow for future
-# interface extension. This also requires the filed names to be kept in
-# sync with the properties passed to -device/device_add.
-#
-# Since: 2.7
-##
-{ 'struct': 'CpuInstanceProperties',
- 'data': { '*node-id': 'int',
- '*socket-id': 'int',
- '*core-id': 'int',
- '*thread-id': 'int'
- }
-}
-
-##
-# @HotpluggableCPU:
-#
-# @type: CPU object type for usage with device_add command
-# @props: list of properties to be used for hotplugging CPU
-# @vcpus-count: number of logical VCPU threads @HotpluggableCPU provides
-# @qom-path: link to existing CPU object if CPU is present or
-# omitted if CPU is not present.
-#
-# Since: 2.7
-##
-{ 'struct': 'HotpluggableCPU',
- 'data': { 'type': 'str',
- 'vcpus-count': 'int',
- 'props': 'CpuInstanceProperties',
- '*qom-path': 'str'
- }
-}
-
-##
-# @query-hotpluggable-cpus:
-#
-# TODO: Better documentation; currently there is none.
-#
-# Returns: a list of HotpluggableCPU objects.
-#
-# Since: 2.7
-#
-# Example:
-#
-# For pseries machine type started with -smp 2,cores=2,maxcpus=4 -cpu POWER8:
-#
-# -> { "execute": "query-hotpluggable-cpus" }
-# <- {"return": [
-# { "props": { "core": 8 }, "type": "POWER8-spapr-cpu-core",
-# "vcpus-count": 1 },
-# { "props": { "core": 0 }, "type": "POWER8-spapr-cpu-core",
-# "vcpus-count": 1, "qom-path": "/machine/unattached/device[0]"}
-# ]}'
-#
-# For pc machine type started with -smp 1,maxcpus=2:
-#
-# -> { "execute": "query-hotpluggable-cpus" }
-# <- {"return": [
-# {
-# "type": "qemu64-x86_64-cpu", "vcpus-count": 1,
-# "props": {"core-id": 0, "socket-id": 1, "thread-id": 0}
-# },
-# {
-# "qom-path": "/machine/unattached/device[0]",
-# "type": "qemu64-x86_64-cpu", "vcpus-count": 1,
-# "props": {"core-id": 0, "socket-id": 0, "thread-id": 0}
-# }
-# ]}
-#
-# For s390x-virtio-ccw machine type started with -smp 1,maxcpus=2 -cpu qemu
-# (Since: 2.11):
-#
-# -> { "execute": "query-hotpluggable-cpus" }
-# <- {"return": [
-# {
-# "type": "qemu-s390x-cpu", "vcpus-count": 1,
-# "props": { "core-id": 1 }
-# },
-# {
-# "qom-path": "/machine/unattached/device[0]",
-# "type": "qemu-s390x-cpu", "vcpus-count": 1,
-# "props": { "core-id": 0 }
-# }
-# ]}
-#
-##
-{ 'command': 'query-hotpluggable-cpus', 'returns': ['HotpluggableCPU'],
- 'allow-preconfig': true }
-
##
# @GuidInfo:
#
##
{ 'command': 'query-vm-generation-id', 'returns': 'GuidInfo' }
-##
-# @set-numa-node:
-#
-# Runtime equivalent of '-numa' CLI option, available at
-# preconfigure stage to configure numa mapping before initializing
-# machine.
-#
-# Since 3.0
-##
-{ 'command': 'set-numa-node', 'boxed': true,
- 'data': 'NumaOptions',
- 'allow-preconfig': true
-}
#
# @step: Delay increase (in ms) after each self-announcement attempt
#
+# @interfaces: An optional list of interface names, which restricts the
+# announcement to the listed interfaces. (Since 4.1)
+#
+# @id: A name to be used to identify an instance of announce-timers
+# and to allow it to modified later. Not for use as
+# part of the migration parameters. (Since 4.1)
+#
# Since: 4.0
##
'data': { 'initial': 'int',
'max': 'int',
'rounds': 'int',
- 'step': 'int' } }
+ 'step': 'int',
+ '*interfaces': ['str'],
+ '*id' : 'str' } }
##
# @announce-self:
#
# Example:
#
-# -> { "execute": "announce-self"
+# -> { "execute": "announce-self",
# "arguments": {
-# "initial": 50, "max": 550, "rounds": 10, "step": 50 } }
+# "initial": 50, "max": 550, "rounds": 10, "step": 50,
+# "interfaces": ["vn2", "vn3"], "id": "bob" } }
# <- { "return": {} }
#
# Since: 4.0
{ 'include': 'crypto.json' }
{ 'include': 'block.json' }
{ 'include': 'char.json' }
+{ 'include': 'dump.json' }
{ 'include': 'job.json' }
{ 'include': 'net.json' }
{ 'include': 'rdma.json' }
{ 'include': 'transaction.json' }
{ 'include': 'trace.json' }
{ 'include': 'introspect.json' }
+{ 'include': 'qom.json' }
+{ 'include': 'qdev.json' }
+{ 'include': 'machine.json' }
+{ 'include': 'machine-target.json' }
{ 'include': 'misc.json' }
-{ 'include': 'target.json' }
+{ 'include': 'misc-target.json' }
{ 'include': 'audio.json' }
--- /dev/null
+# -*- Mode: Python -*-
+#
+# This work is licensed under the terms of the GNU GPL, version 2 or later.
+# See the COPYING file in the top-level directory.
+
+##
+# = Device infrastructure (qdev)
+##
+
+{ 'include': 'qom.json' }
+
+##
+# @device-list-properties:
+#
+# List properties associated with a device.
+#
+# @typename: the type name of a device
+#
+# Returns: a list of ObjectPropertyInfo describing a devices properties
+#
+# Note: objects can create properties at runtime, for example to describe
+# links between different devices and/or objects. These properties
+# are not included in the output of this command.
+#
+# Since: 1.2
+##
+{ 'command': 'device-list-properties',
+ 'data': { 'typename': 'str'},
+ 'returns': [ 'ObjectPropertyInfo' ] }
+
+##
+# @device_add:
+#
+# @driver: the name of the new device's driver
+#
+# @bus: the device's parent bus (device tree path)
+#
+# @id: the device's ID, must be unique
+#
+# Additional arguments depend on the type.
+#
+# Add a device.
+#
+# Notes:
+# 1. For detailed information about this command, please refer to the
+# 'docs/qdev-device-use.txt' file.
+#
+# 2. It's possible to list device properties by running QEMU with the
+# "-device DEVICE,help" command-line argument, where DEVICE is the
+# device's name
+#
+# Example:
+#
+# -> { "execute": "device_add",
+# "arguments": { "driver": "e1000", "id": "net1",
+# "bus": "pci.0",
+# "mac": "52:54:00:12:34:56" } }
+# <- { "return": {} }
+#
+# TODO: This command effectively bypasses QAPI completely due to its
+# "additional arguments" business. It shouldn't have been added to
+# the schema in this form. It should be qapified properly, or
+# replaced by a properly qapified command.
+#
+# Since: 0.13
+##
+{ 'command': 'device_add',
+ 'data': {'driver': 'str', '*bus': 'str', '*id': 'str'},
+ 'gen': false } # so we can get the additional arguments
+
+##
+# @device_del:
+#
+# Remove a device from a guest
+#
+# @id: the device's ID or QOM path
+#
+# Returns: Nothing on success
+# If @id is not a valid device, DeviceNotFound
+#
+# Notes: When this command completes, the device may not be removed from the
+# guest. Hot removal is an operation that requires guest cooperation.
+# This command merely requests that the guest begin the hot removal
+# process. Completion of the device removal process is signaled with a
+# DEVICE_DELETED event. Guest reset will automatically complete removal
+# for all devices.
+#
+# Since: 0.14.0
+#
+# Example:
+#
+# -> { "execute": "device_del",
+# "arguments": { "id": "net1" } }
+# <- { "return": {} }
+#
+# -> { "execute": "device_del",
+# "arguments": { "id": "/machine/peripheral-anon/device[0]" } }
+# <- { "return": {} }
+#
+##
+{ 'command': 'device_del', 'data': {'id': 'str'} }
+
+##
+# @DEVICE_DELETED:
+#
+# Emitted whenever the device removal completion is acknowledged by the guest.
+# At this point, it's safe to reuse the specified device ID. Device removal can
+# be initiated by the guest or by HMP/QMP commands.
+#
+# @device: device name
+#
+# @path: device path
+#
+# Since: 1.5
+#
+# Example:
+#
+# <- { "event": "DEVICE_DELETED",
+# "data": { "device": "virtio-net-pci-0",
+# "path": "/machine/peripheral/virtio-net-pci-0" },
+# "timestamp": { "seconds": 1265044230, "microseconds": 450486 } }
+#
+##
+{ 'event': 'DEVICE_DELETED',
+ 'data': { '*device': 'str', 'path': 'str' } }
--- /dev/null
+# -*- Mode: Python -*-
+#
+# This work is licensed under the terms of the GNU GPL, version 2 or later.
+# See the COPYING file in the top-level directory.
+
+##
+# = QEMU Object Model (QOM)
+##
+
+##
+# @ObjectPropertyInfo:
+#
+# @name: the name of the property
+#
+# @type: the type of the property. This will typically come in one of four
+# forms:
+#
+# 1) A primitive type such as 'u8', 'u16', 'bool', 'str', or 'double'.
+# These types are mapped to the appropriate JSON type.
+#
+# 2) A child type in the form 'child<subtype>' where subtype is a qdev
+# device type name. Child properties create the composition tree.
+#
+# 3) A link type in the form 'link<subtype>' where subtype is a qdev
+# device type name. Link properties form the device model graph.
+#
+# @description: if specified, the description of the property.
+#
+# Since: 1.2
+##
+{ 'struct': 'ObjectPropertyInfo',
+ 'data': { 'name': 'str', 'type': 'str', '*description': 'str' } }
+
+##
+# @qom-list:
+#
+# This command will list any properties of a object given a path in the object
+# model.
+#
+# @path: the path within the object model. See @qom-get for a description of
+# this parameter.
+#
+# Returns: a list of @ObjectPropertyInfo that describe the properties of the
+# object.
+#
+# Since: 1.2
+#
+# Example:
+#
+# -> { "execute": "qom-list",
+# "arguments": { "path": "/chardevs" } }
+# <- { "return": [ { "name": "type", "type": "string" },
+# { "name": "parallel0", "type": "child<chardev-vc>" },
+# { "name": "serial0", "type": "child<chardev-vc>" },
+# { "name": "mon0", "type": "child<chardev-stdio>" } ] }
+#
+##
+{ 'command': 'qom-list',
+ 'data': { 'path': 'str' },
+ 'returns': [ 'ObjectPropertyInfo' ],
+ 'allow-preconfig': true }
+
+##
+# @qom-get:
+#
+# This command will get a property from a object model path and return the
+# value.
+#
+# @path: The path within the object model. There are two forms of supported
+# paths--absolute and partial paths.
+#
+# Absolute paths are derived from the root object and can follow child<>
+# or link<> properties. Since they can follow link<> properties, they
+# can be arbitrarily long. Absolute paths look like absolute filenames
+# and are prefixed with a leading slash.
+#
+# Partial paths look like relative filenames. They do not begin
+# with a prefix. The matching rules for partial paths are subtle but
+# designed to make specifying objects easy. At each level of the
+# composition tree, the partial path is matched as an absolute path.
+# The first match is not returned. At least two matches are searched
+# for. A successful result is only returned if only one match is
+# found. If more than one match is found, a flag is return to
+# indicate that the match was ambiguous.
+#
+# @property: The property name to read
+#
+# Returns: The property value. The type depends on the property
+# type. child<> and link<> properties are returned as #str
+# pathnames. All integer property types (u8, u16, etc) are
+# returned as #int.
+#
+# Since: 1.2
+#
+# Example:
+#
+# 1. Use absolute path
+#
+# -> { "execute": "qom-get",
+# "arguments": { "path": "/machine/unattached/device[0]",
+# "property": "hotplugged" } }
+# <- { "return": false }
+#
+# 2. Use partial path
+#
+# -> { "execute": "qom-get",
+# "arguments": { "path": "unattached/sysbus",
+# "property": "type" } }
+# <- { "return": "System" }
+#
+##
+{ 'command': 'qom-get',
+ 'data': { 'path': 'str', 'property': 'str' },
+ 'returns': 'any',
+ 'allow-preconfig': true }
+
+##
+# @qom-set:
+#
+# This command will set a property from a object model path.
+#
+# @path: see @qom-get for a description of this parameter
+#
+# @property: the property name to set
+#
+# @value: a value who's type is appropriate for the property type. See @qom-get
+# for a description of type mapping.
+#
+# Since: 1.2
+#
+# Example:
+#
+# -> { "execute": "qom-set",
+# "arguments": { "path": "/machine",
+# "property": "graphics",
+# "value": false } }
+# <- { "return": {} }
+#
+##
+{ 'command': 'qom-set',
+ 'data': { 'path': 'str', 'property': 'str', 'value': 'any' },
+ 'allow-preconfig': true }
+
+##
+# @ObjectTypeInfo:
+#
+# This structure describes a search result from @qom-list-types
+#
+# @name: the type name found in the search
+#
+# @abstract: the type is abstract and can't be directly instantiated.
+# Omitted if false. (since 2.10)
+#
+# @parent: Name of parent type, if any (since 2.10)
+#
+# Since: 1.1
+##
+{ 'struct': 'ObjectTypeInfo',
+ 'data': { 'name': 'str', '*abstract': 'bool', '*parent': 'str' } }
+
+##
+# @qom-list-types:
+#
+# This command will return a list of types given search parameters
+#
+# @implements: if specified, only return types that implement this type name
+#
+# @abstract: if true, include abstract types in the results
+#
+# Returns: a list of @ObjectTypeInfo or an empty list if no results are found
+#
+# Since: 1.1
+##
+{ 'command': 'qom-list-types',
+ 'data': { '*implements': 'str', '*abstract': 'bool' },
+ 'returns': [ 'ObjectTypeInfo' ],
+ 'allow-preconfig': true }
+
+##
+# @qom-list-properties:
+#
+# List properties associated with a QOM object.
+#
+# @typename: the type name of an object
+#
+# Note: objects can create properties at runtime, for example to describe
+# links between different devices and/or objects. These properties
+# are not included in the output of this command.
+#
+# Returns: a list of ObjectPropertyInfo describing object properties
+#
+# Since: 2.12
+##
+{ 'command': 'qom-list-properties',
+ 'data': { 'typename': 'str'},
+ 'returns': [ 'ObjectPropertyInfo' ],
+ 'allow-preconfig': true }
+
+##
+# @object-add:
+#
+# Create a QOM object.
+#
+# @qom-type: the class name for the object to be created
+#
+# @id: the name of the new object
+#
+# @props: a dictionary of properties to be passed to the backend
+#
+# Returns: Nothing on success
+# Error if @qom-type is not a valid class name
+#
+# Since: 2.0
+#
+# Example:
+#
+# -> { "execute": "object-add",
+# "arguments": { "qom-type": "rng-random", "id": "rng1",
+# "props": { "filename": "/dev/hwrng" } } }
+# <- { "return": {} }
+#
+##
+{ 'command': 'object-add',
+ 'data': {'qom-type': 'str', 'id': 'str', '*props': 'any'} }
+
+##
+# @object-del:
+#
+# Remove a QOM object.
+#
+# @id: the name of the QOM object to remove
+#
+# Returns: Nothing on success
+# Error if @id is not a valid id for a QOM object
+#
+# Since: 2.0
+#
+# Example:
+#
+# -> { "execute": "object-del", "arguments": { "id": "rng1" } }
+# <- { "return": {} }
+#
+##
+{ 'command': 'object-del', 'data': {'id': 'str'} }
+++ /dev/null
-# -*- Mode: Python -*-
-#
-
-##
-# = Target-specific commands & events
-##
-
-{ 'include': 'misc.json' }
-
-##
-# @RTC_CHANGE:
-#
-# Emitted when the guest changes the RTC time.
-#
-# @offset: offset between base RTC clock (as specified by -rtc base), and
-# new RTC clock value
-#
-# Note: This event is rate-limited.
-#
-# Since: 0.13.0
-#
-# Example:
-#
-# <- { "event": "RTC_CHANGE",
-# "data": { "offset": 78 },
-# "timestamp": { "seconds": 1267020223, "microseconds": 435656 } }
-#
-##
-{ 'event': 'RTC_CHANGE',
- 'data': { 'offset': 'int' },
- 'if': 'defined(TARGET_ALPHA) || defined(TARGET_ARM) || defined(TARGET_HPPA) || defined(TARGET_I386) || defined(TARGET_MIPS) || defined(TARGET_MIPS64) || defined(TARGET_MOXIE) || defined(TARGET_PPC) || defined(TARGET_PPC64) || defined(TARGET_S390X) || defined(TARGET_SH4) || defined(TARGET_SPARC)' }
-
-##
-# @rtc-reset-reinjection:
-#
-# This command will reset the RTC interrupt reinjection backlog.
-# Can be used if another mechanism to synchronize guest time
-# is in effect, for example QEMU guest agent's guest-set-time
-# command.
-#
-# Since: 2.1
-#
-# Example:
-#
-# -> { "execute": "rtc-reset-reinjection" }
-# <- { "return": {} }
-#
-##
-{ 'command': 'rtc-reset-reinjection',
- 'if': 'defined(TARGET_I386)' }
-
-
-##
-# @SevState:
-#
-# An enumeration of SEV state information used during @query-sev.
-#
-# @uninit: The guest is uninitialized.
-#
-# @launch-update: The guest is currently being launched; plaintext data and
-# register state is being imported.
-#
-# @launch-secret: The guest is currently being launched; ciphertext data
-# is being imported.
-#
-# @running: The guest is fully launched or migrated in.
-#
-# @send-update: The guest is currently being migrated out to another machine.
-#
-# @receive-update: The guest is currently being migrated from another machine.
-#
-# Since: 2.12
-##
-{ 'enum': 'SevState',
- 'data': ['uninit', 'launch-update', 'launch-secret', 'running',
- 'send-update', 'receive-update' ],
- 'if': 'defined(TARGET_I386)' }
-
-##
-# @SevInfo:
-#
-# Information about Secure Encrypted Virtualization (SEV) support
-#
-# @enabled: true if SEV is active
-#
-# @api-major: SEV API major version
-#
-# @api-minor: SEV API minor version
-#
-# @build-id: SEV FW build id
-#
-# @policy: SEV policy value
-#
-# @state: SEV guest state
-#
-# @handle: SEV firmware handle
-#
-# Since: 2.12
-##
-{ 'struct': 'SevInfo',
- 'data': { 'enabled': 'bool',
- 'api-major': 'uint8',
- 'api-minor' : 'uint8',
- 'build-id' : 'uint8',
- 'policy' : 'uint32',
- 'state' : 'SevState',
- 'handle' : 'uint32'
- },
- 'if': 'defined(TARGET_I386)'
-}
-
-##
-# @query-sev:
-#
-# Returns information about SEV
-#
-# Returns: @SevInfo
-#
-# Since: 2.12
-#
-# Example:
-#
-# -> { "execute": "query-sev" }
-# <- { "return": { "enabled": true, "api-major" : 0, "api-minor" : 0,
-# "build-id" : 0, "policy" : 0, "state" : "running",
-# "handle" : 1 } }
-#
-##
-{ 'command': 'query-sev', 'returns': 'SevInfo',
- 'if': 'defined(TARGET_I386)' }
-
-
-##
-# @SevLaunchMeasureInfo:
-#
-# SEV Guest Launch measurement information
-#
-# @data: the measurement value encoded in base64
-#
-# Since: 2.12
-#
-##
-{ 'struct': 'SevLaunchMeasureInfo', 'data': {'data': 'str'},
- 'if': 'defined(TARGET_I386)' }
-
-##
-# @query-sev-launch-measure:
-#
-# Query the SEV guest launch information.
-#
-# Returns: The @SevLaunchMeasureInfo for the guest
-#
-# Since: 2.12
-#
-# Example:
-#
-# -> { "execute": "query-sev-launch-measure" }
-# <- { "return": { "data": "4l8LXeNlSPUDlXPJG5966/8%YZ" } }
-#
-##
-{ 'command': 'query-sev-launch-measure', 'returns': 'SevLaunchMeasureInfo',
- 'if': 'defined(TARGET_I386)' }
-
-
-##
-# @SevCapability:
-#
-# The struct describes capability for a Secure Encrypted Virtualization
-# feature.
-#
-# @pdh: Platform Diffie-Hellman key (base64 encoded)
-#
-# @cert-chain: PDH certificate chain (base64 encoded)
-#
-# @cbitpos: C-bit location in page table entry
-#
-# @reduced-phys-bits: Number of physical Address bit reduction when SEV is
-# enabled
-#
-# Since: 2.12
-##
-{ 'struct': 'SevCapability',
- 'data': { 'pdh': 'str',
- 'cert-chain': 'str',
- 'cbitpos': 'int',
- 'reduced-phys-bits': 'int'},
- 'if': 'defined(TARGET_I386)' }
-
-##
-# @query-sev-capabilities:
-#
-# This command is used to get the SEV capabilities, and is supported on AMD
-# X86 platforms only.
-#
-# Returns: SevCapability objects.
-#
-# Since: 2.12
-#
-# Example:
-#
-# -> { "execute": "query-sev-capabilities" }
-# <- { "return": { "pdh": "8CCDD8DDD", "cert-chain": "888CCCDDDEE",
-# "cbitpos": 47, "reduced-phys-bits": 5}}
-#
-##
-{ 'command': 'query-sev-capabilities', 'returns': 'SevCapability',
- 'if': 'defined(TARGET_I386)' }
-
-##
-# @dump-skeys:
-#
-# Dump guest's storage keys
-#
-# @filename: the path to the file to dump to
-#
-# This command is only supported on s390 architecture.
-#
-# Since: 2.5
-#
-# Example:
-#
-# -> { "execute": "dump-skeys",
-# "arguments": { "filename": "/tmp/skeys" } }
-# <- { "return": {} }
-#
-##
-{ 'command': 'dump-skeys',
- 'data': { 'filename': 'str' },
- 'if': 'defined(TARGET_S390X)' }
-
-##
-# @CpuModelBaselineInfo:
-#
-# The result of a CPU model baseline.
-#
-# @model: the baselined CpuModelInfo.
-#
-# Since: 2.8.0
-##
-{ 'struct': 'CpuModelBaselineInfo',
- 'data': { 'model': 'CpuModelInfo' },
- 'if': 'defined(TARGET_S390X)' }
-
-##
-# @CpuModelCompareInfo:
-#
-# The result of a CPU model comparison.
-#
-# @result: The result of the compare operation.
-# @responsible-properties: List of properties that led to the comparison result
-# not being identical.
-#
-# @responsible-properties is a list of QOM property names that led to
-# both CPUs not being detected as identical. For identical models, this
-# list is empty.
-# If a QOM property is read-only, that means there's no known way to make the
-# CPU models identical. If the special property name "type" is included, the
-# models are by definition not identical and cannot be made identical.
-#
-# Since: 2.8.0
-##
-{ 'struct': 'CpuModelCompareInfo',
- 'data': { 'result': 'CpuModelCompareResult',
- 'responsible-properties': ['str'] },
- 'if': 'defined(TARGET_S390X)' }
-
-##
-# @query-cpu-model-comparison:
-#
-# Compares two CPU models, returning how they compare in a specific
-# configuration. The results indicates how both models compare regarding
-# runnability. This result can be used by tooling to make decisions if a
-# certain CPU model will run in a certain configuration or if a compatible
-# CPU model has to be created by baselining.
-#
-# Usually, a CPU model is compared against the maximum possible CPU model
-# of a certain configuration (e.g. the "host" model for KVM). If that CPU
-# model is identical or a subset, it will run in that configuration.
-#
-# The result returned by this command may be affected by:
-#
-# * QEMU version: CPU models may look different depending on the QEMU version.
-# (Except for CPU models reported as "static" in query-cpu-definitions.)
-# * machine-type: CPU model may look different depending on the machine-type.
-# (Except for CPU models reported as "static" in query-cpu-definitions.)
-# * machine options (including accelerator): in some architectures, CPU models
-# may look different depending on machine and accelerator options. (Except for
-# CPU models reported as "static" in query-cpu-definitions.)
-# * "-cpu" arguments and global properties: arguments to the -cpu option and
-# global properties may affect expansion of CPU models. Using
-# query-cpu-model-expansion while using these is not advised.
-#
-# Some architectures may not support comparing CPU models. s390x supports
-# comparing CPU models.
-#
-# Returns: a CpuModelBaselineInfo. Returns an error if comparing CPU models is
-# not supported, if a model cannot be used, if a model contains
-# an unknown cpu definition name, unknown properties or properties
-# with wrong types.
-#
-# Note: this command isn't specific to s390x, but is only implemented
-# on this architecture currently.
-#
-# Since: 2.8.0
-##
-{ 'command': 'query-cpu-model-comparison',
- 'data': { 'modela': 'CpuModelInfo', 'modelb': 'CpuModelInfo' },
- 'returns': 'CpuModelCompareInfo',
- 'if': 'defined(TARGET_S390X)' }
-
-##
-# @query-cpu-model-baseline:
-#
-# Baseline two CPU models, creating a compatible third model. The created
-# model will always be a static, migration-safe CPU model (see "static"
-# CPU model expansion for details).
-#
-# This interface can be used by tooling to create a compatible CPU model out
-# two CPU models. The created CPU model will be identical to or a subset of
-# both CPU models when comparing them. Therefore, the created CPU model is
-# guaranteed to run where the given CPU models run.
-#
-# The result returned by this command may be affected by:
-#
-# * QEMU version: CPU models may look different depending on the QEMU version.
-# (Except for CPU models reported as "static" in query-cpu-definitions.)
-# * machine-type: CPU model may look different depending on the machine-type.
-# (Except for CPU models reported as "static" in query-cpu-definitions.)
-# * machine options (including accelerator): in some architectures, CPU models
-# may look different depending on machine and accelerator options. (Except for
-# CPU models reported as "static" in query-cpu-definitions.)
-# * "-cpu" arguments and global properties: arguments to the -cpu option and
-# global properties may affect expansion of CPU models. Using
-# query-cpu-model-expansion while using these is not advised.
-#
-# Some architectures may not support baselining CPU models. s390x supports
-# baselining CPU models.
-#
-# Returns: a CpuModelBaselineInfo. Returns an error if baselining CPU models is
-# not supported, if a model cannot be used, if a model contains
-# an unknown cpu definition name, unknown properties or properties
-# with wrong types.
-#
-# Note: this command isn't specific to s390x, but is only implemented
-# on this architecture currently.
-#
-# Since: 2.8.0
-##
-{ 'command': 'query-cpu-model-baseline',
- 'data': { 'modela': 'CpuModelInfo',
- 'modelb': 'CpuModelInfo' },
- 'returns': 'CpuModelBaselineInfo',
- 'if': 'defined(TARGET_S390X)' }
-
-##
-# @GICCapability:
-#
-# The struct describes capability for a specific GIC (Generic
-# Interrupt Controller) version. These bits are not only decided by
-# QEMU/KVM software version, but also decided by the hardware that
-# the program is running upon.
-#
-# @version: version of GIC to be described. Currently, only 2 and 3
-# are supported.
-#
-# @emulated: whether current QEMU/hardware supports emulated GIC
-# device in user space.
-#
-# @kernel: whether current QEMU/hardware supports hardware
-# accelerated GIC device in kernel.
-#
-# Since: 2.6
-##
-{ 'struct': 'GICCapability',
- 'data': { 'version': 'int',
- 'emulated': 'bool',
- 'kernel': 'bool' },
- 'if': 'defined(TARGET_ARM)' }
-
-##
-# @query-gic-capabilities:
-#
-# This command is ARM-only. It will return a list of GICCapability
-# objects that describe its capability bits.
-#
-# Returns: a list of GICCapability objects.
-#
-# Since: 2.6
-#
-# Example:
-#
-# -> { "execute": "query-gic-capabilities" }
-# <- { "return": [{ "version": 2, "emulated": true, "kernel": false },
-# { "version": 3, "emulated": false, "kernel": true } ] }
-#
-##
-{ 'command': 'query-gic-capabilities', 'returns': ['GICCapability'],
- 'if': 'defined(TARGET_ARM)' }
-
-##
-# @CpuModelExpansionInfo:
-#
-# The result of a cpu model expansion.
-#
-# @model: the expanded CpuModelInfo.
-#
-# Since: 2.8.0
-##
-{ 'struct': 'CpuModelExpansionInfo',
- 'data': { 'model': 'CpuModelInfo' },
- 'if': 'defined(TARGET_S390X) || defined(TARGET_I386)' }
-
-##
-# @query-cpu-model-expansion:
-#
-# Expands a given CPU model (or a combination of CPU model + additional options)
-# to different granularities, allowing tooling to get an understanding what a
-# specific CPU model looks like in QEMU under a certain configuration.
-#
-# This interface can be used to query the "host" CPU model.
-#
-# The data returned by this command may be affected by:
-#
-# * QEMU version: CPU models may look different depending on the QEMU version.
-# (Except for CPU models reported as "static" in query-cpu-definitions.)
-# * machine-type: CPU model may look different depending on the machine-type.
-# (Except for CPU models reported as "static" in query-cpu-definitions.)
-# * machine options (including accelerator): in some architectures, CPU models
-# may look different depending on machine and accelerator options. (Except for
-# CPU models reported as "static" in query-cpu-definitions.)
-# * "-cpu" arguments and global properties: arguments to the -cpu option and
-# global properties may affect expansion of CPU models. Using
-# query-cpu-model-expansion while using these is not advised.
-#
-# Some architectures may not support all expansion types. s390x supports
-# "full" and "static".
-#
-# Returns: a CpuModelExpansionInfo. Returns an error if expanding CPU models is
-# not supported, if the model cannot be expanded, if the model contains
-# an unknown CPU definition name, unknown properties or properties
-# with a wrong type. Also returns an error if an expansion type is
-# not supported.
-#
-# Since: 2.8.0
-##
-{ 'command': 'query-cpu-model-expansion',
- 'data': { 'type': 'CpuModelExpansionType',
- 'model': 'CpuModelInfo' },
- 'returns': 'CpuModelExpansionInfo',
- 'if': 'defined(TARGET_S390X) || defined(TARGET_I386)' }
-
-##
-# @CpuDefinitionInfo:
-#
-# Virtual CPU definition.
-#
-# @name: the name of the CPU definition
-#
-# @migration-safe: whether a CPU definition can be safely used for
-# migration in combination with a QEMU compatibility machine
-# when migrating between different QEMU versions and between
-# hosts with different sets of (hardware or software)
-# capabilities. If not provided, information is not available
-# and callers should not assume the CPU definition to be
-# migration-safe. (since 2.8)
-#
-# @static: whether a CPU definition is static and will not change depending on
-# QEMU version, machine type, machine options and accelerator options.
-# A static model is always migration-safe. (since 2.8)
-#
-# @unavailable-features: List of properties that prevent
-# the CPU model from running in the current
-# host. (since 2.8)
-# @typename: Type name that can be used as argument to @device-list-properties,
-# to introspect properties configurable using -cpu or -global.
-# (since 2.9)
-#
-# @unavailable-features is a list of QOM property names that
-# represent CPU model attributes that prevent the CPU from running.
-# If the QOM property is read-only, that means there's no known
-# way to make the CPU model run in the current host. Implementations
-# that choose not to provide specific information return the
-# property name "type".
-# If the property is read-write, it means that it MAY be possible
-# to run the CPU model in the current host if that property is
-# changed. Management software can use it as hints to suggest or
-# choose an alternative for the user, or just to generate meaningful
-# error messages explaining why the CPU model can't be used.
-# If @unavailable-features is an empty list, the CPU model is
-# runnable using the current host and machine-type.
-# If @unavailable-features is not present, runnability
-# information for the CPU is not available.
-#
-# Since: 1.2.0
-##
-{ 'struct': 'CpuDefinitionInfo',
- 'data': { 'name': 'str',
- '*migration-safe': 'bool',
- 'static': 'bool',
- '*unavailable-features': [ 'str' ],
- 'typename': 'str' },
- 'if': 'defined(TARGET_PPC) || defined(TARGET_ARM) || defined(TARGET_I386) || defined(TARGET_S390X) || defined(TARGET_MIPS)' }
-
-##
-# @query-cpu-definitions:
-#
-# Return a list of supported virtual CPU definitions
-#
-# Returns: a list of CpuDefInfo
-#
-# Since: 1.2.0
-##
-{ 'command': 'query-cpu-definitions', 'returns': ['CpuDefinitionInfo'],
- 'if': 'defined(TARGET_PPC) || defined(TARGET_ARM) || defined(TARGET_I386) || defined(TARGET_S390X) || defined(TARGET_MIPS)' }
#include "monitor/qdev.h"
#include "sysemu/arch_init.h"
#include "qapi/error.h"
-#include "qapi/qapi-commands-misc.h"
+#include "qapi/qapi-commands-qdev.h"
#include "qapi/qmp/qdict.h"
#include "qapi/qmp/qerror.h"
#include "qemu/config-file.h"
qdev_print_devinfos(true);
}
-typedef struct QOMCompositionState {
- Monitor *mon;
- int indent;
-} QOMCompositionState;
-
-static void print_qom_composition(Monitor *mon, Object *obj, int indent);
-
-static int print_qom_composition_child(Object *obj, void *opaque)
-{
- QOMCompositionState *s = opaque;
-
- print_qom_composition(s->mon, obj, s->indent);
-
- return 0;
-}
-
-static void print_qom_composition(Monitor *mon, Object *obj, int indent)
-{
- QOMCompositionState s = {
- .mon = mon,
- .indent = indent + 2,
- };
- char *name;
-
- if (obj == object_get_root()) {
- name = g_strdup("");
- } else {
- name = object_get_canonical_path_component(obj);
- }
- monitor_printf(mon, "%*s/%s (%s)\n", indent, "", name,
- object_get_typename(obj));
- g_free(name);
- object_child_foreach(obj, print_qom_composition_child, &s);
-}
-
-void hmp_info_qom_tree(Monitor *mon, const QDict *dict)
-{
- const char *path = qdict_get_try_str(dict, "path");
- Object *obj;
- bool ambiguous = false;
-
- if (path) {
- obj = object_resolve_path(path, &ambiguous);
- if (!obj) {
- monitor_printf(mon, "Path '%s' could not be resolved.\n", path);
- return;
- }
- if (ambiguous) {
- monitor_printf(mon, "Warning: Path '%s' is ambiguous.\n", path);
- return;
- }
- } else {
- obj = qdev_get_machine();
- }
- print_qom_composition(mon, obj, 0);
-}
-
void qmp_device_add(QDict *qdict, QObject **ret_data, Error **errp)
{
Error *local_err = NULL;
*
* This work is licensed under the terms of the GNU GPL, version 2. See
* the COPYING file in the top-level directory.
- *
+ */
+
+/*
+ * Known shortcomings:
+ * - There is no manual page
+ * - The syntax of the ACL file is not documented anywhere
+ * - parse_acl_file() doesn't report fopen() failure properly, fails
+ * to check ferror() after fgets() failure, arbitrarily truncates
+ * long lines, handles whitespace inconsistently, error messages
+ * don't point to the offending file and line, errors in included
+ * files are reported, but otherwise ignored, ...
*/
#include "qemu/osdep.h"
``acl_remove'' commands are deprecated with no replacement. Authorization
for VNC should be performed using the pluggable QAuthZ objects.
+@section Guest Emulator ISAs
+
+@subsection RISC-V ISA privledge specification version 1.09.1 (since 4.1)
+
+The RISC-V ISA privledge specification version 1.09.1 has been deprecated.
+QEMU supports both the newer version 1.10.0 and the ratified version 1.11.0, these
+should be used instead of the 1.09.1 version.
+
@section System emulator CPUS
@subsection RISC-V ISA CPUs (since 4.1)
to just export the entire image and then mount only /dev/nbd0p1 than
it is to reinvoke @command{qemu-nbd -c /dev/nbd0} limited to just a
subset of the image.
+
+@section Build system
+
+@subsection Python 2 support (since 4.1.0)
+
+In the future, QEMU will require Python 3 to be available at
+build time. Support for Python 2 in scripts shipped with QEMU
+is deprecated.
* to take action
*/
ret = bdrv_is_allocated_above(backing_bs(bs), prefix_chain_bs,
- offset, n, &n);
+ false, offset, n, &n);
if (ret < 0) {
error_report("error while reading image metadata: %s",
strerror(-ret));
The file format is libpcap, so it can be analyzed with tools such as tcpdump
or Wireshark.
-@item -object colo-compare,id=@var{id},primary_in=@var{chardevid},secondary_in=@var{chardevid},outdev=@var{chardevid},iothread=@var{id}[,vnet_hdr_support]
+@item -object colo-compare,id=@var{id},primary_in=@var{chardevid},secondary_in=@var{chardevid},outdev=@var{chardevid},iothread=@var{id}[,vnet_hdr_support][,notify_dev=@var{id}]
Colo-compare gets packet from primary_in@var{chardevid} and secondary_in@var{chardevid}, than compare primary packet with
secondary packet. If the packets are same, we will output primary
In order to improve efficiency, we need to put the task of comparison
in another thread. If it has the vnet_hdr_support flag, colo compare
will send/recv packet with vnet_hdr_len.
+If you want to use Xen COLO, will need the notify_dev to notify Xen
+colo-frame to do checkpoint.
we must use it with the help of filter-mirror and filter-redirector.
@example
+KVM COLO
+
primary:
-netdev tap,id=hn0,vhost=off,script=/etc/qemu-ifup,downscript=/etc/qemu-ifdown
-device e1000,id=e0,netdev=hn0,mac=52:a4:00:12:78:66
-object filter-redirector,id=f1,netdev=hn0,queue=tx,indev=red0
-object filter-redirector,id=f2,netdev=hn0,queue=rx,outdev=red1
+
+Xen COLO
+
+primary:
+-netdev tap,id=hn0,vhost=off,script=/etc/qemu-ifup,downscript=/etc/qemu-ifdown
+-device e1000,id=e0,netdev=hn0,mac=52:a4:00:12:78:66
+-chardev socket,id=mirror0,host=3.3.3.3,port=9003,server,nowait
+-chardev socket,id=compare1,host=3.3.3.3,port=9004,server,nowait
+-chardev socket,id=compare0,host=3.3.3.3,port=9001,server,nowait
+-chardev socket,id=compare0-0,host=3.3.3.3,port=9001
+-chardev socket,id=compare_out,host=3.3.3.3,port=9005,server,nowait
+-chardev socket,id=compare_out0,host=3.3.3.3,port=9005
+-chardev socket,id=notify_way,host=3.3.3.3,port=9009,server,nowait
+-object filter-mirror,id=m0,netdev=hn0,queue=tx,outdev=mirror0
+-object filter-redirector,netdev=hn0,id=redire0,queue=rx,indev=compare_out
+-object filter-redirector,netdev=hn0,id=redire1,queue=rx,outdev=compare0
+-object iothread,id=iothread1
+-object colo-compare,id=comp0,primary_in=compare0-0,secondary_in=compare1,outdev=compare_out0,notify_dev=nofity_way,iothread=iothread1
+
+secondary:
+-netdev tap,id=hn0,vhost=off,script=/etc/qemu-ifup,down script=/etc/qemu-ifdown
+-device e1000,netdev=hn0,mac=52:a4:00:12:78:66
+-chardev socket,id=red0,host=3.3.3.3,port=9003
+-chardev socket,id=red1,host=3.3.3.3,port=9004
+-object filter-redirector,id=f1,netdev=hn0,queue=tx,indev=red0
+-object filter-redirector,id=f2,netdev=hn0,queue=rx,outdev=red1
+
@end example
If you want to know the detail of above command line, you can read
qom-obj-y += object_interfaces.o
common-obj-y = cpu.o
+common-obj-$(CONFIG_SOFTMMU) += qom-hmp-cmds.o qom-qmp-cmds.o
--- /dev/null
+/*
+ * HMP commands related to QOM
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or
+ * later. See the COPYING file in the top-level directory.
+ */
+
+#include "qemu/osdep.h"
+#include "hw/qdev-core.h"
+#include "monitor/hmp.h"
+#include "monitor/monitor.h"
+#include "qapi/error.h"
+#include "qapi/qapi-commands-qom.h"
+#include "qapi/qmp/qdict.h"
+#include "qom/object.h"
+
+void hmp_qom_list(Monitor *mon, const QDict *qdict)
+{
+ const char *path = qdict_get_try_str(qdict, "path");
+ ObjectPropertyInfoList *list;
+ Error *err = NULL;
+
+ if (path == NULL) {
+ monitor_printf(mon, "/\n");
+ return;
+ }
+
+ list = qmp_qom_list(path, &err);
+ if (err == NULL) {
+ ObjectPropertyInfoList *start = list;
+ while (list != NULL) {
+ ObjectPropertyInfo *value = list->value;
+
+ monitor_printf(mon, "%s (%s)\n",
+ value->name, value->type);
+ list = list->next;
+ }
+ qapi_free_ObjectPropertyInfoList(start);
+ }
+ hmp_handle_error(mon, &err);
+}
+
+void hmp_qom_set(Monitor *mon, const QDict *qdict)
+{
+ const char *path = qdict_get_str(qdict, "path");
+ const char *property = qdict_get_str(qdict, "property");
+ const char *value = qdict_get_str(qdict, "value");
+ Error *err = NULL;
+ bool ambiguous = false;
+ Object *obj;
+
+ obj = object_resolve_path(path, &ambiguous);
+ if (obj == NULL) {
+ error_set(&err, ERROR_CLASS_DEVICE_NOT_FOUND,
+ "Device '%s' not found", path);
+ } else {
+ if (ambiguous) {
+ monitor_printf(mon, "Warning: Path '%s' is ambiguous\n", path);
+ }
+ object_property_parse(obj, value, property, &err);
+ }
+ hmp_handle_error(mon, &err);
+}
+
+typedef struct QOMCompositionState {
+ Monitor *mon;
+ int indent;
+} QOMCompositionState;
+
+static void print_qom_composition(Monitor *mon, Object *obj, int indent);
+
+static int print_qom_composition_child(Object *obj, void *opaque)
+{
+ QOMCompositionState *s = opaque;
+
+ print_qom_composition(s->mon, obj, s->indent);
+
+ return 0;
+}
+
+static void print_qom_composition(Monitor *mon, Object *obj, int indent)
+{
+ QOMCompositionState s = {
+ .mon = mon,
+ .indent = indent + 2,
+ };
+ char *name;
+
+ if (obj == object_get_root()) {
+ name = g_strdup("");
+ } else {
+ name = object_get_canonical_path_component(obj);
+ }
+ monitor_printf(mon, "%*s/%s (%s)\n", indent, "", name,
+ object_get_typename(obj));
+ g_free(name);
+ object_child_foreach(obj, print_qom_composition_child, &s);
+}
+
+void hmp_info_qom_tree(Monitor *mon, const QDict *dict)
+{
+ const char *path = qdict_get_try_str(dict, "path");
+ Object *obj;
+ bool ambiguous = false;
+
+ if (path) {
+ obj = object_resolve_path(path, &ambiguous);
+ if (!obj) {
+ monitor_printf(mon, "Path '%s' could not be resolved.\n", path);
+ return;
+ }
+ if (ambiguous) {
+ monitor_printf(mon, "Warning: Path '%s' is ambiguous.\n", path);
+ return;
+ }
+ } else {
+ obj = qdev_get_machine();
+ }
+ print_qom_composition(mon, obj, 0);
+}
--- /dev/null
+/*
+ * QMP commands related to QOM
+ *
+ * Copyright IBM, Corp. 2011
+ *
+ * Authors:
+ * Anthony Liguori <aliguori@us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2. See
+ * the COPYING file in the top-level directory.
+ *
+ * Contributions after 2012-01-13 are licensed under the terms of the
+ * GNU GPL, version 2 or (at your option) any later version.
+ */
+
+#include "qemu/osdep.h"
+#include "hw/qdev.h"
+#include "qapi/error.h"
+#include "qapi/qapi-commands-qdev.h"
+#include "qapi/qapi-commands-qom.h"
+#include "qapi/qmp/qdict.h"
+#include "qapi/qmp/qerror.h"
+#include "qapi/qobject-input-visitor.h"
+#include "qemu/cutils.h"
+#include "qom/object_interfaces.h"
+#include "qom/qom-qobject.h"
+
+ObjectPropertyInfoList *qmp_qom_list(const char *path, Error **errp)
+{
+ Object *obj;
+ bool ambiguous = false;
+ ObjectPropertyInfoList *props = NULL;
+ ObjectProperty *prop;
+ ObjectPropertyIterator iter;
+
+ obj = object_resolve_path(path, &ambiguous);
+ if (obj == NULL) {
+ if (ambiguous) {
+ error_setg(errp, "Path '%s' is ambiguous", path);
+ } else {
+ error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
+ "Device '%s' not found", path);
+ }
+ return NULL;
+ }
+
+ object_property_iter_init(&iter, obj);
+ while ((prop = object_property_iter_next(&iter))) {
+ ObjectPropertyInfoList *entry = g_malloc0(sizeof(*entry));
+
+ entry->value = g_malloc0(sizeof(ObjectPropertyInfo));
+ entry->next = props;
+ props = entry;
+
+ entry->value->name = g_strdup(prop->name);
+ entry->value->type = g_strdup(prop->type);
+ }
+
+ return props;
+}
+
+void qmp_qom_set(const char *path, const char *property, QObject *value,
+ Error **errp)
+{
+ Object *obj;
+
+ obj = object_resolve_path(path, NULL);
+ if (!obj) {
+ error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
+ "Device '%s' not found", path);
+ return;
+ }
+
+ object_property_set_qobject(obj, value, property, errp);
+}
+
+QObject *qmp_qom_get(const char *path, const char *property, Error **errp)
+{
+ Object *obj;
+
+ obj = object_resolve_path(path, NULL);
+ if (!obj) {
+ error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
+ "Device '%s' not found", path);
+ return NULL;
+ }
+
+ return object_property_get_qobject(obj, property, errp);
+}
+
+static void qom_list_types_tramp(ObjectClass *klass, void *data)
+{
+ ObjectTypeInfoList *e, **pret = data;
+ ObjectTypeInfo *info;
+ ObjectClass *parent = object_class_get_parent(klass);
+
+ info = g_malloc0(sizeof(*info));
+ info->name = g_strdup(object_class_get_name(klass));
+ info->has_abstract = info->abstract = object_class_is_abstract(klass);
+ if (parent) {
+ info->has_parent = true;
+ info->parent = g_strdup(object_class_get_name(parent));
+ }
+
+ e = g_malloc0(sizeof(*e));
+ e->value = info;
+ e->next = *pret;
+ *pret = e;
+}
+
+ObjectTypeInfoList *qmp_qom_list_types(bool has_implements,
+ const char *implements,
+ bool has_abstract,
+ bool abstract,
+ Error **errp)
+{
+ ObjectTypeInfoList *ret = NULL;
+
+ object_class_foreach(qom_list_types_tramp, implements, abstract, &ret);
+
+ return ret;
+}
+
+/* Return a DevicePropertyInfo for a qdev property.
+ *
+ * If a qdev property with the given name does not exist, use the given default
+ * type. If the qdev property info should not be shown, return NULL.
+ *
+ * The caller must free the return value.
+ */
+static ObjectPropertyInfo *make_device_property_info(ObjectClass *klass,
+ const char *name,
+ const char *default_type,
+ const char *description)
+{
+ ObjectPropertyInfo *info;
+ Property *prop;
+
+ do {
+ for (prop = DEVICE_CLASS(klass)->props; prop && prop->name; prop++) {
+ if (strcmp(name, prop->name) != 0) {
+ continue;
+ }
+
+ /*
+ * TODO Properties without a parser are just for dirty hacks.
+ * qdev_prop_ptr is the only such PropertyInfo. It's marked
+ * for removal. This conditional should be removed along with
+ * it.
+ */
+ if (!prop->info->set && !prop->info->create) {
+ return NULL; /* no way to set it, don't show */
+ }
+
+ info = g_malloc0(sizeof(*info));
+ info->name = g_strdup(prop->name);
+ info->type = default_type ? g_strdup(default_type)
+ : g_strdup(prop->info->name);
+ info->has_description = !!prop->info->description;
+ info->description = g_strdup(prop->info->description);
+ return info;
+ }
+ klass = object_class_get_parent(klass);
+ } while (klass != object_class_by_name(TYPE_DEVICE));
+
+ /* Not a qdev property, use the default type */
+ info = g_malloc0(sizeof(*info));
+ info->name = g_strdup(name);
+ info->type = g_strdup(default_type);
+ info->has_description = !!description;
+ info->description = g_strdup(description);
+
+ return info;
+}
+
+ObjectPropertyInfoList *qmp_device_list_properties(const char *typename,
+ Error **errp)
+{
+ ObjectClass *klass;
+ Object *obj;
+ ObjectProperty *prop;
+ ObjectPropertyIterator iter;
+ ObjectPropertyInfoList *prop_list = NULL;
+
+ klass = object_class_by_name(typename);
+ if (klass == NULL) {
+ error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
+ "Device '%s' not found", typename);
+ return NULL;
+ }
+
+ klass = object_class_dynamic_cast(klass, TYPE_DEVICE);
+ if (klass == NULL) {
+ error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "typename", TYPE_DEVICE);
+ return NULL;
+ }
+
+ if (object_class_is_abstract(klass)) {
+ error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "typename",
+ "non-abstract device type");
+ return NULL;
+ }
+
+ obj = object_new(typename);
+
+ object_property_iter_init(&iter, obj);
+ while ((prop = object_property_iter_next(&iter))) {
+ ObjectPropertyInfo *info;
+ ObjectPropertyInfoList *entry;
+
+ /* Skip Object and DeviceState properties */
+ if (strcmp(prop->name, "type") == 0 ||
+ strcmp(prop->name, "realized") == 0 ||
+ strcmp(prop->name, "hotpluggable") == 0 ||
+ strcmp(prop->name, "hotplugged") == 0 ||
+ strcmp(prop->name, "parent_bus") == 0) {
+ continue;
+ }
+
+ /* Skip legacy properties since they are just string versions of
+ * properties that we already list.
+ */
+ if (strstart(prop->name, "legacy-", NULL)) {
+ continue;
+ }
+
+ info = make_device_property_info(klass, prop->name, prop->type,
+ prop->description);
+ if (!info) {
+ continue;
+ }
+
+ entry = g_malloc0(sizeof(*entry));
+ entry->value = info;
+ entry->next = prop_list;
+ prop_list = entry;
+ }
+
+ object_unref(obj);
+
+ return prop_list;
+}
+
+ObjectPropertyInfoList *qmp_qom_list_properties(const char *typename,
+ Error **errp)
+{
+ ObjectClass *klass;
+ Object *obj = NULL;
+ ObjectProperty *prop;
+ ObjectPropertyIterator iter;
+ ObjectPropertyInfoList *prop_list = NULL;
+
+ klass = object_class_by_name(typename);
+ if (klass == NULL) {
+ error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
+ "Class '%s' not found", typename);
+ return NULL;
+ }
+
+ klass = object_class_dynamic_cast(klass, TYPE_OBJECT);
+ if (klass == NULL) {
+ error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "typename", TYPE_OBJECT);
+ return NULL;
+ }
+
+ if (object_class_is_abstract(klass)) {
+ object_class_property_iter_init(&iter, klass);
+ } else {
+ obj = object_new(typename);
+ object_property_iter_init(&iter, obj);
+ }
+ while ((prop = object_property_iter_next(&iter))) {
+ ObjectPropertyInfo *info;
+ ObjectPropertyInfoList *entry;
+
+ info = g_malloc0(sizeof(*info));
+ info->name = g_strdup(prop->name);
+ info->type = g_strdup(prop->type);
+ info->has_description = !!prop->description;
+ info->description = g_strdup(prop->description);
+
+ entry = g_malloc0(sizeof(*entry));
+ entry->value = info;
+ entry->next = prop_list;
+ prop_list = entry;
+ }
+
+ object_unref(obj);
+
+ return prop_list;
+}
+
+void qmp_object_add(const char *type, const char *id,
+ bool has_props, QObject *props, Error **errp)
+{
+ QDict *pdict;
+ Visitor *v;
+ Object *obj;
+
+ if (props) {
+ pdict = qobject_to(QDict, props);
+ if (!pdict) {
+ error_setg(errp, QERR_INVALID_PARAMETER_TYPE, "props", "dict");
+ return;
+ }
+ qobject_ref(pdict);
+ } else {
+ pdict = qdict_new();
+ }
+
+ v = qobject_input_visitor_new(QOBJECT(pdict));
+ obj = user_creatable_add_type(type, id, pdict, v, errp);
+ visit_free(v);
+ if (obj) {
+ object_unref(obj);
+ }
+ qobject_unref(pdict);
+}
+
+void qmp_object_del(const char *id, Error **errp)
+{
+ user_creatable_del(id, errp);
+}
--- /dev/null
+CONFIG_QEMU=y
+CONFIG_BUILD_VGABIOS=y
+CONFIG_VGA_ATI=y
+CONFIG_VGA_PCI=y
-Subproject commit 3464681b2b5983df80086a40179d324102347da3
+Subproject commit c79e0ecb84f4f1ee3f73f521622e264edd1bf174
from itertools import chain
sys.path.append(os.path.join(os.path.dirname(__file__), '..', 'python'))
-from qemu import QEMUMachine
+from qemu.machine import QEMUMachine
logger = logging.getLogger('device-crash-test')
dbg = logger.debug
sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..', 'python'))
from qemu import qmp
+if sys.version_info[0] == 2:
+ input = raw_input
+
class QMPCompleter(list):
def complete(self, text, state):
for cmd in self:
@return True if execution was ok, return False if disconnected.
"""
try:
- cmdline = raw_input(prompt)
+ cmdline = input(prompt)
except EOFError:
print()
return False
from graphviz import Digraph
sys.path.append(os.path.join(os.path.dirname(__file__), '..', 'python'))
-from qemu import MonitorResponseError
+from qemu.machine import MonitorResponseError
def perm(arr):
-obj-y += arm-semi.o
-obj-$(CONFIG_SOFTMMU) += machine.o psci.o arch_dump.o monitor.o
+obj-$(CONFIG_TCG) += arm-semi.o
+obj-y += helper.o vfp_helper.o
+obj-y += cpu.o gdbstub.o
+obj-$(TARGET_AARCH64) += cpu64.o gdbstub64.o
+
+obj-$(CONFIG_SOFTMMU) += machine.o arch_dump.o monitor.o
+obj-$(CONFIG_SOFTMMU) += arm-powerctl.o
+
obj-$(CONFIG_KVM) += kvm.o
obj-$(call land,$(CONFIG_KVM),$(call lnot,$(TARGET_AARCH64))) += kvm32.o
obj-$(call land,$(CONFIG_KVM),$(TARGET_AARCH64)) += kvm64.o
obj-$(call lnot,$(CONFIG_KVM)) += kvm-stub.o
-obj-y += translate.o op_helper.o helper.o cpu.o
-obj-y += neon_helper.o iwmmxt_helper.o vec_helper.o vfp_helper.o
-obj-y += gdbstub.o
-obj-$(TARGET_AARCH64) += cpu64.o translate-a64.o helper-a64.o gdbstub64.o
-obj-$(TARGET_AARCH64) += pauth_helper.o
-obj-y += crypto_helper.o
-obj-$(CONFIG_SOFTMMU) += arm-powerctl.o
DECODETREE = $(SRC_PATH)/scripts/decodetree.py
target/arm/translate.o: target/arm/decode-vfp.inc.c
target/arm/translate.o: target/arm/decode-vfp-uncond.inc.c
+obj-y += tlb_helper.o debug_helper.o
+obj-y += translate.o op_helper.o
+obj-y += crypto_helper.o
+obj-y += iwmmxt_helper.o vec_helper.o neon_helper.o
+obj-y += m_helper.o
+
+obj-$(CONFIG_SOFTMMU) += psci.o
+
+obj-$(TARGET_AARCH64) += translate-a64.o helper-a64.o
obj-$(TARGET_AARCH64) += translate-sve.o sve_helper.o
+obj-$(TARGET_AARCH64) += pauth_helper.o
*/
#include "qemu/osdep.h"
+#include "qemu/qemu-print.h"
#include "qemu-common.h"
#include "target/arm/idau.h"
#include "qemu/module.h"
#endif
}
+#ifdef TARGET_AARCH64
+
+static void aarch64_cpu_dump_state(CPUState *cs, FILE *f, int flags)
+{
+ ARMCPU *cpu = ARM_CPU(cs);
+ CPUARMState *env = &cpu->env;
+ uint32_t psr = pstate_read(env);
+ int i;
+ int el = arm_current_el(env);
+ const char *ns_status;
+
+ qemu_fprintf(f, " PC=%016" PRIx64 " ", env->pc);
+ for (i = 0; i < 32; i++) {
+ if (i == 31) {
+ qemu_fprintf(f, " SP=%016" PRIx64 "\n", env->xregs[i]);
+ } else {
+ qemu_fprintf(f, "X%02d=%016" PRIx64 "%s", i, env->xregs[i],
+ (i + 2) % 3 ? " " : "\n");
+ }
+ }
+
+ if (arm_feature(env, ARM_FEATURE_EL3) && el != 3) {
+ ns_status = env->cp15.scr_el3 & SCR_NS ? "NS " : "S ";
+ } else {
+ ns_status = "";
+ }
+ qemu_fprintf(f, "PSTATE=%08x %c%c%c%c %sEL%d%c",
+ psr,
+ psr & PSTATE_N ? 'N' : '-',
+ psr & PSTATE_Z ? 'Z' : '-',
+ psr & PSTATE_C ? 'C' : '-',
+ psr & PSTATE_V ? 'V' : '-',
+ ns_status,
+ el,
+ psr & PSTATE_SP ? 'h' : 't');
+
+ if (cpu_isar_feature(aa64_bti, cpu)) {
+ qemu_fprintf(f, " BTYPE=%d", (psr & PSTATE_BTYPE) >> 10);
+ }
+ if (!(flags & CPU_DUMP_FPU)) {
+ qemu_fprintf(f, "\n");
+ return;
+ }
+ if (fp_exception_el(env, el) != 0) {
+ qemu_fprintf(f, " FPU disabled\n");
+ return;
+ }
+ qemu_fprintf(f, " FPCR=%08x FPSR=%08x\n",
+ vfp_get_fpcr(env), vfp_get_fpsr(env));
+
+ if (cpu_isar_feature(aa64_sve, cpu) && sve_exception_el(env, el) == 0) {
+ int j, zcr_len = sve_zcr_len_for_el(env, el);
+
+ for (i = 0; i <= FFR_PRED_NUM; i++) {
+ bool eol;
+ if (i == FFR_PRED_NUM) {
+ qemu_fprintf(f, "FFR=");
+ /* It's last, so end the line. */
+ eol = true;
+ } else {
+ qemu_fprintf(f, "P%02d=", i);
+ switch (zcr_len) {
+ case 0:
+ eol = i % 8 == 7;
+ break;
+ case 1:
+ eol = i % 6 == 5;
+ break;
+ case 2:
+ case 3:
+ eol = i % 3 == 2;
+ break;
+ default:
+ /* More than one quadword per predicate. */
+ eol = true;
+ break;
+ }
+ }
+ for (j = zcr_len / 4; j >= 0; j--) {
+ int digits;
+ if (j * 4 + 4 <= zcr_len + 1) {
+ digits = 16;
+ } else {
+ digits = (zcr_len % 4 + 1) * 4;
+ }
+ qemu_fprintf(f, "%0*" PRIx64 "%s", digits,
+ env->vfp.pregs[i].p[j],
+ j ? ":" : eol ? "\n" : " ");
+ }
+ }
+
+ for (i = 0; i < 32; i++) {
+ if (zcr_len == 0) {
+ qemu_fprintf(f, "Z%02d=%016" PRIx64 ":%016" PRIx64 "%s",
+ i, env->vfp.zregs[i].d[1],
+ env->vfp.zregs[i].d[0], i & 1 ? "\n" : " ");
+ } else if (zcr_len == 1) {
+ qemu_fprintf(f, "Z%02d=%016" PRIx64 ":%016" PRIx64
+ ":%016" PRIx64 ":%016" PRIx64 "\n",
+ i, env->vfp.zregs[i].d[3], env->vfp.zregs[i].d[2],
+ env->vfp.zregs[i].d[1], env->vfp.zregs[i].d[0]);
+ } else {
+ for (j = zcr_len; j >= 0; j--) {
+ bool odd = (zcr_len - j) % 2 != 0;
+ if (j == zcr_len) {
+ qemu_fprintf(f, "Z%02d[%x-%x]=", i, j, j - 1);
+ } else if (!odd) {
+ if (j > 0) {
+ qemu_fprintf(f, " [%x-%x]=", j, j - 1);
+ } else {
+ qemu_fprintf(f, " [%x]=", j);
+ }
+ }
+ qemu_fprintf(f, "%016" PRIx64 ":%016" PRIx64 "%s",
+ env->vfp.zregs[i].d[j * 2 + 1],
+ env->vfp.zregs[i].d[j * 2],
+ odd || j == 0 ? "\n" : ":");
+ }
+ }
+ }
+ } else {
+ for (i = 0; i < 32; i++) {
+ uint64_t *q = aa64_vfp_qreg(env, i);
+ qemu_fprintf(f, "Q%02d=%016" PRIx64 ":%016" PRIx64 "%s",
+ i, q[1], q[0], (i & 1 ? "\n" : " "));
+ }
+ }
+}
+
+#else
+
+static inline void aarch64_cpu_dump_state(CPUState *cs, FILE *f, int flags)
+{
+ g_assert_not_reached();
+}
+
+#endif
+
+static void arm_cpu_dump_state(CPUState *cs, FILE *f, int flags)
+{
+ ARMCPU *cpu = ARM_CPU(cs);
+ CPUARMState *env = &cpu->env;
+ int i;
+
+ if (is_a64(env)) {
+ aarch64_cpu_dump_state(cs, f, flags);
+ return;
+ }
+
+ for (i = 0; i < 16; i++) {
+ qemu_fprintf(f, "R%02d=%08x", i, env->regs[i]);
+ if ((i % 4) == 3) {
+ qemu_fprintf(f, "\n");
+ } else {
+ qemu_fprintf(f, " ");
+ }
+ }
+
+ if (arm_feature(env, ARM_FEATURE_M)) {
+ uint32_t xpsr = xpsr_read(env);
+ const char *mode;
+ const char *ns_status = "";
+
+ if (arm_feature(env, ARM_FEATURE_M_SECURITY)) {
+ ns_status = env->v7m.secure ? "S " : "NS ";
+ }
+
+ if (xpsr & XPSR_EXCP) {
+ mode = "handler";
+ } else {
+ if (env->v7m.control[env->v7m.secure] & R_V7M_CONTROL_NPRIV_MASK) {
+ mode = "unpriv-thread";
+ } else {
+ mode = "priv-thread";
+ }
+ }
+
+ qemu_fprintf(f, "XPSR=%08x %c%c%c%c %c %s%s\n",
+ xpsr,
+ xpsr & XPSR_N ? 'N' : '-',
+ xpsr & XPSR_Z ? 'Z' : '-',
+ xpsr & XPSR_C ? 'C' : '-',
+ xpsr & XPSR_V ? 'V' : '-',
+ xpsr & XPSR_T ? 'T' : 'A',
+ ns_status,
+ mode);
+ } else {
+ uint32_t psr = cpsr_read(env);
+ const char *ns_status = "";
+
+ if (arm_feature(env, ARM_FEATURE_EL3) &&
+ (psr & CPSR_M) != ARM_CPU_MODE_MON) {
+ ns_status = env->cp15.scr_el3 & SCR_NS ? "NS " : "S ";
+ }
+
+ qemu_fprintf(f, "PSR=%08x %c%c%c%c %c %s%s%d\n",
+ psr,
+ psr & CPSR_N ? 'N' : '-',
+ psr & CPSR_Z ? 'Z' : '-',
+ psr & CPSR_C ? 'C' : '-',
+ psr & CPSR_V ? 'V' : '-',
+ psr & CPSR_T ? 'T' : 'A',
+ ns_status,
+ aarch32_mode_name(psr), (psr & 0x10) ? 32 : 26);
+ }
+
+ if (flags & CPU_DUMP_FPU) {
+ int numvfpregs = 0;
+ if (arm_feature(env, ARM_FEATURE_VFP)) {
+ numvfpregs += 16;
+ }
+ if (arm_feature(env, ARM_FEATURE_VFP3)) {
+ numvfpregs += 16;
+ }
+ for (i = 0; i < numvfpregs; i++) {
+ uint64_t v = *aa32_vfp_dreg(env, i);
+ qemu_fprintf(f, "s%02d=%08x s%02d=%08x d%02d=%016" PRIx64 "\n",
+ i * 2, (uint32_t)v,
+ i * 2 + 1, (uint32_t)(v >> 32),
+ i, v);
+ }
+ qemu_fprintf(f, "FPSCR: %08x\n", vfp_get_fpscr(env));
+ }
+}
+
uint64_t arm_cpu_mp_affinity(int idx, uint8_t clustersz)
{
uint32_t Aff1 = idx / clustersz;
cc->gdb_write_register = arm_cpu_gdb_write_register;
#ifndef CONFIG_USER_ONLY
cc->do_interrupt = arm_cpu_do_interrupt;
- cc->do_unaligned_access = arm_cpu_do_unaligned_access;
- cc->do_transaction_failed = arm_cpu_do_transaction_failed;
cc->get_phys_page_attrs_debug = arm_cpu_get_phys_page_attrs_debug;
cc->asidx_from_attrs = arm_asidx_from_attrs;
cc->vmsd = &vmstate_arm_cpu;
cc->gdb_arch_name = arm_gdb_arch_name;
cc->gdb_get_dynamic_xml = arm_gdb_get_dynamic_xml;
cc->gdb_stop_before_watchpoint = true;
- cc->debug_excp_handler = arm_debug_excp_handler;
- cc->debug_check_watchpoint = arm_debug_check_watchpoint;
-#if !defined(CONFIG_USER_ONLY)
- cc->adjust_watchpoint_address = arm_adjust_watchpoint_address;
-#endif
-
cc->disas_set_info = arm_disas_set_info;
#ifdef CONFIG_TCG
cc->tcg_initialize = arm_translate_init;
cc->tlb_fill = arm_cpu_tlb_fill;
+ cc->debug_excp_handler = arm_debug_excp_handler;
+ cc->debug_check_watchpoint = arm_debug_check_watchpoint;
+#if !defined(CONFIG_USER_ONLY)
+ cc->do_unaligned_access = arm_cpu_do_unaligned_access;
+ cc->do_transaction_failed = arm_cpu_do_transaction_failed;
+ cc->adjust_watchpoint_address = arm_adjust_watchpoint_address;
+#endif /* CONFIG_TCG && !CONFIG_USER_ONLY */
#endif
}
void arm_v7m_cpu_do_interrupt(CPUState *cpu);
bool arm_cpu_exec_interrupt(CPUState *cpu, int int_req);
-void arm_cpu_dump_state(CPUState *cs, FILE *f, int flags);
-
hwaddr arm_cpu_get_phys_page_attrs_debug(CPUState *cpu, vaddr addr,
MemTxAttrs *attrs);
{ }
#endif
+#if !defined(CONFIG_TCG)
+static inline target_ulong do_arm_semihosting(CPUARMState *env)
+{
+ g_assert_not_reached();
+}
+#else
target_ulong do_arm_semihosting(CPUARMState *env);
+#endif
void aarch64_sync_32_to_64(CPUARMState *env);
void aarch64_sync_64_to_32(CPUARMState *env);
--- /dev/null
+/*
+ * ARM debug helpers.
+ *
+ * This code is licensed under the GNU GPL v2 or later.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+#include "qemu/osdep.h"
+#include "cpu.h"
+#include "internals.h"
+#include "exec/exec-all.h"
+#include "exec/helper-proto.h"
+
+/* Return true if the linked breakpoint entry lbn passes its checks */
+static bool linked_bp_matches(ARMCPU *cpu, int lbn)
+{
+ CPUARMState *env = &cpu->env;
+ uint64_t bcr = env->cp15.dbgbcr[lbn];
+ int brps = extract32(cpu->dbgdidr, 24, 4);
+ int ctx_cmps = extract32(cpu->dbgdidr, 20, 4);
+ int bt;
+ uint32_t contextidr;
+
+ /*
+ * Links to unimplemented or non-context aware breakpoints are
+ * CONSTRAINED UNPREDICTABLE: either behave as if disabled, or
+ * as if linked to an UNKNOWN context-aware breakpoint (in which
+ * case DBGWCR<n>_EL1.LBN must indicate that breakpoint).
+ * We choose the former.
+ */
+ if (lbn > brps || lbn < (brps - ctx_cmps)) {
+ return false;
+ }
+
+ bcr = env->cp15.dbgbcr[lbn];
+
+ if (extract64(bcr, 0, 1) == 0) {
+ /* Linked breakpoint disabled : generate no events */
+ return false;
+ }
+
+ bt = extract64(bcr, 20, 4);
+
+ /*
+ * We match the whole register even if this is AArch32 using the
+ * short descriptor format (in which case it holds both PROCID and ASID),
+ * since we don't implement the optional v7 context ID masking.
+ */
+ contextidr = extract64(env->cp15.contextidr_el[1], 0, 32);
+
+ switch (bt) {
+ case 3: /* linked context ID match */
+ if (arm_current_el(env) > 1) {
+ /* Context matches never fire in EL2 or (AArch64) EL3 */
+ return false;
+ }
+ return (contextidr == extract64(env->cp15.dbgbvr[lbn], 0, 32));
+ case 5: /* linked address mismatch (reserved in AArch64) */
+ case 9: /* linked VMID match (reserved if no EL2) */
+ case 11: /* linked context ID and VMID match (reserved if no EL2) */
+ default:
+ /*
+ * Links to Unlinked context breakpoints must generate no
+ * events; we choose to do the same for reserved values too.
+ */
+ return false;
+ }
+
+ return false;
+}
+
+static bool bp_wp_matches(ARMCPU *cpu, int n, bool is_wp)
+{
+ CPUARMState *env = &cpu->env;
+ uint64_t cr;
+ int pac, hmc, ssc, wt, lbn;
+ /*
+ * Note that for watchpoints the check is against the CPU security
+ * state, not the S/NS attribute on the offending data access.
+ */
+ bool is_secure = arm_is_secure(env);
+ int access_el = arm_current_el(env);
+
+ if (is_wp) {
+ CPUWatchpoint *wp = env->cpu_watchpoint[n];
+
+ if (!wp || !(wp->flags & BP_WATCHPOINT_HIT)) {
+ return false;
+ }
+ cr = env->cp15.dbgwcr[n];
+ if (wp->hitattrs.user) {
+ /*
+ * The LDRT/STRT/LDT/STT "unprivileged access" instructions should
+ * match watchpoints as if they were accesses done at EL0, even if
+ * the CPU is at EL1 or higher.
+ */
+ access_el = 0;
+ }
+ } else {
+ uint64_t pc = is_a64(env) ? env->pc : env->regs[15];
+
+ if (!env->cpu_breakpoint[n] || env->cpu_breakpoint[n]->pc != pc) {
+ return false;
+ }
+ cr = env->cp15.dbgbcr[n];
+ }
+ /*
+ * The WATCHPOINT_HIT flag guarantees us that the watchpoint is
+ * enabled and that the address and access type match; for breakpoints
+ * we know the address matched; check the remaining fields, including
+ * linked breakpoints. We rely on WCR and BCR having the same layout
+ * for the LBN, SSC, HMC, PAC/PMC and is-linked fields.
+ * Note that some combinations of {PAC, HMC, SSC} are reserved and
+ * must act either like some valid combination or as if the watchpoint
+ * were disabled. We choose the former, and use this together with
+ * the fact that EL3 must always be Secure and EL2 must always be
+ * Non-Secure to simplify the code slightly compared to the full
+ * table in the ARM ARM.
+ */
+ pac = extract64(cr, 1, 2);
+ hmc = extract64(cr, 13, 1);
+ ssc = extract64(cr, 14, 2);
+
+ switch (ssc) {
+ case 0:
+ break;
+ case 1:
+ case 3:
+ if (is_secure) {
+ return false;
+ }
+ break;
+ case 2:
+ if (!is_secure) {
+ return false;
+ }
+ break;
+ }
+
+ switch (access_el) {
+ case 3:
+ case 2:
+ if (!hmc) {
+ return false;
+ }
+ break;
+ case 1:
+ if (extract32(pac, 0, 1) == 0) {
+ return false;
+ }
+ break;
+ case 0:
+ if (extract32(pac, 1, 1) == 0) {
+ return false;
+ }
+ break;
+ default:
+ g_assert_not_reached();
+ }
+
+ wt = extract64(cr, 20, 1);
+ lbn = extract64(cr, 16, 4);
+
+ if (wt && !linked_bp_matches(cpu, lbn)) {
+ return false;
+ }
+
+ return true;
+}
+
+static bool check_watchpoints(ARMCPU *cpu)
+{
+ CPUARMState *env = &cpu->env;
+ int n;
+
+ /*
+ * If watchpoints are disabled globally or we can't take debug
+ * exceptions here then watchpoint firings are ignored.
+ */
+ if (extract32(env->cp15.mdscr_el1, 15, 1) == 0
+ || !arm_generate_debug_exceptions(env)) {
+ return false;
+ }
+
+ for (n = 0; n < ARRAY_SIZE(env->cpu_watchpoint); n++) {
+ if (bp_wp_matches(cpu, n, true)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+static bool check_breakpoints(ARMCPU *cpu)
+{
+ CPUARMState *env = &cpu->env;
+ int n;
+
+ /*
+ * If breakpoints are disabled globally or we can't take debug
+ * exceptions here then breakpoint firings are ignored.
+ */
+ if (extract32(env->cp15.mdscr_el1, 15, 1) == 0
+ || !arm_generate_debug_exceptions(env)) {
+ return false;
+ }
+
+ for (n = 0; n < ARRAY_SIZE(env->cpu_breakpoint); n++) {
+ if (bp_wp_matches(cpu, n, false)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+void HELPER(check_breakpoints)(CPUARMState *env)
+{
+ ARMCPU *cpu = env_archcpu(env);
+
+ if (check_breakpoints(cpu)) {
+ HELPER(exception_internal(env, EXCP_DEBUG));
+ }
+}
+
+bool arm_debug_check_watchpoint(CPUState *cs, CPUWatchpoint *wp)
+{
+ /*
+ * Called by core code when a CPU watchpoint fires; need to check if this
+ * is also an architectural watchpoint match.
+ */
+ ARMCPU *cpu = ARM_CPU(cs);
+
+ return check_watchpoints(cpu);
+}
+
+void arm_debug_excp_handler(CPUState *cs)
+{
+ /*
+ * Called by core code when a watchpoint or breakpoint fires;
+ * need to check which one and raise the appropriate exception.
+ */
+ ARMCPU *cpu = ARM_CPU(cs);
+ CPUARMState *env = &cpu->env;
+ CPUWatchpoint *wp_hit = cs->watchpoint_hit;
+
+ if (wp_hit) {
+ if (wp_hit->flags & BP_CPU) {
+ bool wnr = (wp_hit->flags & BP_WATCHPOINT_HIT_WRITE) != 0;
+ bool same_el = arm_debug_target_el(env) == arm_current_el(env);
+
+ cs->watchpoint_hit = NULL;
+
+ env->exception.fsr = arm_debug_exception_fsr(env);
+ env->exception.vaddress = wp_hit->hitaddr;
+ raise_exception(env, EXCP_DATA_ABORT,
+ syn_watchpoint(same_el, 0, wnr),
+ arm_debug_target_el(env));
+ }
+ } else {
+ uint64_t pc = is_a64(env) ? env->pc : env->regs[15];
+ bool same_el = (arm_debug_target_el(env) == arm_current_el(env));
+
+ /*
+ * (1) GDB breakpoints should be handled first.
+ * (2) Do not raise a CPU exception if no CPU breakpoint has fired,
+ * since singlestep is also done by generating a debug internal
+ * exception.
+ */
+ if (cpu_breakpoint_test(cs, pc, BP_GDB)
+ || !cpu_breakpoint_test(cs, pc, BP_CPU)) {
+ return;
+ }
+
+ env->exception.fsr = arm_debug_exception_fsr(env);
+ /*
+ * FAR is UNKNOWN: clear vaddress to avoid potentially exposing
+ * values to the guest that it shouldn't be able to see at its
+ * exception/security level.
+ */
+ env->exception.vaddress = 0;
+ raise_exception(env, EXCP_PREFETCH_ABORT,
+ syn_breakpoint(same_el),
+ arm_debug_target_el(env));
+ }
+}
+
+#if !defined(CONFIG_USER_ONLY)
+
+vaddr arm_adjust_watchpoint_address(CPUState *cs, vaddr addr, int len)
+{
+ ARMCPU *cpu = ARM_CPU(cs);
+ CPUARMState *env = &cpu->env;
+
+ /*
+ * In BE32 system mode, target memory is stored byteswapped (on a
+ * little-endian host system), and by the time we reach here (via an
+ * opcode helper) the addresses of subword accesses have been adjusted
+ * to account for that, which means that watchpoints will not match.
+ * Undo the adjustment here.
+ */
+ if (arm_sctlr_b(env)) {
+ if (len == 1) {
+ addr ^= 3;
+ } else if (len == 2) {
+ addr ^= 2;
+ }
+ }
+
+ return addr;
+}
+
+#endif
+/*
+ * ARM generic helpers.
+ *
+ * This code is licensed under the GNU GPL v2 or later.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
#include "qemu/osdep.h"
#include "qemu/units.h"
#include "target/arm/idau.h"
#include "exec/gdbstub.h"
#include "exec/helper-proto.h"
#include "qemu/host-utils.h"
-#include "sysemu/arch_init.h"
#include "sysemu/sysemu.h"
#include "qemu/bitops.h"
#include "qemu/crc32c.h"
#include "qemu/qemu-print.h"
#include "exec/exec-all.h"
-#include "exec/cpu_ldst.h"
-#include "arm_ldst.h"
#include <zlib.h> /* For crc32 */
#include "hw/semihosting/semihost.h"
#include "sysemu/cpus.h"
#include "sysemu/kvm.h"
-#include "fpu/softfloat.h"
#include "qemu/range.h"
-#include "qapi/qapi-commands-target.h"
+#include "qapi/qapi-commands-machine-target.h"
#include "qapi/error.h"
#include "qemu/guest-random.h"
+#ifdef CONFIG_TCG
+#include "arm_ldst.h"
+#include "exec/cpu_ldst.h"
+#endif
#define ARM_CPU_FREQ 1000000000 /* FIXME: 1 GHz, should be configurable */
#ifndef CONFIG_USER_ONLY
-/* Cacheability and shareability attributes for a memory access */
-typedef struct ARMCacheAttrs {
- unsigned int attrs:8; /* as in the MAIR register encoding */
- unsigned int shareability:2; /* as in the SH field of the VMSAv8-64 PTEs */
-} ARMCacheAttrs;
-
-static bool get_phys_addr(CPUARMState *env, target_ulong address,
- MMUAccessType access_type, ARMMMUIdx mmu_idx,
- hwaddr *phys_ptr, MemTxAttrs *attrs, int *prot,
- target_ulong *page_size,
- ARMMMUFaultInfo *fi, ARMCacheAttrs *cacheattrs);
static bool get_phys_addr_lpae(CPUARMState *env, target_ulong address,
MMUAccessType access_type, ARMMMUIdx mmu_idx,
hwaddr *phys_ptr, MemTxAttrs *txattrs, int *prot,
target_ulong *page_size_ptr,
ARMMMUFaultInfo *fi, ARMCacheAttrs *cacheattrs);
-
-/* Security attributes for an address, as returned by v8m_security_lookup. */
-typedef struct V8M_SAttributes {
- bool subpage; /* true if these attrs don't cover the whole TARGET_PAGE */
- bool ns;
- bool nsc;
- uint8_t sregion;
- bool srvalid;
- uint8_t iregion;
- bool irvalid;
-} V8M_SAttributes;
-
-static void v8m_security_lookup(CPUARMState *env, uint32_t address,
- MMUAccessType access_type, ARMMMUIdx mmu_idx,
- V8M_SAttributes *sattrs);
#endif
static void switch_mode(CPUARMState *env, int mode);
#ifdef CONFIG_USER_ONLY
-/* These should probably raise undefined insn exceptions. */
-void HELPER(v7m_msr)(CPUARMState *env, uint32_t reg, uint32_t val)
-{
- ARMCPU *cpu = env_archcpu(env);
-
- cpu_abort(CPU(cpu), "v7m_msr %d\n", reg);
-}
-
-uint32_t HELPER(v7m_mrs)(CPUARMState *env, uint32_t reg)
-{
- ARMCPU *cpu = env_archcpu(env);
-
- cpu_abort(CPU(cpu), "v7m_mrs %d\n", reg);
- return 0;
-}
-
-void HELPER(v7m_bxns)(CPUARMState *env, uint32_t dest)
-{
- /* translate.c should never generate calls here in user-only mode */
- g_assert_not_reached();
-}
-
-void HELPER(v7m_blxns)(CPUARMState *env, uint32_t dest)
-{
- /* translate.c should never generate calls here in user-only mode */
- g_assert_not_reached();
-}
-
-void HELPER(v7m_preserve_fp_state)(CPUARMState *env)
-{
- /* translate.c should never generate calls here in user-only mode */
- g_assert_not_reached();
-}
-
-void HELPER(v7m_vlstm)(CPUARMState *env, uint32_t fptr)
-{
- /* translate.c should never generate calls here in user-only mode */
- g_assert_not_reached();
-}
-
-void HELPER(v7m_vlldm)(CPUARMState *env, uint32_t fptr)
-{
- /* translate.c should never generate calls here in user-only mode */
- g_assert_not_reached();
-}
-
-uint32_t HELPER(v7m_tt)(CPUARMState *env, uint32_t addr, uint32_t op)
-{
- /* The TT instructions can be used by unprivileged code, but in
- * user-only emulation we don't have the MPU.
- * Luckily since we know we are NonSecure unprivileged (and that in
- * turn means that the A flag wasn't specified), all the bits in the
- * register must be zero:
- * IREGION: 0 because IRVALID is 0
- * IRVALID: 0 because NS
- * S: 0 because NS
- * NSRW: 0 because NS
- * NSR: 0 because NS
- * RW: 0 because unpriv and A flag not set
- * R: 0 because unpriv and A flag not set
- * SRVALID: 0 because NS
- * MRVALID: 0 because unpriv and A flag not set
- * SREGION: 0 becaus SRVALID is 0
- * MREGION: 0 because MRVALID is 0
- */
- return 0;
-}
-
static void switch_mode(CPUARMState *env, int mode)
{
ARMCPU *cpu = env_archcpu(env);
return target_el;
}
-/*
- * Return true if the v7M CPACR permits access to the FPU for the specified
- * security state and privilege level.
- */
-static bool v7m_cpacr_pass(CPUARMState *env, bool is_secure, bool is_priv)
+void arm_log_exception(int idx)
{
- switch (extract32(env->v7m.cpacr[is_secure], 20, 2)) {
- case 0:
- case 2: /* UNPREDICTABLE: we treat like 0 */
- return false;
- case 1:
- return is_priv;
- case 3:
- return true;
- default:
- g_assert_not_reached();
- }
-}
-
-/*
- * What kind of stack write are we doing? This affects how exceptions
- * generated during the stacking are treated.
- */
-typedef enum StackingMode {
- STACK_NORMAL,
- STACK_IGNFAULTS,
- STACK_LAZYFP,
-} StackingMode;
+ if (qemu_loglevel_mask(CPU_LOG_INT)) {
+ const char *exc = NULL;
+ static const char * const excnames[] = {
+ [EXCP_UDEF] = "Undefined Instruction",
+ [EXCP_SWI] = "SVC",
+ [EXCP_PREFETCH_ABORT] = "Prefetch Abort",
+ [EXCP_DATA_ABORT] = "Data Abort",
+ [EXCP_IRQ] = "IRQ",
+ [EXCP_FIQ] = "FIQ",
+ [EXCP_BKPT] = "Breakpoint",
+ [EXCP_EXCEPTION_EXIT] = "QEMU v7M exception exit",
+ [EXCP_KERNEL_TRAP] = "QEMU intercept of kernel commpage",
+ [EXCP_HVC] = "Hypervisor Call",
+ [EXCP_HYP_TRAP] = "Hypervisor Trap",
+ [EXCP_SMC] = "Secure Monitor Call",
+ [EXCP_VIRQ] = "Virtual IRQ",
+ [EXCP_VFIQ] = "Virtual FIQ",
+ [EXCP_SEMIHOST] = "Semihosting call",
+ [EXCP_NOCP] = "v7M NOCP UsageFault",
+ [EXCP_INVSTATE] = "v7M INVSTATE UsageFault",
+ [EXCP_STKOF] = "v8M STKOF UsageFault",
+ [EXCP_LAZYFP] = "v7M exception during lazy FP stacking",
+ [EXCP_LSERR] = "v8M LSERR UsageFault",
+ [EXCP_UNALIGNED] = "v7M UNALIGNED UsageFault",
+ };
-static bool v7m_stack_write(ARMCPU *cpu, uint32_t addr, uint32_t value,
- ARMMMUIdx mmu_idx, StackingMode mode)
-{
- CPUState *cs = CPU(cpu);
- CPUARMState *env = &cpu->env;
- MemTxAttrs attrs = {};
- MemTxResult txres;
- target_ulong page_size;
- hwaddr physaddr;
- int prot;
- ARMMMUFaultInfo fi = {};
- bool secure = mmu_idx & ARM_MMU_IDX_M_S;
- int exc;
- bool exc_secure;
-
- if (get_phys_addr(env, addr, MMU_DATA_STORE, mmu_idx, &physaddr,
- &attrs, &prot, &page_size, &fi, NULL)) {
- /* MPU/SAU lookup failed */
- if (fi.type == ARMFault_QEMU_SFault) {
- if (mode == STACK_LAZYFP) {
- qemu_log_mask(CPU_LOG_INT,
- "...SecureFault with SFSR.LSPERR "
- "during lazy stacking\n");
- env->v7m.sfsr |= R_V7M_SFSR_LSPERR_MASK;
- } else {
- qemu_log_mask(CPU_LOG_INT,
- "...SecureFault with SFSR.AUVIOL "
- "during stacking\n");
- env->v7m.sfsr |= R_V7M_SFSR_AUVIOL_MASK;
- }
- env->v7m.sfsr |= R_V7M_SFSR_SFARVALID_MASK;
- env->v7m.sfar = addr;
- exc = ARMV7M_EXCP_SECURE;
- exc_secure = false;
- } else {
- if (mode == STACK_LAZYFP) {
- qemu_log_mask(CPU_LOG_INT,
- "...MemManageFault with CFSR.MLSPERR\n");
- env->v7m.cfsr[secure] |= R_V7M_CFSR_MLSPERR_MASK;
- } else {
- qemu_log_mask(CPU_LOG_INT,
- "...MemManageFault with CFSR.MSTKERR\n");
- env->v7m.cfsr[secure] |= R_V7M_CFSR_MSTKERR_MASK;
- }
- exc = ARMV7M_EXCP_MEM;
- exc_secure = secure;
- }
- goto pend_fault;
- }
- address_space_stl_le(arm_addressspace(cs, attrs), physaddr, value,
- attrs, &txres);
- if (txres != MEMTX_OK) {
- /* BusFault trying to write the data */
- if (mode == STACK_LAZYFP) {
- qemu_log_mask(CPU_LOG_INT, "...BusFault with BFSR.LSPERR\n");
- env->v7m.cfsr[M_REG_NS] |= R_V7M_CFSR_LSPERR_MASK;
- } else {
- qemu_log_mask(CPU_LOG_INT, "...BusFault with BFSR.STKERR\n");
- env->v7m.cfsr[M_REG_NS] |= R_V7M_CFSR_STKERR_MASK;
+ if (idx >= 0 && idx < ARRAY_SIZE(excnames)) {
+ exc = excnames[idx];
}
- exc = ARMV7M_EXCP_BUS;
- exc_secure = false;
- goto pend_fault;
- }
- return true;
-
-pend_fault:
- /* By pending the exception at this point we are making
- * the IMPDEF choice "overridden exceptions pended" (see the
- * MergeExcInfo() pseudocode). The other choice would be to not
- * pend them now and then make a choice about which to throw away
- * later if we have two derived exceptions.
- * The only case when we must not pend the exception but instead
- * throw it away is if we are doing the push of the callee registers
- * and we've already generated a derived exception (this is indicated
- * by the caller passing STACK_IGNFAULTS). Even in this case we will
- * still update the fault status registers.
- */
- switch (mode) {
- case STACK_NORMAL:
- armv7m_nvic_set_pending_derived(env->nvic, exc, exc_secure);
- break;
- case STACK_LAZYFP:
- armv7m_nvic_set_pending_lazyfp(env->nvic, exc, exc_secure);
- break;
- case STACK_IGNFAULTS:
- break;
+ if (!exc) {
+ exc = "unknown";
+ }
+ qemu_log_mask(CPU_LOG_INT, "Taking exception %d [%s]\n", idx, exc);
}
- return false;
}
-static bool v7m_stack_read(ARMCPU *cpu, uint32_t *dest, uint32_t addr,
- ARMMMUIdx mmu_idx)
+/*
+ * Function used to synchronize QEMU's AArch64 register set with AArch32
+ * register set. This is necessary when switching between AArch32 and AArch64
+ * execution state.
+ */
+void aarch64_sync_32_to_64(CPUARMState *env)
{
- CPUState *cs = CPU(cpu);
- CPUARMState *env = &cpu->env;
- MemTxAttrs attrs = {};
- MemTxResult txres;
- target_ulong page_size;
- hwaddr physaddr;
- int prot;
- ARMMMUFaultInfo fi = {};
- bool secure = mmu_idx & ARM_MMU_IDX_M_S;
- int exc;
- bool exc_secure;
- uint32_t value;
-
- if (get_phys_addr(env, addr, MMU_DATA_LOAD, mmu_idx, &physaddr,
- &attrs, &prot, &page_size, &fi, NULL)) {
- /* MPU/SAU lookup failed */
- if (fi.type == ARMFault_QEMU_SFault) {
- qemu_log_mask(CPU_LOG_INT,
- "...SecureFault with SFSR.AUVIOL during unstack\n");
- env->v7m.sfsr |= R_V7M_SFSR_AUVIOL_MASK | R_V7M_SFSR_SFARVALID_MASK;
- env->v7m.sfar = addr;
- exc = ARMV7M_EXCP_SECURE;
- exc_secure = false;
- } else {
- qemu_log_mask(CPU_LOG_INT,
- "...MemManageFault with CFSR.MUNSTKERR\n");
- env->v7m.cfsr[secure] |= R_V7M_CFSR_MUNSTKERR_MASK;
- exc = ARMV7M_EXCP_MEM;
- exc_secure = secure;
- }
- goto pend_fault;
- }
+ int i;
+ uint32_t mode = env->uncached_cpsr & CPSR_M;
- value = address_space_ldl(arm_addressspace(cs, attrs), physaddr,
- attrs, &txres);
- if (txres != MEMTX_OK) {
- /* BusFault trying to read the data */
- qemu_log_mask(CPU_LOG_INT, "...BusFault with BFSR.UNSTKERR\n");
- env->v7m.cfsr[M_REG_NS] |= R_V7M_CFSR_UNSTKERR_MASK;
- exc = ARMV7M_EXCP_BUS;
- exc_secure = false;
- goto pend_fault;
+ /* We can blanket copy R[0:7] to X[0:7] */
+ for (i = 0; i < 8; i++) {
+ env->xregs[i] = env->regs[i];
}
- *dest = value;
- return true;
-
-pend_fault:
- /* By pending the exception at this point we are making
- * the IMPDEF choice "overridden exceptions pended" (see the
- * MergeExcInfo() pseudocode). The other choice would be to not
- * pend them now and then make a choice about which to throw away
- * later if we have two derived exceptions.
- */
- armv7m_nvic_set_pending(env->nvic, exc, exc_secure);
- return false;
-}
-
-void HELPER(v7m_preserve_fp_state)(CPUARMState *env)
-{
/*
- * Preserve FP state (because LSPACT was set and we are about
- * to execute an FP instruction). This corresponds to the
- * PreserveFPState() pseudocode.
- * We may throw an exception if the stacking fails.
+ * Unless we are in FIQ mode, x8-x12 come from the user registers r8-r12.
+ * Otherwise, they come from the banked user regs.
*/
- ARMCPU *cpu = env_archcpu(env);
- bool is_secure = env->v7m.fpccr[M_REG_S] & R_V7M_FPCCR_S_MASK;
- bool negpri = !(env->v7m.fpccr[M_REG_S] & R_V7M_FPCCR_HFRDY_MASK);
- bool is_priv = !(env->v7m.fpccr[is_secure] & R_V7M_FPCCR_USER_MASK);
- bool splimviol = env->v7m.fpccr[is_secure] & R_V7M_FPCCR_SPLIMVIOL_MASK;
- uint32_t fpcar = env->v7m.fpcar[is_secure];
- bool stacked_ok = true;
- bool ts = is_secure && (env->v7m.fpccr[M_REG_S] & R_V7M_FPCCR_TS_MASK);
- bool take_exception;
-
- /* Take the iothread lock as we are going to touch the NVIC */
- qemu_mutex_lock_iothread();
-
- /* Check the background context had access to the FPU */
- if (!v7m_cpacr_pass(env, is_secure, is_priv)) {
- armv7m_nvic_set_pending_lazyfp(env->nvic, ARMV7M_EXCP_USAGE, is_secure);
- env->v7m.cfsr[is_secure] |= R_V7M_CFSR_NOCP_MASK;
- stacked_ok = false;
- } else if (!is_secure && !extract32(env->v7m.nsacr, 10, 1)) {
- armv7m_nvic_set_pending_lazyfp(env->nvic, ARMV7M_EXCP_USAGE, M_REG_S);
- env->v7m.cfsr[M_REG_S] |= R_V7M_CFSR_NOCP_MASK;
- stacked_ok = false;
- }
-
- if (!splimviol && stacked_ok) {
- /* We only stack if the stack limit wasn't violated */
- int i;
- ARMMMUIdx mmu_idx;
-
- mmu_idx = arm_v7m_mmu_idx_all(env, is_secure, is_priv, negpri);
- for (i = 0; i < (ts ? 32 : 16); i += 2) {
- uint64_t dn = *aa32_vfp_dreg(env, i / 2);
- uint32_t faddr = fpcar + 4 * i;
- uint32_t slo = extract64(dn, 0, 32);
- uint32_t shi = extract64(dn, 32, 32);
-
- if (i >= 16) {
- faddr += 8; /* skip the slot for the FPSCR */
- }
- stacked_ok = stacked_ok &&
- v7m_stack_write(cpu, faddr, slo, mmu_idx, STACK_LAZYFP) &&
- v7m_stack_write(cpu, faddr + 4, shi, mmu_idx, STACK_LAZYFP);
+ if (mode == ARM_CPU_MODE_FIQ) {
+ for (i = 8; i < 13; i++) {
+ env->xregs[i] = env->usr_regs[i - 8];
+ }
+ } else {
+ for (i = 8; i < 13; i++) {
+ env->xregs[i] = env->regs[i];
}
-
- stacked_ok = stacked_ok &&
- v7m_stack_write(cpu, fpcar + 0x40,
- vfp_get_fpscr(env), mmu_idx, STACK_LAZYFP);
}
/*
- * We definitely pended an exception, but it's possible that it
- * might not be able to be taken now. If its priority permits us
- * to take it now, then we must not update the LSPACT or FP regs,
- * but instead jump out to take the exception immediately.
- * If it's just pending and won't be taken until the current
- * handler exits, then we do update LSPACT and the FP regs.
+ * Registers x13-x23 are the various mode SP and FP registers. Registers
+ * r13 and r14 are only copied if we are in that mode, otherwise we copy
+ * from the mode banked register.
*/
- take_exception = !stacked_ok &&
- armv7m_nvic_can_take_pending_exception(env->nvic);
-
- qemu_mutex_unlock_iothread();
-
- if (take_exception) {
- raise_exception_ra(env, EXCP_LAZYFP, 0, 1, GETPC());
- }
-
- env->v7m.fpccr[is_secure] &= ~R_V7M_FPCCR_LSPACT_MASK;
-
- if (ts) {
- /* Clear s0 to s31 and the FPSCR */
- int i;
-
- for (i = 0; i < 32; i += 2) {
- *aa32_vfp_dreg(env, i / 2) = 0;
+ if (mode == ARM_CPU_MODE_USR || mode == ARM_CPU_MODE_SYS) {
+ env->xregs[13] = env->regs[13];
+ env->xregs[14] = env->regs[14];
+ } else {
+ env->xregs[13] = env->banked_r13[bank_number(ARM_CPU_MODE_USR)];
+ /* HYP is an exception in that it is copied from r14 */
+ if (mode == ARM_CPU_MODE_HYP) {
+ env->xregs[14] = env->regs[14];
+ } else {
+ env->xregs[14] = env->banked_r14[r14_bank_number(ARM_CPU_MODE_USR)];
}
- vfp_set_fpscr(env, 0);
}
- /*
- * Otherwise s0 to s15 and FPSCR are UNKNOWN; we choose to leave them
- * unchanged.
- */
-}
-
-/* Write to v7M CONTROL.SPSEL bit for the specified security bank.
- * This may change the current stack pointer between Main and Process
- * stack pointers if it is done for the CONTROL register for the current
- * security state.
- */
-static void write_v7m_control_spsel_for_secstate(CPUARMState *env,
- bool new_spsel,
- bool secstate)
-{
- bool old_is_psp = v7m_using_psp(env);
-
- env->v7m.control[secstate] =
- deposit32(env->v7m.control[secstate],
- R_V7M_CONTROL_SPSEL_SHIFT,
- R_V7M_CONTROL_SPSEL_LENGTH, new_spsel);
- if (secstate == env->v7m.secure) {
- bool new_is_psp = v7m_using_psp(env);
- uint32_t tmp;
-
- if (old_is_psp != new_is_psp) {
- tmp = env->v7m.other_sp;
- env->v7m.other_sp = env->regs[13];
- env->regs[13] = tmp;
- }
+ if (mode == ARM_CPU_MODE_HYP) {
+ env->xregs[15] = env->regs[13];
+ } else {
+ env->xregs[15] = env->banked_r13[bank_number(ARM_CPU_MODE_HYP)];
}
-}
-
-/* Write to v7M CONTROL.SPSEL bit. This may change the current
- * stack pointer between Main and Process stack pointers.
- */
-static void write_v7m_control_spsel(CPUARMState *env, bool new_spsel)
-{
- write_v7m_control_spsel_for_secstate(env, new_spsel, env->v7m.secure);
-}
-
-void write_v7m_exception(CPUARMState *env, uint32_t new_exc)
-{
- /* Write a new value to v7m.exception, thus transitioning into or out
- * of Handler mode; this may result in a change of active stack pointer.
- */
- bool new_is_psp, old_is_psp = v7m_using_psp(env);
- uint32_t tmp;
- env->v7m.exception = new_exc;
-
- new_is_psp = v7m_using_psp(env);
-
- if (old_is_psp != new_is_psp) {
- tmp = env->v7m.other_sp;
- env->v7m.other_sp = env->regs[13];
- env->regs[13] = tmp;
+ if (mode == ARM_CPU_MODE_IRQ) {
+ env->xregs[16] = env->regs[14];
+ env->xregs[17] = env->regs[13];
+ } else {
+ env->xregs[16] = env->banked_r14[r14_bank_number(ARM_CPU_MODE_IRQ)];
+ env->xregs[17] = env->banked_r13[bank_number(ARM_CPU_MODE_IRQ)];
}
-}
-
-/* Switch M profile security state between NS and S */
-static void switch_v7m_security_state(CPUARMState *env, bool new_secstate)
-{
- uint32_t new_ss_msp, new_ss_psp;
- if (env->v7m.secure == new_secstate) {
- return;
+ if (mode == ARM_CPU_MODE_SVC) {
+ env->xregs[18] = env->regs[14];
+ env->xregs[19] = env->regs[13];
+ } else {
+ env->xregs[18] = env->banked_r14[r14_bank_number(ARM_CPU_MODE_SVC)];
+ env->xregs[19] = env->banked_r13[bank_number(ARM_CPU_MODE_SVC)];
}
- /* All the banked state is accessed by looking at env->v7m.secure
- * except for the stack pointer; rearrange the SP appropriately.
- */
- new_ss_msp = env->v7m.other_ss_msp;
- new_ss_psp = env->v7m.other_ss_psp;
-
- if (v7m_using_psp(env)) {
- env->v7m.other_ss_psp = env->regs[13];
- env->v7m.other_ss_msp = env->v7m.other_sp;
+ if (mode == ARM_CPU_MODE_ABT) {
+ env->xregs[20] = env->regs[14];
+ env->xregs[21] = env->regs[13];
} else {
- env->v7m.other_ss_msp = env->regs[13];
- env->v7m.other_ss_psp = env->v7m.other_sp;
+ env->xregs[20] = env->banked_r14[r14_bank_number(ARM_CPU_MODE_ABT)];
+ env->xregs[21] = env->banked_r13[bank_number(ARM_CPU_MODE_ABT)];
}
- env->v7m.secure = new_secstate;
-
- if (v7m_using_psp(env)) {
- env->regs[13] = new_ss_psp;
- env->v7m.other_sp = new_ss_msp;
+ if (mode == ARM_CPU_MODE_UND) {
+ env->xregs[22] = env->regs[14];
+ env->xregs[23] = env->regs[13];
} else {
- env->regs[13] = new_ss_msp;
- env->v7m.other_sp = new_ss_psp;
+ env->xregs[22] = env->banked_r14[r14_bank_number(ARM_CPU_MODE_UND)];
+ env->xregs[23] = env->banked_r13[bank_number(ARM_CPU_MODE_UND)];
}
-}
-void HELPER(v7m_bxns)(CPUARMState *env, uint32_t dest)
-{
- /* Handle v7M BXNS:
- * - if the return value is a magic value, do exception return (like BX)
- * - otherwise bit 0 of the return value is the target security state
+ /*
+ * Registers x24-x30 are mapped to r8-r14 in FIQ mode. If we are in FIQ
+ * mode, then we can copy from r8-r14. Otherwise, we copy from the
+ * FIQ bank for r8-r14.
*/
- uint32_t min_magic;
-
- if (arm_feature(env, ARM_FEATURE_M_SECURITY)) {
- /* Covers FNC_RETURN and EXC_RETURN magic */
- min_magic = FNC_RETURN_MIN_MAGIC;
+ if (mode == ARM_CPU_MODE_FIQ) {
+ for (i = 24; i < 31; i++) {
+ env->xregs[i] = env->regs[i - 16]; /* X[24:30] <- R[8:14] */
+ }
} else {
- /* EXC_RETURN magic only */
- min_magic = EXC_RETURN_MIN_MAGIC;
- }
-
- if (dest >= min_magic) {
- /* This is an exception return magic value; put it where
- * do_v7m_exception_exit() expects and raise EXCEPTION_EXIT.
- * Note that if we ever add gen_ss_advance() singlestep support to
- * M profile this should count as an "instruction execution complete"
- * event (compare gen_bx_excret_final_code()).
- */
- env->regs[15] = dest & ~1;
- env->thumb = dest & 1;
- HELPER(exception_internal)(env, EXCP_EXCEPTION_EXIT);
- /* notreached */
+ for (i = 24; i < 29; i++) {
+ env->xregs[i] = env->fiq_regs[i - 24];
+ }
+ env->xregs[29] = env->banked_r13[bank_number(ARM_CPU_MODE_FIQ)];
+ env->xregs[30] = env->banked_r14[r14_bank_number(ARM_CPU_MODE_FIQ)];
}
- /* translate.c should have made BXNS UNDEF unless we're secure */
- assert(env->v7m.secure);
-
- if (!(dest & 1)) {
- env->v7m.control[M_REG_S] &= ~R_V7M_CONTROL_SFPA_MASK;
- }
- switch_v7m_security_state(env, dest & 1);
- env->thumb = 1;
- env->regs[15] = dest & ~1;
+ env->pc = env->regs[15];
}
-void HELPER(v7m_blxns)(CPUARMState *env, uint32_t dest)
+/*
+ * Function used to synchronize QEMU's AArch32 register set with AArch64
+ * register set. This is necessary when switching between AArch32 and AArch64
+ * execution state.
+ */
+void aarch64_sync_64_to_32(CPUARMState *env)
{
- /* Handle v7M BLXNS:
- * - bit 0 of the destination address is the target security state
- */
-
- /* At this point regs[15] is the address just after the BLXNS */
- uint32_t nextinst = env->regs[15] | 1;
- uint32_t sp = env->regs[13] - 8;
- uint32_t saved_psr;
-
- /* translate.c will have made BLXNS UNDEF unless we're secure */
- assert(env->v7m.secure);
-
- if (dest & 1) {
- /* target is Secure, so this is just a normal BLX,
- * except that the low bit doesn't indicate Thumb/not.
- */
- env->regs[14] = nextinst;
- env->thumb = 1;
- env->regs[15] = dest & ~1;
- return;
- }
-
- /* Target is non-secure: first push a stack frame */
- if (!QEMU_IS_ALIGNED(sp, 8)) {
- qemu_log_mask(LOG_GUEST_ERROR,
- "BLXNS with misaligned SP is UNPREDICTABLE\n");
- }
-
- if (sp < v7m_sp_limit(env)) {
- raise_exception(env, EXCP_STKOF, 0, 1);
- }
-
- saved_psr = env->v7m.exception;
- if (env->v7m.control[M_REG_S] & R_V7M_CONTROL_SFPA_MASK) {
- saved_psr |= XPSR_SFPA;
- }
-
- /* Note that these stores can throw exceptions on MPU faults */
- cpu_stl_data(env, sp, nextinst);
- cpu_stl_data(env, sp + 4, saved_psr);
-
- env->regs[13] = sp;
- env->regs[14] = 0xfeffffff;
- if (arm_v7m_is_handler_mode(env)) {
- /* Write a dummy value to IPSR, to avoid leaking the current secure
- * exception number to non-secure code. This is guaranteed not
- * to cause write_v7m_exception() to actually change stacks.
- */
- write_v7m_exception(env, 1);
- }
- env->v7m.control[M_REG_S] &= ~R_V7M_CONTROL_SFPA_MASK;
- switch_v7m_security_state(env, 0);
- env->thumb = 1;
- env->regs[15] = dest;
-}
-
-static uint32_t *get_v7m_sp_ptr(CPUARMState *env, bool secure, bool threadmode,
- bool spsel)
-{
- /* Return a pointer to the location where we currently store the
- * stack pointer for the requested security state and thread mode.
- * This pointer will become invalid if the CPU state is updated
- * such that the stack pointers are switched around (eg changing
- * the SPSEL control bit).
- * Compare the v8M ARM ARM pseudocode LookUpSP_with_security_mode().
- * Unlike that pseudocode, we require the caller to pass us in the
- * SPSEL control bit value; this is because we also use this
- * function in handling of pushing of the callee-saves registers
- * part of the v8M stack frame (pseudocode PushCalleeStack()),
- * and in the tailchain codepath the SPSEL bit comes from the exception
- * return magic LR value from the previous exception. The pseudocode
- * opencodes the stack-selection in PushCalleeStack(), but we prefer
- * to make this utility function generic enough to do the job.
- */
- bool want_psp = threadmode && spsel;
-
- if (secure == env->v7m.secure) {
- if (want_psp == v7m_using_psp(env)) {
- return &env->regs[13];
- } else {
- return &env->v7m.other_sp;
- }
- } else {
- if (want_psp) {
- return &env->v7m.other_ss_psp;
- } else {
- return &env->v7m.other_ss_msp;
- }
- }
-}
-
-static bool arm_v7m_load_vector(ARMCPU *cpu, int exc, bool targets_secure,
- uint32_t *pvec)
-{
- CPUState *cs = CPU(cpu);
- CPUARMState *env = &cpu->env;
- MemTxResult result;
- uint32_t addr = env->v7m.vecbase[targets_secure] + exc * 4;
- uint32_t vector_entry;
- MemTxAttrs attrs = {};
- ARMMMUIdx mmu_idx;
- bool exc_secure;
-
- mmu_idx = arm_v7m_mmu_idx_for_secstate_and_priv(env, targets_secure, true);
-
- /* We don't do a get_phys_addr() here because the rules for vector
- * loads are special: they always use the default memory map, and
- * the default memory map permits reads from all addresses.
- * Since there's no easy way to pass through to pmsav8_mpu_lookup()
- * that we want this special case which would always say "yes",
- * we just do the SAU lookup here followed by a direct physical load.
- */
- attrs.secure = targets_secure;
- attrs.user = false;
-
- if (arm_feature(env, ARM_FEATURE_M_SECURITY)) {
- V8M_SAttributes sattrs = {};
-
- v8m_security_lookup(env, addr, MMU_DATA_LOAD, mmu_idx, &sattrs);
- if (sattrs.ns) {
- attrs.secure = false;
- } else if (!targets_secure) {
- /* NS access to S memory */
- goto load_fail;
- }
- }
-
- vector_entry = address_space_ldl(arm_addressspace(cs, attrs), addr,
- attrs, &result);
- if (result != MEMTX_OK) {
- goto load_fail;
- }
- *pvec = vector_entry;
- return true;
-
-load_fail:
- /* All vector table fetch fails are reported as HardFault, with
- * HFSR.VECTTBL and .FORCED set. (FORCED is set because
- * technically the underlying exception is a MemManage or BusFault
- * that is escalated to HardFault.) This is a terminal exception,
- * so we will either take the HardFault immediately or else enter
- * lockup (the latter case is handled in armv7m_nvic_set_pending_derived()).
- */
- exc_secure = targets_secure ||
- !(cpu->env.v7m.aircr & R_V7M_AIRCR_BFHFNMINS_MASK);
- env->v7m.hfsr |= R_V7M_HFSR_VECTTBL_MASK | R_V7M_HFSR_FORCED_MASK;
- armv7m_nvic_set_pending_derived(env->nvic, ARMV7M_EXCP_HARD, exc_secure);
- return false;
-}
-
-static uint32_t v7m_integrity_sig(CPUARMState *env, uint32_t lr)
-{
- /*
- * Return the integrity signature value for the callee-saves
- * stack frame section. @lr is the exception return payload/LR value
- * whose FType bit forms bit 0 of the signature if FP is present.
- */
- uint32_t sig = 0xfefa125a;
-
- if (!arm_feature(env, ARM_FEATURE_VFP) || (lr & R_V7M_EXCRET_FTYPE_MASK)) {
- sig |= 1;
- }
- return sig;
-}
-
-static bool v7m_push_callee_stack(ARMCPU *cpu, uint32_t lr, bool dotailchain,
- bool ignore_faults)
-{
- /* For v8M, push the callee-saves register part of the stack frame.
- * Compare the v8M pseudocode PushCalleeStack().
- * In the tailchaining case this may not be the current stack.
- */
- CPUARMState *env = &cpu->env;
- uint32_t *frame_sp_p;
- uint32_t frameptr;
- ARMMMUIdx mmu_idx;
- bool stacked_ok;
- uint32_t limit;
- bool want_psp;
- uint32_t sig;
- StackingMode smode = ignore_faults ? STACK_IGNFAULTS : STACK_NORMAL;
-
- if (dotailchain) {
- bool mode = lr & R_V7M_EXCRET_MODE_MASK;
- bool priv = !(env->v7m.control[M_REG_S] & R_V7M_CONTROL_NPRIV_MASK) ||
- !mode;
-
- mmu_idx = arm_v7m_mmu_idx_for_secstate_and_priv(env, M_REG_S, priv);
- frame_sp_p = get_v7m_sp_ptr(env, M_REG_S, mode,
- lr & R_V7M_EXCRET_SPSEL_MASK);
- want_psp = mode && (lr & R_V7M_EXCRET_SPSEL_MASK);
- if (want_psp) {
- limit = env->v7m.psplim[M_REG_S];
- } else {
- limit = env->v7m.msplim[M_REG_S];
- }
- } else {
- mmu_idx = arm_mmu_idx(env);
- frame_sp_p = &env->regs[13];
- limit = v7m_sp_limit(env);
- }
-
- frameptr = *frame_sp_p - 0x28;
- if (frameptr < limit) {
- /*
- * Stack limit failure: set SP to the limit value, and generate
- * STKOF UsageFault. Stack pushes below the limit must not be
- * performed. It is IMPDEF whether pushes above the limit are
- * performed; we choose not to.
- */
- qemu_log_mask(CPU_LOG_INT,
- "...STKOF during callee-saves register stacking\n");
- env->v7m.cfsr[env->v7m.secure] |= R_V7M_CFSR_STKOF_MASK;
- armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE,
- env->v7m.secure);
- *frame_sp_p = limit;
- return true;
- }
-
- /* Write as much of the stack frame as we can. A write failure may
- * cause us to pend a derived exception.
- */
- sig = v7m_integrity_sig(env, lr);
- stacked_ok =
- v7m_stack_write(cpu, frameptr, sig, mmu_idx, smode) &&
- v7m_stack_write(cpu, frameptr + 0x8, env->regs[4], mmu_idx, smode) &&
- v7m_stack_write(cpu, frameptr + 0xc, env->regs[5], mmu_idx, smode) &&
- v7m_stack_write(cpu, frameptr + 0x10, env->regs[6], mmu_idx, smode) &&
- v7m_stack_write(cpu, frameptr + 0x14, env->regs[7], mmu_idx, smode) &&
- v7m_stack_write(cpu, frameptr + 0x18, env->regs[8], mmu_idx, smode) &&
- v7m_stack_write(cpu, frameptr + 0x1c, env->regs[9], mmu_idx, smode) &&
- v7m_stack_write(cpu, frameptr + 0x20, env->regs[10], mmu_idx, smode) &&
- v7m_stack_write(cpu, frameptr + 0x24, env->regs[11], mmu_idx, smode);
-
- /* Update SP regardless of whether any of the stack accesses failed. */
- *frame_sp_p = frameptr;
-
- return !stacked_ok;
-}
-
-static void v7m_exception_taken(ARMCPU *cpu, uint32_t lr, bool dotailchain,
- bool ignore_stackfaults)
-{
- /* Do the "take the exception" parts of exception entry,
- * but not the pushing of state to the stack. This is
- * similar to the pseudocode ExceptionTaken() function.
- */
- CPUARMState *env = &cpu->env;
- uint32_t addr;
- bool targets_secure;
- int exc;
- bool push_failed = false;
-
- armv7m_nvic_get_pending_irq_info(env->nvic, &exc, &targets_secure);
- qemu_log_mask(CPU_LOG_INT, "...taking pending %s exception %d\n",
- targets_secure ? "secure" : "nonsecure", exc);
-
- if (dotailchain) {
- /* Sanitize LR FType and PREFIX bits */
- if (!arm_feature(env, ARM_FEATURE_VFP)) {
- lr |= R_V7M_EXCRET_FTYPE_MASK;
- }
- lr = deposit32(lr, 24, 8, 0xff);
- }
-
- if (arm_feature(env, ARM_FEATURE_V8)) {
- if (arm_feature(env, ARM_FEATURE_M_SECURITY) &&
- (lr & R_V7M_EXCRET_S_MASK)) {
- /* The background code (the owner of the registers in the
- * exception frame) is Secure. This means it may either already
- * have or now needs to push callee-saves registers.
- */
- if (targets_secure) {
- if (dotailchain && !(lr & R_V7M_EXCRET_ES_MASK)) {
- /* We took an exception from Secure to NonSecure
- * (which means the callee-saved registers got stacked)
- * and are now tailchaining to a Secure exception.
- * Clear DCRS so eventual return from this Secure
- * exception unstacks the callee-saved registers.
- */
- lr &= ~R_V7M_EXCRET_DCRS_MASK;
- }
- } else {
- /* We're going to a non-secure exception; push the
- * callee-saves registers to the stack now, if they're
- * not already saved.
- */
- if (lr & R_V7M_EXCRET_DCRS_MASK &&
- !(dotailchain && !(lr & R_V7M_EXCRET_ES_MASK))) {
- push_failed = v7m_push_callee_stack(cpu, lr, dotailchain,
- ignore_stackfaults);
- }
- lr |= R_V7M_EXCRET_DCRS_MASK;
- }
- }
-
- lr &= ~R_V7M_EXCRET_ES_MASK;
- if (targets_secure || !arm_feature(env, ARM_FEATURE_M_SECURITY)) {
- lr |= R_V7M_EXCRET_ES_MASK;
- }
- lr &= ~R_V7M_EXCRET_SPSEL_MASK;
- if (env->v7m.control[targets_secure] & R_V7M_CONTROL_SPSEL_MASK) {
- lr |= R_V7M_EXCRET_SPSEL_MASK;
- }
-
- /* Clear registers if necessary to prevent non-secure exception
- * code being able to see register values from secure code.
- * Where register values become architecturally UNKNOWN we leave
- * them with their previous values.
- */
- if (arm_feature(env, ARM_FEATURE_M_SECURITY)) {
- if (!targets_secure) {
- /* Always clear the caller-saved registers (they have been
- * pushed to the stack earlier in v7m_push_stack()).
- * Clear callee-saved registers if the background code is
- * Secure (in which case these regs were saved in
- * v7m_push_callee_stack()).
- */
- int i;
-
- for (i = 0; i < 13; i++) {
- /* r4..r11 are callee-saves, zero only if EXCRET.S == 1 */
- if (i < 4 || i > 11 || (lr & R_V7M_EXCRET_S_MASK)) {
- env->regs[i] = 0;
- }
- }
- /* Clear EAPSR */
- xpsr_write(env, 0, XPSR_NZCV | XPSR_Q | XPSR_GE | XPSR_IT);
- }
- }
- }
-
- if (push_failed && !ignore_stackfaults) {
- /* Derived exception on callee-saves register stacking:
- * we might now want to take a different exception which
- * targets a different security state, so try again from the top.
- */
- qemu_log_mask(CPU_LOG_INT,
- "...derived exception on callee-saves register stacking");
- v7m_exception_taken(cpu, lr, true, true);
- return;
- }
-
- if (!arm_v7m_load_vector(cpu, exc, targets_secure, &addr)) {
- /* Vector load failed: derived exception */
- qemu_log_mask(CPU_LOG_INT, "...derived exception on vector table load");
- v7m_exception_taken(cpu, lr, true, true);
- return;
- }
-
- /* Now we've done everything that might cause a derived exception
- * we can go ahead and activate whichever exception we're going to
- * take (which might now be the derived exception).
- */
- armv7m_nvic_acknowledge_irq(env->nvic);
-
- /* Switch to target security state -- must do this before writing SPSEL */
- switch_v7m_security_state(env, targets_secure);
- write_v7m_control_spsel(env, 0);
- arm_clear_exclusive(env);
- /* Clear SFPA and FPCA (has no effect if no FPU) */
- env->v7m.control[M_REG_S] &=
- ~(R_V7M_CONTROL_FPCA_MASK | R_V7M_CONTROL_SFPA_MASK);
- /* Clear IT bits */
- env->condexec_bits = 0;
- env->regs[14] = lr;
- env->regs[15] = addr & 0xfffffffe;
- env->thumb = addr & 1;
-}
-
-static void v7m_update_fpccr(CPUARMState *env, uint32_t frameptr,
- bool apply_splim)
-{
- /*
- * Like the pseudocode UpdateFPCCR: save state in FPCAR and FPCCR
- * that we will need later in order to do lazy FP reg stacking.
- */
- bool is_secure = env->v7m.secure;
- void *nvic = env->nvic;
- /*
- * Some bits are unbanked and live always in fpccr[M_REG_S]; some bits
- * are banked and we want to update the bit in the bank for the
- * current security state; and in one case we want to specifically
- * update the NS banked version of a bit even if we are secure.
- */
- uint32_t *fpccr_s = &env->v7m.fpccr[M_REG_S];
- uint32_t *fpccr_ns = &env->v7m.fpccr[M_REG_NS];
- uint32_t *fpccr = &env->v7m.fpccr[is_secure];
- bool hfrdy, bfrdy, mmrdy, ns_ufrdy, s_ufrdy, sfrdy, monrdy;
-
- env->v7m.fpcar[is_secure] = frameptr & ~0x7;
-
- if (apply_splim && arm_feature(env, ARM_FEATURE_V8)) {
- bool splimviol;
- uint32_t splim = v7m_sp_limit(env);
- bool ign = armv7m_nvic_neg_prio_requested(nvic, is_secure) &&
- (env->v7m.ccr[is_secure] & R_V7M_CCR_STKOFHFNMIGN_MASK);
-
- splimviol = !ign && frameptr < splim;
- *fpccr = FIELD_DP32(*fpccr, V7M_FPCCR, SPLIMVIOL, splimviol);
- }
-
- *fpccr = FIELD_DP32(*fpccr, V7M_FPCCR, LSPACT, 1);
-
- *fpccr_s = FIELD_DP32(*fpccr_s, V7M_FPCCR, S, is_secure);
-
- *fpccr = FIELD_DP32(*fpccr, V7M_FPCCR, USER, arm_current_el(env) == 0);
-
- *fpccr = FIELD_DP32(*fpccr, V7M_FPCCR, THREAD,
- !arm_v7m_is_handler_mode(env));
-
- hfrdy = armv7m_nvic_get_ready_status(nvic, ARMV7M_EXCP_HARD, false);
- *fpccr_s = FIELD_DP32(*fpccr_s, V7M_FPCCR, HFRDY, hfrdy);
-
- bfrdy = armv7m_nvic_get_ready_status(nvic, ARMV7M_EXCP_BUS, false);
- *fpccr_s = FIELD_DP32(*fpccr_s, V7M_FPCCR, BFRDY, bfrdy);
-
- mmrdy = armv7m_nvic_get_ready_status(nvic, ARMV7M_EXCP_MEM, is_secure);
- *fpccr = FIELD_DP32(*fpccr, V7M_FPCCR, MMRDY, mmrdy);
-
- ns_ufrdy = armv7m_nvic_get_ready_status(nvic, ARMV7M_EXCP_USAGE, false);
- *fpccr_ns = FIELD_DP32(*fpccr_ns, V7M_FPCCR, UFRDY, ns_ufrdy);
-
- monrdy = armv7m_nvic_get_ready_status(nvic, ARMV7M_EXCP_DEBUG, false);
- *fpccr_s = FIELD_DP32(*fpccr_s, V7M_FPCCR, MONRDY, monrdy);
-
- if (arm_feature(env, ARM_FEATURE_M_SECURITY)) {
- s_ufrdy = armv7m_nvic_get_ready_status(nvic, ARMV7M_EXCP_USAGE, true);
- *fpccr_s = FIELD_DP32(*fpccr_s, V7M_FPCCR, UFRDY, s_ufrdy);
-
- sfrdy = armv7m_nvic_get_ready_status(nvic, ARMV7M_EXCP_SECURE, false);
- *fpccr_s = FIELD_DP32(*fpccr_s, V7M_FPCCR, SFRDY, sfrdy);
- }
-}
-
-void HELPER(v7m_vlstm)(CPUARMState *env, uint32_t fptr)
-{
- /* fptr is the value of Rn, the frame pointer we store the FP regs to */
- bool s = env->v7m.fpccr[M_REG_S] & R_V7M_FPCCR_S_MASK;
- bool lspact = env->v7m.fpccr[s] & R_V7M_FPCCR_LSPACT_MASK;
-
- assert(env->v7m.secure);
-
- if (!(env->v7m.control[M_REG_S] & R_V7M_CONTROL_SFPA_MASK)) {
- return;
- }
-
- /* Check access to the coprocessor is permitted */
- if (!v7m_cpacr_pass(env, true, arm_current_el(env) != 0)) {
- raise_exception_ra(env, EXCP_NOCP, 0, 1, GETPC());
- }
-
- if (lspact) {
- /* LSPACT should not be active when there is active FP state */
- raise_exception_ra(env, EXCP_LSERR, 0, 1, GETPC());
- }
-
- if (fptr & 7) {
- raise_exception_ra(env, EXCP_UNALIGNED, 0, 1, GETPC());
- }
-
- /*
- * Note that we do not use v7m_stack_write() here, because the
- * accesses should not set the FSR bits for stacking errors if they
- * fail. (In pseudocode terms, they are AccType_NORMAL, not AccType_STACK
- * or AccType_LAZYFP). Faults in cpu_stl_data() will throw exceptions
- * and longjmp out.
- */
- if (!(env->v7m.fpccr[M_REG_S] & R_V7M_FPCCR_LSPEN_MASK)) {
- bool ts = env->v7m.fpccr[M_REG_S] & R_V7M_FPCCR_TS_MASK;
- int i;
-
- for (i = 0; i < (ts ? 32 : 16); i += 2) {
- uint64_t dn = *aa32_vfp_dreg(env, i / 2);
- uint32_t faddr = fptr + 4 * i;
- uint32_t slo = extract64(dn, 0, 32);
- uint32_t shi = extract64(dn, 32, 32);
-
- if (i >= 16) {
- faddr += 8; /* skip the slot for the FPSCR */
- }
- cpu_stl_data(env, faddr, slo);
- cpu_stl_data(env, faddr + 4, shi);
- }
- cpu_stl_data(env, fptr + 0x40, vfp_get_fpscr(env));
-
- /*
- * If TS is 0 then s0 to s15 and FPSCR are UNKNOWN; we choose to
- * leave them unchanged, matching our choice in v7m_preserve_fp_state.
- */
- if (ts) {
- for (i = 0; i < 32; i += 2) {
- *aa32_vfp_dreg(env, i / 2) = 0;
- }
- vfp_set_fpscr(env, 0);
- }
- } else {
- v7m_update_fpccr(env, fptr, false);
- }
-
- env->v7m.control[M_REG_S] &= ~R_V7M_CONTROL_FPCA_MASK;
-}
-
-void HELPER(v7m_vlldm)(CPUARMState *env, uint32_t fptr)
-{
- /* fptr is the value of Rn, the frame pointer we load the FP regs from */
- assert(env->v7m.secure);
-
- if (!(env->v7m.control[M_REG_S] & R_V7M_CONTROL_SFPA_MASK)) {
- return;
- }
-
- /* Check access to the coprocessor is permitted */
- if (!v7m_cpacr_pass(env, true, arm_current_el(env) != 0)) {
- raise_exception_ra(env, EXCP_NOCP, 0, 1, GETPC());
- }
-
- if (env->v7m.fpccr[M_REG_S] & R_V7M_FPCCR_LSPACT_MASK) {
- /* State in FP is still valid */
- env->v7m.fpccr[M_REG_S] &= ~R_V7M_FPCCR_LSPACT_MASK;
- } else {
- bool ts = env->v7m.fpccr[M_REG_S] & R_V7M_FPCCR_TS_MASK;
- int i;
- uint32_t fpscr;
-
- if (fptr & 7) {
- raise_exception_ra(env, EXCP_UNALIGNED, 0, 1, GETPC());
- }
-
- for (i = 0; i < (ts ? 32 : 16); i += 2) {
- uint32_t slo, shi;
- uint64_t dn;
- uint32_t faddr = fptr + 4 * i;
-
- if (i >= 16) {
- faddr += 8; /* skip the slot for the FPSCR */
- }
-
- slo = cpu_ldl_data(env, faddr);
- shi = cpu_ldl_data(env, faddr + 4);
-
- dn = (uint64_t) shi << 32 | slo;
- *aa32_vfp_dreg(env, i / 2) = dn;
- }
- fpscr = cpu_ldl_data(env, fptr + 0x40);
- vfp_set_fpscr(env, fpscr);
- }
-
- env->v7m.control[M_REG_S] |= R_V7M_CONTROL_FPCA_MASK;
-}
-
-static bool v7m_push_stack(ARMCPU *cpu)
-{
- /* Do the "set up stack frame" part of exception entry,
- * similar to pseudocode PushStack().
- * Return true if we generate a derived exception (and so
- * should ignore further stack faults trying to process
- * that derived exception.)
- */
- bool stacked_ok = true, limitviol = false;
- CPUARMState *env = &cpu->env;
- uint32_t xpsr = xpsr_read(env);
- uint32_t frameptr = env->regs[13];
- ARMMMUIdx mmu_idx = arm_mmu_idx(env);
- uint32_t framesize;
- bool nsacr_cp10 = extract32(env->v7m.nsacr, 10, 1);
-
- if ((env->v7m.control[M_REG_S] & R_V7M_CONTROL_FPCA_MASK) &&
- (env->v7m.secure || nsacr_cp10)) {
- if (env->v7m.secure &&
- env->v7m.fpccr[M_REG_S] & R_V7M_FPCCR_TS_MASK) {
- framesize = 0xa8;
- } else {
- framesize = 0x68;
- }
- } else {
- framesize = 0x20;
- }
-
- /* Align stack pointer if the guest wants that */
- if ((frameptr & 4) &&
- (env->v7m.ccr[env->v7m.secure] & R_V7M_CCR_STKALIGN_MASK)) {
- frameptr -= 4;
- xpsr |= XPSR_SPREALIGN;
- }
-
- xpsr &= ~XPSR_SFPA;
- if (env->v7m.secure &&
- (env->v7m.control[M_REG_S] & R_V7M_CONTROL_SFPA_MASK)) {
- xpsr |= XPSR_SFPA;
- }
-
- frameptr -= framesize;
-
- if (arm_feature(env, ARM_FEATURE_V8)) {
- uint32_t limit = v7m_sp_limit(env);
-
- if (frameptr < limit) {
- /*
- * Stack limit failure: set SP to the limit value, and generate
- * STKOF UsageFault. Stack pushes below the limit must not be
- * performed. It is IMPDEF whether pushes above the limit are
- * performed; we choose not to.
- */
- qemu_log_mask(CPU_LOG_INT,
- "...STKOF during stacking\n");
- env->v7m.cfsr[env->v7m.secure] |= R_V7M_CFSR_STKOF_MASK;
- armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE,
- env->v7m.secure);
- env->regs[13] = limit;
- /*
- * We won't try to perform any further memory accesses but
- * we must continue through the following code to check for
- * permission faults during FPU state preservation, and we
- * must update FPCCR if lazy stacking is enabled.
- */
- limitviol = true;
- stacked_ok = false;
- }
- }
-
- /* Write as much of the stack frame as we can. If we fail a stack
- * write this will result in a derived exception being pended
- * (which may be taken in preference to the one we started with
- * if it has higher priority).
- */
- stacked_ok = stacked_ok &&
- v7m_stack_write(cpu, frameptr, env->regs[0], mmu_idx, STACK_NORMAL) &&
- v7m_stack_write(cpu, frameptr + 4, env->regs[1],
- mmu_idx, STACK_NORMAL) &&
- v7m_stack_write(cpu, frameptr + 8, env->regs[2],
- mmu_idx, STACK_NORMAL) &&
- v7m_stack_write(cpu, frameptr + 12, env->regs[3],
- mmu_idx, STACK_NORMAL) &&
- v7m_stack_write(cpu, frameptr + 16, env->regs[12],
- mmu_idx, STACK_NORMAL) &&
- v7m_stack_write(cpu, frameptr + 20, env->regs[14],
- mmu_idx, STACK_NORMAL) &&
- v7m_stack_write(cpu, frameptr + 24, env->regs[15],
- mmu_idx, STACK_NORMAL) &&
- v7m_stack_write(cpu, frameptr + 28, xpsr, mmu_idx, STACK_NORMAL);
-
- if (env->v7m.control[M_REG_S] & R_V7M_CONTROL_FPCA_MASK) {
- /* FPU is active, try to save its registers */
- bool fpccr_s = env->v7m.fpccr[M_REG_S] & R_V7M_FPCCR_S_MASK;
- bool lspact = env->v7m.fpccr[fpccr_s] & R_V7M_FPCCR_LSPACT_MASK;
-
- if (lspact && arm_feature(env, ARM_FEATURE_M_SECURITY)) {
- qemu_log_mask(CPU_LOG_INT,
- "...SecureFault because LSPACT and FPCA both set\n");
- env->v7m.sfsr |= R_V7M_SFSR_LSERR_MASK;
- armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_SECURE, false);
- } else if (!env->v7m.secure && !nsacr_cp10) {
- qemu_log_mask(CPU_LOG_INT,
- "...Secure UsageFault with CFSR.NOCP because "
- "NSACR.CP10 prevents stacking FP regs\n");
- armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE, M_REG_S);
- env->v7m.cfsr[M_REG_S] |= R_V7M_CFSR_NOCP_MASK;
- } else {
- if (!(env->v7m.fpccr[M_REG_S] & R_V7M_FPCCR_LSPEN_MASK)) {
- /* Lazy stacking disabled, save registers now */
- int i;
- bool cpacr_pass = v7m_cpacr_pass(env, env->v7m.secure,
- arm_current_el(env) != 0);
-
- if (stacked_ok && !cpacr_pass) {
- /*
- * Take UsageFault if CPACR forbids access. The pseudocode
- * here does a full CheckCPEnabled() but we know the NSACR
- * check can never fail as we have already handled that.
- */
- qemu_log_mask(CPU_LOG_INT,
- "...UsageFault with CFSR.NOCP because "
- "CPACR.CP10 prevents stacking FP regs\n");
- armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE,
- env->v7m.secure);
- env->v7m.cfsr[env->v7m.secure] |= R_V7M_CFSR_NOCP_MASK;
- stacked_ok = false;
- }
-
- for (i = 0; i < ((framesize == 0xa8) ? 32 : 16); i += 2) {
- uint64_t dn = *aa32_vfp_dreg(env, i / 2);
- uint32_t faddr = frameptr + 0x20 + 4 * i;
- uint32_t slo = extract64(dn, 0, 32);
- uint32_t shi = extract64(dn, 32, 32);
-
- if (i >= 16) {
- faddr += 8; /* skip the slot for the FPSCR */
- }
- stacked_ok = stacked_ok &&
- v7m_stack_write(cpu, faddr, slo,
- mmu_idx, STACK_NORMAL) &&
- v7m_stack_write(cpu, faddr + 4, shi,
- mmu_idx, STACK_NORMAL);
- }
- stacked_ok = stacked_ok &&
- v7m_stack_write(cpu, frameptr + 0x60,
- vfp_get_fpscr(env), mmu_idx, STACK_NORMAL);
- if (cpacr_pass) {
- for (i = 0; i < ((framesize == 0xa8) ? 32 : 16); i += 2) {
- *aa32_vfp_dreg(env, i / 2) = 0;
- }
- vfp_set_fpscr(env, 0);
- }
- } else {
- /* Lazy stacking enabled, save necessary info to stack later */
- v7m_update_fpccr(env, frameptr + 0x20, true);
- }
- }
- }
-
- /*
- * If we broke a stack limit then SP was already updated earlier;
- * otherwise we update SP regardless of whether any of the stack
- * accesses failed or we took some other kind of fault.
- */
- if (!limitviol) {
- env->regs[13] = frameptr;
- }
-
- return !stacked_ok;
-}
-
-static void do_v7m_exception_exit(ARMCPU *cpu)
-{
- CPUARMState *env = &cpu->env;
- uint32_t excret;
- uint32_t xpsr, xpsr_mask;
- bool ufault = false;
- bool sfault = false;
- bool return_to_sp_process;
- bool return_to_handler;
- bool rettobase = false;
- bool exc_secure = false;
- bool return_to_secure;
- bool ftype;
- bool restore_s16_s31;
-
- /* If we're not in Handler mode then jumps to magic exception-exit
- * addresses don't have magic behaviour. However for the v8M
- * security extensions the magic secure-function-return has to
- * work in thread mode too, so to avoid doing an extra check in
- * the generated code we allow exception-exit magic to also cause the
- * internal exception and bring us here in thread mode. Correct code
- * will never try to do this (the following insn fetch will always
- * fault) so we the overhead of having taken an unnecessary exception
- * doesn't matter.
- */
- if (!arm_v7m_is_handler_mode(env)) {
- return;
- }
-
- /* In the spec pseudocode ExceptionReturn() is called directly
- * from BXWritePC() and gets the full target PC value including
- * bit zero. In QEMU's implementation we treat it as a normal
- * jump-to-register (which is then caught later on), and so split
- * the target value up between env->regs[15] and env->thumb in
- * gen_bx(). Reconstitute it.
- */
- excret = env->regs[15];
- if (env->thumb) {
- excret |= 1;
- }
-
- qemu_log_mask(CPU_LOG_INT, "Exception return: magic PC %" PRIx32
- " previous exception %d\n",
- excret, env->v7m.exception);
-
- if ((excret & R_V7M_EXCRET_RES1_MASK) != R_V7M_EXCRET_RES1_MASK) {
- qemu_log_mask(LOG_GUEST_ERROR, "M profile: zero high bits in exception "
- "exit PC value 0x%" PRIx32 " are UNPREDICTABLE\n",
- excret);
- }
-
- ftype = excret & R_V7M_EXCRET_FTYPE_MASK;
-
- if (!arm_feature(env, ARM_FEATURE_VFP) && !ftype) {
- qemu_log_mask(LOG_GUEST_ERROR, "M profile: zero FTYPE in exception "
- "exit PC value 0x%" PRIx32 " is UNPREDICTABLE "
- "if FPU not present\n",
- excret);
- ftype = true;
- }
-
- if (arm_feature(env, ARM_FEATURE_M_SECURITY)) {
- /* EXC_RETURN.ES validation check (R_SMFL). We must do this before
- * we pick which FAULTMASK to clear.
- */
- if (!env->v7m.secure &&
- ((excret & R_V7M_EXCRET_ES_MASK) ||
- !(excret & R_V7M_EXCRET_DCRS_MASK))) {
- sfault = 1;
- /* For all other purposes, treat ES as 0 (R_HXSR) */
- excret &= ~R_V7M_EXCRET_ES_MASK;
- }
- exc_secure = excret & R_V7M_EXCRET_ES_MASK;
- }
-
- if (env->v7m.exception != ARMV7M_EXCP_NMI) {
- /* Auto-clear FAULTMASK on return from other than NMI.
- * If the security extension is implemented then this only
- * happens if the raw execution priority is >= 0; the
- * value of the ES bit in the exception return value indicates
- * which security state's faultmask to clear. (v8M ARM ARM R_KBNF.)
- */
- if (arm_feature(env, ARM_FEATURE_M_SECURITY)) {
- if (armv7m_nvic_raw_execution_priority(env->nvic) >= 0) {
- env->v7m.faultmask[exc_secure] = 0;
- }
- } else {
- env->v7m.faultmask[M_REG_NS] = 0;
- }
- }
-
- switch (armv7m_nvic_complete_irq(env->nvic, env->v7m.exception,
- exc_secure)) {
- case -1:
- /* attempt to exit an exception that isn't active */
- ufault = true;
- break;
- case 0:
- /* still an irq active now */
- break;
- case 1:
- /* we returned to base exception level, no nesting.
- * (In the pseudocode this is written using "NestedActivation != 1"
- * where we have 'rettobase == false'.)
- */
- rettobase = true;
- break;
- default:
- g_assert_not_reached();
- }
-
- return_to_handler = !(excret & R_V7M_EXCRET_MODE_MASK);
- return_to_sp_process = excret & R_V7M_EXCRET_SPSEL_MASK;
- return_to_secure = arm_feature(env, ARM_FEATURE_M_SECURITY) &&
- (excret & R_V7M_EXCRET_S_MASK);
-
- if (arm_feature(env, ARM_FEATURE_V8)) {
- if (!arm_feature(env, ARM_FEATURE_M_SECURITY)) {
- /* UNPREDICTABLE if S == 1 or DCRS == 0 or ES == 1 (R_XLCP);
- * we choose to take the UsageFault.
- */
- if ((excret & R_V7M_EXCRET_S_MASK) ||
- (excret & R_V7M_EXCRET_ES_MASK) ||
- !(excret & R_V7M_EXCRET_DCRS_MASK)) {
- ufault = true;
- }
- }
- if (excret & R_V7M_EXCRET_RES0_MASK) {
- ufault = true;
- }
- } else {
- /* For v7M we only recognize certain combinations of the low bits */
- switch (excret & 0xf) {
- case 1: /* Return to Handler */
- break;
- case 13: /* Return to Thread using Process stack */
- case 9: /* Return to Thread using Main stack */
- /* We only need to check NONBASETHRDENA for v7M, because in
- * v8M this bit does not exist (it is RES1).
- */
- if (!rettobase &&
- !(env->v7m.ccr[env->v7m.secure] &
- R_V7M_CCR_NONBASETHRDENA_MASK)) {
- ufault = true;
- }
- break;
- default:
- ufault = true;
- }
- }
-
- /*
- * Set CONTROL.SPSEL from excret.SPSEL. Since we're still in
- * Handler mode (and will be until we write the new XPSR.Interrupt
- * field) this does not switch around the current stack pointer.
- * We must do this before we do any kind of tailchaining, including
- * for the derived exceptions on integrity check failures, or we will
- * give the guest an incorrect EXCRET.SPSEL value on exception entry.
- */
- write_v7m_control_spsel_for_secstate(env, return_to_sp_process, exc_secure);
-
- /*
- * Clear scratch FP values left in caller saved registers; this
- * must happen before any kind of tail chaining.
- */
- if ((env->v7m.fpccr[M_REG_S] & R_V7M_FPCCR_CLRONRET_MASK) &&
- (env->v7m.control[M_REG_S] & R_V7M_CONTROL_FPCA_MASK)) {
- if (env->v7m.fpccr[M_REG_S] & R_V7M_FPCCR_LSPACT_MASK) {
- env->v7m.sfsr |= R_V7M_SFSR_LSERR_MASK;
- armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_SECURE, false);
- qemu_log_mask(CPU_LOG_INT, "...taking SecureFault on existing "
- "stackframe: error during lazy state deactivation\n");
- v7m_exception_taken(cpu, excret, true, false);
- return;
- } else {
- /* Clear s0..s15 and FPSCR */
- int i;
-
- for (i = 0; i < 16; i += 2) {
- *aa32_vfp_dreg(env, i / 2) = 0;
- }
- vfp_set_fpscr(env, 0);
- }
- }
-
- if (sfault) {
- env->v7m.sfsr |= R_V7M_SFSR_INVER_MASK;
- armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_SECURE, false);
- qemu_log_mask(CPU_LOG_INT, "...taking SecureFault on existing "
- "stackframe: failed EXC_RETURN.ES validity check\n");
- v7m_exception_taken(cpu, excret, true, false);
- return;
- }
-
- if (ufault) {
- /* Bad exception return: instead of popping the exception
- * stack, directly take a usage fault on the current stack.
- */
- env->v7m.cfsr[env->v7m.secure] |= R_V7M_CFSR_INVPC_MASK;
- armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE, env->v7m.secure);
- qemu_log_mask(CPU_LOG_INT, "...taking UsageFault on existing "
- "stackframe: failed exception return integrity check\n");
- v7m_exception_taken(cpu, excret, true, false);
- return;
- }
-
- /*
- * Tailchaining: if there is currently a pending exception that
- * is high enough priority to preempt execution at the level we're
- * about to return to, then just directly take that exception now,
- * avoiding an unstack-and-then-stack. Note that now we have
- * deactivated the previous exception by calling armv7m_nvic_complete_irq()
- * our current execution priority is already the execution priority we are
- * returning to -- none of the state we would unstack or set based on
- * the EXCRET value affects it.
- */
- if (armv7m_nvic_can_take_pending_exception(env->nvic)) {
- qemu_log_mask(CPU_LOG_INT, "...tailchaining to pending exception\n");
- v7m_exception_taken(cpu, excret, true, false);
- return;
- }
-
- switch_v7m_security_state(env, return_to_secure);
-
- {
- /* The stack pointer we should be reading the exception frame from
- * depends on bits in the magic exception return type value (and
- * for v8M isn't necessarily the stack pointer we will eventually
- * end up resuming execution with). Get a pointer to the location
- * in the CPU state struct where the SP we need is currently being
- * stored; we will use and modify it in place.
- * We use this limited C variable scope so we don't accidentally
- * use 'frame_sp_p' after we do something that makes it invalid.
- */
- uint32_t *frame_sp_p = get_v7m_sp_ptr(env,
- return_to_secure,
- !return_to_handler,
- return_to_sp_process);
- uint32_t frameptr = *frame_sp_p;
- bool pop_ok = true;
- ARMMMUIdx mmu_idx;
- bool return_to_priv = return_to_handler ||
- !(env->v7m.control[return_to_secure] & R_V7M_CONTROL_NPRIV_MASK);
-
- mmu_idx = arm_v7m_mmu_idx_for_secstate_and_priv(env, return_to_secure,
- return_to_priv);
-
- if (!QEMU_IS_ALIGNED(frameptr, 8) &&
- arm_feature(env, ARM_FEATURE_V8)) {
- qemu_log_mask(LOG_GUEST_ERROR,
- "M profile exception return with non-8-aligned SP "
- "for destination state is UNPREDICTABLE\n");
- }
-
- /* Do we need to pop callee-saved registers? */
- if (return_to_secure &&
- ((excret & R_V7M_EXCRET_ES_MASK) == 0 ||
- (excret & R_V7M_EXCRET_DCRS_MASK) == 0)) {
- uint32_t actual_sig;
-
- pop_ok = v7m_stack_read(cpu, &actual_sig, frameptr, mmu_idx);
-
- if (pop_ok && v7m_integrity_sig(env, excret) != actual_sig) {
- /* Take a SecureFault on the current stack */
- env->v7m.sfsr |= R_V7M_SFSR_INVIS_MASK;
- armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_SECURE, false);
- qemu_log_mask(CPU_LOG_INT, "...taking SecureFault on existing "
- "stackframe: failed exception return integrity "
- "signature check\n");
- v7m_exception_taken(cpu, excret, true, false);
- return;
- }
-
- pop_ok = pop_ok &&
- v7m_stack_read(cpu, &env->regs[4], frameptr + 0x8, mmu_idx) &&
- v7m_stack_read(cpu, &env->regs[5], frameptr + 0xc, mmu_idx) &&
- v7m_stack_read(cpu, &env->regs[6], frameptr + 0x10, mmu_idx) &&
- v7m_stack_read(cpu, &env->regs[7], frameptr + 0x14, mmu_idx) &&
- v7m_stack_read(cpu, &env->regs[8], frameptr + 0x18, mmu_idx) &&
- v7m_stack_read(cpu, &env->regs[9], frameptr + 0x1c, mmu_idx) &&
- v7m_stack_read(cpu, &env->regs[10], frameptr + 0x20, mmu_idx) &&
- v7m_stack_read(cpu, &env->regs[11], frameptr + 0x24, mmu_idx);
-
- frameptr += 0x28;
- }
-
- /* Pop registers */
- pop_ok = pop_ok &&
- v7m_stack_read(cpu, &env->regs[0], frameptr, mmu_idx) &&
- v7m_stack_read(cpu, &env->regs[1], frameptr + 0x4, mmu_idx) &&
- v7m_stack_read(cpu, &env->regs[2], frameptr + 0x8, mmu_idx) &&
- v7m_stack_read(cpu, &env->regs[3], frameptr + 0xc, mmu_idx) &&
- v7m_stack_read(cpu, &env->regs[12], frameptr + 0x10, mmu_idx) &&
- v7m_stack_read(cpu, &env->regs[14], frameptr + 0x14, mmu_idx) &&
- v7m_stack_read(cpu, &env->regs[15], frameptr + 0x18, mmu_idx) &&
- v7m_stack_read(cpu, &xpsr, frameptr + 0x1c, mmu_idx);
-
- if (!pop_ok) {
- /* v7m_stack_read() pended a fault, so take it (as a tail
- * chained exception on the same stack frame)
- */
- qemu_log_mask(CPU_LOG_INT, "...derived exception on unstacking\n");
- v7m_exception_taken(cpu, excret, true, false);
- return;
- }
-
- /* Returning from an exception with a PC with bit 0 set is defined
- * behaviour on v8M (bit 0 is ignored), but for v7M it was specified
- * to be UNPREDICTABLE. In practice actual v7M hardware seems to ignore
- * the lsbit, and there are several RTOSes out there which incorrectly
- * assume the r15 in the stack frame should be a Thumb-style "lsbit
- * indicates ARM/Thumb" value, so ignore the bit on v7M as well, but
- * complain about the badly behaved guest.
- */
- if (env->regs[15] & 1) {
- env->regs[15] &= ~1U;
- if (!arm_feature(env, ARM_FEATURE_V8)) {
- qemu_log_mask(LOG_GUEST_ERROR,
- "M profile return from interrupt with misaligned "
- "PC is UNPREDICTABLE on v7M\n");
- }
- }
-
- if (arm_feature(env, ARM_FEATURE_V8)) {
- /* For v8M we have to check whether the xPSR exception field
- * matches the EXCRET value for return to handler/thread
- * before we commit to changing the SP and xPSR.
- */
- bool will_be_handler = (xpsr & XPSR_EXCP) != 0;
- if (return_to_handler != will_be_handler) {
- /* Take an INVPC UsageFault on the current stack.
- * By this point we will have switched to the security state
- * for the background state, so this UsageFault will target
- * that state.
- */
- armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE,
- env->v7m.secure);
- env->v7m.cfsr[env->v7m.secure] |= R_V7M_CFSR_INVPC_MASK;
- qemu_log_mask(CPU_LOG_INT, "...taking UsageFault on existing "
- "stackframe: failed exception return integrity "
- "check\n");
- v7m_exception_taken(cpu, excret, true, false);
- return;
- }
- }
-
- if (!ftype) {
- /* FP present and we need to handle it */
- if (!return_to_secure &&
- (env->v7m.fpccr[M_REG_S] & R_V7M_FPCCR_LSPACT_MASK)) {
- armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_SECURE, false);
- env->v7m.sfsr |= R_V7M_SFSR_LSERR_MASK;
- qemu_log_mask(CPU_LOG_INT,
- "...taking SecureFault on existing stackframe: "
- "Secure LSPACT set but exception return is "
- "not to secure state\n");
- v7m_exception_taken(cpu, excret, true, false);
- return;
- }
-
- restore_s16_s31 = return_to_secure &&
- (env->v7m.fpccr[M_REG_S] & R_V7M_FPCCR_TS_MASK);
-
- if (env->v7m.fpccr[return_to_secure] & R_V7M_FPCCR_LSPACT_MASK) {
- /* State in FPU is still valid, just clear LSPACT */
- env->v7m.fpccr[return_to_secure] &= ~R_V7M_FPCCR_LSPACT_MASK;
- } else {
- int i;
- uint32_t fpscr;
- bool cpacr_pass, nsacr_pass;
-
- cpacr_pass = v7m_cpacr_pass(env, return_to_secure,
- return_to_priv);
- nsacr_pass = return_to_secure ||
- extract32(env->v7m.nsacr, 10, 1);
-
- if (!cpacr_pass) {
- armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE,
- return_to_secure);
- env->v7m.cfsr[return_to_secure] |= R_V7M_CFSR_NOCP_MASK;
- qemu_log_mask(CPU_LOG_INT,
- "...taking UsageFault on existing "
- "stackframe: CPACR.CP10 prevents unstacking "
- "FP regs\n");
- v7m_exception_taken(cpu, excret, true, false);
- return;
- } else if (!nsacr_pass) {
- armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE, true);
- env->v7m.cfsr[M_REG_S] |= R_V7M_CFSR_INVPC_MASK;
- qemu_log_mask(CPU_LOG_INT,
- "...taking Secure UsageFault on existing "
- "stackframe: NSACR.CP10 prevents unstacking "
- "FP regs\n");
- v7m_exception_taken(cpu, excret, true, false);
- return;
- }
-
- for (i = 0; i < (restore_s16_s31 ? 32 : 16); i += 2) {
- uint32_t slo, shi;
- uint64_t dn;
- uint32_t faddr = frameptr + 0x20 + 4 * i;
-
- if (i >= 16) {
- faddr += 8; /* Skip the slot for the FPSCR */
- }
-
- pop_ok = pop_ok &&
- v7m_stack_read(cpu, &slo, faddr, mmu_idx) &&
- v7m_stack_read(cpu, &shi, faddr + 4, mmu_idx);
-
- if (!pop_ok) {
- break;
- }
-
- dn = (uint64_t)shi << 32 | slo;
- *aa32_vfp_dreg(env, i / 2) = dn;
- }
- pop_ok = pop_ok &&
- v7m_stack_read(cpu, &fpscr, frameptr + 0x60, mmu_idx);
- if (pop_ok) {
- vfp_set_fpscr(env, fpscr);
- }
- if (!pop_ok) {
- /*
- * These regs are 0 if security extension present;
- * otherwise merely UNKNOWN. We zero always.
- */
- for (i = 0; i < (restore_s16_s31 ? 32 : 16); i += 2) {
- *aa32_vfp_dreg(env, i / 2) = 0;
- }
- vfp_set_fpscr(env, 0);
- }
- }
- }
- env->v7m.control[M_REG_S] = FIELD_DP32(env->v7m.control[M_REG_S],
- V7M_CONTROL, FPCA, !ftype);
-
- /* Commit to consuming the stack frame */
- frameptr += 0x20;
- if (!ftype) {
- frameptr += 0x48;
- if (restore_s16_s31) {
- frameptr += 0x40;
- }
- }
- /* Undo stack alignment (the SPREALIGN bit indicates that the original
- * pre-exception SP was not 8-aligned and we added a padding word to
- * align it, so we undo this by ORing in the bit that increases it
- * from the current 8-aligned value to the 8-unaligned value. (Adding 4
- * would work too but a logical OR is how the pseudocode specifies it.)
- */
- if (xpsr & XPSR_SPREALIGN) {
- frameptr |= 4;
- }
- *frame_sp_p = frameptr;
- }
-
- xpsr_mask = ~(XPSR_SPREALIGN | XPSR_SFPA);
- if (!arm_feature(env, ARM_FEATURE_THUMB_DSP)) {
- xpsr_mask &= ~XPSR_GE;
- }
- /* This xpsr_write() will invalidate frame_sp_p as it may switch stack */
- xpsr_write(env, xpsr, xpsr_mask);
-
- if (env->v7m.secure) {
- bool sfpa = xpsr & XPSR_SFPA;
-
- env->v7m.control[M_REG_S] = FIELD_DP32(env->v7m.control[M_REG_S],
- V7M_CONTROL, SFPA, sfpa);
- }
-
- /* The restored xPSR exception field will be zero if we're
- * resuming in Thread mode. If that doesn't match what the
- * exception return excret specified then this is a UsageFault.
- * v7M requires we make this check here; v8M did it earlier.
- */
- if (return_to_handler != arm_v7m_is_handler_mode(env)) {
- /* Take an INVPC UsageFault by pushing the stack again;
- * we know we're v7M so this is never a Secure UsageFault.
- */
- bool ignore_stackfaults;
-
- assert(!arm_feature(env, ARM_FEATURE_V8));
- armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE, false);
- env->v7m.cfsr[env->v7m.secure] |= R_V7M_CFSR_INVPC_MASK;
- ignore_stackfaults = v7m_push_stack(cpu);
- qemu_log_mask(CPU_LOG_INT, "...taking UsageFault on new stackframe: "
- "failed exception return integrity check\n");
- v7m_exception_taken(cpu, excret, false, ignore_stackfaults);
- return;
- }
-
- /* Otherwise, we have a successful exception exit. */
- arm_clear_exclusive(env);
- qemu_log_mask(CPU_LOG_INT, "...successful exception return\n");
-}
-
-static bool do_v7m_function_return(ARMCPU *cpu)
-{
- /* v8M security extensions magic function return.
- * We may either:
- * (1) throw an exception (longjump)
- * (2) return true if we successfully handled the function return
- * (3) return false if we failed a consistency check and have
- * pended a UsageFault that needs to be taken now
- *
- * At this point the magic return value is split between env->regs[15]
- * and env->thumb. We don't bother to reconstitute it because we don't
- * need it (all values are handled the same way).
- */
- CPUARMState *env = &cpu->env;
- uint32_t newpc, newpsr, newpsr_exc;
-
- qemu_log_mask(CPU_LOG_INT, "...really v7M secure function return\n");
-
- {
- bool threadmode, spsel;
- TCGMemOpIdx oi;
- ARMMMUIdx mmu_idx;
- uint32_t *frame_sp_p;
- uint32_t frameptr;
-
- /* Pull the return address and IPSR from the Secure stack */
- threadmode = !arm_v7m_is_handler_mode(env);
- spsel = env->v7m.control[M_REG_S] & R_V7M_CONTROL_SPSEL_MASK;
-
- frame_sp_p = get_v7m_sp_ptr(env, true, threadmode, spsel);
- frameptr = *frame_sp_p;
-
- /* These loads may throw an exception (for MPU faults). We want to
- * do them as secure, so work out what MMU index that is.
- */
- mmu_idx = arm_v7m_mmu_idx_for_secstate(env, true);
- oi = make_memop_idx(MO_LE, arm_to_core_mmu_idx(mmu_idx));
- newpc = helper_le_ldul_mmu(env, frameptr, oi, 0);
- newpsr = helper_le_ldul_mmu(env, frameptr + 4, oi, 0);
-
- /* Consistency checks on new IPSR */
- newpsr_exc = newpsr & XPSR_EXCP;
- if (!((env->v7m.exception == 0 && newpsr_exc == 0) ||
- (env->v7m.exception == 1 && newpsr_exc != 0))) {
- /* Pend the fault and tell our caller to take it */
- env->v7m.cfsr[env->v7m.secure] |= R_V7M_CFSR_INVPC_MASK;
- armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE,
- env->v7m.secure);
- qemu_log_mask(CPU_LOG_INT,
- "...taking INVPC UsageFault: "
- "IPSR consistency check failed\n");
- return false;
- }
-
- *frame_sp_p = frameptr + 8;
- }
-
- /* This invalidates frame_sp_p */
- switch_v7m_security_state(env, true);
- env->v7m.exception = newpsr_exc;
- env->v7m.control[M_REG_S] &= ~R_V7M_CONTROL_SFPA_MASK;
- if (newpsr & XPSR_SFPA) {
- env->v7m.control[M_REG_S] |= R_V7M_CONTROL_SFPA_MASK;
- }
- xpsr_write(env, 0, XPSR_IT);
- env->thumb = newpc & 1;
- env->regs[15] = newpc & ~1;
-
- qemu_log_mask(CPU_LOG_INT, "...function return successful\n");
- return true;
-}
-
-static void arm_log_exception(int idx)
-{
- if (qemu_loglevel_mask(CPU_LOG_INT)) {
- const char *exc = NULL;
- static const char * const excnames[] = {
- [EXCP_UDEF] = "Undefined Instruction",
- [EXCP_SWI] = "SVC",
- [EXCP_PREFETCH_ABORT] = "Prefetch Abort",
- [EXCP_DATA_ABORT] = "Data Abort",
- [EXCP_IRQ] = "IRQ",
- [EXCP_FIQ] = "FIQ",
- [EXCP_BKPT] = "Breakpoint",
- [EXCP_EXCEPTION_EXIT] = "QEMU v7M exception exit",
- [EXCP_KERNEL_TRAP] = "QEMU intercept of kernel commpage",
- [EXCP_HVC] = "Hypervisor Call",
- [EXCP_HYP_TRAP] = "Hypervisor Trap",
- [EXCP_SMC] = "Secure Monitor Call",
- [EXCP_VIRQ] = "Virtual IRQ",
- [EXCP_VFIQ] = "Virtual FIQ",
- [EXCP_SEMIHOST] = "Semihosting call",
- [EXCP_NOCP] = "v7M NOCP UsageFault",
- [EXCP_INVSTATE] = "v7M INVSTATE UsageFault",
- [EXCP_STKOF] = "v8M STKOF UsageFault",
- [EXCP_LAZYFP] = "v7M exception during lazy FP stacking",
- [EXCP_LSERR] = "v8M LSERR UsageFault",
- [EXCP_UNALIGNED] = "v7M UNALIGNED UsageFault",
- };
-
- if (idx >= 0 && idx < ARRAY_SIZE(excnames)) {
- exc = excnames[idx];
- }
- if (!exc) {
- exc = "unknown";
- }
- qemu_log_mask(CPU_LOG_INT, "Taking exception %d [%s]\n", idx, exc);
- }
-}
-
-static bool v7m_read_half_insn(ARMCPU *cpu, ARMMMUIdx mmu_idx,
- uint32_t addr, uint16_t *insn)
-{
- /* Load a 16-bit portion of a v7M instruction, returning true on success,
- * or false on failure (in which case we will have pended the appropriate
- * exception).
- * We need to do the instruction fetch's MPU and SAU checks
- * like this because there is no MMU index that would allow
- * doing the load with a single function call. Instead we must
- * first check that the security attributes permit the load
- * and that they don't mismatch on the two halves of the instruction,
- * and then we do the load as a secure load (ie using the security
- * attributes of the address, not the CPU, as architecturally required).
- */
- CPUState *cs = CPU(cpu);
- CPUARMState *env = &cpu->env;
- V8M_SAttributes sattrs = {};
- MemTxAttrs attrs = {};
- ARMMMUFaultInfo fi = {};
- MemTxResult txres;
- target_ulong page_size;
- hwaddr physaddr;
- int prot;
-
- v8m_security_lookup(env, addr, MMU_INST_FETCH, mmu_idx, &sattrs);
- if (!sattrs.nsc || sattrs.ns) {
- /* This must be the second half of the insn, and it straddles a
- * region boundary with the second half not being S&NSC.
- */
- env->v7m.sfsr |= R_V7M_SFSR_INVEP_MASK;
- armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_SECURE, false);
- qemu_log_mask(CPU_LOG_INT,
- "...really SecureFault with SFSR.INVEP\n");
- return false;
- }
- if (get_phys_addr(env, addr, MMU_INST_FETCH, mmu_idx,
- &physaddr, &attrs, &prot, &page_size, &fi, NULL)) {
- /* the MPU lookup failed */
- env->v7m.cfsr[env->v7m.secure] |= R_V7M_CFSR_IACCVIOL_MASK;
- armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_MEM, env->v7m.secure);
- qemu_log_mask(CPU_LOG_INT, "...really MemManage with CFSR.IACCVIOL\n");
- return false;
- }
- *insn = address_space_lduw_le(arm_addressspace(cs, attrs), physaddr,
- attrs, &txres);
- if (txres != MEMTX_OK) {
- env->v7m.cfsr[M_REG_NS] |= R_V7M_CFSR_IBUSERR_MASK;
- armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_BUS, false);
- qemu_log_mask(CPU_LOG_INT, "...really BusFault with CFSR.IBUSERR\n");
- return false;
- }
- return true;
-}
-
-static bool v7m_handle_execute_nsc(ARMCPU *cpu)
-{
- /* Check whether this attempt to execute code in a Secure & NS-Callable
- * memory region is for an SG instruction; if so, then emulate the
- * effect of the SG instruction and return true. Otherwise pend
- * the correct kind of exception and return false.
- */
- CPUARMState *env = &cpu->env;
- ARMMMUIdx mmu_idx;
- uint16_t insn;
-
- /* We should never get here unless get_phys_addr_pmsav8() caused
- * an exception for NS executing in S&NSC memory.
- */
- assert(!env->v7m.secure);
- assert(arm_feature(env, ARM_FEATURE_M_SECURITY));
-
- /* We want to do the MPU lookup as secure; work out what mmu_idx that is */
- mmu_idx = arm_v7m_mmu_idx_for_secstate(env, true);
-
- if (!v7m_read_half_insn(cpu, mmu_idx, env->regs[15], &insn)) {
- return false;
- }
-
- if (!env->thumb) {
- goto gen_invep;
- }
-
- if (insn != 0xe97f) {
- /* Not an SG instruction first half (we choose the IMPDEF
- * early-SG-check option).
- */
- goto gen_invep;
- }
-
- if (!v7m_read_half_insn(cpu, mmu_idx, env->regs[15] + 2, &insn)) {
- return false;
- }
-
- if (insn != 0xe97f) {
- /* Not an SG instruction second half (yes, both halves of the SG
- * insn have the same hex value)
- */
- goto gen_invep;
- }
-
- /* OK, we have confirmed that we really have an SG instruction.
- * We know we're NS in S memory so don't need to repeat those checks.
- */
- qemu_log_mask(CPU_LOG_INT, "...really an SG instruction at 0x%08" PRIx32
- ", executing it\n", env->regs[15]);
- env->regs[14] &= ~1;
- env->v7m.control[M_REG_S] &= ~R_V7M_CONTROL_SFPA_MASK;
- switch_v7m_security_state(env, true);
- xpsr_write(env, 0, XPSR_IT);
- env->regs[15] += 4;
- return true;
-
-gen_invep:
- env->v7m.sfsr |= R_V7M_SFSR_INVEP_MASK;
- armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_SECURE, false);
- qemu_log_mask(CPU_LOG_INT,
- "...really SecureFault with SFSR.INVEP\n");
- return false;
-}
-
-void arm_v7m_cpu_do_interrupt(CPUState *cs)
-{
- ARMCPU *cpu = ARM_CPU(cs);
- CPUARMState *env = &cpu->env;
- uint32_t lr;
- bool ignore_stackfaults;
-
- arm_log_exception(cs->exception_index);
-
- /* For exceptions we just mark as pending on the NVIC, and let that
- handle it. */
- switch (cs->exception_index) {
- case EXCP_UDEF:
- armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE, env->v7m.secure);
- env->v7m.cfsr[env->v7m.secure] |= R_V7M_CFSR_UNDEFINSTR_MASK;
- break;
- case EXCP_NOCP:
- {
- /*
- * NOCP might be directed to something other than the current
- * security state if this fault is because of NSACR; we indicate
- * the target security state using exception.target_el.
- */
- int target_secstate;
-
- if (env->exception.target_el == 3) {
- target_secstate = M_REG_S;
- } else {
- target_secstate = env->v7m.secure;
- }
- armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE, target_secstate);
- env->v7m.cfsr[target_secstate] |= R_V7M_CFSR_NOCP_MASK;
- break;
- }
- case EXCP_INVSTATE:
- armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE, env->v7m.secure);
- env->v7m.cfsr[env->v7m.secure] |= R_V7M_CFSR_INVSTATE_MASK;
- break;
- case EXCP_STKOF:
- armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE, env->v7m.secure);
- env->v7m.cfsr[env->v7m.secure] |= R_V7M_CFSR_STKOF_MASK;
- break;
- case EXCP_LSERR:
- armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_SECURE, false);
- env->v7m.sfsr |= R_V7M_SFSR_LSERR_MASK;
- break;
- case EXCP_UNALIGNED:
- armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE, env->v7m.secure);
- env->v7m.cfsr[env->v7m.secure] |= R_V7M_CFSR_UNALIGNED_MASK;
- break;
- case EXCP_SWI:
- /* The PC already points to the next instruction. */
- armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_SVC, env->v7m.secure);
- break;
- case EXCP_PREFETCH_ABORT:
- case EXCP_DATA_ABORT:
- /* Note that for M profile we don't have a guest facing FSR, but
- * the env->exception.fsr will be populated by the code that
- * raises the fault, in the A profile short-descriptor format.
- */
- switch (env->exception.fsr & 0xf) {
- case M_FAKE_FSR_NSC_EXEC:
- /* Exception generated when we try to execute code at an address
- * which is marked as Secure & Non-Secure Callable and the CPU
- * is in the Non-Secure state. The only instruction which can
- * be executed like this is SG (and that only if both halves of
- * the SG instruction have the same security attributes.)
- * Everything else must generate an INVEP SecureFault, so we
- * emulate the SG instruction here.
- */
- if (v7m_handle_execute_nsc(cpu)) {
- return;
- }
- break;
- case M_FAKE_FSR_SFAULT:
- /* Various flavours of SecureFault for attempts to execute or
- * access data in the wrong security state.
- */
- switch (cs->exception_index) {
- case EXCP_PREFETCH_ABORT:
- if (env->v7m.secure) {
- env->v7m.sfsr |= R_V7M_SFSR_INVTRAN_MASK;
- qemu_log_mask(CPU_LOG_INT,
- "...really SecureFault with SFSR.INVTRAN\n");
- } else {
- env->v7m.sfsr |= R_V7M_SFSR_INVEP_MASK;
- qemu_log_mask(CPU_LOG_INT,
- "...really SecureFault with SFSR.INVEP\n");
- }
- break;
- case EXCP_DATA_ABORT:
- /* This must be an NS access to S memory */
- env->v7m.sfsr |= R_V7M_SFSR_AUVIOL_MASK;
- qemu_log_mask(CPU_LOG_INT,
- "...really SecureFault with SFSR.AUVIOL\n");
- break;
- }
- armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_SECURE, false);
- break;
- case 0x8: /* External Abort */
- switch (cs->exception_index) {
- case EXCP_PREFETCH_ABORT:
- env->v7m.cfsr[M_REG_NS] |= R_V7M_CFSR_IBUSERR_MASK;
- qemu_log_mask(CPU_LOG_INT, "...with CFSR.IBUSERR\n");
- break;
- case EXCP_DATA_ABORT:
- env->v7m.cfsr[M_REG_NS] |=
- (R_V7M_CFSR_PRECISERR_MASK | R_V7M_CFSR_BFARVALID_MASK);
- env->v7m.bfar = env->exception.vaddress;
- qemu_log_mask(CPU_LOG_INT,
- "...with CFSR.PRECISERR and BFAR 0x%x\n",
- env->v7m.bfar);
- break;
- }
- armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_BUS, false);
- break;
- default:
- /* All other FSR values are either MPU faults or "can't happen
- * for M profile" cases.
- */
- switch (cs->exception_index) {
- case EXCP_PREFETCH_ABORT:
- env->v7m.cfsr[env->v7m.secure] |= R_V7M_CFSR_IACCVIOL_MASK;
- qemu_log_mask(CPU_LOG_INT, "...with CFSR.IACCVIOL\n");
- break;
- case EXCP_DATA_ABORT:
- env->v7m.cfsr[env->v7m.secure] |=
- (R_V7M_CFSR_DACCVIOL_MASK | R_V7M_CFSR_MMARVALID_MASK);
- env->v7m.mmfar[env->v7m.secure] = env->exception.vaddress;
- qemu_log_mask(CPU_LOG_INT,
- "...with CFSR.DACCVIOL and MMFAR 0x%x\n",
- env->v7m.mmfar[env->v7m.secure]);
- break;
- }
- armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_MEM,
- env->v7m.secure);
- break;
- }
- break;
- case EXCP_BKPT:
- if (semihosting_enabled()) {
- int nr;
- nr = arm_lduw_code(env, env->regs[15], arm_sctlr_b(env)) & 0xff;
- if (nr == 0xab) {
- env->regs[15] += 2;
- qemu_log_mask(CPU_LOG_INT,
- "...handling as semihosting call 0x%x\n",
- env->regs[0]);
- env->regs[0] = do_arm_semihosting(env);
- return;
- }
- }
- armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_DEBUG, false);
- break;
- case EXCP_IRQ:
- break;
- case EXCP_EXCEPTION_EXIT:
- if (env->regs[15] < EXC_RETURN_MIN_MAGIC) {
- /* Must be v8M security extension function return */
- assert(env->regs[15] >= FNC_RETURN_MIN_MAGIC);
- assert(arm_feature(env, ARM_FEATURE_M_SECURITY));
- if (do_v7m_function_return(cpu)) {
- return;
- }
- } else {
- do_v7m_exception_exit(cpu);
- return;
- }
- break;
- case EXCP_LAZYFP:
- /*
- * We already pended the specific exception in the NVIC in the
- * v7m_preserve_fp_state() helper function.
- */
- break;
- default:
- cpu_abort(cs, "Unhandled exception 0x%x\n", cs->exception_index);
- return; /* Never happens. Keep compiler happy. */
- }
-
- if (arm_feature(env, ARM_FEATURE_V8)) {
- lr = R_V7M_EXCRET_RES1_MASK |
- R_V7M_EXCRET_DCRS_MASK;
- /* The S bit indicates whether we should return to Secure
- * or NonSecure (ie our current state).
- * The ES bit indicates whether we're taking this exception
- * to Secure or NonSecure (ie our target state). We set it
- * later, in v7m_exception_taken().
- * The SPSEL bit is also set in v7m_exception_taken() for v8M.
- * This corresponds to the ARM ARM pseudocode for v8M setting
- * some LR bits in PushStack() and some in ExceptionTaken();
- * the distinction matters for the tailchain cases where we
- * can take an exception without pushing the stack.
- */
- if (env->v7m.secure) {
- lr |= R_V7M_EXCRET_S_MASK;
- }
- if (!(env->v7m.control[M_REG_S] & R_V7M_CONTROL_FPCA_MASK)) {
- lr |= R_V7M_EXCRET_FTYPE_MASK;
- }
- } else {
- lr = R_V7M_EXCRET_RES1_MASK |
- R_V7M_EXCRET_S_MASK |
- R_V7M_EXCRET_DCRS_MASK |
- R_V7M_EXCRET_FTYPE_MASK |
- R_V7M_EXCRET_ES_MASK;
- if (env->v7m.control[M_REG_NS] & R_V7M_CONTROL_SPSEL_MASK) {
- lr |= R_V7M_EXCRET_SPSEL_MASK;
- }
- }
- if (!arm_v7m_is_handler_mode(env)) {
- lr |= R_V7M_EXCRET_MODE_MASK;
- }
-
- ignore_stackfaults = v7m_push_stack(cpu);
- v7m_exception_taken(cpu, lr, false, ignore_stackfaults);
-}
-
-/* Function used to synchronize QEMU's AArch64 register set with AArch32
- * register set. This is necessary when switching between AArch32 and AArch64
- * execution state.
- */
-void aarch64_sync_32_to_64(CPUARMState *env)
-{
- int i;
- uint32_t mode = env->uncached_cpsr & CPSR_M;
-
- /* We can blanket copy R[0:7] to X[0:7] */
- for (i = 0; i < 8; i++) {
- env->xregs[i] = env->regs[i];
- }
-
- /* Unless we are in FIQ mode, x8-x12 come from the user registers r8-r12.
- * Otherwise, they come from the banked user regs.
- */
- if (mode == ARM_CPU_MODE_FIQ) {
- for (i = 8; i < 13; i++) {
- env->xregs[i] = env->usr_regs[i - 8];
- }
- } else {
- for (i = 8; i < 13; i++) {
- env->xregs[i] = env->regs[i];
- }
- }
-
- /* Registers x13-x23 are the various mode SP and FP registers. Registers
- * r13 and r14 are only copied if we are in that mode, otherwise we copy
- * from the mode banked register.
- */
- if (mode == ARM_CPU_MODE_USR || mode == ARM_CPU_MODE_SYS) {
- env->xregs[13] = env->regs[13];
- env->xregs[14] = env->regs[14];
- } else {
- env->xregs[13] = env->banked_r13[bank_number(ARM_CPU_MODE_USR)];
- /* HYP is an exception in that it is copied from r14 */
- if (mode == ARM_CPU_MODE_HYP) {
- env->xregs[14] = env->regs[14];
- } else {
- env->xregs[14] = env->banked_r14[r14_bank_number(ARM_CPU_MODE_USR)];
- }
- }
-
- if (mode == ARM_CPU_MODE_HYP) {
- env->xregs[15] = env->regs[13];
- } else {
- env->xregs[15] = env->banked_r13[bank_number(ARM_CPU_MODE_HYP)];
- }
-
- if (mode == ARM_CPU_MODE_IRQ) {
- env->xregs[16] = env->regs[14];
- env->xregs[17] = env->regs[13];
- } else {
- env->xregs[16] = env->banked_r14[r14_bank_number(ARM_CPU_MODE_IRQ)];
- env->xregs[17] = env->banked_r13[bank_number(ARM_CPU_MODE_IRQ)];
- }
-
- if (mode == ARM_CPU_MODE_SVC) {
- env->xregs[18] = env->regs[14];
- env->xregs[19] = env->regs[13];
- } else {
- env->xregs[18] = env->banked_r14[r14_bank_number(ARM_CPU_MODE_SVC)];
- env->xregs[19] = env->banked_r13[bank_number(ARM_CPU_MODE_SVC)];
- }
-
- if (mode == ARM_CPU_MODE_ABT) {
- env->xregs[20] = env->regs[14];
- env->xregs[21] = env->regs[13];
- } else {
- env->xregs[20] = env->banked_r14[r14_bank_number(ARM_CPU_MODE_ABT)];
- env->xregs[21] = env->banked_r13[bank_number(ARM_CPU_MODE_ABT)];
- }
-
- if (mode == ARM_CPU_MODE_UND) {
- env->xregs[22] = env->regs[14];
- env->xregs[23] = env->regs[13];
- } else {
- env->xregs[22] = env->banked_r14[r14_bank_number(ARM_CPU_MODE_UND)];
- env->xregs[23] = env->banked_r13[bank_number(ARM_CPU_MODE_UND)];
- }
-
- /* Registers x24-x30 are mapped to r8-r14 in FIQ mode. If we are in FIQ
- * mode, then we can copy from r8-r14. Otherwise, we copy from the
- * FIQ bank for r8-r14.
- */
- if (mode == ARM_CPU_MODE_FIQ) {
- for (i = 24; i < 31; i++) {
- env->xregs[i] = env->regs[i - 16]; /* X[24:30] <- R[8:14] */
- }
- } else {
- for (i = 24; i < 29; i++) {
- env->xregs[i] = env->fiq_regs[i - 24];
- }
- env->xregs[29] = env->banked_r13[bank_number(ARM_CPU_MODE_FIQ)];
- env->xregs[30] = env->banked_r14[r14_bank_number(ARM_CPU_MODE_FIQ)];
- }
-
- env->pc = env->regs[15];
-}
-
-/* Function used to synchronize QEMU's AArch32 register set with AArch64
- * register set. This is necessary when switching between AArch32 and AArch64
- * execution state.
- */
-void aarch64_sync_64_to_32(CPUARMState *env)
-{
- int i;
- uint32_t mode = env->uncached_cpsr & CPSR_M;
+ int i;
+ uint32_t mode = env->uncached_cpsr & CPSR_M;
/* We can blanket copy X[0:7] to R[0:7] */
for (i = 0; i < 8; i++) {
env->regs[i] = env->xregs[i];
}
- /* Unless we are in FIQ mode, r8-r12 come from the user registers x8-x12.
+ /*
+ * Unless we are in FIQ mode, r8-r12 come from the user registers x8-x12.
* Otherwise, we copy x8-x12 into the banked user regs.
*/
if (mode == ARM_CPU_MODE_FIQ) {
}
}
- /* Registers r13 & r14 depend on the current mode.
+ /*
+ * Registers r13 & r14 depend on the current mode.
* If we are in a given mode, we copy the corresponding x registers to r13
* and r14. Otherwise, we copy the x register to the banked r13 and r14
* for the mode.
} else {
env->banked_r13[bank_number(ARM_CPU_MODE_USR)] = env->xregs[13];
- /* HYP is an exception in that it does not have its own banked r14 but
+ /*
+ * HYP is an exception in that it does not have its own banked r14 but
* shares the USR r14
*/
if (mode == ARM_CPU_MODE_HYP) {
static inline bool check_for_semihosting(CPUState *cs)
{
+#ifdef CONFIG_TCG
/* Check whether this exception is a semihosting call; if so
* then handle it and return true; otherwise return false.
*/
env->regs[0] = do_arm_semihosting(env);
return true;
}
+#else
+ return false;
+#endif
}
/* Handle a CPU exception for A and R profile CPUs.
(address >= 0xe00ff000 && address <= 0xe00fffff);
}
-static void v8m_security_lookup(CPUARMState *env, uint32_t address,
+void v8m_security_lookup(CPUARMState *env, uint32_t address,
MMUAccessType access_type, ARMMMUIdx mmu_idx,
V8M_SAttributes *sattrs)
{
}
}
-static bool pmsav8_mpu_lookup(CPUARMState *env, uint32_t address,
+bool pmsav8_mpu_lookup(CPUARMState *env, uint32_t address,
MMUAccessType access_type, ARMMMUIdx mmu_idx,
hwaddr *phys_ptr, MemTxAttrs *txattrs,
int *prot, bool *is_subpage,
* @fi: set to fault info if the translation fails
* @cacheattrs: (if non-NULL) set to the cacheability/shareability attributes
*/
-static bool get_phys_addr(CPUARMState *env, target_ulong address,
- MMUAccessType access_type, ARMMMUIdx mmu_idx,
- hwaddr *phys_ptr, MemTxAttrs *attrs, int *prot,
- target_ulong *page_size,
- ARMMMUFaultInfo *fi, ARMCacheAttrs *cacheattrs)
+bool get_phys_addr(CPUARMState *env, target_ulong address,
+ MMUAccessType access_type, ARMMMUIdx mmu_idx,
+ hwaddr *phys_ptr, MemTxAttrs *attrs, int *prot,
+ target_ulong *page_size,
+ ARMMMUFaultInfo *fi, ARMCacheAttrs *cacheattrs)
{
if (mmu_idx == ARMMMUIdx_S12NSE0 || mmu_idx == ARMMMUIdx_S12NSE1) {
/* Call ourselves recursively to do the stage 1 and then stage 2
return phys_addr;
}
-uint32_t HELPER(v7m_mrs)(CPUARMState *env, uint32_t reg)
-{
- uint32_t mask;
- unsigned el = arm_current_el(env);
-
- /* First handle registers which unprivileged can read */
-
- switch (reg) {
- case 0 ... 7: /* xPSR sub-fields */
- mask = 0;
- if ((reg & 1) && el) {
- mask |= XPSR_EXCP; /* IPSR (unpriv. reads as zero) */
- }
- if (!(reg & 4)) {
- mask |= XPSR_NZCV | XPSR_Q; /* APSR */
- if (arm_feature(env, ARM_FEATURE_THUMB_DSP)) {
- mask |= XPSR_GE;
- }
- }
- /* EPSR reads as zero */
- return xpsr_read(env) & mask;
- break;
- case 20: /* CONTROL */
- {
- uint32_t value = env->v7m.control[env->v7m.secure];
- if (!env->v7m.secure) {
- /* SFPA is RAZ/WI from NS; FPCA is stored in the M_REG_S bank */
- value |= env->v7m.control[M_REG_S] & R_V7M_CONTROL_FPCA_MASK;
- }
- return value;
- }
- case 0x94: /* CONTROL_NS */
- /* We have to handle this here because unprivileged Secure code
- * can read the NS CONTROL register.
- */
- if (!env->v7m.secure) {
- return 0;
- }
- return env->v7m.control[M_REG_NS] |
- (env->v7m.control[M_REG_S] & R_V7M_CONTROL_FPCA_MASK);
- }
-
- if (el == 0) {
- return 0; /* unprivileged reads others as zero */
- }
-
- if (arm_feature(env, ARM_FEATURE_M_SECURITY)) {
- switch (reg) {
- case 0x88: /* MSP_NS */
- if (!env->v7m.secure) {
- return 0;
- }
- return env->v7m.other_ss_msp;
- case 0x89: /* PSP_NS */
- if (!env->v7m.secure) {
- return 0;
- }
- return env->v7m.other_ss_psp;
- case 0x8a: /* MSPLIM_NS */
- if (!env->v7m.secure) {
- return 0;
- }
- return env->v7m.msplim[M_REG_NS];
- case 0x8b: /* PSPLIM_NS */
- if (!env->v7m.secure) {
- return 0;
- }
- return env->v7m.psplim[M_REG_NS];
- case 0x90: /* PRIMASK_NS */
- if (!env->v7m.secure) {
- return 0;
- }
- return env->v7m.primask[M_REG_NS];
- case 0x91: /* BASEPRI_NS */
- if (!env->v7m.secure) {
- return 0;
- }
- return env->v7m.basepri[M_REG_NS];
- case 0x93: /* FAULTMASK_NS */
- if (!env->v7m.secure) {
- return 0;
- }
- return env->v7m.faultmask[M_REG_NS];
- case 0x98: /* SP_NS */
- {
- /* This gives the non-secure SP selected based on whether we're
- * currently in handler mode or not, using the NS CONTROL.SPSEL.
- */
- bool spsel = env->v7m.control[M_REG_NS] & R_V7M_CONTROL_SPSEL_MASK;
-
- if (!env->v7m.secure) {
- return 0;
- }
- if (!arm_v7m_is_handler_mode(env) && spsel) {
- return env->v7m.other_ss_psp;
- } else {
- return env->v7m.other_ss_msp;
- }
- }
- default:
- break;
- }
- }
-
- switch (reg) {
- case 8: /* MSP */
- return v7m_using_psp(env) ? env->v7m.other_sp : env->regs[13];
- case 9: /* PSP */
- return v7m_using_psp(env) ? env->regs[13] : env->v7m.other_sp;
- case 10: /* MSPLIM */
- if (!arm_feature(env, ARM_FEATURE_V8)) {
- goto bad_reg;
- }
- return env->v7m.msplim[env->v7m.secure];
- case 11: /* PSPLIM */
- if (!arm_feature(env, ARM_FEATURE_V8)) {
- goto bad_reg;
- }
- return env->v7m.psplim[env->v7m.secure];
- case 16: /* PRIMASK */
- return env->v7m.primask[env->v7m.secure];
- case 17: /* BASEPRI */
- case 18: /* BASEPRI_MAX */
- return env->v7m.basepri[env->v7m.secure];
- case 19: /* FAULTMASK */
- return env->v7m.faultmask[env->v7m.secure];
- default:
- bad_reg:
- qemu_log_mask(LOG_GUEST_ERROR, "Attempt to read unknown special"
- " register %d\n", reg);
- return 0;
- }
-}
-
-void HELPER(v7m_msr)(CPUARMState *env, uint32_t maskreg, uint32_t val)
-{
- /* We're passed bits [11..0] of the instruction; extract
- * SYSm and the mask bits.
- * Invalid combinations of SYSm and mask are UNPREDICTABLE;
- * we choose to treat them as if the mask bits were valid.
- * NB that the pseudocode 'mask' variable is bits [11..10],
- * whereas ours is [11..8].
- */
- uint32_t mask = extract32(maskreg, 8, 4);
- uint32_t reg = extract32(maskreg, 0, 8);
- int cur_el = arm_current_el(env);
-
- if (cur_el == 0 && reg > 7 && reg != 20) {
- /*
- * only xPSR sub-fields and CONTROL.SFPA may be written by
- * unprivileged code
- */
- return;
- }
-
- if (arm_feature(env, ARM_FEATURE_M_SECURITY)) {
- switch (reg) {
- case 0x88: /* MSP_NS */
- if (!env->v7m.secure) {
- return;
- }
- env->v7m.other_ss_msp = val;
- return;
- case 0x89: /* PSP_NS */
- if (!env->v7m.secure) {
- return;
- }
- env->v7m.other_ss_psp = val;
- return;
- case 0x8a: /* MSPLIM_NS */
- if (!env->v7m.secure) {
- return;
- }
- env->v7m.msplim[M_REG_NS] = val & ~7;
- return;
- case 0x8b: /* PSPLIM_NS */
- if (!env->v7m.secure) {
- return;
- }
- env->v7m.psplim[M_REG_NS] = val & ~7;
- return;
- case 0x90: /* PRIMASK_NS */
- if (!env->v7m.secure) {
- return;
- }
- env->v7m.primask[M_REG_NS] = val & 1;
- return;
- case 0x91: /* BASEPRI_NS */
- if (!env->v7m.secure || !arm_feature(env, ARM_FEATURE_M_MAIN)) {
- return;
- }
- env->v7m.basepri[M_REG_NS] = val & 0xff;
- return;
- case 0x93: /* FAULTMASK_NS */
- if (!env->v7m.secure || !arm_feature(env, ARM_FEATURE_M_MAIN)) {
- return;
- }
- env->v7m.faultmask[M_REG_NS] = val & 1;
- return;
- case 0x94: /* CONTROL_NS */
- if (!env->v7m.secure) {
- return;
- }
- write_v7m_control_spsel_for_secstate(env,
- val & R_V7M_CONTROL_SPSEL_MASK,
- M_REG_NS);
- if (arm_feature(env, ARM_FEATURE_M_MAIN)) {
- env->v7m.control[M_REG_NS] &= ~R_V7M_CONTROL_NPRIV_MASK;
- env->v7m.control[M_REG_NS] |= val & R_V7M_CONTROL_NPRIV_MASK;
- }
- /*
- * SFPA is RAZ/WI from NS. FPCA is RO if NSACR.CP10 == 0,
- * RES0 if the FPU is not present, and is stored in the S bank
- */
- if (arm_feature(env, ARM_FEATURE_VFP) &&
- extract32(env->v7m.nsacr, 10, 1)) {
- env->v7m.control[M_REG_S] &= ~R_V7M_CONTROL_FPCA_MASK;
- env->v7m.control[M_REG_S] |= val & R_V7M_CONTROL_FPCA_MASK;
- }
- return;
- case 0x98: /* SP_NS */
- {
- /* This gives the non-secure SP selected based on whether we're
- * currently in handler mode or not, using the NS CONTROL.SPSEL.
- */
- bool spsel = env->v7m.control[M_REG_NS] & R_V7M_CONTROL_SPSEL_MASK;
- bool is_psp = !arm_v7m_is_handler_mode(env) && spsel;
- uint32_t limit;
-
- if (!env->v7m.secure) {
- return;
- }
-
- limit = is_psp ? env->v7m.psplim[false] : env->v7m.msplim[false];
-
- if (val < limit) {
- CPUState *cs = env_cpu(env);
-
- cpu_restore_state(cs, GETPC(), true);
- raise_exception(env, EXCP_STKOF, 0, 1);
- }
-
- if (is_psp) {
- env->v7m.other_ss_psp = val;
- } else {
- env->v7m.other_ss_msp = val;
- }
- return;
- }
- default:
- break;
- }
- }
-
- switch (reg) {
- case 0 ... 7: /* xPSR sub-fields */
- /* only APSR is actually writable */
- if (!(reg & 4)) {
- uint32_t apsrmask = 0;
-
- if (mask & 8) {
- apsrmask |= XPSR_NZCV | XPSR_Q;
- }
- if ((mask & 4) && arm_feature(env, ARM_FEATURE_THUMB_DSP)) {
- apsrmask |= XPSR_GE;
- }
- xpsr_write(env, val, apsrmask);
- }
- break;
- case 8: /* MSP */
- if (v7m_using_psp(env)) {
- env->v7m.other_sp = val;
- } else {
- env->regs[13] = val;
- }
- break;
- case 9: /* PSP */
- if (v7m_using_psp(env)) {
- env->regs[13] = val;
- } else {
- env->v7m.other_sp = val;
- }
- break;
- case 10: /* MSPLIM */
- if (!arm_feature(env, ARM_FEATURE_V8)) {
- goto bad_reg;
- }
- env->v7m.msplim[env->v7m.secure] = val & ~7;
- break;
- case 11: /* PSPLIM */
- if (!arm_feature(env, ARM_FEATURE_V8)) {
- goto bad_reg;
- }
- env->v7m.psplim[env->v7m.secure] = val & ~7;
- break;
- case 16: /* PRIMASK */
- env->v7m.primask[env->v7m.secure] = val & 1;
- break;
- case 17: /* BASEPRI */
- if (!arm_feature(env, ARM_FEATURE_M_MAIN)) {
- goto bad_reg;
- }
- env->v7m.basepri[env->v7m.secure] = val & 0xff;
- break;
- case 18: /* BASEPRI_MAX */
- if (!arm_feature(env, ARM_FEATURE_M_MAIN)) {
- goto bad_reg;
- }
- val &= 0xff;
- if (val != 0 && (val < env->v7m.basepri[env->v7m.secure]
- || env->v7m.basepri[env->v7m.secure] == 0)) {
- env->v7m.basepri[env->v7m.secure] = val;
- }
- break;
- case 19: /* FAULTMASK */
- if (!arm_feature(env, ARM_FEATURE_M_MAIN)) {
- goto bad_reg;
- }
- env->v7m.faultmask[env->v7m.secure] = val & 1;
- break;
- case 20: /* CONTROL */
- /*
- * Writing to the SPSEL bit only has an effect if we are in
- * thread mode; other bits can be updated by any privileged code.
- * write_v7m_control_spsel() deals with updating the SPSEL bit in
- * env->v7m.control, so we only need update the others.
- * For v7M, we must just ignore explicit writes to SPSEL in handler
- * mode; for v8M the write is permitted but will have no effect.
- * All these bits are writes-ignored from non-privileged code,
- * except for SFPA.
- */
- if (cur_el > 0 && (arm_feature(env, ARM_FEATURE_V8) ||
- !arm_v7m_is_handler_mode(env))) {
- write_v7m_control_spsel(env, (val & R_V7M_CONTROL_SPSEL_MASK) != 0);
- }
- if (cur_el > 0 && arm_feature(env, ARM_FEATURE_M_MAIN)) {
- env->v7m.control[env->v7m.secure] &= ~R_V7M_CONTROL_NPRIV_MASK;
- env->v7m.control[env->v7m.secure] |= val & R_V7M_CONTROL_NPRIV_MASK;
- }
- if (arm_feature(env, ARM_FEATURE_VFP)) {
- /*
- * SFPA is RAZ/WI from NS or if no FPU.
- * FPCA is RO if NSACR.CP10 == 0, RES0 if the FPU is not present.
- * Both are stored in the S bank.
- */
- if (env->v7m.secure) {
- env->v7m.control[M_REG_S] &= ~R_V7M_CONTROL_SFPA_MASK;
- env->v7m.control[M_REG_S] |= val & R_V7M_CONTROL_SFPA_MASK;
- }
- if (cur_el > 0 &&
- (env->v7m.secure || !arm_feature(env, ARM_FEATURE_M_SECURITY) ||
- extract32(env->v7m.nsacr, 10, 1))) {
- env->v7m.control[M_REG_S] &= ~R_V7M_CONTROL_FPCA_MASK;
- env->v7m.control[M_REG_S] |= val & R_V7M_CONTROL_FPCA_MASK;
- }
- }
- break;
- default:
- bad_reg:
- qemu_log_mask(LOG_GUEST_ERROR, "Attempt to write unknown special"
- " register %d\n", reg);
- return;
- }
-}
-
-uint32_t HELPER(v7m_tt)(CPUARMState *env, uint32_t addr, uint32_t op)
-{
- /* Implement the TT instruction. op is bits [7:6] of the insn. */
- bool forceunpriv = op & 1;
- bool alt = op & 2;
- V8M_SAttributes sattrs = {};
- uint32_t tt_resp;
- bool r, rw, nsr, nsrw, mrvalid;
- int prot;
- ARMMMUFaultInfo fi = {};
- MemTxAttrs attrs = {};
- hwaddr phys_addr;
- ARMMMUIdx mmu_idx;
- uint32_t mregion;
- bool targetpriv;
- bool targetsec = env->v7m.secure;
- bool is_subpage;
-
- /* Work out what the security state and privilege level we're
- * interested in is...
- */
- if (alt) {
- targetsec = !targetsec;
- }
-
- if (forceunpriv) {
- targetpriv = false;
- } else {
- targetpriv = arm_v7m_is_handler_mode(env) ||
- !(env->v7m.control[targetsec] & R_V7M_CONTROL_NPRIV_MASK);
- }
-
- /* ...and then figure out which MMU index this is */
- mmu_idx = arm_v7m_mmu_idx_for_secstate_and_priv(env, targetsec, targetpriv);
-
- /* We know that the MPU and SAU don't care about the access type
- * for our purposes beyond that we don't want to claim to be
- * an insn fetch, so we arbitrarily call this a read.
- */
-
- /* MPU region info only available for privileged or if
- * inspecting the other MPU state.
- */
- if (arm_current_el(env) != 0 || alt) {
- /* We can ignore the return value as prot is always set */
- pmsav8_mpu_lookup(env, addr, MMU_DATA_LOAD, mmu_idx,
- &phys_addr, &attrs, &prot, &is_subpage,
- &fi, &mregion);
- if (mregion == -1) {
- mrvalid = false;
- mregion = 0;
- } else {
- mrvalid = true;
- }
- r = prot & PAGE_READ;
- rw = prot & PAGE_WRITE;
- } else {
- r = false;
- rw = false;
- mrvalid = false;
- mregion = 0;
- }
-
- if (env->v7m.secure) {
- v8m_security_lookup(env, addr, MMU_DATA_LOAD, mmu_idx, &sattrs);
- nsr = sattrs.ns && r;
- nsrw = sattrs.ns && rw;
- } else {
- sattrs.ns = true;
- nsr = false;
- nsrw = false;
- }
-
- tt_resp = (sattrs.iregion << 24) |
- (sattrs.irvalid << 23) |
- ((!sattrs.ns) << 22) |
- (nsrw << 21) |
- (nsr << 20) |
- (rw << 19) |
- (r << 18) |
- (sattrs.srvalid << 17) |
- (mrvalid << 16) |
- (sattrs.sregion << 8) |
- mregion;
-
- return tt_resp;
-}
-
-#endif
-
-bool arm_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
- MMUAccessType access_type, int mmu_idx,
- bool probe, uintptr_t retaddr)
-{
- ARMCPU *cpu = ARM_CPU(cs);
-
-#ifdef CONFIG_USER_ONLY
- cpu->env.exception.vaddress = address;
- if (access_type == MMU_INST_FETCH) {
- cs->exception_index = EXCP_PREFETCH_ABORT;
- } else {
- cs->exception_index = EXCP_DATA_ABORT;
- }
- cpu_loop_exit_restore(cs, retaddr);
-#else
- hwaddr phys_addr;
- target_ulong page_size;
- int prot, ret;
- MemTxAttrs attrs = {};
- ARMMMUFaultInfo fi = {};
-
- /*
- * Walk the page table and (if the mapping exists) add the page
- * to the TLB. On success, return true. Otherwise, if probing,
- * return false. Otherwise populate fsr with ARM DFSR/IFSR fault
- * register format, and signal the fault.
- */
- ret = get_phys_addr(&cpu->env, address, access_type,
- core_to_arm_mmu_idx(&cpu->env, mmu_idx),
- &phys_addr, &attrs, &prot, &page_size, &fi, NULL);
- if (likely(!ret)) {
- /*
- * Map a single [sub]page. Regions smaller than our declared
- * target page size are handled specially, so for those we
- * pass in the exact addresses.
- */
- if (page_size >= TARGET_PAGE_SIZE) {
- phys_addr &= TARGET_PAGE_MASK;
- address &= TARGET_PAGE_MASK;
- }
- tlb_set_page_with_attrs(cs, address, phys_addr, attrs,
- prot, mmu_idx, page_size);
- return true;
- } else if (probe) {
- return false;
- } else {
- /* now we have a real cpu fault */
- cpu_restore_state(cs, retaddr, true);
- arm_deliver_fault(cpu, address, access_type, mmu_idx, &fi);
- }
-#endif
-}
-
-void HELPER(dc_zva)(CPUARMState *env, uint64_t vaddr_in)
-{
- /* Implement DC ZVA, which zeroes a fixed-length block of memory.
- * Note that we do not implement the (architecturally mandated)
- * alignment fault for attempts to use this on Device memory
- * (which matches the usual QEMU behaviour of not implementing either
- * alignment faults or any memory attribute handling).
- */
-
- ARMCPU *cpu = env_archcpu(env);
- uint64_t blocklen = 4 << cpu->dcz_blocksize;
- uint64_t vaddr = vaddr_in & ~(blocklen - 1);
-
-#ifndef CONFIG_USER_ONLY
- {
- /* Slightly awkwardly, QEMU's TARGET_PAGE_SIZE may be less than
- * the block size so we might have to do more than one TLB lookup.
- * We know that in fact for any v8 CPU the page size is at least 4K
- * and the block size must be 2K or less, but TARGET_PAGE_SIZE is only
- * 1K as an artefact of legacy v5 subpage support being present in the
- * same QEMU executable. So in practice the hostaddr[] array has
- * two entries, given the current setting of TARGET_PAGE_BITS_MIN.
- */
- int maxidx = DIV_ROUND_UP(blocklen, TARGET_PAGE_SIZE);
- void *hostaddr[DIV_ROUND_UP(2 * KiB, 1 << TARGET_PAGE_BITS_MIN)];
- int try, i;
- unsigned mmu_idx = cpu_mmu_index(env, false);
- TCGMemOpIdx oi = make_memop_idx(MO_UB, mmu_idx);
-
- assert(maxidx <= ARRAY_SIZE(hostaddr));
-
- for (try = 0; try < 2; try++) {
-
- for (i = 0; i < maxidx; i++) {
- hostaddr[i] = tlb_vaddr_to_host(env,
- vaddr + TARGET_PAGE_SIZE * i,
- 1, mmu_idx);
- if (!hostaddr[i]) {
- break;
- }
- }
- if (i == maxidx) {
- /* If it's all in the TLB it's fair game for just writing to;
- * we know we don't need to update dirty status, etc.
- */
- for (i = 0; i < maxidx - 1; i++) {
- memset(hostaddr[i], 0, TARGET_PAGE_SIZE);
- }
- memset(hostaddr[i], 0, blocklen - (i * TARGET_PAGE_SIZE));
- return;
- }
- /* OK, try a store and see if we can populate the tlb. This
- * might cause an exception if the memory isn't writable,
- * in which case we will longjmp out of here. We must for
- * this purpose use the actual register value passed to us
- * so that we get the fault address right.
- */
- helper_ret_stb_mmu(env, vaddr_in, 0, oi, GETPC());
- /* Now we can populate the other TLB entries, if any */
- for (i = 0; i < maxidx; i++) {
- uint64_t va = vaddr + TARGET_PAGE_SIZE * i;
- if (va != (vaddr_in & TARGET_PAGE_MASK)) {
- helper_ret_stb_mmu(env, va, 0, oi, GETPC());
- }
- }
- }
-
- /* Slow path (probably attempt to do this to an I/O device or
- * similar, or clearing of a block of code we have translations
- * cached for). Just do a series of byte writes as the architecture
- * demands. It's not worth trying to use a cpu_physical_memory_map(),
- * memset(), unmap() sequence here because:
- * + we'd need to account for the blocksize being larger than a page
- * + the direct-RAM access case is almost always going to be dealt
- * with in the fastpath code above, so there's no speed benefit
- * + we would have to deal with the map returning NULL because the
- * bounce buffer was in use
- */
- for (i = 0; i < blocklen; i++) {
- helper_ret_stb_mmu(env, vaddr + i, 0, oi, GETPC());
- }
- }
-#else
- memset(g2h(vaddr), 0, blocklen);
#endif
-}
/* Note that signed overflow is undefined in C. The following routines are
careful to use unsigned types where modulo arithmetic is required.
return 0;
}
-ARMMMUIdx arm_v7m_mmu_idx_all(CPUARMState *env,
- bool secstate, bool priv, bool negpri)
-{
- ARMMMUIdx mmu_idx = ARM_MMU_IDX_M;
-
- if (priv) {
- mmu_idx |= ARM_MMU_IDX_M_PRIV;
- }
-
- if (negpri) {
- mmu_idx |= ARM_MMU_IDX_M_NEGPRI;
- }
-
- if (secstate) {
- mmu_idx |= ARM_MMU_IDX_M_S;
- }
-
- return mmu_idx;
-}
-
-ARMMMUIdx arm_v7m_mmu_idx_for_secstate_and_priv(CPUARMState *env,
- bool secstate, bool priv)
-{
- bool negpri = armv7m_nvic_neg_prio_requested(env->nvic, secstate);
-
- return arm_v7m_mmu_idx_all(env, secstate, priv, negpri);
-}
-
-/* Return the MMU index for a v7M CPU in the specified security state */
+#ifndef CONFIG_TCG
ARMMMUIdx arm_v7m_mmu_idx_for_secstate(CPUARMState *env, bool secstate)
{
- bool priv = arm_current_el(env) != 0;
-
- return arm_v7m_mmu_idx_for_secstate_and_priv(env, secstate, priv);
+ g_assert_not_reached();
}
+#endif
ARMMMUIdx arm_mmu_idx(CPUARMState *env)
{
/* Callback function for when a watchpoint or breakpoint triggers. */
void arm_debug_excp_handler(CPUState *cs);
-#ifdef CONFIG_USER_ONLY
+#if defined(CONFIG_USER_ONLY) || !defined(CONFIG_TCG)
static inline bool arm_is_psci_call(ARMCPU *cpu, int excp_type)
{
return false;
}
+static inline void arm_handle_psci_call(ARMCPU *cpu)
+{
+ g_assert_not_reached();
+}
#else
/* Return true if the r0/x0 value indicates that this SMC/HVC is a PSCI call. */
bool arm_is_psci_call(ARMCPU *cpu, int excp_type);
MMUAccessType access_type, int mmu_idx,
bool probe, uintptr_t retaddr);
-void arm_deliver_fault(ARMCPU *cpu, vaddr addr, MMUAccessType access_type,
- int mmu_idx, ARMMMUFaultInfo *fi) QEMU_NORETURN;
-
/* Return true if the stage 1 translation regime is using LPAE format page
* tables */
bool arm_s1_regime_using_lpae_format(CPUARMState *env, ARMMMUIdx mmu_idx);
}
}
+/**
+ * v7m_cpacr_pass:
+ * Return true if the v7M CPACR permits access to the FPU for the specified
+ * security state and privilege level.
+ */
+static inline bool v7m_cpacr_pass(CPUARMState *env,
+ bool is_secure, bool is_priv)
+{
+ switch (extract32(env->v7m.cpacr[is_secure], 20, 2)) {
+ case 0:
+ case 2: /* UNPREDICTABLE: we treat like 0 */
+ return false;
+ case 1:
+ return is_priv;
+ case 3:
+ return true;
+ default:
+ g_assert_not_reached();
+ }
+}
+
/**
* aarch32_mode_name(): Return name of the AArch32 CPU mode
* @psr: Program Status Register indicating CPU mode
return target_el;
}
+#ifndef CONFIG_USER_ONLY
+
+/* Security attributes for an address, as returned by v8m_security_lookup. */
+typedef struct V8M_SAttributes {
+ bool subpage; /* true if these attrs don't cover the whole TARGET_PAGE */
+ bool ns;
+ bool nsc;
+ uint8_t sregion;
+ bool srvalid;
+ uint8_t iregion;
+ bool irvalid;
+} V8M_SAttributes;
+
+void v8m_security_lookup(CPUARMState *env, uint32_t address,
+ MMUAccessType access_type, ARMMMUIdx mmu_idx,
+ V8M_SAttributes *sattrs);
+
+bool pmsav8_mpu_lookup(CPUARMState *env, uint32_t address,
+ MMUAccessType access_type, ARMMMUIdx mmu_idx,
+ hwaddr *phys_ptr, MemTxAttrs *txattrs,
+ int *prot, bool *is_subpage,
+ ARMMMUFaultInfo *fi, uint32_t *mregion);
+
+/* Cacheability and shareability attributes for a memory access */
+typedef struct ARMCacheAttrs {
+ unsigned int attrs:8; /* as in the MAIR register encoding */
+ unsigned int shareability:2; /* as in the SH field of the VMSAv8-64 PTEs */
+} ARMCacheAttrs;
+
+bool get_phys_addr(CPUARMState *env, target_ulong address,
+ MMUAccessType access_type, ARMMMUIdx mmu_idx,
+ hwaddr *phys_ptr, MemTxAttrs *attrs, int *prot,
+ target_ulong *page_size,
+ ARMMMUFaultInfo *fi, ARMCacheAttrs *cacheattrs);
+
+void arm_log_exception(int idx);
+
+#endif /* !CONFIG_USER_ONLY */
+
#endif
--- /dev/null
+/*
+ * ARM generic helpers.
+ *
+ * This code is licensed under the GNU GPL v2 or later.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+#include "qemu/osdep.h"
+#include "qemu/units.h"
+#include "target/arm/idau.h"
+#include "trace.h"
+#include "cpu.h"
+#include "internals.h"
+#include "exec/gdbstub.h"
+#include "exec/helper-proto.h"
+#include "qemu/host-utils.h"
+#include "sysemu/sysemu.h"
+#include "qemu/bitops.h"
+#include "qemu/crc32c.h"
+#include "qemu/qemu-print.h"
+#include "exec/exec-all.h"
+#include <zlib.h> /* For crc32 */
+#include "hw/semihosting/semihost.h"
+#include "sysemu/cpus.h"
+#include "sysemu/kvm.h"
+#include "qemu/range.h"
+#include "qapi/qapi-commands-machine-target.h"
+#include "qapi/error.h"
+#include "qemu/guest-random.h"
+#ifdef CONFIG_TCG
+#include "arm_ldst.h"
+#include "exec/cpu_ldst.h"
+#endif
+
+#ifdef CONFIG_USER_ONLY
+
+/* These should probably raise undefined insn exceptions. */
+void HELPER(v7m_msr)(CPUARMState *env, uint32_t reg, uint32_t val)
+{
+ ARMCPU *cpu = env_archcpu(env);
+
+ cpu_abort(CPU(cpu), "v7m_msr %d\n", reg);
+}
+
+uint32_t HELPER(v7m_mrs)(CPUARMState *env, uint32_t reg)
+{
+ ARMCPU *cpu = env_archcpu(env);
+
+ cpu_abort(CPU(cpu), "v7m_mrs %d\n", reg);
+ return 0;
+}
+
+void HELPER(v7m_bxns)(CPUARMState *env, uint32_t dest)
+{
+ /* translate.c should never generate calls here in user-only mode */
+ g_assert_not_reached();
+}
+
+void HELPER(v7m_blxns)(CPUARMState *env, uint32_t dest)
+{
+ /* translate.c should never generate calls here in user-only mode */
+ g_assert_not_reached();
+}
+
+void HELPER(v7m_preserve_fp_state)(CPUARMState *env)
+{
+ /* translate.c should never generate calls here in user-only mode */
+ g_assert_not_reached();
+}
+
+void HELPER(v7m_vlstm)(CPUARMState *env, uint32_t fptr)
+{
+ /* translate.c should never generate calls here in user-only mode */
+ g_assert_not_reached();
+}
+
+void HELPER(v7m_vlldm)(CPUARMState *env, uint32_t fptr)
+{
+ /* translate.c should never generate calls here in user-only mode */
+ g_assert_not_reached();
+}
+
+uint32_t HELPER(v7m_tt)(CPUARMState *env, uint32_t addr, uint32_t op)
+{
+ /*
+ * The TT instructions can be used by unprivileged code, but in
+ * user-only emulation we don't have the MPU.
+ * Luckily since we know we are NonSecure unprivileged (and that in
+ * turn means that the A flag wasn't specified), all the bits in the
+ * register must be zero:
+ * IREGION: 0 because IRVALID is 0
+ * IRVALID: 0 because NS
+ * S: 0 because NS
+ * NSRW: 0 because NS
+ * NSR: 0 because NS
+ * RW: 0 because unpriv and A flag not set
+ * R: 0 because unpriv and A flag not set
+ * SRVALID: 0 because NS
+ * MRVALID: 0 because unpriv and A flag not set
+ * SREGION: 0 becaus SRVALID is 0
+ * MREGION: 0 because MRVALID is 0
+ */
+ return 0;
+}
+
+#else
+
+/*
+ * What kind of stack write are we doing? This affects how exceptions
+ * generated during the stacking are treated.
+ */
+typedef enum StackingMode {
+ STACK_NORMAL,
+ STACK_IGNFAULTS,
+ STACK_LAZYFP,
+} StackingMode;
+
+static bool v7m_stack_write(ARMCPU *cpu, uint32_t addr, uint32_t value,
+ ARMMMUIdx mmu_idx, StackingMode mode)
+{
+ CPUState *cs = CPU(cpu);
+ CPUARMState *env = &cpu->env;
+ MemTxAttrs attrs = {};
+ MemTxResult txres;
+ target_ulong page_size;
+ hwaddr physaddr;
+ int prot;
+ ARMMMUFaultInfo fi = {};
+ bool secure = mmu_idx & ARM_MMU_IDX_M_S;
+ int exc;
+ bool exc_secure;
+
+ if (get_phys_addr(env, addr, MMU_DATA_STORE, mmu_idx, &physaddr,
+ &attrs, &prot, &page_size, &fi, NULL)) {
+ /* MPU/SAU lookup failed */
+ if (fi.type == ARMFault_QEMU_SFault) {
+ if (mode == STACK_LAZYFP) {
+ qemu_log_mask(CPU_LOG_INT,
+ "...SecureFault with SFSR.LSPERR "
+ "during lazy stacking\n");
+ env->v7m.sfsr |= R_V7M_SFSR_LSPERR_MASK;
+ } else {
+ qemu_log_mask(CPU_LOG_INT,
+ "...SecureFault with SFSR.AUVIOL "
+ "during stacking\n");
+ env->v7m.sfsr |= R_V7M_SFSR_AUVIOL_MASK;
+ }
+ env->v7m.sfsr |= R_V7M_SFSR_SFARVALID_MASK;
+ env->v7m.sfar = addr;
+ exc = ARMV7M_EXCP_SECURE;
+ exc_secure = false;
+ } else {
+ if (mode == STACK_LAZYFP) {
+ qemu_log_mask(CPU_LOG_INT,
+ "...MemManageFault with CFSR.MLSPERR\n");
+ env->v7m.cfsr[secure] |= R_V7M_CFSR_MLSPERR_MASK;
+ } else {
+ qemu_log_mask(CPU_LOG_INT,
+ "...MemManageFault with CFSR.MSTKERR\n");
+ env->v7m.cfsr[secure] |= R_V7M_CFSR_MSTKERR_MASK;
+ }
+ exc = ARMV7M_EXCP_MEM;
+ exc_secure = secure;
+ }
+ goto pend_fault;
+ }
+ address_space_stl_le(arm_addressspace(cs, attrs), physaddr, value,
+ attrs, &txres);
+ if (txres != MEMTX_OK) {
+ /* BusFault trying to write the data */
+ if (mode == STACK_LAZYFP) {
+ qemu_log_mask(CPU_LOG_INT, "...BusFault with BFSR.LSPERR\n");
+ env->v7m.cfsr[M_REG_NS] |= R_V7M_CFSR_LSPERR_MASK;
+ } else {
+ qemu_log_mask(CPU_LOG_INT, "...BusFault with BFSR.STKERR\n");
+ env->v7m.cfsr[M_REG_NS] |= R_V7M_CFSR_STKERR_MASK;
+ }
+ exc = ARMV7M_EXCP_BUS;
+ exc_secure = false;
+ goto pend_fault;
+ }
+ return true;
+
+pend_fault:
+ /*
+ * By pending the exception at this point we are making
+ * the IMPDEF choice "overridden exceptions pended" (see the
+ * MergeExcInfo() pseudocode). The other choice would be to not
+ * pend them now and then make a choice about which to throw away
+ * later if we have two derived exceptions.
+ * The only case when we must not pend the exception but instead
+ * throw it away is if we are doing the push of the callee registers
+ * and we've already generated a derived exception (this is indicated
+ * by the caller passing STACK_IGNFAULTS). Even in this case we will
+ * still update the fault status registers.
+ */
+ switch (mode) {
+ case STACK_NORMAL:
+ armv7m_nvic_set_pending_derived(env->nvic, exc, exc_secure);
+ break;
+ case STACK_LAZYFP:
+ armv7m_nvic_set_pending_lazyfp(env->nvic, exc, exc_secure);
+ break;
+ case STACK_IGNFAULTS:
+ break;
+ }
+ return false;
+}
+
+static bool v7m_stack_read(ARMCPU *cpu, uint32_t *dest, uint32_t addr,
+ ARMMMUIdx mmu_idx)
+{
+ CPUState *cs = CPU(cpu);
+ CPUARMState *env = &cpu->env;
+ MemTxAttrs attrs = {};
+ MemTxResult txres;
+ target_ulong page_size;
+ hwaddr physaddr;
+ int prot;
+ ARMMMUFaultInfo fi = {};
+ bool secure = mmu_idx & ARM_MMU_IDX_M_S;
+ int exc;
+ bool exc_secure;
+ uint32_t value;
+
+ if (get_phys_addr(env, addr, MMU_DATA_LOAD, mmu_idx, &physaddr,
+ &attrs, &prot, &page_size, &fi, NULL)) {
+ /* MPU/SAU lookup failed */
+ if (fi.type == ARMFault_QEMU_SFault) {
+ qemu_log_mask(CPU_LOG_INT,
+ "...SecureFault with SFSR.AUVIOL during unstack\n");
+ env->v7m.sfsr |= R_V7M_SFSR_AUVIOL_MASK | R_V7M_SFSR_SFARVALID_MASK;
+ env->v7m.sfar = addr;
+ exc = ARMV7M_EXCP_SECURE;
+ exc_secure = false;
+ } else {
+ qemu_log_mask(CPU_LOG_INT,
+ "...MemManageFault with CFSR.MUNSTKERR\n");
+ env->v7m.cfsr[secure] |= R_V7M_CFSR_MUNSTKERR_MASK;
+ exc = ARMV7M_EXCP_MEM;
+ exc_secure = secure;
+ }
+ goto pend_fault;
+ }
+
+ value = address_space_ldl(arm_addressspace(cs, attrs), physaddr,
+ attrs, &txres);
+ if (txres != MEMTX_OK) {
+ /* BusFault trying to read the data */
+ qemu_log_mask(CPU_LOG_INT, "...BusFault with BFSR.UNSTKERR\n");
+ env->v7m.cfsr[M_REG_NS] |= R_V7M_CFSR_UNSTKERR_MASK;
+ exc = ARMV7M_EXCP_BUS;
+ exc_secure = false;
+ goto pend_fault;
+ }
+
+ *dest = value;
+ return true;
+
+pend_fault:
+ /*
+ * By pending the exception at this point we are making
+ * the IMPDEF choice "overridden exceptions pended" (see the
+ * MergeExcInfo() pseudocode). The other choice would be to not
+ * pend them now and then make a choice about which to throw away
+ * later if we have two derived exceptions.
+ */
+ armv7m_nvic_set_pending(env->nvic, exc, exc_secure);
+ return false;
+}
+
+void HELPER(v7m_preserve_fp_state)(CPUARMState *env)
+{
+ /*
+ * Preserve FP state (because LSPACT was set and we are about
+ * to execute an FP instruction). This corresponds to the
+ * PreserveFPState() pseudocode.
+ * We may throw an exception if the stacking fails.
+ */
+ ARMCPU *cpu = env_archcpu(env);
+ bool is_secure = env->v7m.fpccr[M_REG_S] & R_V7M_FPCCR_S_MASK;
+ bool negpri = !(env->v7m.fpccr[M_REG_S] & R_V7M_FPCCR_HFRDY_MASK);
+ bool is_priv = !(env->v7m.fpccr[is_secure] & R_V7M_FPCCR_USER_MASK);
+ bool splimviol = env->v7m.fpccr[is_secure] & R_V7M_FPCCR_SPLIMVIOL_MASK;
+ uint32_t fpcar = env->v7m.fpcar[is_secure];
+ bool stacked_ok = true;
+ bool ts = is_secure && (env->v7m.fpccr[M_REG_S] & R_V7M_FPCCR_TS_MASK);
+ bool take_exception;
+
+ /* Take the iothread lock as we are going to touch the NVIC */
+ qemu_mutex_lock_iothread();
+
+ /* Check the background context had access to the FPU */
+ if (!v7m_cpacr_pass(env, is_secure, is_priv)) {
+ armv7m_nvic_set_pending_lazyfp(env->nvic, ARMV7M_EXCP_USAGE, is_secure);
+ env->v7m.cfsr[is_secure] |= R_V7M_CFSR_NOCP_MASK;
+ stacked_ok = false;
+ } else if (!is_secure && !extract32(env->v7m.nsacr, 10, 1)) {
+ armv7m_nvic_set_pending_lazyfp(env->nvic, ARMV7M_EXCP_USAGE, M_REG_S);
+ env->v7m.cfsr[M_REG_S] |= R_V7M_CFSR_NOCP_MASK;
+ stacked_ok = false;
+ }
+
+ if (!splimviol && stacked_ok) {
+ /* We only stack if the stack limit wasn't violated */
+ int i;
+ ARMMMUIdx mmu_idx;
+
+ mmu_idx = arm_v7m_mmu_idx_all(env, is_secure, is_priv, negpri);
+ for (i = 0; i < (ts ? 32 : 16); i += 2) {
+ uint64_t dn = *aa32_vfp_dreg(env, i / 2);
+ uint32_t faddr = fpcar + 4 * i;
+ uint32_t slo = extract64(dn, 0, 32);
+ uint32_t shi = extract64(dn, 32, 32);
+
+ if (i >= 16) {
+ faddr += 8; /* skip the slot for the FPSCR */
+ }
+ stacked_ok = stacked_ok &&
+ v7m_stack_write(cpu, faddr, slo, mmu_idx, STACK_LAZYFP) &&
+ v7m_stack_write(cpu, faddr + 4, shi, mmu_idx, STACK_LAZYFP);
+ }
+
+ stacked_ok = stacked_ok &&
+ v7m_stack_write(cpu, fpcar + 0x40,
+ vfp_get_fpscr(env), mmu_idx, STACK_LAZYFP);
+ }
+
+ /*
+ * We definitely pended an exception, but it's possible that it
+ * might not be able to be taken now. If its priority permits us
+ * to take it now, then we must not update the LSPACT or FP regs,
+ * but instead jump out to take the exception immediately.
+ * If it's just pending and won't be taken until the current
+ * handler exits, then we do update LSPACT and the FP regs.
+ */
+ take_exception = !stacked_ok &&
+ armv7m_nvic_can_take_pending_exception(env->nvic);
+
+ qemu_mutex_unlock_iothread();
+
+ if (take_exception) {
+ raise_exception_ra(env, EXCP_LAZYFP, 0, 1, GETPC());
+ }
+
+ env->v7m.fpccr[is_secure] &= ~R_V7M_FPCCR_LSPACT_MASK;
+
+ if (ts) {
+ /* Clear s0 to s31 and the FPSCR */
+ int i;
+
+ for (i = 0; i < 32; i += 2) {
+ *aa32_vfp_dreg(env, i / 2) = 0;
+ }
+ vfp_set_fpscr(env, 0);
+ }
+ /*
+ * Otherwise s0 to s15 and FPSCR are UNKNOWN; we choose to leave them
+ * unchanged.
+ */
+}
+
+/*
+ * Write to v7M CONTROL.SPSEL bit for the specified security bank.
+ * This may change the current stack pointer between Main and Process
+ * stack pointers if it is done for the CONTROL register for the current
+ * security state.
+ */
+static void write_v7m_control_spsel_for_secstate(CPUARMState *env,
+ bool new_spsel,
+ bool secstate)
+{
+ bool old_is_psp = v7m_using_psp(env);
+
+ env->v7m.control[secstate] =
+ deposit32(env->v7m.control[secstate],
+ R_V7M_CONTROL_SPSEL_SHIFT,
+ R_V7M_CONTROL_SPSEL_LENGTH, new_spsel);
+
+ if (secstate == env->v7m.secure) {
+ bool new_is_psp = v7m_using_psp(env);
+ uint32_t tmp;
+
+ if (old_is_psp != new_is_psp) {
+ tmp = env->v7m.other_sp;
+ env->v7m.other_sp = env->regs[13];
+ env->regs[13] = tmp;
+ }
+ }
+}
+
+/*
+ * Write to v7M CONTROL.SPSEL bit. This may change the current
+ * stack pointer between Main and Process stack pointers.
+ */
+static void write_v7m_control_spsel(CPUARMState *env, bool new_spsel)
+{
+ write_v7m_control_spsel_for_secstate(env, new_spsel, env->v7m.secure);
+}
+
+void write_v7m_exception(CPUARMState *env, uint32_t new_exc)
+{
+ /*
+ * Write a new value to v7m.exception, thus transitioning into or out
+ * of Handler mode; this may result in a change of active stack pointer.
+ */
+ bool new_is_psp, old_is_psp = v7m_using_psp(env);
+ uint32_t tmp;
+
+ env->v7m.exception = new_exc;
+
+ new_is_psp = v7m_using_psp(env);
+
+ if (old_is_psp != new_is_psp) {
+ tmp = env->v7m.other_sp;
+ env->v7m.other_sp = env->regs[13];
+ env->regs[13] = tmp;
+ }
+}
+
+/* Switch M profile security state between NS and S */
+static void switch_v7m_security_state(CPUARMState *env, bool new_secstate)
+{
+ uint32_t new_ss_msp, new_ss_psp;
+
+ if (env->v7m.secure == new_secstate) {
+ return;
+ }
+
+ /*
+ * All the banked state is accessed by looking at env->v7m.secure
+ * except for the stack pointer; rearrange the SP appropriately.
+ */
+ new_ss_msp = env->v7m.other_ss_msp;
+ new_ss_psp = env->v7m.other_ss_psp;
+
+ if (v7m_using_psp(env)) {
+ env->v7m.other_ss_psp = env->regs[13];
+ env->v7m.other_ss_msp = env->v7m.other_sp;
+ } else {
+ env->v7m.other_ss_msp = env->regs[13];
+ env->v7m.other_ss_psp = env->v7m.other_sp;
+ }
+
+ env->v7m.secure = new_secstate;
+
+ if (v7m_using_psp(env)) {
+ env->regs[13] = new_ss_psp;
+ env->v7m.other_sp = new_ss_msp;
+ } else {
+ env->regs[13] = new_ss_msp;
+ env->v7m.other_sp = new_ss_psp;
+ }
+}
+
+void HELPER(v7m_bxns)(CPUARMState *env, uint32_t dest)
+{
+ /*
+ * Handle v7M BXNS:
+ * - if the return value is a magic value, do exception return (like BX)
+ * - otherwise bit 0 of the return value is the target security state
+ */
+ uint32_t min_magic;
+
+ if (arm_feature(env, ARM_FEATURE_M_SECURITY)) {
+ /* Covers FNC_RETURN and EXC_RETURN magic */
+ min_magic = FNC_RETURN_MIN_MAGIC;
+ } else {
+ /* EXC_RETURN magic only */
+ min_magic = EXC_RETURN_MIN_MAGIC;
+ }
+
+ if (dest >= min_magic) {
+ /*
+ * This is an exception return magic value; put it where
+ * do_v7m_exception_exit() expects and raise EXCEPTION_EXIT.
+ * Note that if we ever add gen_ss_advance() singlestep support to
+ * M profile this should count as an "instruction execution complete"
+ * event (compare gen_bx_excret_final_code()).
+ */
+ env->regs[15] = dest & ~1;
+ env->thumb = dest & 1;
+ HELPER(exception_internal)(env, EXCP_EXCEPTION_EXIT);
+ /* notreached */
+ }
+
+ /* translate.c should have made BXNS UNDEF unless we're secure */
+ assert(env->v7m.secure);
+
+ if (!(dest & 1)) {
+ env->v7m.control[M_REG_S] &= ~R_V7M_CONTROL_SFPA_MASK;
+ }
+ switch_v7m_security_state(env, dest & 1);
+ env->thumb = 1;
+ env->regs[15] = dest & ~1;
+}
+
+void HELPER(v7m_blxns)(CPUARMState *env, uint32_t dest)
+{
+ /*
+ * Handle v7M BLXNS:
+ * - bit 0 of the destination address is the target security state
+ */
+
+ /* At this point regs[15] is the address just after the BLXNS */
+ uint32_t nextinst = env->regs[15] | 1;
+ uint32_t sp = env->regs[13] - 8;
+ uint32_t saved_psr;
+
+ /* translate.c will have made BLXNS UNDEF unless we're secure */
+ assert(env->v7m.secure);
+
+ if (dest & 1) {
+ /*
+ * Target is Secure, so this is just a normal BLX,
+ * except that the low bit doesn't indicate Thumb/not.
+ */
+ env->regs[14] = nextinst;
+ env->thumb = 1;
+ env->regs[15] = dest & ~1;
+ return;
+ }
+
+ /* Target is non-secure: first push a stack frame */
+ if (!QEMU_IS_ALIGNED(sp, 8)) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "BLXNS with misaligned SP is UNPREDICTABLE\n");
+ }
+
+ if (sp < v7m_sp_limit(env)) {
+ raise_exception(env, EXCP_STKOF, 0, 1);
+ }
+
+ saved_psr = env->v7m.exception;
+ if (env->v7m.control[M_REG_S] & R_V7M_CONTROL_SFPA_MASK) {
+ saved_psr |= XPSR_SFPA;
+ }
+
+ /* Note that these stores can throw exceptions on MPU faults */
+ cpu_stl_data_ra(env, sp, nextinst, GETPC());
+ cpu_stl_data_ra(env, sp + 4, saved_psr, GETPC());
+
+ env->regs[13] = sp;
+ env->regs[14] = 0xfeffffff;
+ if (arm_v7m_is_handler_mode(env)) {
+ /*
+ * Write a dummy value to IPSR, to avoid leaking the current secure
+ * exception number to non-secure code. This is guaranteed not
+ * to cause write_v7m_exception() to actually change stacks.
+ */
+ write_v7m_exception(env, 1);
+ }
+ env->v7m.control[M_REG_S] &= ~R_V7M_CONTROL_SFPA_MASK;
+ switch_v7m_security_state(env, 0);
+ env->thumb = 1;
+ env->regs[15] = dest;
+}
+
+static uint32_t *get_v7m_sp_ptr(CPUARMState *env, bool secure, bool threadmode,
+ bool spsel)
+{
+ /*
+ * Return a pointer to the location where we currently store the
+ * stack pointer for the requested security state and thread mode.
+ * This pointer will become invalid if the CPU state is updated
+ * such that the stack pointers are switched around (eg changing
+ * the SPSEL control bit).
+ * Compare the v8M ARM ARM pseudocode LookUpSP_with_security_mode().
+ * Unlike that pseudocode, we require the caller to pass us in the
+ * SPSEL control bit value; this is because we also use this
+ * function in handling of pushing of the callee-saves registers
+ * part of the v8M stack frame (pseudocode PushCalleeStack()),
+ * and in the tailchain codepath the SPSEL bit comes from the exception
+ * return magic LR value from the previous exception. The pseudocode
+ * opencodes the stack-selection in PushCalleeStack(), but we prefer
+ * to make this utility function generic enough to do the job.
+ */
+ bool want_psp = threadmode && spsel;
+
+ if (secure == env->v7m.secure) {
+ if (want_psp == v7m_using_psp(env)) {
+ return &env->regs[13];
+ } else {
+ return &env->v7m.other_sp;
+ }
+ } else {
+ if (want_psp) {
+ return &env->v7m.other_ss_psp;
+ } else {
+ return &env->v7m.other_ss_msp;
+ }
+ }
+}
+
+static bool arm_v7m_load_vector(ARMCPU *cpu, int exc, bool targets_secure,
+ uint32_t *pvec)
+{
+ CPUState *cs = CPU(cpu);
+ CPUARMState *env = &cpu->env;
+ MemTxResult result;
+ uint32_t addr = env->v7m.vecbase[targets_secure] + exc * 4;
+ uint32_t vector_entry;
+ MemTxAttrs attrs = {};
+ ARMMMUIdx mmu_idx;
+ bool exc_secure;
+
+ mmu_idx = arm_v7m_mmu_idx_for_secstate_and_priv(env, targets_secure, true);
+
+ /*
+ * We don't do a get_phys_addr() here because the rules for vector
+ * loads are special: they always use the default memory map, and
+ * the default memory map permits reads from all addresses.
+ * Since there's no easy way to pass through to pmsav8_mpu_lookup()
+ * that we want this special case which would always say "yes",
+ * we just do the SAU lookup here followed by a direct physical load.
+ */
+ attrs.secure = targets_secure;
+ attrs.user = false;
+
+ if (arm_feature(env, ARM_FEATURE_M_SECURITY)) {
+ V8M_SAttributes sattrs = {};
+
+ v8m_security_lookup(env, addr, MMU_DATA_LOAD, mmu_idx, &sattrs);
+ if (sattrs.ns) {
+ attrs.secure = false;
+ } else if (!targets_secure) {
+ /* NS access to S memory */
+ goto load_fail;
+ }
+ }
+
+ vector_entry = address_space_ldl(arm_addressspace(cs, attrs), addr,
+ attrs, &result);
+ if (result != MEMTX_OK) {
+ goto load_fail;
+ }
+ *pvec = vector_entry;
+ return true;
+
+load_fail:
+ /*
+ * All vector table fetch fails are reported as HardFault, with
+ * HFSR.VECTTBL and .FORCED set. (FORCED is set because
+ * technically the underlying exception is a MemManage or BusFault
+ * that is escalated to HardFault.) This is a terminal exception,
+ * so we will either take the HardFault immediately or else enter
+ * lockup (the latter case is handled in armv7m_nvic_set_pending_derived()).
+ */
+ exc_secure = targets_secure ||
+ !(cpu->env.v7m.aircr & R_V7M_AIRCR_BFHFNMINS_MASK);
+ env->v7m.hfsr |= R_V7M_HFSR_VECTTBL_MASK | R_V7M_HFSR_FORCED_MASK;
+ armv7m_nvic_set_pending_derived(env->nvic, ARMV7M_EXCP_HARD, exc_secure);
+ return false;
+}
+
+static uint32_t v7m_integrity_sig(CPUARMState *env, uint32_t lr)
+{
+ /*
+ * Return the integrity signature value for the callee-saves
+ * stack frame section. @lr is the exception return payload/LR value
+ * whose FType bit forms bit 0 of the signature if FP is present.
+ */
+ uint32_t sig = 0xfefa125a;
+
+ if (!arm_feature(env, ARM_FEATURE_VFP) || (lr & R_V7M_EXCRET_FTYPE_MASK)) {
+ sig |= 1;
+ }
+ return sig;
+}
+
+static bool v7m_push_callee_stack(ARMCPU *cpu, uint32_t lr, bool dotailchain,
+ bool ignore_faults)
+{
+ /*
+ * For v8M, push the callee-saves register part of the stack frame.
+ * Compare the v8M pseudocode PushCalleeStack().
+ * In the tailchaining case this may not be the current stack.
+ */
+ CPUARMState *env = &cpu->env;
+ uint32_t *frame_sp_p;
+ uint32_t frameptr;
+ ARMMMUIdx mmu_idx;
+ bool stacked_ok;
+ uint32_t limit;
+ bool want_psp;
+ uint32_t sig;
+ StackingMode smode = ignore_faults ? STACK_IGNFAULTS : STACK_NORMAL;
+
+ if (dotailchain) {
+ bool mode = lr & R_V7M_EXCRET_MODE_MASK;
+ bool priv = !(env->v7m.control[M_REG_S] & R_V7M_CONTROL_NPRIV_MASK) ||
+ !mode;
+
+ mmu_idx = arm_v7m_mmu_idx_for_secstate_and_priv(env, M_REG_S, priv);
+ frame_sp_p = get_v7m_sp_ptr(env, M_REG_S, mode,
+ lr & R_V7M_EXCRET_SPSEL_MASK);
+ want_psp = mode && (lr & R_V7M_EXCRET_SPSEL_MASK);
+ if (want_psp) {
+ limit = env->v7m.psplim[M_REG_S];
+ } else {
+ limit = env->v7m.msplim[M_REG_S];
+ }
+ } else {
+ mmu_idx = arm_mmu_idx(env);
+ frame_sp_p = &env->regs[13];
+ limit = v7m_sp_limit(env);
+ }
+
+ frameptr = *frame_sp_p - 0x28;
+ if (frameptr < limit) {
+ /*
+ * Stack limit failure: set SP to the limit value, and generate
+ * STKOF UsageFault. Stack pushes below the limit must not be
+ * performed. It is IMPDEF whether pushes above the limit are
+ * performed; we choose not to.
+ */
+ qemu_log_mask(CPU_LOG_INT,
+ "...STKOF during callee-saves register stacking\n");
+ env->v7m.cfsr[env->v7m.secure] |= R_V7M_CFSR_STKOF_MASK;
+ armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE,
+ env->v7m.secure);
+ *frame_sp_p = limit;
+ return true;
+ }
+
+ /*
+ * Write as much of the stack frame as we can. A write failure may
+ * cause us to pend a derived exception.
+ */
+ sig = v7m_integrity_sig(env, lr);
+ stacked_ok =
+ v7m_stack_write(cpu, frameptr, sig, mmu_idx, smode) &&
+ v7m_stack_write(cpu, frameptr + 0x8, env->regs[4], mmu_idx, smode) &&
+ v7m_stack_write(cpu, frameptr + 0xc, env->regs[5], mmu_idx, smode) &&
+ v7m_stack_write(cpu, frameptr + 0x10, env->regs[6], mmu_idx, smode) &&
+ v7m_stack_write(cpu, frameptr + 0x14, env->regs[7], mmu_idx, smode) &&
+ v7m_stack_write(cpu, frameptr + 0x18, env->regs[8], mmu_idx, smode) &&
+ v7m_stack_write(cpu, frameptr + 0x1c, env->regs[9], mmu_idx, smode) &&
+ v7m_stack_write(cpu, frameptr + 0x20, env->regs[10], mmu_idx, smode) &&
+ v7m_stack_write(cpu, frameptr + 0x24, env->regs[11], mmu_idx, smode);
+
+ /* Update SP regardless of whether any of the stack accesses failed. */
+ *frame_sp_p = frameptr;
+
+ return !stacked_ok;
+}
+
+static void v7m_exception_taken(ARMCPU *cpu, uint32_t lr, bool dotailchain,
+ bool ignore_stackfaults)
+{
+ /*
+ * Do the "take the exception" parts of exception entry,
+ * but not the pushing of state to the stack. This is
+ * similar to the pseudocode ExceptionTaken() function.
+ */
+ CPUARMState *env = &cpu->env;
+ uint32_t addr;
+ bool targets_secure;
+ int exc;
+ bool push_failed = false;
+
+ armv7m_nvic_get_pending_irq_info(env->nvic, &exc, &targets_secure);
+ qemu_log_mask(CPU_LOG_INT, "...taking pending %s exception %d\n",
+ targets_secure ? "secure" : "nonsecure", exc);
+
+ if (dotailchain) {
+ /* Sanitize LR FType and PREFIX bits */
+ if (!arm_feature(env, ARM_FEATURE_VFP)) {
+ lr |= R_V7M_EXCRET_FTYPE_MASK;
+ }
+ lr = deposit32(lr, 24, 8, 0xff);
+ }
+
+ if (arm_feature(env, ARM_FEATURE_V8)) {
+ if (arm_feature(env, ARM_FEATURE_M_SECURITY) &&
+ (lr & R_V7M_EXCRET_S_MASK)) {
+ /*
+ * The background code (the owner of the registers in the
+ * exception frame) is Secure. This means it may either already
+ * have or now needs to push callee-saves registers.
+ */
+ if (targets_secure) {
+ if (dotailchain && !(lr & R_V7M_EXCRET_ES_MASK)) {
+ /*
+ * We took an exception from Secure to NonSecure
+ * (which means the callee-saved registers got stacked)
+ * and are now tailchaining to a Secure exception.
+ * Clear DCRS so eventual return from this Secure
+ * exception unstacks the callee-saved registers.
+ */
+ lr &= ~R_V7M_EXCRET_DCRS_MASK;
+ }
+ } else {
+ /*
+ * We're going to a non-secure exception; push the
+ * callee-saves registers to the stack now, if they're
+ * not already saved.
+ */
+ if (lr & R_V7M_EXCRET_DCRS_MASK &&
+ !(dotailchain && !(lr & R_V7M_EXCRET_ES_MASK))) {
+ push_failed = v7m_push_callee_stack(cpu, lr, dotailchain,
+ ignore_stackfaults);
+ }
+ lr |= R_V7M_EXCRET_DCRS_MASK;
+ }
+ }
+
+ lr &= ~R_V7M_EXCRET_ES_MASK;
+ if (targets_secure || !arm_feature(env, ARM_FEATURE_M_SECURITY)) {
+ lr |= R_V7M_EXCRET_ES_MASK;
+ }
+ lr &= ~R_V7M_EXCRET_SPSEL_MASK;
+ if (env->v7m.control[targets_secure] & R_V7M_CONTROL_SPSEL_MASK) {
+ lr |= R_V7M_EXCRET_SPSEL_MASK;
+ }
+
+ /*
+ * Clear registers if necessary to prevent non-secure exception
+ * code being able to see register values from secure code.
+ * Where register values become architecturally UNKNOWN we leave
+ * them with their previous values.
+ */
+ if (arm_feature(env, ARM_FEATURE_M_SECURITY)) {
+ if (!targets_secure) {
+ /*
+ * Always clear the caller-saved registers (they have been
+ * pushed to the stack earlier in v7m_push_stack()).
+ * Clear callee-saved registers if the background code is
+ * Secure (in which case these regs were saved in
+ * v7m_push_callee_stack()).
+ */
+ int i;
+
+ for (i = 0; i < 13; i++) {
+ /* r4..r11 are callee-saves, zero only if EXCRET.S == 1 */
+ if (i < 4 || i > 11 || (lr & R_V7M_EXCRET_S_MASK)) {
+ env->regs[i] = 0;
+ }
+ }
+ /* Clear EAPSR */
+ xpsr_write(env, 0, XPSR_NZCV | XPSR_Q | XPSR_GE | XPSR_IT);
+ }
+ }
+ }
+
+ if (push_failed && !ignore_stackfaults) {
+ /*
+ * Derived exception on callee-saves register stacking:
+ * we might now want to take a different exception which
+ * targets a different security state, so try again from the top.
+ */
+ qemu_log_mask(CPU_LOG_INT,
+ "...derived exception on callee-saves register stacking");
+ v7m_exception_taken(cpu, lr, true, true);
+ return;
+ }
+
+ if (!arm_v7m_load_vector(cpu, exc, targets_secure, &addr)) {
+ /* Vector load failed: derived exception */
+ qemu_log_mask(CPU_LOG_INT, "...derived exception on vector table load");
+ v7m_exception_taken(cpu, lr, true, true);
+ return;
+ }
+
+ /*
+ * Now we've done everything that might cause a derived exception
+ * we can go ahead and activate whichever exception we're going to
+ * take (which might now be the derived exception).
+ */
+ armv7m_nvic_acknowledge_irq(env->nvic);
+
+ /* Switch to target security state -- must do this before writing SPSEL */
+ switch_v7m_security_state(env, targets_secure);
+ write_v7m_control_spsel(env, 0);
+ arm_clear_exclusive(env);
+ /* Clear SFPA and FPCA (has no effect if no FPU) */
+ env->v7m.control[M_REG_S] &=
+ ~(R_V7M_CONTROL_FPCA_MASK | R_V7M_CONTROL_SFPA_MASK);
+ /* Clear IT bits */
+ env->condexec_bits = 0;
+ env->regs[14] = lr;
+ env->regs[15] = addr & 0xfffffffe;
+ env->thumb = addr & 1;
+}
+
+static void v7m_update_fpccr(CPUARMState *env, uint32_t frameptr,
+ bool apply_splim)
+{
+ /*
+ * Like the pseudocode UpdateFPCCR: save state in FPCAR and FPCCR
+ * that we will need later in order to do lazy FP reg stacking.
+ */
+ bool is_secure = env->v7m.secure;
+ void *nvic = env->nvic;
+ /*
+ * Some bits are unbanked and live always in fpccr[M_REG_S]; some bits
+ * are banked and we want to update the bit in the bank for the
+ * current security state; and in one case we want to specifically
+ * update the NS banked version of a bit even if we are secure.
+ */
+ uint32_t *fpccr_s = &env->v7m.fpccr[M_REG_S];
+ uint32_t *fpccr_ns = &env->v7m.fpccr[M_REG_NS];
+ uint32_t *fpccr = &env->v7m.fpccr[is_secure];
+ bool hfrdy, bfrdy, mmrdy, ns_ufrdy, s_ufrdy, sfrdy, monrdy;
+
+ env->v7m.fpcar[is_secure] = frameptr & ~0x7;
+
+ if (apply_splim && arm_feature(env, ARM_FEATURE_V8)) {
+ bool splimviol;
+ uint32_t splim = v7m_sp_limit(env);
+ bool ign = armv7m_nvic_neg_prio_requested(nvic, is_secure) &&
+ (env->v7m.ccr[is_secure] & R_V7M_CCR_STKOFHFNMIGN_MASK);
+
+ splimviol = !ign && frameptr < splim;
+ *fpccr = FIELD_DP32(*fpccr, V7M_FPCCR, SPLIMVIOL, splimviol);
+ }
+
+ *fpccr = FIELD_DP32(*fpccr, V7M_FPCCR, LSPACT, 1);
+
+ *fpccr_s = FIELD_DP32(*fpccr_s, V7M_FPCCR, S, is_secure);
+
+ *fpccr = FIELD_DP32(*fpccr, V7M_FPCCR, USER, arm_current_el(env) == 0);
+
+ *fpccr = FIELD_DP32(*fpccr, V7M_FPCCR, THREAD,
+ !arm_v7m_is_handler_mode(env));
+
+ hfrdy = armv7m_nvic_get_ready_status(nvic, ARMV7M_EXCP_HARD, false);
+ *fpccr_s = FIELD_DP32(*fpccr_s, V7M_FPCCR, HFRDY, hfrdy);
+
+ bfrdy = armv7m_nvic_get_ready_status(nvic, ARMV7M_EXCP_BUS, false);
+ *fpccr_s = FIELD_DP32(*fpccr_s, V7M_FPCCR, BFRDY, bfrdy);
+
+ mmrdy = armv7m_nvic_get_ready_status(nvic, ARMV7M_EXCP_MEM, is_secure);
+ *fpccr = FIELD_DP32(*fpccr, V7M_FPCCR, MMRDY, mmrdy);
+
+ ns_ufrdy = armv7m_nvic_get_ready_status(nvic, ARMV7M_EXCP_USAGE, false);
+ *fpccr_ns = FIELD_DP32(*fpccr_ns, V7M_FPCCR, UFRDY, ns_ufrdy);
+
+ monrdy = armv7m_nvic_get_ready_status(nvic, ARMV7M_EXCP_DEBUG, false);
+ *fpccr_s = FIELD_DP32(*fpccr_s, V7M_FPCCR, MONRDY, monrdy);
+
+ if (arm_feature(env, ARM_FEATURE_M_SECURITY)) {
+ s_ufrdy = armv7m_nvic_get_ready_status(nvic, ARMV7M_EXCP_USAGE, true);
+ *fpccr_s = FIELD_DP32(*fpccr_s, V7M_FPCCR, UFRDY, s_ufrdy);
+
+ sfrdy = armv7m_nvic_get_ready_status(nvic, ARMV7M_EXCP_SECURE, false);
+ *fpccr_s = FIELD_DP32(*fpccr_s, V7M_FPCCR, SFRDY, sfrdy);
+ }
+}
+
+void HELPER(v7m_vlstm)(CPUARMState *env, uint32_t fptr)
+{
+ /* fptr is the value of Rn, the frame pointer we store the FP regs to */
+ bool s = env->v7m.fpccr[M_REG_S] & R_V7M_FPCCR_S_MASK;
+ bool lspact = env->v7m.fpccr[s] & R_V7M_FPCCR_LSPACT_MASK;
+ uintptr_t ra = GETPC();
+
+ assert(env->v7m.secure);
+
+ if (!(env->v7m.control[M_REG_S] & R_V7M_CONTROL_SFPA_MASK)) {
+ return;
+ }
+
+ /* Check access to the coprocessor is permitted */
+ if (!v7m_cpacr_pass(env, true, arm_current_el(env) != 0)) {
+ raise_exception_ra(env, EXCP_NOCP, 0, 1, GETPC());
+ }
+
+ if (lspact) {
+ /* LSPACT should not be active when there is active FP state */
+ raise_exception_ra(env, EXCP_LSERR, 0, 1, GETPC());
+ }
+
+ if (fptr & 7) {
+ raise_exception_ra(env, EXCP_UNALIGNED, 0, 1, GETPC());
+ }
+
+ /*
+ * Note that we do not use v7m_stack_write() here, because the
+ * accesses should not set the FSR bits for stacking errors if they
+ * fail. (In pseudocode terms, they are AccType_NORMAL, not AccType_STACK
+ * or AccType_LAZYFP). Faults in cpu_stl_data_ra() will throw exceptions
+ * and longjmp out.
+ */
+ if (!(env->v7m.fpccr[M_REG_S] & R_V7M_FPCCR_LSPEN_MASK)) {
+ bool ts = env->v7m.fpccr[M_REG_S] & R_V7M_FPCCR_TS_MASK;
+ int i;
+
+ for (i = 0; i < (ts ? 32 : 16); i += 2) {
+ uint64_t dn = *aa32_vfp_dreg(env, i / 2);
+ uint32_t faddr = fptr + 4 * i;
+ uint32_t slo = extract64(dn, 0, 32);
+ uint32_t shi = extract64(dn, 32, 32);
+
+ if (i >= 16) {
+ faddr += 8; /* skip the slot for the FPSCR */
+ }
+ cpu_stl_data_ra(env, faddr, slo, ra);
+ cpu_stl_data_ra(env, faddr + 4, shi, ra);
+ }
+ cpu_stl_data_ra(env, fptr + 0x40, vfp_get_fpscr(env), ra);
+
+ /*
+ * If TS is 0 then s0 to s15 and FPSCR are UNKNOWN; we choose to
+ * leave them unchanged, matching our choice in v7m_preserve_fp_state.
+ */
+ if (ts) {
+ for (i = 0; i < 32; i += 2) {
+ *aa32_vfp_dreg(env, i / 2) = 0;
+ }
+ vfp_set_fpscr(env, 0);
+ }
+ } else {
+ v7m_update_fpccr(env, fptr, false);
+ }
+
+ env->v7m.control[M_REG_S] &= ~R_V7M_CONTROL_FPCA_MASK;
+}
+
+void HELPER(v7m_vlldm)(CPUARMState *env, uint32_t fptr)
+{
+ uintptr_t ra = GETPC();
+
+ /* fptr is the value of Rn, the frame pointer we load the FP regs from */
+ assert(env->v7m.secure);
+
+ if (!(env->v7m.control[M_REG_S] & R_V7M_CONTROL_SFPA_MASK)) {
+ return;
+ }
+
+ /* Check access to the coprocessor is permitted */
+ if (!v7m_cpacr_pass(env, true, arm_current_el(env) != 0)) {
+ raise_exception_ra(env, EXCP_NOCP, 0, 1, GETPC());
+ }
+
+ if (env->v7m.fpccr[M_REG_S] & R_V7M_FPCCR_LSPACT_MASK) {
+ /* State in FP is still valid */
+ env->v7m.fpccr[M_REG_S] &= ~R_V7M_FPCCR_LSPACT_MASK;
+ } else {
+ bool ts = env->v7m.fpccr[M_REG_S] & R_V7M_FPCCR_TS_MASK;
+ int i;
+ uint32_t fpscr;
+
+ if (fptr & 7) {
+ raise_exception_ra(env, EXCP_UNALIGNED, 0, 1, GETPC());
+ }
+
+ for (i = 0; i < (ts ? 32 : 16); i += 2) {
+ uint32_t slo, shi;
+ uint64_t dn;
+ uint32_t faddr = fptr + 4 * i;
+
+ if (i >= 16) {
+ faddr += 8; /* skip the slot for the FPSCR */
+ }
+
+ slo = cpu_ldl_data_ra(env, faddr, ra);
+ shi = cpu_ldl_data_ra(env, faddr + 4, ra);
+
+ dn = (uint64_t) shi << 32 | slo;
+ *aa32_vfp_dreg(env, i / 2) = dn;
+ }
+ fpscr = cpu_ldl_data_ra(env, fptr + 0x40, ra);
+ vfp_set_fpscr(env, fpscr);
+ }
+
+ env->v7m.control[M_REG_S] |= R_V7M_CONTROL_FPCA_MASK;
+}
+
+static bool v7m_push_stack(ARMCPU *cpu)
+{
+ /*
+ * Do the "set up stack frame" part of exception entry,
+ * similar to pseudocode PushStack().
+ * Return true if we generate a derived exception (and so
+ * should ignore further stack faults trying to process
+ * that derived exception.)
+ */
+ bool stacked_ok = true, limitviol = false;
+ CPUARMState *env = &cpu->env;
+ uint32_t xpsr = xpsr_read(env);
+ uint32_t frameptr = env->regs[13];
+ ARMMMUIdx mmu_idx = arm_mmu_idx(env);
+ uint32_t framesize;
+ bool nsacr_cp10 = extract32(env->v7m.nsacr, 10, 1);
+
+ if ((env->v7m.control[M_REG_S] & R_V7M_CONTROL_FPCA_MASK) &&
+ (env->v7m.secure || nsacr_cp10)) {
+ if (env->v7m.secure &&
+ env->v7m.fpccr[M_REG_S] & R_V7M_FPCCR_TS_MASK) {
+ framesize = 0xa8;
+ } else {
+ framesize = 0x68;
+ }
+ } else {
+ framesize = 0x20;
+ }
+
+ /* Align stack pointer if the guest wants that */
+ if ((frameptr & 4) &&
+ (env->v7m.ccr[env->v7m.secure] & R_V7M_CCR_STKALIGN_MASK)) {
+ frameptr -= 4;
+ xpsr |= XPSR_SPREALIGN;
+ }
+
+ xpsr &= ~XPSR_SFPA;
+ if (env->v7m.secure &&
+ (env->v7m.control[M_REG_S] & R_V7M_CONTROL_SFPA_MASK)) {
+ xpsr |= XPSR_SFPA;
+ }
+
+ frameptr -= framesize;
+
+ if (arm_feature(env, ARM_FEATURE_V8)) {
+ uint32_t limit = v7m_sp_limit(env);
+
+ if (frameptr < limit) {
+ /*
+ * Stack limit failure: set SP to the limit value, and generate
+ * STKOF UsageFault. Stack pushes below the limit must not be
+ * performed. It is IMPDEF whether pushes above the limit are
+ * performed; we choose not to.
+ */
+ qemu_log_mask(CPU_LOG_INT,
+ "...STKOF during stacking\n");
+ env->v7m.cfsr[env->v7m.secure] |= R_V7M_CFSR_STKOF_MASK;
+ armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE,
+ env->v7m.secure);
+ env->regs[13] = limit;
+ /*
+ * We won't try to perform any further memory accesses but
+ * we must continue through the following code to check for
+ * permission faults during FPU state preservation, and we
+ * must update FPCCR if lazy stacking is enabled.
+ */
+ limitviol = true;
+ stacked_ok = false;
+ }
+ }
+
+ /*
+ * Write as much of the stack frame as we can. If we fail a stack
+ * write this will result in a derived exception being pended
+ * (which may be taken in preference to the one we started with
+ * if it has higher priority).
+ */
+ stacked_ok = stacked_ok &&
+ v7m_stack_write(cpu, frameptr, env->regs[0], mmu_idx, STACK_NORMAL) &&
+ v7m_stack_write(cpu, frameptr + 4, env->regs[1],
+ mmu_idx, STACK_NORMAL) &&
+ v7m_stack_write(cpu, frameptr + 8, env->regs[2],
+ mmu_idx, STACK_NORMAL) &&
+ v7m_stack_write(cpu, frameptr + 12, env->regs[3],
+ mmu_idx, STACK_NORMAL) &&
+ v7m_stack_write(cpu, frameptr + 16, env->regs[12],
+ mmu_idx, STACK_NORMAL) &&
+ v7m_stack_write(cpu, frameptr + 20, env->regs[14],
+ mmu_idx, STACK_NORMAL) &&
+ v7m_stack_write(cpu, frameptr + 24, env->regs[15],
+ mmu_idx, STACK_NORMAL) &&
+ v7m_stack_write(cpu, frameptr + 28, xpsr, mmu_idx, STACK_NORMAL);
+
+ if (env->v7m.control[M_REG_S] & R_V7M_CONTROL_FPCA_MASK) {
+ /* FPU is active, try to save its registers */
+ bool fpccr_s = env->v7m.fpccr[M_REG_S] & R_V7M_FPCCR_S_MASK;
+ bool lspact = env->v7m.fpccr[fpccr_s] & R_V7M_FPCCR_LSPACT_MASK;
+
+ if (lspact && arm_feature(env, ARM_FEATURE_M_SECURITY)) {
+ qemu_log_mask(CPU_LOG_INT,
+ "...SecureFault because LSPACT and FPCA both set\n");
+ env->v7m.sfsr |= R_V7M_SFSR_LSERR_MASK;
+ armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_SECURE, false);
+ } else if (!env->v7m.secure && !nsacr_cp10) {
+ qemu_log_mask(CPU_LOG_INT,
+ "...Secure UsageFault with CFSR.NOCP because "
+ "NSACR.CP10 prevents stacking FP regs\n");
+ armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE, M_REG_S);
+ env->v7m.cfsr[M_REG_S] |= R_V7M_CFSR_NOCP_MASK;
+ } else {
+ if (!(env->v7m.fpccr[M_REG_S] & R_V7M_FPCCR_LSPEN_MASK)) {
+ /* Lazy stacking disabled, save registers now */
+ int i;
+ bool cpacr_pass = v7m_cpacr_pass(env, env->v7m.secure,
+ arm_current_el(env) != 0);
+
+ if (stacked_ok && !cpacr_pass) {
+ /*
+ * Take UsageFault if CPACR forbids access. The pseudocode
+ * here does a full CheckCPEnabled() but we know the NSACR
+ * check can never fail as we have already handled that.
+ */
+ qemu_log_mask(CPU_LOG_INT,
+ "...UsageFault with CFSR.NOCP because "
+ "CPACR.CP10 prevents stacking FP regs\n");
+ armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE,
+ env->v7m.secure);
+ env->v7m.cfsr[env->v7m.secure] |= R_V7M_CFSR_NOCP_MASK;
+ stacked_ok = false;
+ }
+
+ for (i = 0; i < ((framesize == 0xa8) ? 32 : 16); i += 2) {
+ uint64_t dn = *aa32_vfp_dreg(env, i / 2);
+ uint32_t faddr = frameptr + 0x20 + 4 * i;
+ uint32_t slo = extract64(dn, 0, 32);
+ uint32_t shi = extract64(dn, 32, 32);
+
+ if (i >= 16) {
+ faddr += 8; /* skip the slot for the FPSCR */
+ }
+ stacked_ok = stacked_ok &&
+ v7m_stack_write(cpu, faddr, slo,
+ mmu_idx, STACK_NORMAL) &&
+ v7m_stack_write(cpu, faddr + 4, shi,
+ mmu_idx, STACK_NORMAL);
+ }
+ stacked_ok = stacked_ok &&
+ v7m_stack_write(cpu, frameptr + 0x60,
+ vfp_get_fpscr(env), mmu_idx, STACK_NORMAL);
+ if (cpacr_pass) {
+ for (i = 0; i < ((framesize == 0xa8) ? 32 : 16); i += 2) {
+ *aa32_vfp_dreg(env, i / 2) = 0;
+ }
+ vfp_set_fpscr(env, 0);
+ }
+ } else {
+ /* Lazy stacking enabled, save necessary info to stack later */
+ v7m_update_fpccr(env, frameptr + 0x20, true);
+ }
+ }
+ }
+
+ /*
+ * If we broke a stack limit then SP was already updated earlier;
+ * otherwise we update SP regardless of whether any of the stack
+ * accesses failed or we took some other kind of fault.
+ */
+ if (!limitviol) {
+ env->regs[13] = frameptr;
+ }
+
+ return !stacked_ok;
+}
+
+static void do_v7m_exception_exit(ARMCPU *cpu)
+{
+ CPUARMState *env = &cpu->env;
+ uint32_t excret;
+ uint32_t xpsr, xpsr_mask;
+ bool ufault = false;
+ bool sfault = false;
+ bool return_to_sp_process;
+ bool return_to_handler;
+ bool rettobase = false;
+ bool exc_secure = false;
+ bool return_to_secure;
+ bool ftype;
+ bool restore_s16_s31;
+
+ /*
+ * If we're not in Handler mode then jumps to magic exception-exit
+ * addresses don't have magic behaviour. However for the v8M
+ * security extensions the magic secure-function-return has to
+ * work in thread mode too, so to avoid doing an extra check in
+ * the generated code we allow exception-exit magic to also cause the
+ * internal exception and bring us here in thread mode. Correct code
+ * will never try to do this (the following insn fetch will always
+ * fault) so we the overhead of having taken an unnecessary exception
+ * doesn't matter.
+ */
+ if (!arm_v7m_is_handler_mode(env)) {
+ return;
+ }
+
+ /*
+ * In the spec pseudocode ExceptionReturn() is called directly
+ * from BXWritePC() and gets the full target PC value including
+ * bit zero. In QEMU's implementation we treat it as a normal
+ * jump-to-register (which is then caught later on), and so split
+ * the target value up between env->regs[15] and env->thumb in
+ * gen_bx(). Reconstitute it.
+ */
+ excret = env->regs[15];
+ if (env->thumb) {
+ excret |= 1;
+ }
+
+ qemu_log_mask(CPU_LOG_INT, "Exception return: magic PC %" PRIx32
+ " previous exception %d\n",
+ excret, env->v7m.exception);
+
+ if ((excret & R_V7M_EXCRET_RES1_MASK) != R_V7M_EXCRET_RES1_MASK) {
+ qemu_log_mask(LOG_GUEST_ERROR, "M profile: zero high bits in exception "
+ "exit PC value 0x%" PRIx32 " are UNPREDICTABLE\n",
+ excret);
+ }
+
+ ftype = excret & R_V7M_EXCRET_FTYPE_MASK;
+
+ if (!arm_feature(env, ARM_FEATURE_VFP) && !ftype) {
+ qemu_log_mask(LOG_GUEST_ERROR, "M profile: zero FTYPE in exception "
+ "exit PC value 0x%" PRIx32 " is UNPREDICTABLE "
+ "if FPU not present\n",
+ excret);
+ ftype = true;
+ }
+
+ if (arm_feature(env, ARM_FEATURE_M_SECURITY)) {
+ /*
+ * EXC_RETURN.ES validation check (R_SMFL). We must do this before
+ * we pick which FAULTMASK to clear.
+ */
+ if (!env->v7m.secure &&
+ ((excret & R_V7M_EXCRET_ES_MASK) ||
+ !(excret & R_V7M_EXCRET_DCRS_MASK))) {
+ sfault = 1;
+ /* For all other purposes, treat ES as 0 (R_HXSR) */
+ excret &= ~R_V7M_EXCRET_ES_MASK;
+ }
+ exc_secure = excret & R_V7M_EXCRET_ES_MASK;
+ }
+
+ if (env->v7m.exception != ARMV7M_EXCP_NMI) {
+ /*
+ * Auto-clear FAULTMASK on return from other than NMI.
+ * If the security extension is implemented then this only
+ * happens if the raw execution priority is >= 0; the
+ * value of the ES bit in the exception return value indicates
+ * which security state's faultmask to clear. (v8M ARM ARM R_KBNF.)
+ */
+ if (arm_feature(env, ARM_FEATURE_M_SECURITY)) {
+ if (armv7m_nvic_raw_execution_priority(env->nvic) >= 0) {
+ env->v7m.faultmask[exc_secure] = 0;
+ }
+ } else {
+ env->v7m.faultmask[M_REG_NS] = 0;
+ }
+ }
+
+ switch (armv7m_nvic_complete_irq(env->nvic, env->v7m.exception,
+ exc_secure)) {
+ case -1:
+ /* attempt to exit an exception that isn't active */
+ ufault = true;
+ break;
+ case 0:
+ /* still an irq active now */
+ break;
+ case 1:
+ /*
+ * We returned to base exception level, no nesting.
+ * (In the pseudocode this is written using "NestedActivation != 1"
+ * where we have 'rettobase == false'.)
+ */
+ rettobase = true;
+ break;
+ default:
+ g_assert_not_reached();
+ }
+
+ return_to_handler = !(excret & R_V7M_EXCRET_MODE_MASK);
+ return_to_sp_process = excret & R_V7M_EXCRET_SPSEL_MASK;
+ return_to_secure = arm_feature(env, ARM_FEATURE_M_SECURITY) &&
+ (excret & R_V7M_EXCRET_S_MASK);
+
+ if (arm_feature(env, ARM_FEATURE_V8)) {
+ if (!arm_feature(env, ARM_FEATURE_M_SECURITY)) {
+ /*
+ * UNPREDICTABLE if S == 1 or DCRS == 0 or ES == 1 (R_XLCP);
+ * we choose to take the UsageFault.
+ */
+ if ((excret & R_V7M_EXCRET_S_MASK) ||
+ (excret & R_V7M_EXCRET_ES_MASK) ||
+ !(excret & R_V7M_EXCRET_DCRS_MASK)) {
+ ufault = true;
+ }
+ }
+ if (excret & R_V7M_EXCRET_RES0_MASK) {
+ ufault = true;
+ }
+ } else {
+ /* For v7M we only recognize certain combinations of the low bits */
+ switch (excret & 0xf) {
+ case 1: /* Return to Handler */
+ break;
+ case 13: /* Return to Thread using Process stack */
+ case 9: /* Return to Thread using Main stack */
+ /*
+ * We only need to check NONBASETHRDENA for v7M, because in
+ * v8M this bit does not exist (it is RES1).
+ */
+ if (!rettobase &&
+ !(env->v7m.ccr[env->v7m.secure] &
+ R_V7M_CCR_NONBASETHRDENA_MASK)) {
+ ufault = true;
+ }
+ break;
+ default:
+ ufault = true;
+ }
+ }
+
+ /*
+ * Set CONTROL.SPSEL from excret.SPSEL. Since we're still in
+ * Handler mode (and will be until we write the new XPSR.Interrupt
+ * field) this does not switch around the current stack pointer.
+ * We must do this before we do any kind of tailchaining, including
+ * for the derived exceptions on integrity check failures, or we will
+ * give the guest an incorrect EXCRET.SPSEL value on exception entry.
+ */
+ write_v7m_control_spsel_for_secstate(env, return_to_sp_process, exc_secure);
+
+ /*
+ * Clear scratch FP values left in caller saved registers; this
+ * must happen before any kind of tail chaining.
+ */
+ if ((env->v7m.fpccr[M_REG_S] & R_V7M_FPCCR_CLRONRET_MASK) &&
+ (env->v7m.control[M_REG_S] & R_V7M_CONTROL_FPCA_MASK)) {
+ if (env->v7m.fpccr[M_REG_S] & R_V7M_FPCCR_LSPACT_MASK) {
+ env->v7m.sfsr |= R_V7M_SFSR_LSERR_MASK;
+ armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_SECURE, false);
+ qemu_log_mask(CPU_LOG_INT, "...taking SecureFault on existing "
+ "stackframe: error during lazy state deactivation\n");
+ v7m_exception_taken(cpu, excret, true, false);
+ return;
+ } else {
+ /* Clear s0..s15 and FPSCR */
+ int i;
+
+ for (i = 0; i < 16; i += 2) {
+ *aa32_vfp_dreg(env, i / 2) = 0;
+ }
+ vfp_set_fpscr(env, 0);
+ }
+ }
+
+ if (sfault) {
+ env->v7m.sfsr |= R_V7M_SFSR_INVER_MASK;
+ armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_SECURE, false);
+ qemu_log_mask(CPU_LOG_INT, "...taking SecureFault on existing "
+ "stackframe: failed EXC_RETURN.ES validity check\n");
+ v7m_exception_taken(cpu, excret, true, false);
+ return;
+ }
+
+ if (ufault) {
+ /*
+ * Bad exception return: instead of popping the exception
+ * stack, directly take a usage fault on the current stack.
+ */
+ env->v7m.cfsr[env->v7m.secure] |= R_V7M_CFSR_INVPC_MASK;
+ armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE, env->v7m.secure);
+ qemu_log_mask(CPU_LOG_INT, "...taking UsageFault on existing "
+ "stackframe: failed exception return integrity check\n");
+ v7m_exception_taken(cpu, excret, true, false);
+ return;
+ }
+
+ /*
+ * Tailchaining: if there is currently a pending exception that
+ * is high enough priority to preempt execution at the level we're
+ * about to return to, then just directly take that exception now,
+ * avoiding an unstack-and-then-stack. Note that now we have
+ * deactivated the previous exception by calling armv7m_nvic_complete_irq()
+ * our current execution priority is already the execution priority we are
+ * returning to -- none of the state we would unstack or set based on
+ * the EXCRET value affects it.
+ */
+ if (armv7m_nvic_can_take_pending_exception(env->nvic)) {
+ qemu_log_mask(CPU_LOG_INT, "...tailchaining to pending exception\n");
+ v7m_exception_taken(cpu, excret, true, false);
+ return;
+ }
+
+ switch_v7m_security_state(env, return_to_secure);
+
+ {
+ /*
+ * The stack pointer we should be reading the exception frame from
+ * depends on bits in the magic exception return type value (and
+ * for v8M isn't necessarily the stack pointer we will eventually
+ * end up resuming execution with). Get a pointer to the location
+ * in the CPU state struct where the SP we need is currently being
+ * stored; we will use and modify it in place.
+ * We use this limited C variable scope so we don't accidentally
+ * use 'frame_sp_p' after we do something that makes it invalid.
+ */
+ uint32_t *frame_sp_p = get_v7m_sp_ptr(env,
+ return_to_secure,
+ !return_to_handler,
+ return_to_sp_process);
+ uint32_t frameptr = *frame_sp_p;
+ bool pop_ok = true;
+ ARMMMUIdx mmu_idx;
+ bool return_to_priv = return_to_handler ||
+ !(env->v7m.control[return_to_secure] & R_V7M_CONTROL_NPRIV_MASK);
+
+ mmu_idx = arm_v7m_mmu_idx_for_secstate_and_priv(env, return_to_secure,
+ return_to_priv);
+
+ if (!QEMU_IS_ALIGNED(frameptr, 8) &&
+ arm_feature(env, ARM_FEATURE_V8)) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "M profile exception return with non-8-aligned SP "
+ "for destination state is UNPREDICTABLE\n");
+ }
+
+ /* Do we need to pop callee-saved registers? */
+ if (return_to_secure &&
+ ((excret & R_V7M_EXCRET_ES_MASK) == 0 ||
+ (excret & R_V7M_EXCRET_DCRS_MASK) == 0)) {
+ uint32_t actual_sig;
+
+ pop_ok = v7m_stack_read(cpu, &actual_sig, frameptr, mmu_idx);
+
+ if (pop_ok && v7m_integrity_sig(env, excret) != actual_sig) {
+ /* Take a SecureFault on the current stack */
+ env->v7m.sfsr |= R_V7M_SFSR_INVIS_MASK;
+ armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_SECURE, false);
+ qemu_log_mask(CPU_LOG_INT, "...taking SecureFault on existing "
+ "stackframe: failed exception return integrity "
+ "signature check\n");
+ v7m_exception_taken(cpu, excret, true, false);
+ return;
+ }
+
+ pop_ok = pop_ok &&
+ v7m_stack_read(cpu, &env->regs[4], frameptr + 0x8, mmu_idx) &&
+ v7m_stack_read(cpu, &env->regs[5], frameptr + 0xc, mmu_idx) &&
+ v7m_stack_read(cpu, &env->regs[6], frameptr + 0x10, mmu_idx) &&
+ v7m_stack_read(cpu, &env->regs[7], frameptr + 0x14, mmu_idx) &&
+ v7m_stack_read(cpu, &env->regs[8], frameptr + 0x18, mmu_idx) &&
+ v7m_stack_read(cpu, &env->regs[9], frameptr + 0x1c, mmu_idx) &&
+ v7m_stack_read(cpu, &env->regs[10], frameptr + 0x20, mmu_idx) &&
+ v7m_stack_read(cpu, &env->regs[11], frameptr + 0x24, mmu_idx);
+
+ frameptr += 0x28;
+ }
+
+ /* Pop registers */
+ pop_ok = pop_ok &&
+ v7m_stack_read(cpu, &env->regs[0], frameptr, mmu_idx) &&
+ v7m_stack_read(cpu, &env->regs[1], frameptr + 0x4, mmu_idx) &&
+ v7m_stack_read(cpu, &env->regs[2], frameptr + 0x8, mmu_idx) &&
+ v7m_stack_read(cpu, &env->regs[3], frameptr + 0xc, mmu_idx) &&
+ v7m_stack_read(cpu, &env->regs[12], frameptr + 0x10, mmu_idx) &&
+ v7m_stack_read(cpu, &env->regs[14], frameptr + 0x14, mmu_idx) &&
+ v7m_stack_read(cpu, &env->regs[15], frameptr + 0x18, mmu_idx) &&
+ v7m_stack_read(cpu, &xpsr, frameptr + 0x1c, mmu_idx);
+
+ if (!pop_ok) {
+ /*
+ * v7m_stack_read() pended a fault, so take it (as a tail
+ * chained exception on the same stack frame)
+ */
+ qemu_log_mask(CPU_LOG_INT, "...derived exception on unstacking\n");
+ v7m_exception_taken(cpu, excret, true, false);
+ return;
+ }
+
+ /*
+ * Returning from an exception with a PC with bit 0 set is defined
+ * behaviour on v8M (bit 0 is ignored), but for v7M it was specified
+ * to be UNPREDICTABLE. In practice actual v7M hardware seems to ignore
+ * the lsbit, and there are several RTOSes out there which incorrectly
+ * assume the r15 in the stack frame should be a Thumb-style "lsbit
+ * indicates ARM/Thumb" value, so ignore the bit on v7M as well, but
+ * complain about the badly behaved guest.
+ */
+ if (env->regs[15] & 1) {
+ env->regs[15] &= ~1U;
+ if (!arm_feature(env, ARM_FEATURE_V8)) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "M profile return from interrupt with misaligned "
+ "PC is UNPREDICTABLE on v7M\n");
+ }
+ }
+
+ if (arm_feature(env, ARM_FEATURE_V8)) {
+ /*
+ * For v8M we have to check whether the xPSR exception field
+ * matches the EXCRET value for return to handler/thread
+ * before we commit to changing the SP and xPSR.
+ */
+ bool will_be_handler = (xpsr & XPSR_EXCP) != 0;
+ if (return_to_handler != will_be_handler) {
+ /*
+ * Take an INVPC UsageFault on the current stack.
+ * By this point we will have switched to the security state
+ * for the background state, so this UsageFault will target
+ * that state.
+ */
+ armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE,
+ env->v7m.secure);
+ env->v7m.cfsr[env->v7m.secure] |= R_V7M_CFSR_INVPC_MASK;
+ qemu_log_mask(CPU_LOG_INT, "...taking UsageFault on existing "
+ "stackframe: failed exception return integrity "
+ "check\n");
+ v7m_exception_taken(cpu, excret, true, false);
+ return;
+ }
+ }
+
+ if (!ftype) {
+ /* FP present and we need to handle it */
+ if (!return_to_secure &&
+ (env->v7m.fpccr[M_REG_S] & R_V7M_FPCCR_LSPACT_MASK)) {
+ armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_SECURE, false);
+ env->v7m.sfsr |= R_V7M_SFSR_LSERR_MASK;
+ qemu_log_mask(CPU_LOG_INT,
+ "...taking SecureFault on existing stackframe: "
+ "Secure LSPACT set but exception return is "
+ "not to secure state\n");
+ v7m_exception_taken(cpu, excret, true, false);
+ return;
+ }
+
+ restore_s16_s31 = return_to_secure &&
+ (env->v7m.fpccr[M_REG_S] & R_V7M_FPCCR_TS_MASK);
+
+ if (env->v7m.fpccr[return_to_secure] & R_V7M_FPCCR_LSPACT_MASK) {
+ /* State in FPU is still valid, just clear LSPACT */
+ env->v7m.fpccr[return_to_secure] &= ~R_V7M_FPCCR_LSPACT_MASK;
+ } else {
+ int i;
+ uint32_t fpscr;
+ bool cpacr_pass, nsacr_pass;
+
+ cpacr_pass = v7m_cpacr_pass(env, return_to_secure,
+ return_to_priv);
+ nsacr_pass = return_to_secure ||
+ extract32(env->v7m.nsacr, 10, 1);
+
+ if (!cpacr_pass) {
+ armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE,
+ return_to_secure);
+ env->v7m.cfsr[return_to_secure] |= R_V7M_CFSR_NOCP_MASK;
+ qemu_log_mask(CPU_LOG_INT,
+ "...taking UsageFault on existing "
+ "stackframe: CPACR.CP10 prevents unstacking "
+ "FP regs\n");
+ v7m_exception_taken(cpu, excret, true, false);
+ return;
+ } else if (!nsacr_pass) {
+ armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE, true);
+ env->v7m.cfsr[M_REG_S] |= R_V7M_CFSR_INVPC_MASK;
+ qemu_log_mask(CPU_LOG_INT,
+ "...taking Secure UsageFault on existing "
+ "stackframe: NSACR.CP10 prevents unstacking "
+ "FP regs\n");
+ v7m_exception_taken(cpu, excret, true, false);
+ return;
+ }
+
+ for (i = 0; i < (restore_s16_s31 ? 32 : 16); i += 2) {
+ uint32_t slo, shi;
+ uint64_t dn;
+ uint32_t faddr = frameptr + 0x20 + 4 * i;
+
+ if (i >= 16) {
+ faddr += 8; /* Skip the slot for the FPSCR */
+ }
+
+ pop_ok = pop_ok &&
+ v7m_stack_read(cpu, &slo, faddr, mmu_idx) &&
+ v7m_stack_read(cpu, &shi, faddr + 4, mmu_idx);
+
+ if (!pop_ok) {
+ break;
+ }
+
+ dn = (uint64_t)shi << 32 | slo;
+ *aa32_vfp_dreg(env, i / 2) = dn;
+ }
+ pop_ok = pop_ok &&
+ v7m_stack_read(cpu, &fpscr, frameptr + 0x60, mmu_idx);
+ if (pop_ok) {
+ vfp_set_fpscr(env, fpscr);
+ }
+ if (!pop_ok) {
+ /*
+ * These regs are 0 if security extension present;
+ * otherwise merely UNKNOWN. We zero always.
+ */
+ for (i = 0; i < (restore_s16_s31 ? 32 : 16); i += 2) {
+ *aa32_vfp_dreg(env, i / 2) = 0;
+ }
+ vfp_set_fpscr(env, 0);
+ }
+ }
+ }
+ env->v7m.control[M_REG_S] = FIELD_DP32(env->v7m.control[M_REG_S],
+ V7M_CONTROL, FPCA, !ftype);
+
+ /* Commit to consuming the stack frame */
+ frameptr += 0x20;
+ if (!ftype) {
+ frameptr += 0x48;
+ if (restore_s16_s31) {
+ frameptr += 0x40;
+ }
+ }
+ /*
+ * Undo stack alignment (the SPREALIGN bit indicates that the original
+ * pre-exception SP was not 8-aligned and we added a padding word to
+ * align it, so we undo this by ORing in the bit that increases it
+ * from the current 8-aligned value to the 8-unaligned value. (Adding 4
+ * would work too but a logical OR is how the pseudocode specifies it.)
+ */
+ if (xpsr & XPSR_SPREALIGN) {
+ frameptr |= 4;
+ }
+ *frame_sp_p = frameptr;
+ }
+
+ xpsr_mask = ~(XPSR_SPREALIGN | XPSR_SFPA);
+ if (!arm_feature(env, ARM_FEATURE_THUMB_DSP)) {
+ xpsr_mask &= ~XPSR_GE;
+ }
+ /* This xpsr_write() will invalidate frame_sp_p as it may switch stack */
+ xpsr_write(env, xpsr, xpsr_mask);
+
+ if (env->v7m.secure) {
+ bool sfpa = xpsr & XPSR_SFPA;
+
+ env->v7m.control[M_REG_S] = FIELD_DP32(env->v7m.control[M_REG_S],
+ V7M_CONTROL, SFPA, sfpa);
+ }
+
+ /*
+ * The restored xPSR exception field will be zero if we're
+ * resuming in Thread mode. If that doesn't match what the
+ * exception return excret specified then this is a UsageFault.
+ * v7M requires we make this check here; v8M did it earlier.
+ */
+ if (return_to_handler != arm_v7m_is_handler_mode(env)) {
+ /*
+ * Take an INVPC UsageFault by pushing the stack again;
+ * we know we're v7M so this is never a Secure UsageFault.
+ */
+ bool ignore_stackfaults;
+
+ assert(!arm_feature(env, ARM_FEATURE_V8));
+ armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE, false);
+ env->v7m.cfsr[env->v7m.secure] |= R_V7M_CFSR_INVPC_MASK;
+ ignore_stackfaults = v7m_push_stack(cpu);
+ qemu_log_mask(CPU_LOG_INT, "...taking UsageFault on new stackframe: "
+ "failed exception return integrity check\n");
+ v7m_exception_taken(cpu, excret, false, ignore_stackfaults);
+ return;
+ }
+
+ /* Otherwise, we have a successful exception exit. */
+ arm_clear_exclusive(env);
+ qemu_log_mask(CPU_LOG_INT, "...successful exception return\n");
+}
+
+static bool do_v7m_function_return(ARMCPU *cpu)
+{
+ /*
+ * v8M security extensions magic function return.
+ * We may either:
+ * (1) throw an exception (longjump)
+ * (2) return true if we successfully handled the function return
+ * (3) return false if we failed a consistency check and have
+ * pended a UsageFault that needs to be taken now
+ *
+ * At this point the magic return value is split between env->regs[15]
+ * and env->thumb. We don't bother to reconstitute it because we don't
+ * need it (all values are handled the same way).
+ */
+ CPUARMState *env = &cpu->env;
+ uint32_t newpc, newpsr, newpsr_exc;
+
+ qemu_log_mask(CPU_LOG_INT, "...really v7M secure function return\n");
+
+ {
+ bool threadmode, spsel;
+ TCGMemOpIdx oi;
+ ARMMMUIdx mmu_idx;
+ uint32_t *frame_sp_p;
+ uint32_t frameptr;
+
+ /* Pull the return address and IPSR from the Secure stack */
+ threadmode = !arm_v7m_is_handler_mode(env);
+ spsel = env->v7m.control[M_REG_S] & R_V7M_CONTROL_SPSEL_MASK;
+
+ frame_sp_p = get_v7m_sp_ptr(env, true, threadmode, spsel);
+ frameptr = *frame_sp_p;
+
+ /*
+ * These loads may throw an exception (for MPU faults). We want to
+ * do them as secure, so work out what MMU index that is.
+ */
+ mmu_idx = arm_v7m_mmu_idx_for_secstate(env, true);
+ oi = make_memop_idx(MO_LE, arm_to_core_mmu_idx(mmu_idx));
+ newpc = helper_le_ldul_mmu(env, frameptr, oi, 0);
+ newpsr = helper_le_ldul_mmu(env, frameptr + 4, oi, 0);
+
+ /* Consistency checks on new IPSR */
+ newpsr_exc = newpsr & XPSR_EXCP;
+ if (!((env->v7m.exception == 0 && newpsr_exc == 0) ||
+ (env->v7m.exception == 1 && newpsr_exc != 0))) {
+ /* Pend the fault and tell our caller to take it */
+ env->v7m.cfsr[env->v7m.secure] |= R_V7M_CFSR_INVPC_MASK;
+ armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE,
+ env->v7m.secure);
+ qemu_log_mask(CPU_LOG_INT,
+ "...taking INVPC UsageFault: "
+ "IPSR consistency check failed\n");
+ return false;
+ }
+
+ *frame_sp_p = frameptr + 8;
+ }
+
+ /* This invalidates frame_sp_p */
+ switch_v7m_security_state(env, true);
+ env->v7m.exception = newpsr_exc;
+ env->v7m.control[M_REG_S] &= ~R_V7M_CONTROL_SFPA_MASK;
+ if (newpsr & XPSR_SFPA) {
+ env->v7m.control[M_REG_S] |= R_V7M_CONTROL_SFPA_MASK;
+ }
+ xpsr_write(env, 0, XPSR_IT);
+ env->thumb = newpc & 1;
+ env->regs[15] = newpc & ~1;
+
+ qemu_log_mask(CPU_LOG_INT, "...function return successful\n");
+ return true;
+}
+
+static bool v7m_read_half_insn(ARMCPU *cpu, ARMMMUIdx mmu_idx,
+ uint32_t addr, uint16_t *insn)
+{
+ /*
+ * Load a 16-bit portion of a v7M instruction, returning true on success,
+ * or false on failure (in which case we will have pended the appropriate
+ * exception).
+ * We need to do the instruction fetch's MPU and SAU checks
+ * like this because there is no MMU index that would allow
+ * doing the load with a single function call. Instead we must
+ * first check that the security attributes permit the load
+ * and that they don't mismatch on the two halves of the instruction,
+ * and then we do the load as a secure load (ie using the security
+ * attributes of the address, not the CPU, as architecturally required).
+ */
+ CPUState *cs = CPU(cpu);
+ CPUARMState *env = &cpu->env;
+ V8M_SAttributes sattrs = {};
+ MemTxAttrs attrs = {};
+ ARMMMUFaultInfo fi = {};
+ MemTxResult txres;
+ target_ulong page_size;
+ hwaddr physaddr;
+ int prot;
+
+ v8m_security_lookup(env, addr, MMU_INST_FETCH, mmu_idx, &sattrs);
+ if (!sattrs.nsc || sattrs.ns) {
+ /*
+ * This must be the second half of the insn, and it straddles a
+ * region boundary with the second half not being S&NSC.
+ */
+ env->v7m.sfsr |= R_V7M_SFSR_INVEP_MASK;
+ armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_SECURE, false);
+ qemu_log_mask(CPU_LOG_INT,
+ "...really SecureFault with SFSR.INVEP\n");
+ return false;
+ }
+ if (get_phys_addr(env, addr, MMU_INST_FETCH, mmu_idx,
+ &physaddr, &attrs, &prot, &page_size, &fi, NULL)) {
+ /* the MPU lookup failed */
+ env->v7m.cfsr[env->v7m.secure] |= R_V7M_CFSR_IACCVIOL_MASK;
+ armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_MEM, env->v7m.secure);
+ qemu_log_mask(CPU_LOG_INT, "...really MemManage with CFSR.IACCVIOL\n");
+ return false;
+ }
+ *insn = address_space_lduw_le(arm_addressspace(cs, attrs), physaddr,
+ attrs, &txres);
+ if (txres != MEMTX_OK) {
+ env->v7m.cfsr[M_REG_NS] |= R_V7M_CFSR_IBUSERR_MASK;
+ armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_BUS, false);
+ qemu_log_mask(CPU_LOG_INT, "...really BusFault with CFSR.IBUSERR\n");
+ return false;
+ }
+ return true;
+}
+
+static bool v7m_handle_execute_nsc(ARMCPU *cpu)
+{
+ /*
+ * Check whether this attempt to execute code in a Secure & NS-Callable
+ * memory region is for an SG instruction; if so, then emulate the
+ * effect of the SG instruction and return true. Otherwise pend
+ * the correct kind of exception and return false.
+ */
+ CPUARMState *env = &cpu->env;
+ ARMMMUIdx mmu_idx;
+ uint16_t insn;
+
+ /*
+ * We should never get here unless get_phys_addr_pmsav8() caused
+ * an exception for NS executing in S&NSC memory.
+ */
+ assert(!env->v7m.secure);
+ assert(arm_feature(env, ARM_FEATURE_M_SECURITY));
+
+ /* We want to do the MPU lookup as secure; work out what mmu_idx that is */
+ mmu_idx = arm_v7m_mmu_idx_for_secstate(env, true);
+
+ if (!v7m_read_half_insn(cpu, mmu_idx, env->regs[15], &insn)) {
+ return false;
+ }
+
+ if (!env->thumb) {
+ goto gen_invep;
+ }
+
+ if (insn != 0xe97f) {
+ /*
+ * Not an SG instruction first half (we choose the IMPDEF
+ * early-SG-check option).
+ */
+ goto gen_invep;
+ }
+
+ if (!v7m_read_half_insn(cpu, mmu_idx, env->regs[15] + 2, &insn)) {
+ return false;
+ }
+
+ if (insn != 0xe97f) {
+ /*
+ * Not an SG instruction second half (yes, both halves of the SG
+ * insn have the same hex value)
+ */
+ goto gen_invep;
+ }
+
+ /*
+ * OK, we have confirmed that we really have an SG instruction.
+ * We know we're NS in S memory so don't need to repeat those checks.
+ */
+ qemu_log_mask(CPU_LOG_INT, "...really an SG instruction at 0x%08" PRIx32
+ ", executing it\n", env->regs[15]);
+ env->regs[14] &= ~1;
+ env->v7m.control[M_REG_S] &= ~R_V7M_CONTROL_SFPA_MASK;
+ switch_v7m_security_state(env, true);
+ xpsr_write(env, 0, XPSR_IT);
+ env->regs[15] += 4;
+ return true;
+
+gen_invep:
+ env->v7m.sfsr |= R_V7M_SFSR_INVEP_MASK;
+ armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_SECURE, false);
+ qemu_log_mask(CPU_LOG_INT,
+ "...really SecureFault with SFSR.INVEP\n");
+ return false;
+}
+
+void arm_v7m_cpu_do_interrupt(CPUState *cs)
+{
+ ARMCPU *cpu = ARM_CPU(cs);
+ CPUARMState *env = &cpu->env;
+ uint32_t lr;
+ bool ignore_stackfaults;
+
+ arm_log_exception(cs->exception_index);
+
+ /*
+ * For exceptions we just mark as pending on the NVIC, and let that
+ * handle it.
+ */
+ switch (cs->exception_index) {
+ case EXCP_UDEF:
+ armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE, env->v7m.secure);
+ env->v7m.cfsr[env->v7m.secure] |= R_V7M_CFSR_UNDEFINSTR_MASK;
+ break;
+ case EXCP_NOCP:
+ {
+ /*
+ * NOCP might be directed to something other than the current
+ * security state if this fault is because of NSACR; we indicate
+ * the target security state using exception.target_el.
+ */
+ int target_secstate;
+
+ if (env->exception.target_el == 3) {
+ target_secstate = M_REG_S;
+ } else {
+ target_secstate = env->v7m.secure;
+ }
+ armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE, target_secstate);
+ env->v7m.cfsr[target_secstate] |= R_V7M_CFSR_NOCP_MASK;
+ break;
+ }
+ case EXCP_INVSTATE:
+ armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE, env->v7m.secure);
+ env->v7m.cfsr[env->v7m.secure] |= R_V7M_CFSR_INVSTATE_MASK;
+ break;
+ case EXCP_STKOF:
+ armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE, env->v7m.secure);
+ env->v7m.cfsr[env->v7m.secure] |= R_V7M_CFSR_STKOF_MASK;
+ break;
+ case EXCP_LSERR:
+ armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_SECURE, false);
+ env->v7m.sfsr |= R_V7M_SFSR_LSERR_MASK;
+ break;
+ case EXCP_UNALIGNED:
+ armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE, env->v7m.secure);
+ env->v7m.cfsr[env->v7m.secure] |= R_V7M_CFSR_UNALIGNED_MASK;
+ break;
+ case EXCP_SWI:
+ /* The PC already points to the next instruction. */
+ armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_SVC, env->v7m.secure);
+ break;
+ case EXCP_PREFETCH_ABORT:
+ case EXCP_DATA_ABORT:
+ /*
+ * Note that for M profile we don't have a guest facing FSR, but
+ * the env->exception.fsr will be populated by the code that
+ * raises the fault, in the A profile short-descriptor format.
+ */
+ switch (env->exception.fsr & 0xf) {
+ case M_FAKE_FSR_NSC_EXEC:
+ /*
+ * Exception generated when we try to execute code at an address
+ * which is marked as Secure & Non-Secure Callable and the CPU
+ * is in the Non-Secure state. The only instruction which can
+ * be executed like this is SG (and that only if both halves of
+ * the SG instruction have the same security attributes.)
+ * Everything else must generate an INVEP SecureFault, so we
+ * emulate the SG instruction here.
+ */
+ if (v7m_handle_execute_nsc(cpu)) {
+ return;
+ }
+ break;
+ case M_FAKE_FSR_SFAULT:
+ /*
+ * Various flavours of SecureFault for attempts to execute or
+ * access data in the wrong security state.
+ */
+ switch (cs->exception_index) {
+ case EXCP_PREFETCH_ABORT:
+ if (env->v7m.secure) {
+ env->v7m.sfsr |= R_V7M_SFSR_INVTRAN_MASK;
+ qemu_log_mask(CPU_LOG_INT,
+ "...really SecureFault with SFSR.INVTRAN\n");
+ } else {
+ env->v7m.sfsr |= R_V7M_SFSR_INVEP_MASK;
+ qemu_log_mask(CPU_LOG_INT,
+ "...really SecureFault with SFSR.INVEP\n");
+ }
+ break;
+ case EXCP_DATA_ABORT:
+ /* This must be an NS access to S memory */
+ env->v7m.sfsr |= R_V7M_SFSR_AUVIOL_MASK;
+ qemu_log_mask(CPU_LOG_INT,
+ "...really SecureFault with SFSR.AUVIOL\n");
+ break;
+ }
+ armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_SECURE, false);
+ break;
+ case 0x8: /* External Abort */
+ switch (cs->exception_index) {
+ case EXCP_PREFETCH_ABORT:
+ env->v7m.cfsr[M_REG_NS] |= R_V7M_CFSR_IBUSERR_MASK;
+ qemu_log_mask(CPU_LOG_INT, "...with CFSR.IBUSERR\n");
+ break;
+ case EXCP_DATA_ABORT:
+ env->v7m.cfsr[M_REG_NS] |=
+ (R_V7M_CFSR_PRECISERR_MASK | R_V7M_CFSR_BFARVALID_MASK);
+ env->v7m.bfar = env->exception.vaddress;
+ qemu_log_mask(CPU_LOG_INT,
+ "...with CFSR.PRECISERR and BFAR 0x%x\n",
+ env->v7m.bfar);
+ break;
+ }
+ armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_BUS, false);
+ break;
+ default:
+ /*
+ * All other FSR values are either MPU faults or "can't happen
+ * for M profile" cases.
+ */
+ switch (cs->exception_index) {
+ case EXCP_PREFETCH_ABORT:
+ env->v7m.cfsr[env->v7m.secure] |= R_V7M_CFSR_IACCVIOL_MASK;
+ qemu_log_mask(CPU_LOG_INT, "...with CFSR.IACCVIOL\n");
+ break;
+ case EXCP_DATA_ABORT:
+ env->v7m.cfsr[env->v7m.secure] |=
+ (R_V7M_CFSR_DACCVIOL_MASK | R_V7M_CFSR_MMARVALID_MASK);
+ env->v7m.mmfar[env->v7m.secure] = env->exception.vaddress;
+ qemu_log_mask(CPU_LOG_INT,
+ "...with CFSR.DACCVIOL and MMFAR 0x%x\n",
+ env->v7m.mmfar[env->v7m.secure]);
+ break;
+ }
+ armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_MEM,
+ env->v7m.secure);
+ break;
+ }
+ break;
+ case EXCP_BKPT:
+ if (semihosting_enabled()) {
+ int nr;
+ nr = arm_lduw_code(env, env->regs[15], arm_sctlr_b(env)) & 0xff;
+ if (nr == 0xab) {
+ env->regs[15] += 2;
+ qemu_log_mask(CPU_LOG_INT,
+ "...handling as semihosting call 0x%x\n",
+ env->regs[0]);
+ env->regs[0] = do_arm_semihosting(env);
+ return;
+ }
+ }
+ armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_DEBUG, false);
+ break;
+ case EXCP_IRQ:
+ break;
+ case EXCP_EXCEPTION_EXIT:
+ if (env->regs[15] < EXC_RETURN_MIN_MAGIC) {
+ /* Must be v8M security extension function return */
+ assert(env->regs[15] >= FNC_RETURN_MIN_MAGIC);
+ assert(arm_feature(env, ARM_FEATURE_M_SECURITY));
+ if (do_v7m_function_return(cpu)) {
+ return;
+ }
+ } else {
+ do_v7m_exception_exit(cpu);
+ return;
+ }
+ break;
+ case EXCP_LAZYFP:
+ /*
+ * We already pended the specific exception in the NVIC in the
+ * v7m_preserve_fp_state() helper function.
+ */
+ break;
+ default:
+ cpu_abort(cs, "Unhandled exception 0x%x\n", cs->exception_index);
+ return; /* Never happens. Keep compiler happy. */
+ }
+
+ if (arm_feature(env, ARM_FEATURE_V8)) {
+ lr = R_V7M_EXCRET_RES1_MASK |
+ R_V7M_EXCRET_DCRS_MASK;
+ /*
+ * The S bit indicates whether we should return to Secure
+ * or NonSecure (ie our current state).
+ * The ES bit indicates whether we're taking this exception
+ * to Secure or NonSecure (ie our target state). We set it
+ * later, in v7m_exception_taken().
+ * The SPSEL bit is also set in v7m_exception_taken() for v8M.
+ * This corresponds to the ARM ARM pseudocode for v8M setting
+ * some LR bits in PushStack() and some in ExceptionTaken();
+ * the distinction matters for the tailchain cases where we
+ * can take an exception without pushing the stack.
+ */
+ if (env->v7m.secure) {
+ lr |= R_V7M_EXCRET_S_MASK;
+ }
+ if (!(env->v7m.control[M_REG_S] & R_V7M_CONTROL_FPCA_MASK)) {
+ lr |= R_V7M_EXCRET_FTYPE_MASK;
+ }
+ } else {
+ lr = R_V7M_EXCRET_RES1_MASK |
+ R_V7M_EXCRET_S_MASK |
+ R_V7M_EXCRET_DCRS_MASK |
+ R_V7M_EXCRET_FTYPE_MASK |
+ R_V7M_EXCRET_ES_MASK;
+ if (env->v7m.control[M_REG_NS] & R_V7M_CONTROL_SPSEL_MASK) {
+ lr |= R_V7M_EXCRET_SPSEL_MASK;
+ }
+ }
+ if (!arm_v7m_is_handler_mode(env)) {
+ lr |= R_V7M_EXCRET_MODE_MASK;
+ }
+
+ ignore_stackfaults = v7m_push_stack(cpu);
+ v7m_exception_taken(cpu, lr, false, ignore_stackfaults);
+}
+
+uint32_t HELPER(v7m_mrs)(CPUARMState *env, uint32_t reg)
+{
+ uint32_t mask;
+ unsigned el = arm_current_el(env);
+
+ /* First handle registers which unprivileged can read */
+
+ switch (reg) {
+ case 0 ... 7: /* xPSR sub-fields */
+ mask = 0;
+ if ((reg & 1) && el) {
+ mask |= XPSR_EXCP; /* IPSR (unpriv. reads as zero) */
+ }
+ if (!(reg & 4)) {
+ mask |= XPSR_NZCV | XPSR_Q; /* APSR */
+ if (arm_feature(env, ARM_FEATURE_THUMB_DSP)) {
+ mask |= XPSR_GE;
+ }
+ }
+ /* EPSR reads as zero */
+ return xpsr_read(env) & mask;
+ break;
+ case 20: /* CONTROL */
+ {
+ uint32_t value = env->v7m.control[env->v7m.secure];
+ if (!env->v7m.secure) {
+ /* SFPA is RAZ/WI from NS; FPCA is stored in the M_REG_S bank */
+ value |= env->v7m.control[M_REG_S] & R_V7M_CONTROL_FPCA_MASK;
+ }
+ return value;
+ }
+ case 0x94: /* CONTROL_NS */
+ /*
+ * We have to handle this here because unprivileged Secure code
+ * can read the NS CONTROL register.
+ */
+ if (!env->v7m.secure) {
+ return 0;
+ }
+ return env->v7m.control[M_REG_NS] |
+ (env->v7m.control[M_REG_S] & R_V7M_CONTROL_FPCA_MASK);
+ }
+
+ if (el == 0) {
+ return 0; /* unprivileged reads others as zero */
+ }
+
+ if (arm_feature(env, ARM_FEATURE_M_SECURITY)) {
+ switch (reg) {
+ case 0x88: /* MSP_NS */
+ if (!env->v7m.secure) {
+ return 0;
+ }
+ return env->v7m.other_ss_msp;
+ case 0x89: /* PSP_NS */
+ if (!env->v7m.secure) {
+ return 0;
+ }
+ return env->v7m.other_ss_psp;
+ case 0x8a: /* MSPLIM_NS */
+ if (!env->v7m.secure) {
+ return 0;
+ }
+ return env->v7m.msplim[M_REG_NS];
+ case 0x8b: /* PSPLIM_NS */
+ if (!env->v7m.secure) {
+ return 0;
+ }
+ return env->v7m.psplim[M_REG_NS];
+ case 0x90: /* PRIMASK_NS */
+ if (!env->v7m.secure) {
+ return 0;
+ }
+ return env->v7m.primask[M_REG_NS];
+ case 0x91: /* BASEPRI_NS */
+ if (!env->v7m.secure) {
+ return 0;
+ }
+ return env->v7m.basepri[M_REG_NS];
+ case 0x93: /* FAULTMASK_NS */
+ if (!env->v7m.secure) {
+ return 0;
+ }
+ return env->v7m.faultmask[M_REG_NS];
+ case 0x98: /* SP_NS */
+ {
+ /*
+ * This gives the non-secure SP selected based on whether we're
+ * currently in handler mode or not, using the NS CONTROL.SPSEL.
+ */
+ bool spsel = env->v7m.control[M_REG_NS] & R_V7M_CONTROL_SPSEL_MASK;
+
+ if (!env->v7m.secure) {
+ return 0;
+ }
+ if (!arm_v7m_is_handler_mode(env) && spsel) {
+ return env->v7m.other_ss_psp;
+ } else {
+ return env->v7m.other_ss_msp;
+ }
+ }
+ default:
+ break;
+ }
+ }
+
+ switch (reg) {
+ case 8: /* MSP */
+ return v7m_using_psp(env) ? env->v7m.other_sp : env->regs[13];
+ case 9: /* PSP */
+ return v7m_using_psp(env) ? env->regs[13] : env->v7m.other_sp;
+ case 10: /* MSPLIM */
+ if (!arm_feature(env, ARM_FEATURE_V8)) {
+ goto bad_reg;
+ }
+ return env->v7m.msplim[env->v7m.secure];
+ case 11: /* PSPLIM */
+ if (!arm_feature(env, ARM_FEATURE_V8)) {
+ goto bad_reg;
+ }
+ return env->v7m.psplim[env->v7m.secure];
+ case 16: /* PRIMASK */
+ return env->v7m.primask[env->v7m.secure];
+ case 17: /* BASEPRI */
+ case 18: /* BASEPRI_MAX */
+ return env->v7m.basepri[env->v7m.secure];
+ case 19: /* FAULTMASK */
+ return env->v7m.faultmask[env->v7m.secure];
+ default:
+ bad_reg:
+ qemu_log_mask(LOG_GUEST_ERROR, "Attempt to read unknown special"
+ " register %d\n", reg);
+ return 0;
+ }
+}
+
+void HELPER(v7m_msr)(CPUARMState *env, uint32_t maskreg, uint32_t val)
+{
+ /*
+ * We're passed bits [11..0] of the instruction; extract
+ * SYSm and the mask bits.
+ * Invalid combinations of SYSm and mask are UNPREDICTABLE;
+ * we choose to treat them as if the mask bits were valid.
+ * NB that the pseudocode 'mask' variable is bits [11..10],
+ * whereas ours is [11..8].
+ */
+ uint32_t mask = extract32(maskreg, 8, 4);
+ uint32_t reg = extract32(maskreg, 0, 8);
+ int cur_el = arm_current_el(env);
+
+ if (cur_el == 0 && reg > 7 && reg != 20) {
+ /*
+ * only xPSR sub-fields and CONTROL.SFPA may be written by
+ * unprivileged code
+ */
+ return;
+ }
+
+ if (arm_feature(env, ARM_FEATURE_M_SECURITY)) {
+ switch (reg) {
+ case 0x88: /* MSP_NS */
+ if (!env->v7m.secure) {
+ return;
+ }
+ env->v7m.other_ss_msp = val;
+ return;
+ case 0x89: /* PSP_NS */
+ if (!env->v7m.secure) {
+ return;
+ }
+ env->v7m.other_ss_psp = val;
+ return;
+ case 0x8a: /* MSPLIM_NS */
+ if (!env->v7m.secure) {
+ return;
+ }
+ env->v7m.msplim[M_REG_NS] = val & ~7;
+ return;
+ case 0x8b: /* PSPLIM_NS */
+ if (!env->v7m.secure) {
+ return;
+ }
+ env->v7m.psplim[M_REG_NS] = val & ~7;
+ return;
+ case 0x90: /* PRIMASK_NS */
+ if (!env->v7m.secure) {
+ return;
+ }
+ env->v7m.primask[M_REG_NS] = val & 1;
+ return;
+ case 0x91: /* BASEPRI_NS */
+ if (!env->v7m.secure || !arm_feature(env, ARM_FEATURE_M_MAIN)) {
+ return;
+ }
+ env->v7m.basepri[M_REG_NS] = val & 0xff;
+ return;
+ case 0x93: /* FAULTMASK_NS */
+ if (!env->v7m.secure || !arm_feature(env, ARM_FEATURE_M_MAIN)) {
+ return;
+ }
+ env->v7m.faultmask[M_REG_NS] = val & 1;
+ return;
+ case 0x94: /* CONTROL_NS */
+ if (!env->v7m.secure) {
+ return;
+ }
+ write_v7m_control_spsel_for_secstate(env,
+ val & R_V7M_CONTROL_SPSEL_MASK,
+ M_REG_NS);
+ if (arm_feature(env, ARM_FEATURE_M_MAIN)) {
+ env->v7m.control[M_REG_NS] &= ~R_V7M_CONTROL_NPRIV_MASK;
+ env->v7m.control[M_REG_NS] |= val & R_V7M_CONTROL_NPRIV_MASK;
+ }
+ /*
+ * SFPA is RAZ/WI from NS. FPCA is RO if NSACR.CP10 == 0,
+ * RES0 if the FPU is not present, and is stored in the S bank
+ */
+ if (arm_feature(env, ARM_FEATURE_VFP) &&
+ extract32(env->v7m.nsacr, 10, 1)) {
+ env->v7m.control[M_REG_S] &= ~R_V7M_CONTROL_FPCA_MASK;
+ env->v7m.control[M_REG_S] |= val & R_V7M_CONTROL_FPCA_MASK;
+ }
+ return;
+ case 0x98: /* SP_NS */
+ {
+ /*
+ * This gives the non-secure SP selected based on whether we're
+ * currently in handler mode or not, using the NS CONTROL.SPSEL.
+ */
+ bool spsel = env->v7m.control[M_REG_NS] & R_V7M_CONTROL_SPSEL_MASK;
+ bool is_psp = !arm_v7m_is_handler_mode(env) && spsel;
+ uint32_t limit;
+
+ if (!env->v7m.secure) {
+ return;
+ }
+
+ limit = is_psp ? env->v7m.psplim[false] : env->v7m.msplim[false];
+
+ if (val < limit) {
+ CPUState *cs = env_cpu(env);
+
+ cpu_restore_state(cs, GETPC(), true);
+ raise_exception(env, EXCP_STKOF, 0, 1);
+ }
+
+ if (is_psp) {
+ env->v7m.other_ss_psp = val;
+ } else {
+ env->v7m.other_ss_msp = val;
+ }
+ return;
+ }
+ default:
+ break;
+ }
+ }
+
+ switch (reg) {
+ case 0 ... 7: /* xPSR sub-fields */
+ /* only APSR is actually writable */
+ if (!(reg & 4)) {
+ uint32_t apsrmask = 0;
+
+ if (mask & 8) {
+ apsrmask |= XPSR_NZCV | XPSR_Q;
+ }
+ if ((mask & 4) && arm_feature(env, ARM_FEATURE_THUMB_DSP)) {
+ apsrmask |= XPSR_GE;
+ }
+ xpsr_write(env, val, apsrmask);
+ }
+ break;
+ case 8: /* MSP */
+ if (v7m_using_psp(env)) {
+ env->v7m.other_sp = val;
+ } else {
+ env->regs[13] = val;
+ }
+ break;
+ case 9: /* PSP */
+ if (v7m_using_psp(env)) {
+ env->regs[13] = val;
+ } else {
+ env->v7m.other_sp = val;
+ }
+ break;
+ case 10: /* MSPLIM */
+ if (!arm_feature(env, ARM_FEATURE_V8)) {
+ goto bad_reg;
+ }
+ env->v7m.msplim[env->v7m.secure] = val & ~7;
+ break;
+ case 11: /* PSPLIM */
+ if (!arm_feature(env, ARM_FEATURE_V8)) {
+ goto bad_reg;
+ }
+ env->v7m.psplim[env->v7m.secure] = val & ~7;
+ break;
+ case 16: /* PRIMASK */
+ env->v7m.primask[env->v7m.secure] = val & 1;
+ break;
+ case 17: /* BASEPRI */
+ if (!arm_feature(env, ARM_FEATURE_M_MAIN)) {
+ goto bad_reg;
+ }
+ env->v7m.basepri[env->v7m.secure] = val & 0xff;
+ break;
+ case 18: /* BASEPRI_MAX */
+ if (!arm_feature(env, ARM_FEATURE_M_MAIN)) {
+ goto bad_reg;
+ }
+ val &= 0xff;
+ if (val != 0 && (val < env->v7m.basepri[env->v7m.secure]
+ || env->v7m.basepri[env->v7m.secure] == 0)) {
+ env->v7m.basepri[env->v7m.secure] = val;
+ }
+ break;
+ case 19: /* FAULTMASK */
+ if (!arm_feature(env, ARM_FEATURE_M_MAIN)) {
+ goto bad_reg;
+ }
+ env->v7m.faultmask[env->v7m.secure] = val & 1;
+ break;
+ case 20: /* CONTROL */
+ /*
+ * Writing to the SPSEL bit only has an effect if we are in
+ * thread mode; other bits can be updated by any privileged code.
+ * write_v7m_control_spsel() deals with updating the SPSEL bit in
+ * env->v7m.control, so we only need update the others.
+ * For v7M, we must just ignore explicit writes to SPSEL in handler
+ * mode; for v8M the write is permitted but will have no effect.
+ * All these bits are writes-ignored from non-privileged code,
+ * except for SFPA.
+ */
+ if (cur_el > 0 && (arm_feature(env, ARM_FEATURE_V8) ||
+ !arm_v7m_is_handler_mode(env))) {
+ write_v7m_control_spsel(env, (val & R_V7M_CONTROL_SPSEL_MASK) != 0);
+ }
+ if (cur_el > 0 && arm_feature(env, ARM_FEATURE_M_MAIN)) {
+ env->v7m.control[env->v7m.secure] &= ~R_V7M_CONTROL_NPRIV_MASK;
+ env->v7m.control[env->v7m.secure] |= val & R_V7M_CONTROL_NPRIV_MASK;
+ }
+ if (arm_feature(env, ARM_FEATURE_VFP)) {
+ /*
+ * SFPA is RAZ/WI from NS or if no FPU.
+ * FPCA is RO if NSACR.CP10 == 0, RES0 if the FPU is not present.
+ * Both are stored in the S bank.
+ */
+ if (env->v7m.secure) {
+ env->v7m.control[M_REG_S] &= ~R_V7M_CONTROL_SFPA_MASK;
+ env->v7m.control[M_REG_S] |= val & R_V7M_CONTROL_SFPA_MASK;
+ }
+ if (cur_el > 0 &&
+ (env->v7m.secure || !arm_feature(env, ARM_FEATURE_M_SECURITY) ||
+ extract32(env->v7m.nsacr, 10, 1))) {
+ env->v7m.control[M_REG_S] &= ~R_V7M_CONTROL_FPCA_MASK;
+ env->v7m.control[M_REG_S] |= val & R_V7M_CONTROL_FPCA_MASK;
+ }
+ }
+ break;
+ default:
+ bad_reg:
+ qemu_log_mask(LOG_GUEST_ERROR, "Attempt to write unknown special"
+ " register %d\n", reg);
+ return;
+ }
+}
+
+uint32_t HELPER(v7m_tt)(CPUARMState *env, uint32_t addr, uint32_t op)
+{
+ /* Implement the TT instruction. op is bits [7:6] of the insn. */
+ bool forceunpriv = op & 1;
+ bool alt = op & 2;
+ V8M_SAttributes sattrs = {};
+ uint32_t tt_resp;
+ bool r, rw, nsr, nsrw, mrvalid;
+ int prot;
+ ARMMMUFaultInfo fi = {};
+ MemTxAttrs attrs = {};
+ hwaddr phys_addr;
+ ARMMMUIdx mmu_idx;
+ uint32_t mregion;
+ bool targetpriv;
+ bool targetsec = env->v7m.secure;
+ bool is_subpage;
+
+ /*
+ * Work out what the security state and privilege level we're
+ * interested in is...
+ */
+ if (alt) {
+ targetsec = !targetsec;
+ }
+
+ if (forceunpriv) {
+ targetpriv = false;
+ } else {
+ targetpriv = arm_v7m_is_handler_mode(env) ||
+ !(env->v7m.control[targetsec] & R_V7M_CONTROL_NPRIV_MASK);
+ }
+
+ /* ...and then figure out which MMU index this is */
+ mmu_idx = arm_v7m_mmu_idx_for_secstate_and_priv(env, targetsec, targetpriv);
+
+ /*
+ * We know that the MPU and SAU don't care about the access type
+ * for our purposes beyond that we don't want to claim to be
+ * an insn fetch, so we arbitrarily call this a read.
+ */
+
+ /*
+ * MPU region info only available for privileged or if
+ * inspecting the other MPU state.
+ */
+ if (arm_current_el(env) != 0 || alt) {
+ /* We can ignore the return value as prot is always set */
+ pmsav8_mpu_lookup(env, addr, MMU_DATA_LOAD, mmu_idx,
+ &phys_addr, &attrs, &prot, &is_subpage,
+ &fi, &mregion);
+ if (mregion == -1) {
+ mrvalid = false;
+ mregion = 0;
+ } else {
+ mrvalid = true;
+ }
+ r = prot & PAGE_READ;
+ rw = prot & PAGE_WRITE;
+ } else {
+ r = false;
+ rw = false;
+ mrvalid = false;
+ mregion = 0;
+ }
+
+ if (env->v7m.secure) {
+ v8m_security_lookup(env, addr, MMU_DATA_LOAD, mmu_idx, &sattrs);
+ nsr = sattrs.ns && r;
+ nsrw = sattrs.ns && rw;
+ } else {
+ sattrs.ns = true;
+ nsr = false;
+ nsrw = false;
+ }
+
+ tt_resp = (sattrs.iregion << 24) |
+ (sattrs.irvalid << 23) |
+ ((!sattrs.ns) << 22) |
+ (nsrw << 21) |
+ (nsr << 20) |
+ (rw << 19) |
+ (r << 18) |
+ (sattrs.srvalid << 17) |
+ (mrvalid << 16) |
+ (sattrs.sregion << 8) |
+ mregion;
+
+ return tt_resp;
+}
+
+#endif /* !CONFIG_USER_ONLY */
+
+ARMMMUIdx arm_v7m_mmu_idx_all(CPUARMState *env,
+ bool secstate, bool priv, bool negpri)
+{
+ ARMMMUIdx mmu_idx = ARM_MMU_IDX_M;
+
+ if (priv) {
+ mmu_idx |= ARM_MMU_IDX_M_PRIV;
+ }
+
+ if (negpri) {
+ mmu_idx |= ARM_MMU_IDX_M_NEGPRI;
+ }
+
+ if (secstate) {
+ mmu_idx |= ARM_MMU_IDX_M_S;
+ }
+
+ return mmu_idx;
+}
+
+ARMMMUIdx arm_v7m_mmu_idx_for_secstate_and_priv(CPUARMState *env,
+ bool secstate, bool priv)
+{
+ bool negpri = armv7m_nvic_neg_prio_requested(env->nvic, secstate);
+
+ return arm_v7m_mmu_idx_all(env, secstate, priv, negpri);
+}
+
+/* Return the MMU index for a v7M CPU in the specified security state */
+ARMMMUIdx arm_v7m_mmu_idx_for_secstate(CPUARMState *env, bool secstate)
+{
+ bool priv = arm_current_el(env) != 0;
+
+ return arm_v7m_mmu_idx_for_secstate_and_priv(env, secstate, priv);
+}
#include "qemu/osdep.h"
#include "hw/boards.h"
#include "kvm_arm.h"
-#include "qapi/qapi-commands-target.h"
+#include "qapi/qapi-commands-misc-target.h"
static GICCapability *gic_cap_new(int version)
{
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#include "qemu/osdep.h"
+#include "qemu/units.h"
#include "qemu/log.h"
#include "qemu/main-loop.h"
#include "cpu.h"
return val;
}
-#if !defined(CONFIG_USER_ONLY)
-
-static inline uint32_t merge_syn_data_abort(uint32_t template_syn,
- unsigned int target_el,
- bool same_el, bool ea,
- bool s1ptw, bool is_write,
- int fsc)
-{
- uint32_t syn;
-
- /* ISV is only set for data aborts routed to EL2 and
- * never for stage-1 page table walks faulting on stage 2.
- *
- * Furthermore, ISV is only set for certain kinds of load/stores.
- * If the template syndrome does not have ISV set, we should leave
- * it cleared.
- *
- * See ARMv8 specs, D7-1974:
- * ISS encoding for an exception from a Data Abort, the
- * ISV field.
- */
- if (!(template_syn & ARM_EL_ISV) || target_el != 2 || s1ptw) {
- syn = syn_data_abort_no_iss(same_el,
- ea, 0, s1ptw, is_write, fsc);
- } else {
- /* Fields: IL, ISV, SAS, SSE, SRT, SF and AR come from the template
- * syndrome created at translation time.
- * Now we create the runtime syndrome with the remaining fields.
- */
- syn = syn_data_abort_with_iss(same_el,
- 0, 0, 0, 0, 0,
- ea, 0, s1ptw, is_write, fsc,
- false);
- /* Merge the runtime syndrome with the template syndrome. */
- syn |= template_syn;
- }
- return syn;
-}
-
-void arm_deliver_fault(ARMCPU *cpu, vaddr addr, MMUAccessType access_type,
- int mmu_idx, ARMMMUFaultInfo *fi)
-{
- CPUARMState *env = &cpu->env;
- int target_el;
- bool same_el;
- uint32_t syn, exc, fsr, fsc;
- ARMMMUIdx arm_mmu_idx = core_to_arm_mmu_idx(env, mmu_idx);
-
- target_el = exception_target_el(env);
- if (fi->stage2) {
- target_el = 2;
- env->cp15.hpfar_el2 = extract64(fi->s2addr, 12, 47) << 4;
- }
- same_el = (arm_current_el(env) == target_el);
-
- if (target_el == 2 || arm_el_is_aa64(env, target_el) ||
- arm_s1_regime_using_lpae_format(env, arm_mmu_idx)) {
- /* LPAE format fault status register : bottom 6 bits are
- * status code in the same form as needed for syndrome
- */
- fsr = arm_fi_to_lfsc(fi);
- fsc = extract32(fsr, 0, 6);
- } else {
- fsr = arm_fi_to_sfsc(fi);
- /* Short format FSR : this fault will never actually be reported
- * to an EL that uses a syndrome register. Use a (currently)
- * reserved FSR code in case the constructed syndrome does leak
- * into the guest somehow.
- */
- fsc = 0x3f;
- }
-
- if (access_type == MMU_INST_FETCH) {
- syn = syn_insn_abort(same_el, fi->ea, fi->s1ptw, fsc);
- exc = EXCP_PREFETCH_ABORT;
- } else {
- syn = merge_syn_data_abort(env->exception.syndrome, target_el,
- same_el, fi->ea, fi->s1ptw,
- access_type == MMU_DATA_STORE,
- fsc);
- if (access_type == MMU_DATA_STORE
- && arm_feature(env, ARM_FEATURE_V6)) {
- fsr |= (1 << 11);
- }
- exc = EXCP_DATA_ABORT;
- }
-
- env->exception.vaddress = addr;
- env->exception.fsr = fsr;
- raise_exception(env, exc, syn, target_el);
-}
-
-/* Raise a data fault alignment exception for the specified virtual address */
-void arm_cpu_do_unaligned_access(CPUState *cs, vaddr vaddr,
- MMUAccessType access_type,
- int mmu_idx, uintptr_t retaddr)
-{
- ARMCPU *cpu = ARM_CPU(cs);
- ARMMMUFaultInfo fi = {};
-
- /* now we have a real cpu fault */
- cpu_restore_state(cs, retaddr, true);
-
- fi.type = ARMFault_Alignment;
- arm_deliver_fault(cpu, vaddr, access_type, mmu_idx, &fi);
-}
-
-/* arm_cpu_do_transaction_failed: handle a memory system error response
- * (eg "no device/memory present at address") by raising an external abort
- * exception
- */
-void arm_cpu_do_transaction_failed(CPUState *cs, hwaddr physaddr,
- vaddr addr, unsigned size,
- MMUAccessType access_type,
- int mmu_idx, MemTxAttrs attrs,
- MemTxResult response, uintptr_t retaddr)
-{
- ARMCPU *cpu = ARM_CPU(cs);
- ARMMMUFaultInfo fi = {};
-
- /* now we have a real cpu fault */
- cpu_restore_state(cs, retaddr, true);
-
- fi.ea = arm_extabort_type(response);
- fi.type = ARMFault_SyncExternal;
- arm_deliver_fault(cpu, addr, access_type, mmu_idx, &fi);
-}
-
-#endif /* !defined(CONFIG_USER_ONLY) */
-
void HELPER(v8m_stackcheck)(CPUARMState *env, uint32_t newvalue)
{
/*
}
}
-/* Return true if the linked breakpoint entry lbn passes its checks */
-static bool linked_bp_matches(ARMCPU *cpu, int lbn)
-{
- CPUARMState *env = &cpu->env;
- uint64_t bcr = env->cp15.dbgbcr[lbn];
- int brps = extract32(cpu->dbgdidr, 24, 4);
- int ctx_cmps = extract32(cpu->dbgdidr, 20, 4);
- int bt;
- uint32_t contextidr;
-
- /* Links to unimplemented or non-context aware breakpoints are
- * CONSTRAINED UNPREDICTABLE: either behave as if disabled, or
- * as if linked to an UNKNOWN context-aware breakpoint (in which
- * case DBGWCR<n>_EL1.LBN must indicate that breakpoint).
- * We choose the former.
- */
- if (lbn > brps || lbn < (brps - ctx_cmps)) {
- return false;
- }
-
- bcr = env->cp15.dbgbcr[lbn];
-
- if (extract64(bcr, 0, 1) == 0) {
- /* Linked breakpoint disabled : generate no events */
- return false;
- }
-
- bt = extract64(bcr, 20, 4);
-
- /* We match the whole register even if this is AArch32 using the
- * short descriptor format (in which case it holds both PROCID and ASID),
- * since we don't implement the optional v7 context ID masking.
- */
- contextidr = extract64(env->cp15.contextidr_el[1], 0, 32);
-
- switch (bt) {
- case 3: /* linked context ID match */
- if (arm_current_el(env) > 1) {
- /* Context matches never fire in EL2 or (AArch64) EL3 */
- return false;
- }
- return (contextidr == extract64(env->cp15.dbgbvr[lbn], 0, 32));
- case 5: /* linked address mismatch (reserved in AArch64) */
- case 9: /* linked VMID match (reserved if no EL2) */
- case 11: /* linked context ID and VMID match (reserved if no EL2) */
- default:
- /* Links to Unlinked context breakpoints must generate no
- * events; we choose to do the same for reserved values too.
- */
- return false;
- }
-
- return false;
-}
-
-static bool bp_wp_matches(ARMCPU *cpu, int n, bool is_wp)
-{
- CPUARMState *env = &cpu->env;
- uint64_t cr;
- int pac, hmc, ssc, wt, lbn;
- /* Note that for watchpoints the check is against the CPU security
- * state, not the S/NS attribute on the offending data access.
- */
- bool is_secure = arm_is_secure(env);
- int access_el = arm_current_el(env);
-
- if (is_wp) {
- CPUWatchpoint *wp = env->cpu_watchpoint[n];
-
- if (!wp || !(wp->flags & BP_WATCHPOINT_HIT)) {
- return false;
- }
- cr = env->cp15.dbgwcr[n];
- if (wp->hitattrs.user) {
- /* The LDRT/STRT/LDT/STT "unprivileged access" instructions should
- * match watchpoints as if they were accesses done at EL0, even if
- * the CPU is at EL1 or higher.
- */
- access_el = 0;
- }
- } else {
- uint64_t pc = is_a64(env) ? env->pc : env->regs[15];
-
- if (!env->cpu_breakpoint[n] || env->cpu_breakpoint[n]->pc != pc) {
- return false;
- }
- cr = env->cp15.dbgbcr[n];
- }
- /* The WATCHPOINT_HIT flag guarantees us that the watchpoint is
- * enabled and that the address and access type match; for breakpoints
- * we know the address matched; check the remaining fields, including
- * linked breakpoints. We rely on WCR and BCR having the same layout
- * for the LBN, SSC, HMC, PAC/PMC and is-linked fields.
- * Note that some combinations of {PAC, HMC, SSC} are reserved and
- * must act either like some valid combination or as if the watchpoint
- * were disabled. We choose the former, and use this together with
- * the fact that EL3 must always be Secure and EL2 must always be
- * Non-Secure to simplify the code slightly compared to the full
- * table in the ARM ARM.
- */
- pac = extract64(cr, 1, 2);
- hmc = extract64(cr, 13, 1);
- ssc = extract64(cr, 14, 2);
-
- switch (ssc) {
- case 0:
- break;
- case 1:
- case 3:
- if (is_secure) {
- return false;
- }
- break;
- case 2:
- if (!is_secure) {
- return false;
- }
- break;
- }
-
- switch (access_el) {
- case 3:
- case 2:
- if (!hmc) {
- return false;
- }
- break;
- case 1:
- if (extract32(pac, 0, 1) == 0) {
- return false;
- }
- break;
- case 0:
- if (extract32(pac, 1, 1) == 0) {
- return false;
- }
- break;
- default:
- g_assert_not_reached();
- }
-
- wt = extract64(cr, 20, 1);
- lbn = extract64(cr, 16, 4);
-
- if (wt && !linked_bp_matches(cpu, lbn)) {
- return false;
- }
-
- return true;
-}
-
-static bool check_watchpoints(ARMCPU *cpu)
-{
- CPUARMState *env = &cpu->env;
- int n;
-
- /* If watchpoints are disabled globally or we can't take debug
- * exceptions here then watchpoint firings are ignored.
- */
- if (extract32(env->cp15.mdscr_el1, 15, 1) == 0
- || !arm_generate_debug_exceptions(env)) {
- return false;
- }
-
- for (n = 0; n < ARRAY_SIZE(env->cpu_watchpoint); n++) {
- if (bp_wp_matches(cpu, n, true)) {
- return true;
- }
- }
- return false;
-}
-
-static bool check_breakpoints(ARMCPU *cpu)
-{
- CPUARMState *env = &cpu->env;
- int n;
-
- /* If breakpoints are disabled globally or we can't take debug
- * exceptions here then breakpoint firings are ignored.
- */
- if (extract32(env->cp15.mdscr_el1, 15, 1) == 0
- || !arm_generate_debug_exceptions(env)) {
- return false;
- }
-
- for (n = 0; n < ARRAY_SIZE(env->cpu_breakpoint); n++) {
- if (bp_wp_matches(cpu, n, false)) {
- return true;
- }
- }
- return false;
-}
-
-void HELPER(check_breakpoints)(CPUARMState *env)
-{
- ARMCPU *cpu = env_archcpu(env);
-
- if (check_breakpoints(cpu)) {
- HELPER(exception_internal(env, EXCP_DEBUG));
- }
-}
-
-bool arm_debug_check_watchpoint(CPUState *cs, CPUWatchpoint *wp)
-{
- /* Called by core code when a CPU watchpoint fires; need to check if this
- * is also an architectural watchpoint match.
- */
- ARMCPU *cpu = ARM_CPU(cs);
-
- return check_watchpoints(cpu);
-}
-
-vaddr arm_adjust_watchpoint_address(CPUState *cs, vaddr addr, int len)
-{
- ARMCPU *cpu = ARM_CPU(cs);
- CPUARMState *env = &cpu->env;
-
- /* In BE32 system mode, target memory is stored byteswapped (on a
- * little-endian host system), and by the time we reach here (via an
- * opcode helper) the addresses of subword accesses have been adjusted
- * to account for that, which means that watchpoints will not match.
- * Undo the adjustment here.
- */
- if (arm_sctlr_b(env)) {
- if (len == 1) {
- addr ^= 3;
- } else if (len == 2) {
- addr ^= 2;
- }
- }
-
- return addr;
-}
-
-void arm_debug_excp_handler(CPUState *cs)
-{
- /* Called by core code when a watchpoint or breakpoint fires;
- * need to check which one and raise the appropriate exception.
- */
- ARMCPU *cpu = ARM_CPU(cs);
- CPUARMState *env = &cpu->env;
- CPUWatchpoint *wp_hit = cs->watchpoint_hit;
-
- if (wp_hit) {
- if (wp_hit->flags & BP_CPU) {
- bool wnr = (wp_hit->flags & BP_WATCHPOINT_HIT_WRITE) != 0;
- bool same_el = arm_debug_target_el(env) == arm_current_el(env);
-
- cs->watchpoint_hit = NULL;
-
- env->exception.fsr = arm_debug_exception_fsr(env);
- env->exception.vaddress = wp_hit->hitaddr;
- raise_exception(env, EXCP_DATA_ABORT,
- syn_watchpoint(same_el, 0, wnr),
- arm_debug_target_el(env));
- }
- } else {
- uint64_t pc = is_a64(env) ? env->pc : env->regs[15];
- bool same_el = (arm_debug_target_el(env) == arm_current_el(env));
-
- /* (1) GDB breakpoints should be handled first.
- * (2) Do not raise a CPU exception if no CPU breakpoint has fired,
- * since singlestep is also done by generating a debug internal
- * exception.
- */
- if (cpu_breakpoint_test(cs, pc, BP_GDB)
- || !cpu_breakpoint_test(cs, pc, BP_CPU)) {
- return;
- }
-
- env->exception.fsr = arm_debug_exception_fsr(env);
- /* FAR is UNKNOWN: clear vaddress to avoid potentially exposing
- * values to the guest that it shouldn't be able to see at its
- * exception/security level.
- */
- env->exception.vaddress = 0;
- raise_exception(env, EXCP_PREFETCH_ABORT,
- syn_breakpoint(same_el),
- arm_debug_target_el(env));
- }
-}
-
/* ??? Flag setting arithmetic is awkward because we need to do comparisons.
The only way to do that in TCG is a conditional branch, which clobbers
all our temporaries. For now implement these as helper functions. */
return ((uint32_t)x >> shift) | (x << (32 - shift));
}
}
+
+void HELPER(dc_zva)(CPUARMState *env, uint64_t vaddr_in)
+{
+ /*
+ * Implement DC ZVA, which zeroes a fixed-length block of memory.
+ * Note that we do not implement the (architecturally mandated)
+ * alignment fault for attempts to use this on Device memory
+ * (which matches the usual QEMU behaviour of not implementing either
+ * alignment faults or any memory attribute handling).
+ */
+
+ ARMCPU *cpu = env_archcpu(env);
+ uint64_t blocklen = 4 << cpu->dcz_blocksize;
+ uint64_t vaddr = vaddr_in & ~(blocklen - 1);
+
+#ifndef CONFIG_USER_ONLY
+ {
+ /*
+ * Slightly awkwardly, QEMU's TARGET_PAGE_SIZE may be less than
+ * the block size so we might have to do more than one TLB lookup.
+ * We know that in fact for any v8 CPU the page size is at least 4K
+ * and the block size must be 2K or less, but TARGET_PAGE_SIZE is only
+ * 1K as an artefact of legacy v5 subpage support being present in the
+ * same QEMU executable. So in practice the hostaddr[] array has
+ * two entries, given the current setting of TARGET_PAGE_BITS_MIN.
+ */
+ int maxidx = DIV_ROUND_UP(blocklen, TARGET_PAGE_SIZE);
+ void *hostaddr[DIV_ROUND_UP(2 * KiB, 1 << TARGET_PAGE_BITS_MIN)];
+ int try, i;
+ unsigned mmu_idx = cpu_mmu_index(env, false);
+ TCGMemOpIdx oi = make_memop_idx(MO_UB, mmu_idx);
+
+ assert(maxidx <= ARRAY_SIZE(hostaddr));
+
+ for (try = 0; try < 2; try++) {
+
+ for (i = 0; i < maxidx; i++) {
+ hostaddr[i] = tlb_vaddr_to_host(env,
+ vaddr + TARGET_PAGE_SIZE * i,
+ 1, mmu_idx);
+ if (!hostaddr[i]) {
+ break;
+ }
+ }
+ if (i == maxidx) {
+ /*
+ * If it's all in the TLB it's fair game for just writing to;
+ * we know we don't need to update dirty status, etc.
+ */
+ for (i = 0; i < maxidx - 1; i++) {
+ memset(hostaddr[i], 0, TARGET_PAGE_SIZE);
+ }
+ memset(hostaddr[i], 0, blocklen - (i * TARGET_PAGE_SIZE));
+ return;
+ }
+ /*
+ * OK, try a store and see if we can populate the tlb. This
+ * might cause an exception if the memory isn't writable,
+ * in which case we will longjmp out of here. We must for
+ * this purpose use the actual register value passed to us
+ * so that we get the fault address right.
+ */
+ helper_ret_stb_mmu(env, vaddr_in, 0, oi, GETPC());
+ /* Now we can populate the other TLB entries, if any */
+ for (i = 0; i < maxidx; i++) {
+ uint64_t va = vaddr + TARGET_PAGE_SIZE * i;
+ if (va != (vaddr_in & TARGET_PAGE_MASK)) {
+ helper_ret_stb_mmu(env, va, 0, oi, GETPC());
+ }
+ }
+ }
+
+ /*
+ * Slow path (probably attempt to do this to an I/O device or
+ * similar, or clearing of a block of code we have translations
+ * cached for). Just do a series of byte writes as the architecture
+ * demands. It's not worth trying to use a cpu_physical_memory_map(),
+ * memset(), unmap() sequence here because:
+ * + we'd need to account for the blocksize being larger than a page
+ * + the direct-RAM access case is almost always going to be dealt
+ * with in the fastpath code above, so there's no speed benefit
+ * + we would have to deal with the map returning NULL because the
+ * bounce buffer was in use
+ */
+ for (i = 0; i < blocklen; i++) {
+ helper_ret_stb_mmu(env, vaddr + i, 0, oi, GETPC());
+ }
+ }
+#else
+ memset(g2h(vaddr), 0, blocklen);
+#endif
+}
--- /dev/null
+/*
+ * ARM TLB (Translation lookaside buffer) helpers.
+ *
+ * This code is licensed under the GNU GPL v2 or later.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+#include "qemu/osdep.h"
+#include "cpu.h"
+#include "internals.h"
+#include "exec/exec-all.h"
+
+#if !defined(CONFIG_USER_ONLY)
+
+static inline uint32_t merge_syn_data_abort(uint32_t template_syn,
+ unsigned int target_el,
+ bool same_el, bool ea,
+ bool s1ptw, bool is_write,
+ int fsc)
+{
+ uint32_t syn;
+
+ /*
+ * ISV is only set for data aborts routed to EL2 and
+ * never for stage-1 page table walks faulting on stage 2.
+ *
+ * Furthermore, ISV is only set for certain kinds of load/stores.
+ * If the template syndrome does not have ISV set, we should leave
+ * it cleared.
+ *
+ * See ARMv8 specs, D7-1974:
+ * ISS encoding for an exception from a Data Abort, the
+ * ISV field.
+ */
+ if (!(template_syn & ARM_EL_ISV) || target_el != 2 || s1ptw) {
+ syn = syn_data_abort_no_iss(same_el,
+ ea, 0, s1ptw, is_write, fsc);
+ } else {
+ /*
+ * Fields: IL, ISV, SAS, SSE, SRT, SF and AR come from the template
+ * syndrome created at translation time.
+ * Now we create the runtime syndrome with the remaining fields.
+ */
+ syn = syn_data_abort_with_iss(same_el,
+ 0, 0, 0, 0, 0,
+ ea, 0, s1ptw, is_write, fsc,
+ false);
+ /* Merge the runtime syndrome with the template syndrome. */
+ syn |= template_syn;
+ }
+ return syn;
+}
+
+static void QEMU_NORETURN arm_deliver_fault(ARMCPU *cpu, vaddr addr,
+ MMUAccessType access_type,
+ int mmu_idx, ARMMMUFaultInfo *fi)
+{
+ CPUARMState *env = &cpu->env;
+ int target_el;
+ bool same_el;
+ uint32_t syn, exc, fsr, fsc;
+ ARMMMUIdx arm_mmu_idx = core_to_arm_mmu_idx(env, mmu_idx);
+
+ target_el = exception_target_el(env);
+ if (fi->stage2) {
+ target_el = 2;
+ env->cp15.hpfar_el2 = extract64(fi->s2addr, 12, 47) << 4;
+ }
+ same_el = (arm_current_el(env) == target_el);
+
+ if (target_el == 2 || arm_el_is_aa64(env, target_el) ||
+ arm_s1_regime_using_lpae_format(env, arm_mmu_idx)) {
+ /*
+ * LPAE format fault status register : bottom 6 bits are
+ * status code in the same form as needed for syndrome
+ */
+ fsr = arm_fi_to_lfsc(fi);
+ fsc = extract32(fsr, 0, 6);
+ } else {
+ fsr = arm_fi_to_sfsc(fi);
+ /*
+ * Short format FSR : this fault will never actually be reported
+ * to an EL that uses a syndrome register. Use a (currently)
+ * reserved FSR code in case the constructed syndrome does leak
+ * into the guest somehow.
+ */
+ fsc = 0x3f;
+ }
+
+ if (access_type == MMU_INST_FETCH) {
+ syn = syn_insn_abort(same_el, fi->ea, fi->s1ptw, fsc);
+ exc = EXCP_PREFETCH_ABORT;
+ } else {
+ syn = merge_syn_data_abort(env->exception.syndrome, target_el,
+ same_el, fi->ea, fi->s1ptw,
+ access_type == MMU_DATA_STORE,
+ fsc);
+ if (access_type == MMU_DATA_STORE
+ && arm_feature(env, ARM_FEATURE_V6)) {
+ fsr |= (1 << 11);
+ }
+ exc = EXCP_DATA_ABORT;
+ }
+
+ env->exception.vaddress = addr;
+ env->exception.fsr = fsr;
+ raise_exception(env, exc, syn, target_el);
+}
+
+/* Raise a data fault alignment exception for the specified virtual address */
+void arm_cpu_do_unaligned_access(CPUState *cs, vaddr vaddr,
+ MMUAccessType access_type,
+ int mmu_idx, uintptr_t retaddr)
+{
+ ARMCPU *cpu = ARM_CPU(cs);
+ ARMMMUFaultInfo fi = {};
+
+ /* now we have a real cpu fault */
+ cpu_restore_state(cs, retaddr, true);
+
+ fi.type = ARMFault_Alignment;
+ arm_deliver_fault(cpu, vaddr, access_type, mmu_idx, &fi);
+}
+
+/*
+ * arm_cpu_do_transaction_failed: handle a memory system error response
+ * (eg "no device/memory present at address") by raising an external abort
+ * exception
+ */
+void arm_cpu_do_transaction_failed(CPUState *cs, hwaddr physaddr,
+ vaddr addr, unsigned size,
+ MMUAccessType access_type,
+ int mmu_idx, MemTxAttrs attrs,
+ MemTxResult response, uintptr_t retaddr)
+{
+ ARMCPU *cpu = ARM_CPU(cs);
+ ARMMMUFaultInfo fi = {};
+
+ /* now we have a real cpu fault */
+ cpu_restore_state(cs, retaddr, true);
+
+ fi.ea = arm_extabort_type(response);
+ fi.type = ARMFault_SyncExternal;
+ arm_deliver_fault(cpu, addr, access_type, mmu_idx, &fi);
+}
+
+#endif /* !defined(CONFIG_USER_ONLY) */
+
+bool arm_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
+ MMUAccessType access_type, int mmu_idx,
+ bool probe, uintptr_t retaddr)
+{
+ ARMCPU *cpu = ARM_CPU(cs);
+
+#ifdef CONFIG_USER_ONLY
+ cpu->env.exception.vaddress = address;
+ if (access_type == MMU_INST_FETCH) {
+ cs->exception_index = EXCP_PREFETCH_ABORT;
+ } else {
+ cs->exception_index = EXCP_DATA_ABORT;
+ }
+ cpu_loop_exit_restore(cs, retaddr);
+#else
+ hwaddr phys_addr;
+ target_ulong page_size;
+ int prot, ret;
+ MemTxAttrs attrs = {};
+ ARMMMUFaultInfo fi = {};
+
+ /*
+ * Walk the page table and (if the mapping exists) add the page
+ * to the TLB. On success, return true. Otherwise, if probing,
+ * return false. Otherwise populate fsr with ARM DFSR/IFSR fault
+ * register format, and signal the fault.
+ */
+ ret = get_phys_addr(&cpu->env, address, access_type,
+ core_to_arm_mmu_idx(&cpu->env, mmu_idx),
+ &phys_addr, &attrs, &prot, &page_size, &fi, NULL);
+ if (likely(!ret)) {
+ /*
+ * Map a single [sub]page. Regions smaller than our declared
+ * target page size are handled specially, so for those we
+ * pass in the exact addresses.
+ */
+ if (page_size >= TARGET_PAGE_SIZE) {
+ phys_addr &= TARGET_PAGE_MASK;
+ address &= TARGET_PAGE_MASK;
+ }
+ tlb_set_page_with_attrs(cs, address, phys_addr, attrs,
+ prot, mmu_idx, page_size);
+ return true;
+ } else if (probe) {
+ return false;
+ } else {
+ /* now we have a real cpu fault */
+ cpu_restore_state(cs, retaddr, true);
+ arm_deliver_fault(cpu, address, access_type, mmu_idx, &fi);
+ }
+#endif
+}
#include "translate.h"
#include "internals.h"
#include "qemu/host-utils.h"
-#include "qemu/qemu-print.h"
#include "hw/semihosting/semihost.h"
#include "exec/gen-icount.h"
s->btype = -1;
}
-void aarch64_cpu_dump_state(CPUState *cs, FILE *f, int flags)
-{
- ARMCPU *cpu = ARM_CPU(cs);
- CPUARMState *env = &cpu->env;
- uint32_t psr = pstate_read(env);
- int i;
- int el = arm_current_el(env);
- const char *ns_status;
-
- qemu_fprintf(f, " PC=%016" PRIx64 " ", env->pc);
- for (i = 0; i < 32; i++) {
- if (i == 31) {
- qemu_fprintf(f, " SP=%016" PRIx64 "\n", env->xregs[i]);
- } else {
- qemu_fprintf(f, "X%02d=%016" PRIx64 "%s", i, env->xregs[i],
- (i + 2) % 3 ? " " : "\n");
- }
- }
-
- if (arm_feature(env, ARM_FEATURE_EL3) && el != 3) {
- ns_status = env->cp15.scr_el3 & SCR_NS ? "NS " : "S ";
- } else {
- ns_status = "";
- }
- qemu_fprintf(f, "PSTATE=%08x %c%c%c%c %sEL%d%c",
- psr,
- psr & PSTATE_N ? 'N' : '-',
- psr & PSTATE_Z ? 'Z' : '-',
- psr & PSTATE_C ? 'C' : '-',
- psr & PSTATE_V ? 'V' : '-',
- ns_status,
- el,
- psr & PSTATE_SP ? 'h' : 't');
-
- if (cpu_isar_feature(aa64_bti, cpu)) {
- qemu_fprintf(f, " BTYPE=%d", (psr & PSTATE_BTYPE) >> 10);
- }
- if (!(flags & CPU_DUMP_FPU)) {
- qemu_fprintf(f, "\n");
- return;
- }
- if (fp_exception_el(env, el) != 0) {
- qemu_fprintf(f, " FPU disabled\n");
- return;
- }
- qemu_fprintf(f, " FPCR=%08x FPSR=%08x\n",
- vfp_get_fpcr(env), vfp_get_fpsr(env));
-
- if (cpu_isar_feature(aa64_sve, cpu) && sve_exception_el(env, el) == 0) {
- int j, zcr_len = sve_zcr_len_for_el(env, el);
-
- for (i = 0; i <= FFR_PRED_NUM; i++) {
- bool eol;
- if (i == FFR_PRED_NUM) {
- qemu_fprintf(f, "FFR=");
- /* It's last, so end the line. */
- eol = true;
- } else {
- qemu_fprintf(f, "P%02d=", i);
- switch (zcr_len) {
- case 0:
- eol = i % 8 == 7;
- break;
- case 1:
- eol = i % 6 == 5;
- break;
- case 2:
- case 3:
- eol = i % 3 == 2;
- break;
- default:
- /* More than one quadword per predicate. */
- eol = true;
- break;
- }
- }
- for (j = zcr_len / 4; j >= 0; j--) {
- int digits;
- if (j * 4 + 4 <= zcr_len + 1) {
- digits = 16;
- } else {
- digits = (zcr_len % 4 + 1) * 4;
- }
- qemu_fprintf(f, "%0*" PRIx64 "%s", digits,
- env->vfp.pregs[i].p[j],
- j ? ":" : eol ? "\n" : " ");
- }
- }
-
- for (i = 0; i < 32; i++) {
- if (zcr_len == 0) {
- qemu_fprintf(f, "Z%02d=%016" PRIx64 ":%016" PRIx64 "%s",
- i, env->vfp.zregs[i].d[1],
- env->vfp.zregs[i].d[0], i & 1 ? "\n" : " ");
- } else if (zcr_len == 1) {
- qemu_fprintf(f, "Z%02d=%016" PRIx64 ":%016" PRIx64
- ":%016" PRIx64 ":%016" PRIx64 "\n",
- i, env->vfp.zregs[i].d[3], env->vfp.zregs[i].d[2],
- env->vfp.zregs[i].d[1], env->vfp.zregs[i].d[0]);
- } else {
- for (j = zcr_len; j >= 0; j--) {
- bool odd = (zcr_len - j) % 2 != 0;
- if (j == zcr_len) {
- qemu_fprintf(f, "Z%02d[%x-%x]=", i, j, j - 1);
- } else if (!odd) {
- if (j > 0) {
- qemu_fprintf(f, " [%x-%x]=", j, j - 1);
- } else {
- qemu_fprintf(f, " [%x]=", j);
- }
- }
- qemu_fprintf(f, "%016" PRIx64 ":%016" PRIx64 "%s",
- env->vfp.zregs[i].d[j * 2 + 1],
- env->vfp.zregs[i].d[j * 2],
- odd || j == 0 ? "\n" : ":");
- }
- }
- }
- } else {
- for (i = 0; i < 32; i++) {
- uint64_t *q = aa64_vfp_qreg(env, i);
- qemu_fprintf(f, "Q%02d=%016" PRIx64 ":%016" PRIx64 "%s",
- i, q[1], q[0], (i & 1 ? "\n" : " "));
- }
- }
-}
-
void gen_a64_set_pc_im(uint64_t val)
{
tcg_gen_movi_i64(cpu_pc, val);
/* Set up the operands for the next iteration */
veclen--;
- vfp_advance_dreg(vd, delta_d);
+ vd = vfp_advance_dreg(vd, delta_d);
}
tcg_temp_free_i64(fd);
#include "tcg-op-gvec.h"
#include "qemu/log.h"
#include "qemu/bitops.h"
-#include "qemu/qemu-print.h"
#include "arm_ldst.h"
#include "hw/semihosting/semihost.h"
loaded_base = 0;
loaded_var = NULL;
n = 0;
- for(i=0;i<16;i++) {
+ for (i = 0; i < 16; i++) {
if (insn & (1 << i))
n++;
}
}
}
j = 0;
- for(i=0;i<16;i++) {
+ for (i = 0; i < 16; i++) {
if (insn & (1 << i)) {
if (is_load) {
/* load */
gen_nop_hint(s, (insn >> 4) & 0xf);
break;
}
- /* If Then. */
+ /*
+ * IT (If-Then)
+ *
+ * Combinations of firstcond and mask which set up an 0b1111
+ * condition are UNPREDICTABLE; we take the CONSTRAINED
+ * UNPREDICTABLE choice to treat 0b1111 the same as 0b1110,
+ * i.e. both meaning "execute always".
+ */
s->condexec_cond = (insn >> 4) & 0xe;
s->condexec_mask = insn & 0x1f;
/* No actual code generated for this insn, just setup state. */
if (dc->condexec_mask && !thumb_insn_is_unconditional(dc, insn)) {
uint32_t cond = dc->condexec_cond;
- if (cond != 0x0e) { /* Skip conditional when condition is AL. */
+ /*
+ * Conditionally skip the insn. Note that both 0xe and 0xf mean
+ * "always"; 0xf is not "never".
+ */
+ if (cond < 0x0e) {
arm_skip_unless(dc, cond);
}
}
translator_loop(ops, &dc.base, cpu, tb, max_insns);
}
-void arm_cpu_dump_state(CPUState *cs, FILE *f, int flags)
-{
- ARMCPU *cpu = ARM_CPU(cs);
- CPUARMState *env = &cpu->env;
- int i;
-
- if (is_a64(env)) {
- aarch64_cpu_dump_state(cs, f, flags);
- return;
- }
-
- for(i=0;i<16;i++) {
- qemu_fprintf(f, "R%02d=%08x", i, env->regs[i]);
- if ((i % 4) == 3)
- qemu_fprintf(f, "\n");
- else
- qemu_fprintf(f, " ");
- }
-
- if (arm_feature(env, ARM_FEATURE_M)) {
- uint32_t xpsr = xpsr_read(env);
- const char *mode;
- const char *ns_status = "";
-
- if (arm_feature(env, ARM_FEATURE_M_SECURITY)) {
- ns_status = env->v7m.secure ? "S " : "NS ";
- }
-
- if (xpsr & XPSR_EXCP) {
- mode = "handler";
- } else {
- if (env->v7m.control[env->v7m.secure] & R_V7M_CONTROL_NPRIV_MASK) {
- mode = "unpriv-thread";
- } else {
- mode = "priv-thread";
- }
- }
-
- qemu_fprintf(f, "XPSR=%08x %c%c%c%c %c %s%s\n",
- xpsr,
- xpsr & XPSR_N ? 'N' : '-',
- xpsr & XPSR_Z ? 'Z' : '-',
- xpsr & XPSR_C ? 'C' : '-',
- xpsr & XPSR_V ? 'V' : '-',
- xpsr & XPSR_T ? 'T' : 'A',
- ns_status,
- mode);
- } else {
- uint32_t psr = cpsr_read(env);
- const char *ns_status = "";
-
- if (arm_feature(env, ARM_FEATURE_EL3) &&
- (psr & CPSR_M) != ARM_CPU_MODE_MON) {
- ns_status = env->cp15.scr_el3 & SCR_NS ? "NS " : "S ";
- }
-
- qemu_fprintf(f, "PSR=%08x %c%c%c%c %c %s%s%d\n",
- psr,
- psr & CPSR_N ? 'N' : '-',
- psr & CPSR_Z ? 'Z' : '-',
- psr & CPSR_C ? 'C' : '-',
- psr & CPSR_V ? 'V' : '-',
- psr & CPSR_T ? 'T' : 'A',
- ns_status,
- aarch32_mode_name(psr), (psr & 0x10) ? 32 : 26);
- }
-
- if (flags & CPU_DUMP_FPU) {
- int numvfpregs = 0;
- if (arm_feature(env, ARM_FEATURE_VFP)) {
- numvfpregs += 16;
- }
- if (arm_feature(env, ARM_FEATURE_VFP3)) {
- numvfpregs += 16;
- }
- for (i = 0; i < numvfpregs; i++) {
- uint64_t v = *aa32_vfp_dreg(env, i);
- qemu_fprintf(f, "s%02d=%08x s%02d=%08x d%02d=%016" PRIx64 "\n",
- i * 2, (uint32_t)v,
- i * 2 + 1, (uint32_t)(v >> 32),
- i, v);
- }
- qemu_fprintf(f, "FPSCR: %08x\n", vfp_get_fpscr(env));
- }
-}
-
void restore_state_to_opc(CPUARMState *env, TranslationBlock *tb,
target_ulong *data)
{
#ifdef TARGET_AARCH64
void a64_translate_init(void);
void gen_a64_set_pc_im(uint64_t val);
-void aarch64_cpu_dump_state(CPUState *cs, FILE *f, int flags);
extern const TranslatorOps aarch64_translator_ops;
#else
static inline void a64_translate_init(void)
static inline void gen_a64_set_pc_im(uint64_t val)
{
}
-
-static inline void aarch64_cpu_dump_state(CPUState *cs, FILE *f, int flags)
-{
-}
#endif
void arm_test_cc(DisasCompare *cmp, int cc);
*/
#include "qemu/osdep.h"
-#include "qemu/log.h"
#include "cpu.h"
#include "exec/helper-proto.h"
-#include "fpu/softfloat.h"
#include "internals.h"
-
+#ifdef CONFIG_TCG
+#include "qemu/log.h"
+#include "fpu/softfloat.h"
+#endif
/* VFP support. We follow the convention used for VFP instructions:
Single precision routines have a "s" suffix, double precision a
"d" suffix. */
+#ifdef CONFIG_TCG
+
/* Convert host exception flags to vfp form. */
static inline int vfp_exceptbits_from_host(int host_bits)
{
int target_bits = 0;
- if (host_bits & float_flag_invalid)
+ if (host_bits & float_flag_invalid) {
target_bits |= 1;
- if (host_bits & float_flag_divbyzero)
+ }
+ if (host_bits & float_flag_divbyzero) {
target_bits |= 2;
- if (host_bits & float_flag_overflow)
+ }
+ if (host_bits & float_flag_overflow) {
target_bits |= 4;
- if (host_bits & (float_flag_underflow | float_flag_output_denormal))
+ }
+ if (host_bits & (float_flag_underflow | float_flag_output_denormal)) {
target_bits |= 8;
- if (host_bits & float_flag_inexact)
+ }
+ if (host_bits & float_flag_inexact) {
target_bits |= 0x10;
- if (host_bits & float_flag_input_denormal)
+ }
+ if (host_bits & float_flag_input_denormal) {
target_bits |= 0x80;
+ }
return target_bits;
}
-uint32_t HELPER(vfp_get_fpscr)(CPUARMState *env)
-{
- uint32_t i, fpscr;
-
- fpscr = env->vfp.xregs[ARM_VFP_FPSCR]
- | (env->vfp.vec_len << 16)
- | (env->vfp.vec_stride << 20);
-
- i = get_float_exception_flags(&env->vfp.fp_status);
- i |= get_float_exception_flags(&env->vfp.standard_fp_status);
- /* FZ16 does not generate an input denormal exception. */
- i |= (get_float_exception_flags(&env->vfp.fp_status_f16)
- & ~float_flag_input_denormal);
- fpscr |= vfp_exceptbits_from_host(i);
-
- i = env->vfp.qc[0] | env->vfp.qc[1] | env->vfp.qc[2] | env->vfp.qc[3];
- fpscr |= i ? FPCR_QC : 0;
-
- return fpscr;
-}
-
-uint32_t vfp_get_fpscr(CPUARMState *env)
-{
- return HELPER(vfp_get_fpscr)(env);
-}
-
/* Convert vfp exception flags to target form. */
static inline int vfp_exceptbits_to_host(int target_bits)
{
int host_bits = 0;
- if (target_bits & 1)
+ if (target_bits & 1) {
host_bits |= float_flag_invalid;
- if (target_bits & 2)
+ }
+ if (target_bits & 2) {
host_bits |= float_flag_divbyzero;
- if (target_bits & 4)
+ }
+ if (target_bits & 4) {
host_bits |= float_flag_overflow;
- if (target_bits & 8)
+ }
+ if (target_bits & 8) {
host_bits |= float_flag_underflow;
- if (target_bits & 0x10)
+ }
+ if (target_bits & 0x10) {
host_bits |= float_flag_inexact;
- if (target_bits & 0x80)
+ }
+ if (target_bits & 0x80) {
host_bits |= float_flag_input_denormal;
+ }
return host_bits;
}
-void HELPER(vfp_set_fpscr)(CPUARMState *env, uint32_t val)
+static uint32_t vfp_get_fpscr_from_host(CPUARMState *env)
{
- int i;
- uint32_t changed = env->vfp.xregs[ARM_VFP_FPSCR];
-
- /* When ARMv8.2-FP16 is not supported, FZ16 is RES0. */
- if (!cpu_isar_feature(aa64_fp16, env_archcpu(env))) {
- val &= ~FPCR_FZ16;
- }
-
- if (arm_feature(env, ARM_FEATURE_M)) {
- /*
- * M profile FPSCR is RES0 for the QC, STRIDE, FZ16, LEN bits
- * and also for the trapped-exception-handling bits IxE.
- */
- val &= 0xf7c0009f;
- }
+ uint32_t i;
- /*
- * We don't implement trapped exception handling, so the
- * trap enable bits, IDE|IXE|UFE|OFE|DZE|IOE are all RAZ/WI (not RES0!)
- *
- * If we exclude the exception flags, IOC|DZC|OFC|UFC|IXC|IDC
- * (which are stored in fp_status), and the other RES0 bits
- * in between, then we clear all of the low 16 bits.
- */
- env->vfp.xregs[ARM_VFP_FPSCR] = val & 0xf7c80000;
- env->vfp.vec_len = (val >> 16) & 7;
- env->vfp.vec_stride = (val >> 20) & 3;
+ i = get_float_exception_flags(&env->vfp.fp_status);
+ i |= get_float_exception_flags(&env->vfp.standard_fp_status);
+ /* FZ16 does not generate an input denormal exception. */
+ i |= (get_float_exception_flags(&env->vfp.fp_status_f16)
+ & ~float_flag_input_denormal);
+ return vfp_exceptbits_from_host(i);
+}
- /*
- * The bit we set within fpscr_q is arbitrary; the register as a
- * whole being zero/non-zero is what counts.
- */
- env->vfp.qc[0] = val & FPCR_QC;
- env->vfp.qc[1] = 0;
- env->vfp.qc[2] = 0;
- env->vfp.qc[3] = 0;
+static void vfp_set_fpscr_to_host(CPUARMState *env, uint32_t val)
+{
+ int i;
+ uint32_t changed = env->vfp.xregs[ARM_VFP_FPSCR];
changed ^= val;
if (changed & (3 << 22)) {
set_default_nan_mode(dnan_enabled, &env->vfp.fp_status_f16);
}
- /* The exception flags are ORed together when we read fpscr so we
+ /*
+ * The exception flags are ORed together when we read fpscr so we
* only need to preserve the current state in one of our
* float_status values.
*/
set_float_exception_flags(0, &env->vfp.standard_fp_status);
}
+#else
+
+static uint32_t vfp_get_fpscr_from_host(CPUARMState *env)
+{
+ return 0;
+}
+
+static void vfp_set_fpscr_to_host(CPUARMState *env, uint32_t val)
+{
+}
+
+#endif
+
+uint32_t HELPER(vfp_get_fpscr)(CPUARMState *env)
+{
+ uint32_t i, fpscr;
+
+ fpscr = env->vfp.xregs[ARM_VFP_FPSCR]
+ | (env->vfp.vec_len << 16)
+ | (env->vfp.vec_stride << 20);
+
+ fpscr |= vfp_get_fpscr_from_host(env);
+
+ i = env->vfp.qc[0] | env->vfp.qc[1] | env->vfp.qc[2] | env->vfp.qc[3];
+ fpscr |= i ? FPCR_QC : 0;
+
+ return fpscr;
+}
+
+uint32_t vfp_get_fpscr(CPUARMState *env)
+{
+ return HELPER(vfp_get_fpscr)(env);
+}
+
+void HELPER(vfp_set_fpscr)(CPUARMState *env, uint32_t val)
+{
+ /* When ARMv8.2-FP16 is not supported, FZ16 is RES0. */
+ if (!cpu_isar_feature(aa64_fp16, env_archcpu(env))) {
+ val &= ~FPCR_FZ16;
+ }
+
+ if (arm_feature(env, ARM_FEATURE_M)) {
+ /*
+ * M profile FPSCR is RES0 for the QC, STRIDE, FZ16, LEN bits
+ * and also for the trapped-exception-handling bits IxE.
+ */
+ val &= 0xf7c0009f;
+ }
+
+ /*
+ * We don't implement trapped exception handling, so the
+ * trap enable bits, IDE|IXE|UFE|OFE|DZE|IOE are all RAZ/WI (not RES0!)
+ *
+ * If we exclude the exception flags, IOC|DZC|OFC|UFC|IXC|IDC
+ * (which are stored in fp_status), and the other RES0 bits
+ * in between, then we clear all of the low 16 bits.
+ */
+ env->vfp.xregs[ARM_VFP_FPSCR] = val & 0xf7c80000;
+ env->vfp.vec_len = (val >> 16) & 7;
+ env->vfp.vec_stride = (val >> 20) & 3;
+
+ /*
+ * The bit we set within fpscr_q is arbitrary; the register as a
+ * whole being zero/non-zero is what counts.
+ */
+ env->vfp.qc[0] = val & FPCR_QC;
+ env->vfp.qc[1] = 0;
+ env->vfp.qc[2] = 0;
+ env->vfp.qc[3] = 0;
+
+ vfp_set_fpscr_to_host(env, val);
+}
+
void vfp_set_fpscr(CPUARMState *env, uint32_t val)
{
HELPER(vfp_set_fpscr)(env, val);
}
+#ifdef CONFIG_TCG
+
#define VFP_HELPER(name, p) HELPER(glue(glue(vfp_,name),p))
#define VFP_BINOP(name) \
{
return frint_d(f, fpst, 64);
}
+
+#endif
#include "qemu/option.h"
#include "qemu/config-file.h"
#include "qapi/error.h"
-#include "qapi/qapi-visit-misc.h"
+#include "qapi/qapi-visit-machine.h"
#include "qapi/qapi-visit-run-state.h"
#include "qapi/qmp/qdict.h"
#include "qapi/qmp/qerror.h"
#include "qapi/visitor.h"
#include "qom/qom-qobject.h"
#include "sysemu/arch_init.h"
-#include "qapi/qapi-commands-target.h"
+#include "qapi/qapi-commands-machine-target.h"
#include "standard-headers/asm-x86/kvm_para.h"
{
switch (exit->type) {
case KVM_EXIT_HYPERV_SYNIC:
- if (!cpu->hyperv_synic) {
+ if (!hyperv_feat_enabled(cpu, HYPERV_FEAT_SYNIC)) {
return -1;
}
#include "cpu.h"
#include "monitor/monitor.h"
#include "monitor/hmp-target.h"
+#include "monitor/hmp.h"
#include "qapi/qmp/qdict.h"
#include "hw/i386/pc.h"
#include "sysemu/kvm.h"
#include "sysemu/sev.h"
-#include "hmp.h"
#include "qapi/error.h"
#include "sev_i386.h"
#include "qapi/qapi-commands-misc.h"
#include "sysemu/kvm.h"
#include "sysemu/sev.h"
#include "qemu/error-report.h"
-#include "qapi/qapi-commands-target.h"
+#include "qapi/qapi-commands-misc-target.h"
#define SEV_POLICY_NODBG 0x1
#define SEV_POLICY_NOKS 0x2
#include "exec/cpu_ldst.h"
#include "exec/log.h"
#include "hw/mips/cpudevs.h"
-#include "qapi/qapi-commands-target.h"
+#include "qapi/qapi-commands-machine-target.h"
enum {
TLBRET_XI = -6,
* --------
*
* +---------------+----------------------------------------------------------+
- * | BMNZ.V | Vector Bit Move If Not Zero |
- * | BMZ.V | Vector Bit Move If Zero |
- * | BSEL.V | Vector Bit Select |
* | BINSL.B | Vector Bit Insert Left (byte) |
* | BINSL.H | Vector Bit Insert Left (halfword) |
* | BINSL.W | Vector Bit Insert Left (word) |
* | BINSR.H | Vector Bit Insert Right (halfword) |
* | BINSR.W | Vector Bit Insert Right (word) |
* | BINSR.D | Vector Bit Insert Right (doubleword) |
+ * | BMNZ.V | Vector Bit Move If Not Zero |
+ * | BMZ.V | Vector Bit Move If Zero |
+ * | BSEL.V | Vector Bit Select |
* +---------------+----------------------------------------------------------+
*/
* | ADDV.H | Vector Add (halfword) |
* | ADDV.W | Vector Add (word) |
* | ADDV.D | Vector Add (doubleword) |
- * | HSUB_S.H | Vector Signed Horizontal Add (halfword) |
- * | HSUB_S.W | Vector Signed Horizontal Add (word) |
- * | HSUB_S.D | Vector Signed Horizontal Add (doubleword) |
- * | HSUB_U.H | Vector Unigned Horizontal Add (halfword) |
- * | HSUB_U.W | Vector Unigned Horizontal Add (word) |
- * | HSUB_U.D | Vector Unigned Horizontal Add (doubleword) |
+ * | HADD_S.H | Vector Signed Horizontal Add (halfword) |
+ * | HADD_S.W | Vector Signed Horizontal Add (word) |
+ * | HADD_S.D | Vector Signed Horizontal Add (doubleword) |
+ * | HADD_U.H | Vector Unigned Horizontal Add (halfword) |
+ * | HADD_U.W | Vector Unigned Horizontal Add (word) |
+ * | HADD_U.D | Vector Unigned Horizontal Add (doubleword) |
* +---------------+----------------------------------------------------------+
*/
* | DOTP_U.H | Vector Unsigned Dot Product (halfword) |
* | DOTP_U.W | Vector Unsigned Dot Product (word) |
* | DOTP_U.D | Vector Unsigned Dot Product (doubleword) |
+ * | DPADD_S.H | Vector Signed Dot Product (halfword) |
+ * | DPADD_S.W | Vector Signed Dot Product (word) |
+ * | DPADD_S.D | Vector Signed Dot Product (doubleword) |
+ * | DPADD_U.H | Vector Unsigned Dot Product (halfword) |
+ * | DPADD_U.W | Vector Unsigned Dot Product (word) |
+ * | DPADD_U.D | Vector Unsigned Dot Product (doubleword) |
+ * | DPSUB_S.H | Vector Signed Dot Product (halfword) |
+ * | DPSUB_S.W | Vector Signed Dot Product (word) |
+ * | DPSUB_S.D | Vector Signed Dot Product (doubleword) |
+ * | DPSUB_U.H | Vector Unsigned Dot Product (halfword) |
+ * | DPSUB_U.W | Vector Unsigned Dot Product (word) |
+ * | DPSUB_U.D | Vector Unsigned Dot Product (doubleword) |
* +---------------+----------------------------------------------------------+
*/
* | SUBS_U.H | Vector Unsigned Saturated Subtract (of Uns.) (halfword) |
* | SUBS_U.W | Vector Unsigned Saturated Subtract (of Uns.) (word) |
* | SUBS_U.D | Vector Unsigned Saturated Subtract (of Uns.) (doubleword)|
- * | SUBSUS_S.B | Vector Uns. Sat. Subtract (of S. from Uns.) (byte) |
- * | SUBSUS_S.H | Vector Uns. Sat. Subtract (of S. from Uns.) (halfword) |
- * | SUBSUS_S.W | Vector Uns. Sat. Subtract (of S. from Uns.) (word) |
- * | SUBSUS_S.D | Vector Uns. Sat. Subtract (of S. from Uns.) (doubleword) |
- * | SUBSUU_U.B | Vector Signed Saturated Subtract (of Uns.) (byte) |
- * | SUBSUU_U.H | Vector Signed Saturated Subtract (of Uns.) (halfword) |
- * | SUBSUU_U.W | Vector Signed Saturated Subtract (of Uns.) (word) |
- * | SUBSUU_U.D | Vector Signed Saturated Subtract (of Uns.) (doubleword) |
+ * | SUBSUS_U.B | Vector Uns. Sat. Subtract (of S. from Uns.) (byte) |
+ * | SUBSUS_U.H | Vector Uns. Sat. Subtract (of S. from Uns.) (halfword) |
+ * | SUBSUS_U.W | Vector Uns. Sat. Subtract (of S. from Uns.) (word) |
+ * | SUBSUS_U.D | Vector Uns. Sat. Subtract (of S. from Uns.) (doubleword) |
+ * | SUBSUU_S.B | Vector Signed Saturated Subtract (of Uns.) (byte) |
+ * | SUBSUU_S.H | Vector Signed Saturated Subtract (of Uns.) (halfword) |
+ * | SUBSUU_S.W | Vector Signed Saturated Subtract (of Uns.) (word) |
+ * | SUBSUU_S.D | Vector Signed Saturated Subtract (of Uns.) (doubleword) |
* | SUBV.B | Vector Subtract (byte) |
* | SUBV.H | Vector Subtract (halfword) |
* | SUBV.W | Vector Subtract (word) |
/* TODO: insert Logic group helpers here */
+/*
+ * Move
+ * ----
+ *
+ * +---------------+----------------------------------------------------------+
+ * | MOVE.V | Vector Move |
+ * +---------------+----------------------------------------------------------+
+ */
+
+/* TODO: insert Move group helpers here */
+
+
/*
* Pack
* ----
wr_t *pwd = &(env->active_fpu.fpr[wd].wr);
wr_t *pws = &(env->active_fpu.fpr[ws].wr);
wr_t *pwt = &(env->active_fpu.fpr[wt].wr);
- uint32_t i;
clear_msacsr_cause(env);
- switch (df) {
- case DF_WORD:
- for (i = 0; i < DF_ELEMENTS(DF_WORD); i++) {
- if (NUMBER_QNAN_PAIR(pws->w[i], pwt->w[i], 32, status)) {
- MSA_FLOAT_MAXOP(pwx->w[i], min, pws->w[i], pws->w[i], 32);
- } else if (NUMBER_QNAN_PAIR(pwt->w[i], pws->w[i], 32, status)) {
- MSA_FLOAT_MAXOP(pwx->w[i], min, pwt->w[i], pwt->w[i], 32);
- } else {
- MSA_FLOAT_MAXOP(pwx->w[i], min, pws->w[i], pwt->w[i], 32);
- }
+ if (df == DF_WORD) {
+
+ if (NUMBER_QNAN_PAIR(pws->w[0], pwt->w[0], 32, status)) {
+ MSA_FLOAT_MAXOP(pwx->w[0], min, pws->w[0], pws->w[0], 32);
+ } else if (NUMBER_QNAN_PAIR(pwt->w[0], pws->w[0], 32, status)) {
+ MSA_FLOAT_MAXOP(pwx->w[0], min, pwt->w[0], pwt->w[0], 32);
+ } else {
+ MSA_FLOAT_MAXOP(pwx->w[0], min, pws->w[0], pwt->w[0], 32);
}
- break;
- case DF_DOUBLE:
- for (i = 0; i < DF_ELEMENTS(DF_DOUBLE); i++) {
- if (NUMBER_QNAN_PAIR(pws->d[i], pwt->d[i], 64, status)) {
- MSA_FLOAT_MAXOP(pwx->d[i], min, pws->d[i], pws->d[i], 64);
- } else if (NUMBER_QNAN_PAIR(pwt->d[i], pws->d[i], 64, status)) {
- MSA_FLOAT_MAXOP(pwx->d[i], min, pwt->d[i], pwt->d[i], 64);
- } else {
- MSA_FLOAT_MAXOP(pwx->d[i], min, pws->d[i], pwt->d[i], 64);
- }
+
+ if (NUMBER_QNAN_PAIR(pws->w[1], pwt->w[1], 32, status)) {
+ MSA_FLOAT_MAXOP(pwx->w[1], min, pws->w[1], pws->w[1], 32);
+ } else if (NUMBER_QNAN_PAIR(pwt->w[1], pws->w[1], 32, status)) {
+ MSA_FLOAT_MAXOP(pwx->w[1], min, pwt->w[1], pwt->w[1], 32);
+ } else {
+ MSA_FLOAT_MAXOP(pwx->w[1], min, pws->w[1], pwt->w[1], 32);
}
- break;
- default:
+
+ if (NUMBER_QNAN_PAIR(pws->w[2], pwt->w[2], 32, status)) {
+ MSA_FLOAT_MAXOP(pwx->w[2], min, pws->w[2], pws->w[2], 32);
+ } else if (NUMBER_QNAN_PAIR(pwt->w[2], pws->w[2], 32, status)) {
+ MSA_FLOAT_MAXOP(pwx->w[2], min, pwt->w[2], pwt->w[2], 32);
+ } else {
+ MSA_FLOAT_MAXOP(pwx->w[2], min, pws->w[2], pwt->w[2], 32);
+ }
+
+ if (NUMBER_QNAN_PAIR(pws->w[3], pwt->w[3], 32, status)) {
+ MSA_FLOAT_MAXOP(pwx->w[3], min, pws->w[3], pws->w[3], 32);
+ } else if (NUMBER_QNAN_PAIR(pwt->w[3], pws->w[3], 32, status)) {
+ MSA_FLOAT_MAXOP(pwx->w[3], min, pwt->w[3], pwt->w[3], 32);
+ } else {
+ MSA_FLOAT_MAXOP(pwx->w[3], min, pws->w[3], pwt->w[3], 32);
+ }
+
+ } else if (df == DF_DOUBLE) {
+
+ if (NUMBER_QNAN_PAIR(pws->d[0], pwt->d[0], 64, status)) {
+ MSA_FLOAT_MAXOP(pwx->d[0], min, pws->d[0], pws->d[0], 64);
+ } else if (NUMBER_QNAN_PAIR(pwt->d[0], pws->d[0], 64, status)) {
+ MSA_FLOAT_MAXOP(pwx->d[0], min, pwt->d[0], pwt->d[0], 64);
+ } else {
+ MSA_FLOAT_MAXOP(pwx->d[0], min, pws->d[0], pwt->d[0], 64);
+ }
+
+ if (NUMBER_QNAN_PAIR(pws->d[1], pwt->d[1], 64, status)) {
+ MSA_FLOAT_MAXOP(pwx->d[1], min, pws->d[1], pws->d[1], 64);
+ } else if (NUMBER_QNAN_PAIR(pwt->d[1], pws->d[1], 64, status)) {
+ MSA_FLOAT_MAXOP(pwx->d[1], min, pwt->d[1], pwt->d[1], 64);
+ } else {
+ MSA_FLOAT_MAXOP(pwx->d[1], min, pws->d[1], pwt->d[1], 64);
+ }
+
+ } else {
+
assert(0);
+
}
check_msacsr_cause(env, GETPC());
wr_t *pwd = &(env->active_fpu.fpr[wd].wr);
wr_t *pws = &(env->active_fpu.fpr[ws].wr);
wr_t *pwt = &(env->active_fpu.fpr[wt].wr);
- uint32_t i;
clear_msacsr_cause(env);
- switch (df) {
- case DF_WORD:
- for (i = 0; i < DF_ELEMENTS(DF_WORD); i++) {
- FMAXMIN_A(min, max, pwx->w[i], pws->w[i], pwt->w[i], 32, status);
- }
- break;
- case DF_DOUBLE:
- for (i = 0; i < DF_ELEMENTS(DF_DOUBLE); i++) {
- FMAXMIN_A(min, max, pwx->d[i], pws->d[i], pwt->d[i], 64, status);
- }
- break;
- default:
+ if (df == DF_WORD) {
+ FMAXMIN_A(min, max, pwx->w[0], pws->w[0], pwt->w[0], 32, status);
+ FMAXMIN_A(min, max, pwx->w[1], pws->w[1], pwt->w[1], 32, status);
+ FMAXMIN_A(min, max, pwx->w[2], pws->w[2], pwt->w[2], 32, status);
+ FMAXMIN_A(min, max, pwx->w[3], pws->w[3], pwt->w[3], 32, status);
+ } else if (df == DF_DOUBLE) {
+ FMAXMIN_A(min, max, pwx->d[0], pws->d[0], pwt->d[0], 64, status);
+ FMAXMIN_A(min, max, pwx->d[1], pws->d[1], pwt->d[1], 64, status);
+ } else {
assert(0);
}
void helper_msa_fmax_df(CPUMIPSState *env, uint32_t df, uint32_t wd,
uint32_t ws, uint32_t wt)
{
- float_status *status = &env->active_tc.msa_fp_status;
+ float_status *status = &env->active_tc.msa_fp_status;
wr_t wx, *pwx = &wx;
wr_t *pwd = &(env->active_fpu.fpr[wd].wr);
wr_t *pws = &(env->active_fpu.fpr[ws].wr);
wr_t *pwt = &(env->active_fpu.fpr[wt].wr);
- uint32_t i;
clear_msacsr_cause(env);
- switch (df) {
- case DF_WORD:
- for (i = 0; i < DF_ELEMENTS(DF_WORD); i++) {
- if (NUMBER_QNAN_PAIR(pws->w[i], pwt->w[i], 32, status)) {
- MSA_FLOAT_MAXOP(pwx->w[i], max, pws->w[i], pws->w[i], 32);
- } else if (NUMBER_QNAN_PAIR(pwt->w[i], pws->w[i], 32, status)) {
- MSA_FLOAT_MAXOP(pwx->w[i], max, pwt->w[i], pwt->w[i], 32);
- } else {
- MSA_FLOAT_MAXOP(pwx->w[i], max, pws->w[i], pwt->w[i], 32);
- }
+ if (df == DF_WORD) {
+
+ if (NUMBER_QNAN_PAIR(pws->w[0], pwt->w[0], 32, status)) {
+ MSA_FLOAT_MAXOP(pwx->w[0], max, pws->w[0], pws->w[0], 32);
+ } else if (NUMBER_QNAN_PAIR(pwt->w[0], pws->w[0], 32, status)) {
+ MSA_FLOAT_MAXOP(pwx->w[0], max, pwt->w[0], pwt->w[0], 32);
+ } else {
+ MSA_FLOAT_MAXOP(pwx->w[0], max, pws->w[0], pwt->w[0], 32);
}
- break;
- case DF_DOUBLE:
- for (i = 0; i < DF_ELEMENTS(DF_DOUBLE); i++) {
- if (NUMBER_QNAN_PAIR(pws->d[i], pwt->d[i], 64, status)) {
- MSA_FLOAT_MAXOP(pwx->d[i], max, pws->d[i], pws->d[i], 64);
- } else if (NUMBER_QNAN_PAIR(pwt->d[i], pws->d[i], 64, status)) {
- MSA_FLOAT_MAXOP(pwx->d[i], max, pwt->d[i], pwt->d[i], 64);
- } else {
- MSA_FLOAT_MAXOP(pwx->d[i], max, pws->d[i], pwt->d[i], 64);
- }
+
+ if (NUMBER_QNAN_PAIR(pws->w[1], pwt->w[1], 32, status)) {
+ MSA_FLOAT_MAXOP(pwx->w[1], max, pws->w[1], pws->w[1], 32);
+ } else if (NUMBER_QNAN_PAIR(pwt->w[1], pws->w[1], 32, status)) {
+ MSA_FLOAT_MAXOP(pwx->w[1], max, pwt->w[1], pwt->w[1], 32);
+ } else {
+ MSA_FLOAT_MAXOP(pwx->w[1], max, pws->w[1], pwt->w[1], 32);
}
- break;
- default:
+
+ if (NUMBER_QNAN_PAIR(pws->w[2], pwt->w[2], 32, status)) {
+ MSA_FLOAT_MAXOP(pwx->w[2], max, pws->w[2], pws->w[2], 32);
+ } else if (NUMBER_QNAN_PAIR(pwt->w[2], pws->w[2], 32, status)) {
+ MSA_FLOAT_MAXOP(pwx->w[2], max, pwt->w[2], pwt->w[2], 32);
+ } else {
+ MSA_FLOAT_MAXOP(pwx->w[2], max, pws->w[2], pwt->w[2], 32);
+ }
+
+ if (NUMBER_QNAN_PAIR(pws->w[3], pwt->w[3], 32, status)) {
+ MSA_FLOAT_MAXOP(pwx->w[3], max, pws->w[3], pws->w[3], 32);
+ } else if (NUMBER_QNAN_PAIR(pwt->w[3], pws->w[3], 32, status)) {
+ MSA_FLOAT_MAXOP(pwx->w[3], max, pwt->w[3], pwt->w[3], 32);
+ } else {
+ MSA_FLOAT_MAXOP(pwx->w[3], max, pws->w[3], pwt->w[3], 32);
+ }
+
+ } else if (df == DF_DOUBLE) {
+
+ if (NUMBER_QNAN_PAIR(pws->d[0], pwt->d[0], 64, status)) {
+ MSA_FLOAT_MAXOP(pwx->d[0], max, pws->d[0], pws->d[0], 64);
+ } else if (NUMBER_QNAN_PAIR(pwt->d[0], pws->d[0], 64, status)) {
+ MSA_FLOAT_MAXOP(pwx->d[0], max, pwt->d[0], pwt->d[0], 64);
+ } else {
+ MSA_FLOAT_MAXOP(pwx->d[0], max, pws->d[0], pwt->d[0], 64);
+ }
+
+ if (NUMBER_QNAN_PAIR(pws->d[1], pwt->d[1], 64, status)) {
+ MSA_FLOAT_MAXOP(pwx->d[1], max, pws->d[1], pws->d[1], 64);
+ } else if (NUMBER_QNAN_PAIR(pwt->d[1], pws->d[1], 64, status)) {
+ MSA_FLOAT_MAXOP(pwx->d[1], max, pwt->d[1], pwt->d[1], 64);
+ } else {
+ MSA_FLOAT_MAXOP(pwx->d[1], max, pws->d[1], pwt->d[1], 64);
+ }
+
+ } else {
+
assert(0);
+
}
check_msacsr_cause(env, GETPC());
wr_t *pwd = &(env->active_fpu.fpr[wd].wr);
wr_t *pws = &(env->active_fpu.fpr[ws].wr);
wr_t *pwt = &(env->active_fpu.fpr[wt].wr);
- uint32_t i;
clear_msacsr_cause(env);
- switch (df) {
- case DF_WORD:
- for (i = 0; i < DF_ELEMENTS(DF_WORD); i++) {
- FMAXMIN_A(max, min, pwx->w[i], pws->w[i], pwt->w[i], 32, status);
- }
- break;
- case DF_DOUBLE:
- for (i = 0; i < DF_ELEMENTS(DF_DOUBLE); i++) {
- FMAXMIN_A(max, min, pwx->d[i], pws->d[i], pwt->d[i], 64, status);
- }
- break;
- default:
+ if (df == DF_WORD) {
+ FMAXMIN_A(max, min, pwx->w[0], pws->w[0], pwt->w[0], 32, status);
+ FMAXMIN_A(max, min, pwx->w[1], pws->w[1], pwt->w[1], 32, status);
+ FMAXMIN_A(max, min, pwx->w[2], pws->w[2], pwt->w[2], 32, status);
+ FMAXMIN_A(max, min, pwx->w[3], pws->w[3], pwt->w[3], 32, status);
+ } else if (df == DF_DOUBLE) {
+ FMAXMIN_A(max, min, pwx->d[0], pws->d[0], pwt->d[0], 64, status);
+ FMAXMIN_A(max, min, pwx->d[1], pws->d[1], pwt->d[1], 64, status);
+ } else {
assert(0);
}
pwd->w[1] = float_class_s(pws->w[1], status);
pwd->w[2] = float_class_s(pws->w[2], status);
pwd->w[3] = float_class_s(pws->w[3], status);
- } else {
+ } else if (df == DF_DOUBLE) {
pwd->d[0] = float_class_d(pws->d[0], status);
pwd->d[1] = float_class_d(pws->d[1], status);
+ } else {
+ assert(0);
}
}
OPC_SPECIAL3D_RESERVED = 0x3D | OPC_SPECIAL,
};
-/* R6 Multiply and Divide instructions have the same Opcode
- and function field as legacy OPC_MULT[U]/OPC_DIV[U] */
+/*
+ * R6 Multiply and Divide instructions have the same opcode
+ * and function field as legacy OPC_MULT[U]/OPC_DIV[U]
+ */
#define MASK_R6_MULDIV(op) (MASK_SPECIAL(op) | (op & (0x7ff)))
enum {
}
}
-/* Verify that the processor is running with COP1X instructions enabled.
- This is associated with the nabla symbol in the MIPS32 and MIPS64
- opcode tables. */
-
+/*
+ * Verify that the processor is running with COP1X instructions enabled.
+ * This is associated with the nabla symbol in the MIPS32 and MIPS64
+ * opcode tables.
+ */
static inline void check_cop1x(DisasContext *ctx)
{
if (unlikely(!(ctx->hflags & MIPS_HFLAG_COP1X))) {
}
}
-/* Verify that the processor is running with 64-bit floating-point
- operations enabled. */
-
+/*
+ * Verify that the processor is running with 64-bit floating-point
+ * operations enabled.
+ */
static inline void check_cp1_64bitmode(DisasContext *ctx)
{
if (unlikely(~ctx->hflags & (MIPS_HFLAG_F64 | MIPS_HFLAG_COP1X))) {
}
}
-/* Verify that the processor is running with DSP instructions enabled.
- This is enabled by CP0 Status register MX(24) bit.
+/*
+ * Verify that the processor is running with DSP instructions enabled.
+ * This is enabled by CP0 Status register MX(24) bit.
*/
-
static inline void check_dsp(DisasContext *ctx)
{
if (unlikely(!(ctx->hflags & MIPS_HFLAG_DSP))) {
}
}
-/* This code generates a "reserved instruction" exception if the
- CPU does not support the instruction set corresponding to flags. */
+/*
+ * This code generates a "reserved instruction" exception if the
+ * CPU does not support the instruction set corresponding to flags.
+ */
static inline void check_insn(DisasContext *ctx, uint64_t flags)
{
if (unlikely(!(ctx->insn_flags & flags))) {
}
}
-/* This code generates a "reserved instruction" exception if the
- CPU has corresponding flag set which indicates that the instruction
- has been removed. */
+/*
+ * This code generates a "reserved instruction" exception if the
+ * CPU has corresponding flag set which indicates that the instruction
+ * has been removed.
+ */
static inline void check_insn_opc_removed(DisasContext *ctx, uint64_t flags)
{
if (unlikely(ctx->insn_flags & flags)) {
#endif
}
-/* This code generates a "reserved instruction" exception if the
- CPU does not support 64-bit paired-single (PS) floating point data type */
+/*
+ * This code generates a "reserved instruction" exception if the
+ * CPU does not support 64-bit paired-single (PS) floating point data type.
+ */
static inline void check_ps(DisasContext *ctx)
{
if (unlikely(!ctx->ps)) {
}
#ifdef TARGET_MIPS64
-/* This code generates a "reserved instruction" exception if 64-bit
- instructions are not enabled. */
+/*
+ * This code generates a "reserved instruction" exception if 64-bit
+ * instructions are not enabled.
+ */
static inline void check_mips_64(DisasContext *ctx)
{
if (unlikely(!(ctx->hflags & MIPS_HFLAG_64))) {
}
-/* Define small wrappers for gen_load_fpr* so that we have a uniform
- calling interface for 32 and 64-bit FPRs. No sense in changing
- all callers for gen_load_fpr32 when we need the CTX parameter for
- this one use. */
+/*
+ * Define small wrappers for gen_load_fpr* so that we have a uniform
+ * calling interface for 32 and 64-bit FPRs. No sense in changing
+ * all callers for gen_load_fpr32 when we need the CTX parameter for
+ * this one use.
+ */
#define gen_ldcmp_fpr32(ctx, x, y) gen_load_fpr32(ctx, x, y)
#define gen_ldcmp_fpr64(ctx, x, y) gen_load_fpr64(ctx, x, y)
#define FOP_CONDS(type, abs, fmt, ifmt, bits) \
int mem_idx = ctx->mem_idx;
if (rt == 0 && ctx->insn_flags & (INSN_LOONGSON2E | INSN_LOONGSON2F)) {
- /* Loongson CPU uses a load to zero register for prefetch.
- We emulate it as a NOP. On other CPU we must perform the
- actual memory access. */
+ /*
+ * Loongson CPU uses a load to zero register for prefetch.
+ * We emulate it as a NOP. On other CPU we must perform the
+ * actual memory access.
+ */
return;
}
break;
case OPC_LDL:
t1 = tcg_temp_new();
- /* Do a byte access to possibly trigger a page
- fault with the unaligned address. */
+ /*
+ * Do a byte access to possibly trigger a page
+ * fault with the unaligned address.
+ */
tcg_gen_qemu_ld_tl(t1, t0, mem_idx, MO_UB);
tcg_gen_andi_tl(t1, t0, 7);
#ifndef TARGET_WORDS_BIGENDIAN
break;
case OPC_LDR:
t1 = tcg_temp_new();
- /* Do a byte access to possibly trigger a page
- fault with the unaligned address. */
+ /*
+ * Do a byte access to possibly trigger a page
+ * fault with the unaligned address.
+ */
tcg_gen_qemu_ld_tl(t1, t0, mem_idx, MO_UB);
tcg_gen_andi_tl(t1, t0, 7);
#ifdef TARGET_WORDS_BIGENDIAN
/* fall through */
case OPC_LWL:
t1 = tcg_temp_new();
- /* Do a byte access to possibly trigger a page
- fault with the unaligned address. */
+ /*
+ * Do a byte access to possibly trigger a page
+ * fault with the unaligned address.
+ */
tcg_gen_qemu_ld_tl(t1, t0, mem_idx, MO_UB);
tcg_gen_andi_tl(t1, t0, 3);
#ifndef TARGET_WORDS_BIGENDIAN
/* fall through */
case OPC_LWR:
t1 = tcg_temp_new();
- /* Do a byte access to possibly trigger a page
- fault with the unaligned address. */
+ /*
+ * Do a byte access to possibly trigger a page
+ * fault with the unaligned address.
+ */
tcg_gen_qemu_ld_tl(t1, t0, mem_idx, MO_UB);
tcg_gen_andi_tl(t1, t0, 3);
#ifdef TARGET_WORDS_BIGENDIAN
static void gen_flt_ldst(DisasContext *ctx, uint32_t opc, int ft,
TCGv t0)
{
- /* Don't do NOP if destination is zero: we must perform the actual
- memory access. */
+ /*
+ * Don't do NOP if destination is zero: we must perform the actual
+ * memory access.
+ */
switch (opc) {
case OPC_LWC1:
{
target_ulong uimm = (target_long)imm; /* Sign extend to 32/64 bits */
if (rt == 0 && opc != OPC_ADDI && opc != OPC_DADDI) {
- /* If no destination, treat it as a NOP.
- For addi, we must generate the overflow exception when needed. */
+ /*
+ * If no destination, treat it as a NOP.
+ * For addi, we must generate the overflow exception when needed.
+ */
return;
}
switch (opc) {
{
if (rd == 0 && opc != OPC_ADD && opc != OPC_SUB
&& opc != OPC_DADD && opc != OPC_DSUB) {
- /* If no destination, treat it as a NOP.
- For add & sub, we must generate the overflow exception when needed. */
+ /*
+ * If no destination, treat it as a NOP.
+ * For add & sub, we must generate the overflow exception when needed.
+ */
return;
}
tcg_temp_free(t2);
tcg_gen_brcondi_tl(TCG_COND_GE, t1, 0, l1);
tcg_temp_free(t1);
- /* operands of different sign, first operand and result different sign */
+ /*
+ * operands of different sign, first operand and the result
+ * of different sign
+ */
generate_exception(ctx, EXCP_OVERFLOW);
gen_set_label(l1);
gen_store_gpr(t0, rd);
TCGv t0, t1;
if (rd == 0) {
- /* If no destination, treat it as a NOP.
- For add & sub, we must generate the overflow exception when needed. */
+ /*
+ * If no destination, treat it as a NOP.
+ * For add & sub, we must generate the overflow exception when needed.
+ */
return;
}
break;
case OPC_SRA_CP2:
case OPC_DSRA_CP2:
- /* Since SRA is UndefinedResult without sign-extended inputs,
- we can treat SRA and DSRA the same. */
+ /*
+ * Since SRA is UndefinedResult without sign-extended inputs,
+ * we can treat SRA and DSRA the same.
+ */
tcg_gen_sar_i64(t0, t0, t1);
break;
case OPC_SRL_CP2:
case OPC_SLT_CP2:
case OPC_SLEU_CP2:
case OPC_SLE_CP2:
- /* ??? Document is unclear: Set FCC[CC]. Does that mean the
- FD field is the CC field? */
+ /*
+ * ??? Document is unclear: Set FCC[CC]. Does that mean the
+ * FD field is the CC field?
+ */
default:
MIPS_INVAL("loongson_cp2");
generate_exception_end(ctx, EXCP_RI);
case OPC_JALR:
/* Jump to register */
if (offset != 0 && offset != 16) {
- /* Hint = 0 is JR/JALR, hint 16 is JR.HB/JALR.HB, the
- others are reserved. */
+ /*
+ * Hint = 0 is JR/JALR, hint 16 is JR.HB/JALR.HB, the
+ * others are reserved.
+ */
MIPS_INVAL("jump hint");
generate_exception_end(ctx, EXCP_RI);
goto out;
/* Treat as NOP. */
goto out;
case OPC_BLTZAL: /* 0 < 0 */
- /* Handle as an unconditional branch to get correct delay
- slot checking. */
+ /*
+ * Handle as an unconditional branch to get correct delay
+ * slot checking.
+ */
blink = 31;
btgt = ctx->base.pc_next + insn_bytes + delayslot_size;
ctx->hflags |= MIPS_HFLAG_B;
case OPC_JALR:
/* Jump to register */
if (offset != 0 && offset != 16) {
- /* Hint = 0 is JR/JALR, hint 16 is JR.HB/JALR.HB, the
- others are reserved. */
+ /*
+ * Hint = 0 is JR/JALR, hint 16 is JR.HB/JALR.HB, the
+ * others are reserved.
+ */
MIPS_INVAL("jump hint");
generate_exception_end(ctx, EXCP_RI);
goto out;
if (msb != 31) {
tcg_gen_extract_tl(t0, t1, lsb, msb + 1);
} else {
- /* The two checks together imply that lsb == 0,
- so this is a simple sign-extension. */
+ /*
+ * The two checks together imply that lsb == 0,
+ * so this is a simple sign-extension.
+ */
tcg_gen_ext32s_tl(t0, t1);
}
break;
case CP0_REGISTER_17:
switch (sel) {
case 0:
- /* LLAddr is read-only (the only exception is bit 0 if LLB is
- supported); the CP0_LLAddr_rw_bitmask does not seem to be
- relevant for modern MIPS cores supporting MTHC0, therefore
- treating MTHC0 to LLAddr as NOP. */
+ /*
+ * LLAddr is read-only (the only exception is bit 0 if LLB is
+ * supported); the CP0_LLAddr_rw_bitmask does not seem to be
+ * relevant for modern MIPS cores supporting MTHC0, therefore
+ * treating MTHC0 to LLAddr as NOP.
+ */
register_name = "LLAddr";
break;
case 1:
register_name = "Context";
break;
case 1:
-// gen_helper_mfc0_contextconfig(arg); /* SmartMIPS ASE */
+ /* gen_helper_mfc0_contextconfig(arg); - SmartMIPS ASE */
register_name = "ContextConfig";
goto cp0_unimplemented;
case 2:
if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) {
gen_io_end();
}
- /* Break the TB to be able to take timer interrupts immediately
- after reading count. DISAS_STOP isn't sufficient, we need to
- ensure we break completely out of translated code. */
+ /*
+ * Break the TB to be able to take timer interrupts immediately
+ * after reading count. DISAS_STOP isn't sufficient, we need to
+ * ensure we break completely out of translated code.
+ */
gen_save_pc(ctx->base.pc_next + 4);
ctx->base.is_jmp = DISAS_EXIT;
register_name = "Count";
register_name = "Performance0";
break;
case 1:
-// gen_helper_mfc0_performance1(arg);
+ /* gen_helper_mfc0_performance1(arg); */
register_name = "Performance1";
goto cp0_unimplemented;
case 2:
-// gen_helper_mfc0_performance2(arg);
+ /* gen_helper_mfc0_performance2(arg); */
register_name = "Performance2";
goto cp0_unimplemented;
case 3:
-// gen_helper_mfc0_performance3(arg);
+ /* gen_helper_mfc0_performance3(arg); */
register_name = "Performance3";
goto cp0_unimplemented;
case 4:
-// gen_helper_mfc0_performance4(arg);
+ /* gen_helper_mfc0_performance4(arg); */
register_name = "Performance4";
goto cp0_unimplemented;
case 5:
-// gen_helper_mfc0_performance5(arg);
+ /* gen_helper_mfc0_performance5(arg); */
register_name = "Performance5";
goto cp0_unimplemented;
case 6:
-// gen_helper_mfc0_performance6(arg);
+ /* gen_helper_mfc0_performance6(arg); */
register_name = "Performance6";
goto cp0_unimplemented;
case 7:
-// gen_helper_mfc0_performance7(arg);
+ /* gen_helper_mfc0_performance7(arg); */
register_name = "Performance7";
goto cp0_unimplemented;
default:
case 0:
save_cpu_state(ctx, 1);
gen_helper_mtc0_cause(cpu_env, arg);
- /* Stop translation as we may have triggered an interrupt.
+ /*
+ * Stop translation as we may have triggered an interrupt.
* DISAS_STOP isn't sufficient, we need to ensure we break out of
- * translated code to check for pending interrupts. */
+ * translated code to check for pending interrupts.
+ */
gen_save_pc(ctx->base.pc_next + 4);
ctx->base.is_jmp = DISAS_EXIT;
register_name = "Cause";
register_name = "Performance0";
break;
case 1:
-// gen_helper_mtc0_performance1(arg);
+ /* gen_helper_mtc0_performance1(arg); */
register_name = "Performance1";
goto cp0_unimplemented;
case 2:
-// gen_helper_mtc0_performance2(arg);
+ /* gen_helper_mtc0_performance2(arg); */
register_name = "Performance2";
goto cp0_unimplemented;
case 3:
-// gen_helper_mtc0_performance3(arg);
+ /* gen_helper_mtc0_performance3(arg); */
register_name = "Performance3";
goto cp0_unimplemented;
case 4:
-// gen_helper_mtc0_performance4(arg);
+ /* gen_helper_mtc0_performance4(arg); */
register_name = "Performance4";
goto cp0_unimplemented;
case 5:
-// gen_helper_mtc0_performance5(arg);
+ /* gen_helper_mtc0_performance5(arg); */
register_name = "Performance5";
goto cp0_unimplemented;
case 6:
-// gen_helper_mtc0_performance6(arg);
+ /* gen_helper_mtc0_performance6(arg); */
register_name = "Performance6";
goto cp0_unimplemented;
case 7:
-// gen_helper_mtc0_performance7(arg);
+ /* gen_helper_mtc0_performance7(arg); */
register_name = "Performance7";
goto cp0_unimplemented;
default:
/* For simplicity assume that all writes can cause interrupts. */
if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) {
gen_io_end();
- /* DISAS_STOP isn't sufficient, we need to ensure we break out of
- * translated code to check for pending interrupts. */
+ /*
+ * DISAS_STOP isn't sufficient, we need to ensure we break out of
+ * translated code to check for pending interrupts.
+ */
gen_save_pc(ctx->base.pc_next + 4);
ctx->base.is_jmp = DISAS_EXIT;
}
if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) {
gen_io_end();
}
- /* Break the TB to be able to take timer interrupts immediately
- after reading count. DISAS_STOP isn't sufficient, we need to
- ensure we break completely out of translated code. */
+ /*
+ * Break the TB to be able to take timer interrupts immediately
+ * after reading count. DISAS_STOP isn't sufficient, we need to
+ * ensure we break completely out of translated code.
+ */
gen_save_pc(ctx->base.pc_next + 4);
ctx->base.is_jmp = DISAS_EXIT;
register_name = "Count";
register_name = "Performance0";
break;
case 1:
-// gen_helper_dmfc0_performance1(arg);
+ /* gen_helper_dmfc0_performance1(arg); */
register_name = "Performance1";
goto cp0_unimplemented;
case 2:
-// gen_helper_dmfc0_performance2(arg);
+ /* gen_helper_dmfc0_performance2(arg); */
register_name = "Performance2";
goto cp0_unimplemented;
case 3:
-// gen_helper_dmfc0_performance3(arg);
+ /* gen_helper_dmfc0_performance3(arg); */
register_name = "Performance3";
goto cp0_unimplemented;
case 4:
-// gen_helper_dmfc0_performance4(arg);
+ /* gen_helper_dmfc0_performance4(arg); */
register_name = "Performance4";
goto cp0_unimplemented;
case 5:
-// gen_helper_dmfc0_performance5(arg);
+ /* gen_helper_dmfc0_performance5(arg); */
register_name = "Performance5";
goto cp0_unimplemented;
case 6:
-// gen_helper_dmfc0_performance6(arg);
+ /* gen_helper_dmfc0_performance6(arg); */
register_name = "Performance6";
goto cp0_unimplemented;
case 7:
-// gen_helper_dmfc0_performance7(arg);
+ /* gen_helper_dmfc0_performance7(arg); */
register_name = "Performance7";
goto cp0_unimplemented;
default:
case 0:
save_cpu_state(ctx, 1);
gen_helper_mtc0_cause(cpu_env, arg);
- /* Stop translation as we may have triggered an interrupt.
+ /*
+ * Stop translation as we may have triggered an interrupt.
* DISAS_STOP isn't sufficient, we need to ensure we break out of
- * translated code to check for pending interrupts. */
+ * translated code to check for pending interrupts.
+ */
gen_save_pc(ctx->base.pc_next + 4);
ctx->base.is_jmp = DISAS_EXIT;
register_name = "Cause";
register_name = "Performance0";
break;
case 1:
-// gen_helper_mtc0_performance1(cpu_env, arg);
+ /* gen_helper_mtc0_performance1(cpu_env, arg); */
register_name = "Performance1";
goto cp0_unimplemented;
case 2:
-// gen_helper_mtc0_performance2(cpu_env, arg);
+ /* gen_helper_mtc0_performance2(cpu_env, arg); */
register_name = "Performance2";
goto cp0_unimplemented;
case 3:
-// gen_helper_mtc0_performance3(cpu_env, arg);
+ /* gen_helper_mtc0_performance3(cpu_env, arg); */
register_name = "Performance3";
goto cp0_unimplemented;
case 4:
-// gen_helper_mtc0_performance4(cpu_env, arg);
+ /* gen_helper_mtc0_performance4(cpu_env, arg); */
register_name = "Performance4";
goto cp0_unimplemented;
case 5:
-// gen_helper_mtc0_performance5(cpu_env, arg);
+ /* gen_helper_mtc0_performance5(cpu_env, arg); */
register_name = "Performance5";
goto cp0_unimplemented;
case 6:
-// gen_helper_mtc0_performance6(cpu_env, arg);
+ /* gen_helper_mtc0_performance6(cpu_env, arg); */
register_name = "Performance6";
goto cp0_unimplemented;
case 7:
-// gen_helper_mtc0_performance7(cpu_env, arg);
+ /* gen_helper_mtc0_performance7(cpu_env, arg); */
register_name = "Performance7";
goto cp0_unimplemented;
default:
/* For simplicity assume that all writes can cause interrupts. */
if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) {
gen_io_end();
- /* DISAS_STOP isn't sufficient, we need to ensure we break out of
- * translated code to check for pending interrupts. */
+ /*
+ * DISAS_STOP isn't sufficient, we need to ensure we break out of
+ * translated code to check for pending interrupts.
+ */
gen_save_pc(ctx->base.pc_next + 4);
ctx->base.is_jmp = DISAS_EXIT;
}
if ((env->CP0_VPEConf0 & (1 << CP0VPEC0_MVP)) == 0 &&
((env->tcs[other_tc].CP0_TCBind & (0xf << CP0TCBd_CurVPE)) !=
(env->active_tc.CP0_TCBind & (0xf << CP0TCBd_CurVPE)))) {
- /* NOP */ ;
+ /* NOP */
+ ;
} else if ((env->CP0_VPEControl & (0xff << CP0VPECo_TargTC)) >
(env->mvp->CP0_MVPConf0 & (0xff << CP0MVPC0_PTC))) {
- /* NOP */ ;
+ /* NOP */
+ ;
} else if (u == 0) {
switch (rd) {
case 1:
} else {
gen_op_addr_add(ctx, t0, cpu_gpr[base], cpu_gpr[index]);
}
- /* Don't do NOP if destination is zero: we must perform the actual
- memory access. */
+ /*
+ * Don't do NOP if destination is zero: we must perform the actual
+ * memory access.
+ */
switch (opc) {
case OPC_LWXC1:
check_cop1x(ctx);
TCGv t0;
#if !defined(CONFIG_USER_ONLY)
- /* The Linux kernel will emulate rdhwr if it's not supported natively.
- Therefore only check the ISA in system mode. */
+ /*
+ * The Linux kernel will emulate rdhwr if it's not supported natively.
+ * Therefore only check the ISA in system mode.
+ */
check_insn(ctx, ISA_MIPS32R2);
#endif
t0 = tcg_temp_new();
gen_io_end();
}
gen_store_gpr(t0, rt);
- /* Break the TB to be able to take timer interrupts immediately
- after reading count. DISAS_STOP isn't sufficient, we need to ensure
- we break completely out of translated code. */
+ /*
+ * Break the TB to be able to take timer interrupts immediately
+ * after reading count. DISAS_STOP isn't sufficient, we need to ensure
+ * we break completely out of translated code.
+ */
gen_save_pc(ctx->base.pc_next + 4);
ctx->base.is_jmp = DISAS_EXIT;
break;
case 4:
check_insn(ctx, ISA_MIPS32R6);
if (sel != 0) {
- /* Performance counter registers are not implemented other than
+ /*
+ * Performance counter registers are not implemented other than
* control register 0.
*/
generate_exception(ctx, EXCP_RI);
if (ctx->base.is_jmp == DISAS_NEXT) {
save_cpu_state(ctx, 0);
} else {
- /* it is not safe to save ctx->hflags as hflags may be changed
- in execution time by the instruction in delay / forbidden slot. */
+ /*
+ * It is not safe to save ctx->hflags as hflags may be changed
+ * in execution time by the instruction in delay / forbidden slot.
+ */
tcg_gen_andi_i32(hflags, hflags, ~MIPS_HFLAG_BMASK);
}
}
| ((ctx->opcode >> 21) & 0x3f) << 5
| (ctx->opcode & 0x1f));
- /* The extended opcodes cleverly reuse the opcodes from their 16-bit
- counterparts. */
+ /*
+ * The extended opcodes cleverly reuse the opcodes from their 16-bit
+ * counterparts.
+ */
switch (op) {
case M16_OPC_ADDIUSP:
gen_arith_imm(ctx, OPC_ADDIU, rx, 29, imm);
if (is_uhi(extract32(ctx->opcode, 5, 6))) {
gen_helper_do_semihosting(cpu_env);
} else {
- /* XXX: not clear which exception should be raised
+ /*
+ * XXX: not clear which exception should be raised
* when in debug mode...
*/
check_insn(ctx, ISA_MIPS32);
/* POOL32A encoding of minor opcode field */
enum {
- /* These opcodes are distinguished only by bits 9..6; those bits are
- * what are recorded below. */
+ /*
+ * These opcodes are distinguished only by bits 9..6; those bits are
+ * what are recorded below.
+ */
SLL32 = 0x0,
SRL32 = 0x1,
SRA = 0x2,
{
int reg = ctx->opcode & 0x1f;
gen_compute_branch(ctx, OPC_JR, 2, reg, 0, 0, 0);
- /* Let normal delay slot handling in our caller take us
- to the branch target. */
+ /*
+ * Let normal delay slot handling in our caller take us
+ * to the branch target.
+ */
}
break;
case JALR16 + 0:
if (is_uhi(extract32(ctx->opcode, 0, 4))) {
gen_helper_do_semihosting(cpu_env);
} else {
- /* XXX: not clear which exception should be raised
+ /*
+ * XXX: not clear which exception should be raised
* when in debug mode...
*/
check_insn(ctx, ISA_MIPS32);
int imm = ZIMM(ctx->opcode, 0, 5);
gen_compute_branch(ctx, OPC_JR, 2, 31, 0, 0, 0);
gen_arith_imm(ctx, OPC_ADDIU, 29, 29, imm << 2);
- /* Let normal delay slot handling in our caller take us
- to the branch target. */
+ /*
+ * Let normal delay slot handling in our caller take us
+ * to the branch target.
+ */
}
break;
default:
save_cpu_state(ctx, 1);
gen_helper_ei(t0, cpu_env);
gen_store_gpr(t0, rs);
- /* DISAS_STOP isn't sufficient, we need to ensure we break out
- of translated code to check for pending interrupts. */
+ /*
+ * DISAS_STOP isn't sufficient, we need to ensure we break out
+ * of translated code to check for pending interrupts.
+ */
gen_save_pc(ctx->base.pc_next + 4);
ctx->base.is_jmp = DISAS_EXIT;
tcg_temp_free(t0);
}
}
-/* Values for microMIPS fmt field. Variable-width, depending on which
- formats the instruction supports. */
-
+/*
+ * Values for microMIPS fmt field. Variable-width, depending on which
+ * formats the instruction supports.
+ */
enum {
FMT_SD_S = 0,
FMT_SD_D = 1,
case TNEI: /* SYNCI */
if (ctx->insn_flags & ISA_MIPS32R6) {
/* SYNCI */
- /* Break the TB to be able to sync copied instructions
- immediately */
+ /*
+ * Break the TB to be able to sync copied instructions
+ * immediately.
+ */
ctx->base.is_jmp = DISAS_STOP;
} else {
/* TNEI */
check_insn_opc_removed(ctx, ISA_MIPS32R6);
gen_compute_branch(ctx, minor == BNEZC ? OPC_BNE : OPC_BEQ,
4, rs, 0, imm << 1, 0);
- /* Compact branches don't have a delay slot, so just let
- the normal delay slot handling take us to the branch
- target. */
+ /*
+ * Compact branches don't have a delay slot, so just let
+ * the normal delay slot handling take us to the branch
+ * target.
+ */
break;
case LUI:
check_insn_opc_removed(ctx, ISA_MIPS32R6);
break;
case SYNCI:
check_insn_opc_removed(ctx, ISA_MIPS32R6);
- /* Break the TB to be able to sync copied instructions
- immediately */
+ /*
+ * Break the TB to be able to sync copied instructions
+ * immediately.
+ */
ctx->base.is_jmp = DISAS_STOP;
break;
case BC2F:
break;
}
if (ctx->insn_flags & ISA_MIPS32R6) {
- /* In the Release 6 the register number location in
+ /*
+ * In the Release 6, the register number location in
* the instruction encoding has changed.
*/
gen_arith(ctx, opc, rs1, rd, rs2);
gen_p_lsx(ctx, rd, rs, rt);
break;
case NM_LSA:
- /* In nanoMIPS, the shift field directly encodes the shift
+ /*
+ * In nanoMIPS, the shift field directly encodes the shift
* amount, meaning that the supported shift values are in
- * the range 0 to 3 (instead of 1 to 4 in MIPSR6). */
+ * the range 0 to 3 (instead of 1 to 4 in MIPSR6).
+ */
gen_lsa(ctx, OPC_LSA, rd, rs, rt,
extract32(ctx->opcode, 9, 2) - 1);
break;
case NM_P_PREFU12:
if (rt == 31) {
/* SYNCI */
- /* Break the TB to be able to sync copied instructions
- immediately */
+ /*
+ * Break the TB to be able to sync copied instructions
+ * immediately.
+ */
ctx->base.is_jmp = DISAS_STOP;
} else {
/* PREF */
case NM_P_PREFS9:
if (rt == 31) {
/* SYNCI */
- /* Break the TB to be able to sync copied instructions
- immediately */
+ /*
+ * Break the TB to be able to sync copied instructions
+ * immediately.
+ */
ctx->base.is_jmp = DISAS_STOP;
} else {
/* PREF */
/* case NM_SYNCIE */
check_eva(ctx);
check_cp0_enabled(ctx);
- /* Break the TB to be able to sync copied instructions
- immediately */
+ /*
+ * Break the TB to be able to sync copied instructions
+ * immediately.
+ */
ctx->base.is_jmp = DISAS_STOP;
} else {
/* case NM_PREFE */
gen_load_gpr(v2_t, v2);
switch (op1) {
- /* OPC_MULT_G_2E, OPC_ADDUH_QB_DSP, OPC_MUL_PH_DSP have
- * the same mask and op1. */
+ /*
+ * OPC_MULT_G_2E, OPC_ADDUH_QB_DSP, OPC_MUL_PH_DSP have
+ * the same mask and op1.
+ */
case OPC_MULT_G_2E:
check_dsp_r2(ctx);
switch (op2) {
case R6_OPC_CLO:
case R6_OPC_CLZ:
if (rt == 0 && sa == 1) {
- /* Major opcode and function field is shared with preR6 MFHI/MTHI.
- We need additionally to check other fields */
+ /*
+ * Major opcode and function field is shared with preR6 MFHI/MTHI.
+ * We need additionally to check other fields.
+ */
gen_cl(ctx, op1, rd, rs);
} else {
generate_exception_end(ctx, EXCP_RI);
case R6_OPC_DCLO:
case R6_OPC_DCLZ:
if (rt == 0 && sa == 1) {
- /* Major opcode and function field is shared with preR6 MFHI/MTHI.
- We need additionally to check other fields */
+ /*
+ * Major opcode and function field is shared with preR6 MFHI/MTHI.
+ * We need additionally to check other fields.
+ */
check_mips_64(ctx);
gen_cl(ctx, op1, rd, rs);
} else {
* | SPECIAL2 | rb |x| s12 | XRa |MXU__POOL08|
* +-----------+---------+-+-------------------+-------+-----------+
*
-*/
+ */
static void decode_opc_mxu__pool08(CPUMIPSState *env, DisasContext *ctx)
{
uint32_t opcode = extract32(ctx->opcode, 20, 1);
if (is_uhi(extract32(ctx->opcode, 6, 20))) {
gen_helper_do_semihosting(cpu_env);
} else {
- /* XXX: not clear which exception should be raised
+ /*
+ * XXX: not clear which exception should be raised
* when in debug mode...
*/
check_insn(ctx, ISA_MIPS32);
case OPC_MODU_G_2E:
case OPC_MULT_G_2E:
case OPC_MULTU_G_2E:
- /* OPC_MULT_G_2E, OPC_ADDUH_QB_DSP, OPC_MUL_PH_DSP have
- * the same mask and op1. */
+ /*
+ * OPC_MULT_G_2E, OPC_ADDUH_QB_DSP, OPC_MUL_PH_DSP have
+ * the same mask and op1.
+ */
if ((ctx->insn_flags & ASE_DSP_R2) && (op1 == OPC_MULT_G_2E)) {
op2 = MASK_ADDUH_QB(ctx->opcode);
switch (op2) {
break;
case OPC_SYNCI:
check_insn(ctx, ISA_MIPS32R2);
- /* Break the TB to be able to sync copied instructions
- immediately */
+ /*
+ * Break the TB to be able to sync copied instructions
+ * immediately.
+ */
ctx->base.is_jmp = DISAS_STOP;
break;
case OPC_BPOSGE32: /* MIPS DSP branch */
save_cpu_state(ctx, 1);
gen_helper_di(t0, cpu_env);
gen_store_gpr(t0, rt);
- /* Stop translation as we may have switched
- the execution mode. */
+ /*
+ * Stop translation as we may have switched
+ * the execution mode.
+ */
ctx->base.is_jmp = DISAS_STOP;
break;
case OPC_EI:
save_cpu_state(ctx, 1);
gen_helper_ei(t0, cpu_env);
gen_store_gpr(t0, rt);
- /* DISAS_STOP isn't sufficient, we need to ensure we break
- out of translated code to check for pending interrupts */
+ /*
+ * DISAS_STOP isn't sufficient, we need to ensure we break
+ * out of translated code to check for pending interrupts.
+ */
gen_save_pc(ctx->base.pc_next + 4);
ctx->base.is_jmp = DISAS_EXIT;
break;
save_cpu_state(ctx, 1);
ctx->base.is_jmp = DISAS_NORETURN;
gen_helper_raise_exception_debug(cpu_env);
- /* The address covered by the breakpoint must be included in
- [tb->pc, tb->pc + tb->size) in order to for it to be
- properly cleared -- thus we increment the PC here so that
- the logic setting tb->size below does the right thing. */
+ /*
+ * The address covered by the breakpoint must be included in
+ * [tb->pc, tb->pc + tb->size) in order to for it to be
+ * properly cleared -- thus we increment the PC here so that
+ * the logic setting tb->size below does the right thing.
+ */
ctx->base.pc_next += 4;
return true;
}
if (ctx->hflags & MIPS_HFLAG_BMASK) {
if (!(ctx->hflags & (MIPS_HFLAG_BDS16 | MIPS_HFLAG_BDS32 |
MIPS_HFLAG_FBNSLOT))) {
- /* force to generate branch as there is neither delay nor
- forbidden slot */
+ /*
+ * Force to generate branch as there is neither delay nor
+ * forbidden slot.
+ */
is_slot = 1;
}
if ((ctx->hflags & MIPS_HFLAG_M16) &&
(ctx->hflags & MIPS_HFLAG_FBNSLOT)) {
- /* Force to generate branch as microMIPS R6 doesn't restrict
- branches in the forbidden slot. */
+ /*
+ * Force to generate branch as microMIPS R6 doesn't restrict
+ * branches in the forbidden slot.
+ */
is_slot = 1;
}
}
if (ctx->base.is_jmp != DISAS_NEXT) {
return;
}
- /* Execute a branch and its delay slot as a single instruction.
- This is what GDB expects and is consistent with what the
- hardware does (e.g. if a delay slot instruction faults, the
- reported PC is the PC of the branch). */
+ /*
+ * Execute a branch and its delay slot as a single instruction.
+ * This is what GDB expects and is consistent with what the
+ * hardware does (e.g. if a delay slot instruction faults, the
+ * reported PC is the PC of the branch).
+ */
if (ctx->base.singlestep_enabled &&
(ctx->hflags & MIPS_HFLAG_BMASK) == 0) {
ctx->base.is_jmp = DISAS_TOO_MANY;
int off = offsetof(CPUMIPSState, active_fpu.fpr[i].wr.d[0]);
msa_wr_d[i * 2] =
tcg_global_mem_new_i64(cpu_env, off, msaregnames[i * 2]);
- /* The scalar floating-point unit (FPU) registers are mapped on
- * the MSA vector registers. */
+ /*
+ * The scalar floating-point unit (FPU) registers are mapped on
+ * the MSA vector registers.
+ */
fpu_f64[i] = msa_wr_d[i * 2];
off = offsetof(CPUMIPSState, active_fpu.fpr[i].wr.d[1]);
msa_wr_d[i * 2 + 1] =
/* Enable 64-bit address mode. */
env->CP0_Status |= (1 << CP0St_UX);
# endif
- /* Enable access to the CPUNum, SYNCI_Step, CC, and CCRes RDHWR
- hardware registers. */
+ /*
+ * Enable access to the CPUNum, SYNCI_Step, CC, and CCRes RDHWR
+ * hardware registers.
+ */
env->CP0_HWREna |= 0x0000000F;
if (env->CP0_Config1 & (1 << CP0C1_FP)) {
env->CP0_Status |= (1 << CP0St_CU1);
# endif
#else
if (env->hflags & MIPS_HFLAG_BMASK) {
- /* If the exception was raised from a delay slot,
- come back to the jump. */
+ /*
+ * If the exception was raised from a delay slot,
+ * come back to the jump.
+ */
env->CP0_ErrorEPC = (env->active_tc.PC
- (env->hflags & MIPS_HFLAG_B16 ? 2 : 4));
} else {
env->CP0_EntryHi_ASID_mask = (env->CP0_Config4 & (1 << CP0C4_AE)) ?
0x3ff : 0xff;
env->CP0_Status = (1 << CP0St_BEV) | (1 << CP0St_ERL);
- /* vectored interrupts not implemented, timer on int 7,
- no performance counters. */
+ /*
+ * Vectored interrupts not implemented, timer on int 7,
+ * no performance counters.
+ */
env->CP0_IntCtl = 0xe0000000;
{
int i;
#include "cpu.h"
#include "monitor/monitor.h"
#include "monitor/hmp-target.h"
-#include "hmp.h"
+#include "monitor/hmp.h"
void hmp_info_tlb(Monitor *mon, const QDict *qdict)
{
* sfprf - set FPRF
*/
#define VSX_ADD_SUB(name, op, nels, tp, fld, sfprf, r2sp) \
-void helper_##name(CPUPPCState *env, uint32_t opcode) \
+void helper_##name(CPUPPCState *env, ppc_vsr_t *xt, \
+ ppc_vsr_t *xa, ppc_vsr_t *xb) \
{ \
- ppc_vsr_t xt, xa, xb; \
+ ppc_vsr_t t = *xt; \
int i; \
\
- getVSR(xA(opcode), &xa, env); \
- getVSR(xB(opcode), &xb, env); \
- getVSR(xT(opcode), &xt, env); \
helper_reset_fpstatus(env); \
\
for (i = 0; i < nels; i++) { \
float_status tstat = env->fp_status; \
set_float_exception_flags(0, &tstat); \
- xt.fld = tp##_##op(xa.fld, xb.fld, &tstat); \
+ t.fld = tp##_##op(xa->fld, xb->fld, &tstat); \
env->fp_status.float_exception_flags |= tstat.float_exception_flags; \
\
if (unlikely(tstat.float_exception_flags & float_flag_invalid)) { \
float_invalid_op_addsub(env, sfprf, GETPC(), \
- tp##_classify(xa.fld) | \
- tp##_classify(xb.fld)); \
+ tp##_classify(xa->fld) | \
+ tp##_classify(xb->fld)); \
} \
\
if (r2sp) { \
- xt.fld = helper_frsp(env, xt.fld); \
+ t.fld = helper_frsp(env, t.fld); \
} \
\
if (sfprf) { \
- helper_compute_fprf_float64(env, xt.fld); \
+ helper_compute_fprf_float64(env, t.fld); \
} \
} \
- putVSR(xT(opcode), &xt, env); \
+ *xt = t; \
do_float_check_status(env, GETPC()); \
}
VSX_ADD_SUB(xvsubdp, sub, 2, float64, VsrD(i), 0, 0)
VSX_ADD_SUB(xvsubsp, sub, 4, float32, VsrW(i), 0, 0)
-void helper_xsaddqp(CPUPPCState *env, uint32_t opcode)
+void helper_xsaddqp(CPUPPCState *env, uint32_t opcode,
+ ppc_vsr_t *xt, ppc_vsr_t *xa, ppc_vsr_t *xb)
{
- ppc_vsr_t xt, xa, xb;
+ ppc_vsr_t t = *xt;
float_status tstat;
- getVSR(rA(opcode) + 32, &xa, env);
- getVSR(rB(opcode) + 32, &xb, env);
- getVSR(rD(opcode) + 32, &xt, env);
helper_reset_fpstatus(env);
tstat = env->fp_status;
}
set_float_exception_flags(0, &tstat);
- xt.f128 = float128_add(xa.f128, xb.f128, &tstat);
+ t.f128 = float128_add(xa->f128, xb->f128, &tstat);
env->fp_status.float_exception_flags |= tstat.float_exception_flags;
if (unlikely(tstat.float_exception_flags & float_flag_invalid)) {
float_invalid_op_addsub(env, 1, GETPC(),
- float128_classify(xa.f128) |
- float128_classify(xb.f128));
+ float128_classify(xa->f128) |
+ float128_classify(xb->f128));
}
- helper_compute_fprf_float128(env, xt.f128);
+ helper_compute_fprf_float128(env, t.f128);
- putVSR(rD(opcode) + 32, &xt, env);
+ *xt = t;
do_float_check_status(env, GETPC());
}
* sfprf - set FPRF
*/
#define VSX_MUL(op, nels, tp, fld, sfprf, r2sp) \
-void helper_##op(CPUPPCState *env, uint32_t opcode) \
+void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, \
+ ppc_vsr_t *xa, ppc_vsr_t *xb) \
{ \
- ppc_vsr_t xt, xa, xb; \
+ ppc_vsr_t t = *xt; \
int i; \
\
- getVSR(xA(opcode), &xa, env); \
- getVSR(xB(opcode), &xb, env); \
- getVSR(xT(opcode), &xt, env); \
helper_reset_fpstatus(env); \
\
for (i = 0; i < nels; i++) { \
float_status tstat = env->fp_status; \
set_float_exception_flags(0, &tstat); \
- xt.fld = tp##_mul(xa.fld, xb.fld, &tstat); \
+ t.fld = tp##_mul(xa->fld, xb->fld, &tstat); \
env->fp_status.float_exception_flags |= tstat.float_exception_flags; \
\
if (unlikely(tstat.float_exception_flags & float_flag_invalid)) { \
float_invalid_op_mul(env, sfprf, GETPC(), \
- tp##_classify(xa.fld) | \
- tp##_classify(xb.fld)); \
+ tp##_classify(xa->fld) | \
+ tp##_classify(xb->fld)); \
} \
\
if (r2sp) { \
- xt.fld = helper_frsp(env, xt.fld); \
+ t.fld = helper_frsp(env, t.fld); \
} \
\
if (sfprf) { \
- helper_compute_fprf_float64(env, xt.fld); \
+ helper_compute_fprf_float64(env, t.fld); \
} \
} \
\
- putVSR(xT(opcode), &xt, env); \
+ *xt = t; \
do_float_check_status(env, GETPC()); \
}
VSX_MUL(xvmuldp, 2, float64, VsrD(i), 0, 0)
VSX_MUL(xvmulsp, 4, float32, VsrW(i), 0, 0)
-void helper_xsmulqp(CPUPPCState *env, uint32_t opcode)
+void helper_xsmulqp(CPUPPCState *env, uint32_t opcode,
+ ppc_vsr_t *xt, ppc_vsr_t *xa, ppc_vsr_t *xb)
{
- ppc_vsr_t xt, xa, xb;
+ ppc_vsr_t t = *xt;
float_status tstat;
- getVSR(rA(opcode) + 32, &xa, env);
- getVSR(rB(opcode) + 32, &xb, env);
- getVSR(rD(opcode) + 32, &xt, env);
-
helper_reset_fpstatus(env);
tstat = env->fp_status;
if (unlikely(Rc(opcode) != 0)) {
}
set_float_exception_flags(0, &tstat);
- xt.f128 = float128_mul(xa.f128, xb.f128, &tstat);
+ t.f128 = float128_mul(xa->f128, xb->f128, &tstat);
env->fp_status.float_exception_flags |= tstat.float_exception_flags;
if (unlikely(tstat.float_exception_flags & float_flag_invalid)) {
float_invalid_op_mul(env, 1, GETPC(),
- float128_classify(xa.f128) |
- float128_classify(xb.f128));
+ float128_classify(xa->f128) |
+ float128_classify(xb->f128));
}
- helper_compute_fprf_float128(env, xt.f128);
+ helper_compute_fprf_float128(env, t.f128);
- putVSR(rD(opcode) + 32, &xt, env);
+ *xt = t;
do_float_check_status(env, GETPC());
}
* sfprf - set FPRF
*/
#define VSX_DIV(op, nels, tp, fld, sfprf, r2sp) \
-void helper_##op(CPUPPCState *env, uint32_t opcode) \
+void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, \
+ ppc_vsr_t *xa, ppc_vsr_t *xb) \
{ \
- ppc_vsr_t xt, xa, xb; \
+ ppc_vsr_t t = *xt; \
int i; \
\
- getVSR(xA(opcode), &xa, env); \
- getVSR(xB(opcode), &xb, env); \
- getVSR(xT(opcode), &xt, env); \
helper_reset_fpstatus(env); \
\
for (i = 0; i < nels; i++) { \
float_status tstat = env->fp_status; \
set_float_exception_flags(0, &tstat); \
- xt.fld = tp##_div(xa.fld, xb.fld, &tstat); \
+ t.fld = tp##_div(xa->fld, xb->fld, &tstat); \
env->fp_status.float_exception_flags |= tstat.float_exception_flags; \
\
if (unlikely(tstat.float_exception_flags & float_flag_invalid)) { \
float_invalid_op_div(env, sfprf, GETPC(), \
- tp##_classify(xa.fld) | \
- tp##_classify(xb.fld)); \
+ tp##_classify(xa->fld) | \
+ tp##_classify(xb->fld)); \
} \
if (unlikely(tstat.float_exception_flags & float_flag_divbyzero)) { \
float_zero_divide_excp(env, GETPC()); \
} \
\
if (r2sp) { \
- xt.fld = helper_frsp(env, xt.fld); \
+ t.fld = helper_frsp(env, t.fld); \
} \
\
if (sfprf) { \
- helper_compute_fprf_float64(env, xt.fld); \
+ helper_compute_fprf_float64(env, t.fld); \
} \
} \
\
- putVSR(xT(opcode), &xt, env); \
+ *xt = t; \
do_float_check_status(env, GETPC()); \
}
VSX_DIV(xvdivdp, 2, float64, VsrD(i), 0, 0)
VSX_DIV(xvdivsp, 4, float32, VsrW(i), 0, 0)
-void helper_xsdivqp(CPUPPCState *env, uint32_t opcode)
+void helper_xsdivqp(CPUPPCState *env, uint32_t opcode,
+ ppc_vsr_t *xt, ppc_vsr_t *xa, ppc_vsr_t *xb)
{
- ppc_vsr_t xt, xa, xb;
+ ppc_vsr_t t = *xt;
float_status tstat;
- getVSR(rA(opcode) + 32, &xa, env);
- getVSR(rB(opcode) + 32, &xb, env);
- getVSR(rD(opcode) + 32, &xt, env);
-
helper_reset_fpstatus(env);
tstat = env->fp_status;
if (unlikely(Rc(opcode) != 0)) {
}
set_float_exception_flags(0, &tstat);
- xt.f128 = float128_div(xa.f128, xb.f128, &tstat);
+ t.f128 = float128_div(xa->f128, xb->f128, &tstat);
env->fp_status.float_exception_flags |= tstat.float_exception_flags;
if (unlikely(tstat.float_exception_flags & float_flag_invalid)) {
float_invalid_op_div(env, 1, GETPC(),
- float128_classify(xa.f128) |
- float128_classify(xb.f128));
+ float128_classify(xa->f128) |
+ float128_classify(xb->f128));
}
if (unlikely(tstat.float_exception_flags & float_flag_divbyzero)) {
float_zero_divide_excp(env, GETPC());
}
- helper_compute_fprf_float128(env, xt.f128);
- putVSR(rD(opcode) + 32, &xt, env);
+ helper_compute_fprf_float128(env, t.f128);
+ *xt = t;
do_float_check_status(env, GETPC());
}
* sfprf - set FPRF
*/
#define VSX_RE(op, nels, tp, fld, sfprf, r2sp) \
-void helper_##op(CPUPPCState *env, uint32_t opcode) \
+void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, ppc_vsr_t *xb) \
{ \
- ppc_vsr_t xt, xb; \
+ ppc_vsr_t t = *xt; \
int i; \
\
- getVSR(xB(opcode), &xb, env); \
- getVSR(xT(opcode), &xt, env); \
helper_reset_fpstatus(env); \
\
for (i = 0; i < nels; i++) { \
- if (unlikely(tp##_is_signaling_nan(xb.fld, &env->fp_status))) { \
+ if (unlikely(tp##_is_signaling_nan(xb->fld, &env->fp_status))) { \
float_invalid_op_vxsnan(env, GETPC()); \
} \
- xt.fld = tp##_div(tp##_one, xb.fld, &env->fp_status); \
+ t.fld = tp##_div(tp##_one, xb->fld, &env->fp_status); \
\
if (r2sp) { \
- xt.fld = helper_frsp(env, xt.fld); \
+ t.fld = helper_frsp(env, t.fld); \
} \
\
if (sfprf) { \
- helper_compute_fprf_float64(env, xt.fld); \
+ helper_compute_fprf_float64(env, t.fld); \
} \
} \
\
- putVSR(xT(opcode), &xt, env); \
+ *xt = t; \
do_float_check_status(env, GETPC()); \
}
* sfprf - set FPRF
*/
#define VSX_SQRT(op, nels, tp, fld, sfprf, r2sp) \
-void helper_##op(CPUPPCState *env, uint32_t opcode) \
+void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, ppc_vsr_t *xb) \
{ \
- ppc_vsr_t xt, xb; \
+ ppc_vsr_t t = *xt; \
int i; \
\
- getVSR(xB(opcode), &xb, env); \
- getVSR(xT(opcode), &xt, env); \
helper_reset_fpstatus(env); \
\
for (i = 0; i < nels; i++) { \
float_status tstat = env->fp_status; \
set_float_exception_flags(0, &tstat); \
- xt.fld = tp##_sqrt(xb.fld, &tstat); \
+ t.fld = tp##_sqrt(xb->fld, &tstat); \
env->fp_status.float_exception_flags |= tstat.float_exception_flags; \
\
if (unlikely(tstat.float_exception_flags & float_flag_invalid)) { \
- if (tp##_is_neg(xb.fld) && !tp##_is_zero(xb.fld)) { \
+ if (tp##_is_neg(xb->fld) && !tp##_is_zero(xb->fld)) { \
float_invalid_op_vxsqrt(env, sfprf, GETPC()); \
- } else if (tp##_is_signaling_nan(xb.fld, &tstat)) { \
+ } else if (tp##_is_signaling_nan(xb->fld, &tstat)) { \
float_invalid_op_vxsnan(env, GETPC()); \
} \
} \
\
if (r2sp) { \
- xt.fld = helper_frsp(env, xt.fld); \
+ t.fld = helper_frsp(env, t.fld); \
} \
\
if (sfprf) { \
- helper_compute_fprf_float64(env, xt.fld); \
+ helper_compute_fprf_float64(env, t.fld); \
} \
} \
\
- putVSR(xT(opcode), &xt, env); \
+ *xt = t; \
do_float_check_status(env, GETPC()); \
}
* sfprf - set FPRF
*/
#define VSX_RSQRTE(op, nels, tp, fld, sfprf, r2sp) \
-void helper_##op(CPUPPCState *env, uint32_t opcode) \
+void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, ppc_vsr_t *xb) \
{ \
- ppc_vsr_t xt, xb; \
+ ppc_vsr_t t = *xt; \
int i; \
\
- getVSR(xB(opcode), &xb, env); \
- getVSR(xT(opcode), &xt, env); \
helper_reset_fpstatus(env); \
\
for (i = 0; i < nels; i++) { \
float_status tstat = env->fp_status; \
set_float_exception_flags(0, &tstat); \
- xt.fld = tp##_sqrt(xb.fld, &tstat); \
- xt.fld = tp##_div(tp##_one, xt.fld, &tstat); \
+ t.fld = tp##_sqrt(xb->fld, &tstat); \
+ t.fld = tp##_div(tp##_one, t.fld, &tstat); \
env->fp_status.float_exception_flags |= tstat.float_exception_flags; \
\
if (unlikely(tstat.float_exception_flags & float_flag_invalid)) { \
- if (tp##_is_neg(xb.fld) && !tp##_is_zero(xb.fld)) { \
+ if (tp##_is_neg(xb->fld) && !tp##_is_zero(xb->fld)) { \
float_invalid_op_vxsqrt(env, sfprf, GETPC()); \
- } else if (tp##_is_signaling_nan(xb.fld, &tstat)) { \
+ } else if (tp##_is_signaling_nan(xb->fld, &tstat)) { \
float_invalid_op_vxsnan(env, GETPC()); \
} \
} \
\
if (r2sp) { \
- xt.fld = helper_frsp(env, xt.fld); \
+ t.fld = helper_frsp(env, t.fld); \
} \
\
if (sfprf) { \
- helper_compute_fprf_float64(env, xt.fld); \
+ helper_compute_fprf_float64(env, t.fld); \
} \
} \
\
- putVSR(xT(opcode), &xt, env); \
+ *xt = t; \
do_float_check_status(env, GETPC()); \
}
* nbits - number of fraction bits
*/
#define VSX_TDIV(op, nels, tp, fld, emin, emax, nbits) \
-void helper_##op(CPUPPCState *env, uint32_t opcode) \
+void helper_##op(CPUPPCState *env, uint32_t opcode, \
+ ppc_vsr_t *xa, ppc_vsr_t *xb) \
{ \
- ppc_vsr_t xa, xb; \
int i; \
int fe_flag = 0; \
int fg_flag = 0; \
\
- getVSR(xA(opcode), &xa, env); \
- getVSR(xB(opcode), &xb, env); \
- \
for (i = 0; i < nels; i++) { \
- if (unlikely(tp##_is_infinity(xa.fld) || \
- tp##_is_infinity(xb.fld) || \
- tp##_is_zero(xb.fld))) { \
+ if (unlikely(tp##_is_infinity(xa->fld) || \
+ tp##_is_infinity(xb->fld) || \
+ tp##_is_zero(xb->fld))) { \
fe_flag = 1; \
fg_flag = 1; \
} else { \
- int e_a = ppc_##tp##_get_unbiased_exp(xa.fld); \
- int e_b = ppc_##tp##_get_unbiased_exp(xb.fld); \
+ int e_a = ppc_##tp##_get_unbiased_exp(xa->fld); \
+ int e_b = ppc_##tp##_get_unbiased_exp(xb->fld); \
\
- if (unlikely(tp##_is_any_nan(xa.fld) || \
- tp##_is_any_nan(xb.fld))) { \
+ if (unlikely(tp##_is_any_nan(xa->fld) || \
+ tp##_is_any_nan(xb->fld))) { \
fe_flag = 1; \
} else if ((e_b <= emin) || (e_b >= (emax - 2))) { \
fe_flag = 1; \
- } else if (!tp##_is_zero(xa.fld) && \
+ } else if (!tp##_is_zero(xa->fld) && \
(((e_a - e_b) >= emax) || \
((e_a - e_b) <= (emin + 1)) || \
(e_a <= (emin + nbits)))) { \
fe_flag = 1; \
} \
\
- if (unlikely(tp##_is_zero_or_denormal(xb.fld))) { \
+ if (unlikely(tp##_is_zero_or_denormal(xb->fld))) { \
/* \
* XB is not zero because of the above check and so \
* must be denormalized. \
* nbits - number of fraction bits
*/
#define VSX_TSQRT(op, nels, tp, fld, emin, nbits) \
-void helper_##op(CPUPPCState *env, uint32_t opcode) \
+void helper_##op(CPUPPCState *env, uint32_t opcode, ppc_vsr_t *xb) \
{ \
- ppc_vsr_t xa, xb; \
int i; \
int fe_flag = 0; \
int fg_flag = 0; \
\
- getVSR(xA(opcode), &xa, env); \
- getVSR(xB(opcode), &xb, env); \
- \
for (i = 0; i < nels; i++) { \
- if (unlikely(tp##_is_infinity(xb.fld) || \
- tp##_is_zero(xb.fld))) { \
+ if (unlikely(tp##_is_infinity(xb->fld) || \
+ tp##_is_zero(xb->fld))) { \
fe_flag = 1; \
fg_flag = 1; \
} else { \
- int e_b = ppc_##tp##_get_unbiased_exp(xb.fld); \
+ int e_b = ppc_##tp##_get_unbiased_exp(xb->fld); \
\
- if (unlikely(tp##_is_any_nan(xb.fld))) { \
+ if (unlikely(tp##_is_any_nan(xb->fld))) { \
fe_flag = 1; \
- } else if (unlikely(tp##_is_zero(xb.fld))) { \
+ } else if (unlikely(tp##_is_zero(xb->fld))) { \
fe_flag = 1; \
- } else if (unlikely(tp##_is_neg(xb.fld))) { \
+ } else if (unlikely(tp##_is_neg(xb->fld))) { \
fe_flag = 1; \
- } else if (!tp##_is_zero(xb.fld) && \
+ } else if (!tp##_is_zero(xb->fld) && \
(e_b <= (emin + nbits))) { \
fe_flag = 1; \
} \
\
- if (unlikely(tp##_is_zero_or_denormal(xb.fld))) { \
+ if (unlikely(tp##_is_zero_or_denormal(xb->fld))) { \
/* \
* XB is not zero because of the above check and \
* therefore must be denormalized. \
* fld - vsr_t field (VsrD(*) or VsrW(*))
* maddflgs - flags for the float*muladd routine that control the
* various forms (madd, msub, nmadd, nmsub)
- * afrm - A form (1=A, 0=M)
* sfprf - set FPRF
*/
-#define VSX_MADD(op, nels, tp, fld, maddflgs, afrm, sfprf, r2sp) \
-void helper_##op(CPUPPCState *env, uint32_t opcode) \
+#define VSX_MADD(op, nels, tp, fld, maddflgs, sfprf, r2sp) \
+void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, \
+ ppc_vsr_t *xa, ppc_vsr_t *b, ppc_vsr_t *c) \
{ \
- ppc_vsr_t xt_in, xa, xb, xt_out; \
- ppc_vsr_t *b, *c; \
+ ppc_vsr_t t = *xt; \
int i; \
\
- if (afrm) { /* AxB + T */ \
- b = &xb; \
- c = &xt_in; \
- } else { /* AxT + B */ \
- b = &xt_in; \
- c = &xb; \
- } \
- \
- getVSR(xA(opcode), &xa, env); \
- getVSR(xB(opcode), &xb, env); \
- getVSR(xT(opcode), &xt_in, env); \
- \
- xt_out = xt_in; \
- \
helper_reset_fpstatus(env); \
\
for (i = 0; i < nels; i++) { \
* result to odd. \
*/ \
set_float_rounding_mode(float_round_to_zero, &tstat); \
- xt_out.fld = tp##_muladd(xa.fld, b->fld, c->fld, \
- maddflgs, &tstat); \
- xt_out.fld |= (get_float_exception_flags(&tstat) & \
- float_flag_inexact) != 0; \
+ t.fld = tp##_muladd(xa->fld, b->fld, c->fld, \
+ maddflgs, &tstat); \
+ t.fld |= (get_float_exception_flags(&tstat) & \
+ float_flag_inexact) != 0; \
} else { \
- xt_out.fld = tp##_muladd(xa.fld, b->fld, c->fld, \
- maddflgs, &tstat); \
+ t.fld = tp##_muladd(xa->fld, b->fld, c->fld, \
+ maddflgs, &tstat); \
} \
env->fp_status.float_exception_flags |= tstat.float_exception_flags; \
\
if (unlikely(tstat.float_exception_flags & float_flag_invalid)) { \
- tp##_maddsub_update_excp(env, xa.fld, b->fld, \
+ tp##_maddsub_update_excp(env, xa->fld, b->fld, \
c->fld, maddflgs, GETPC()); \
} \
\
if (r2sp) { \
- xt_out.fld = helper_frsp(env, xt_out.fld); \
+ t.fld = helper_frsp(env, t.fld); \
} \
\
if (sfprf) { \
- helper_compute_fprf_float64(env, xt_out.fld); \
+ helper_compute_fprf_float64(env, t.fld); \
} \
} \
- putVSR(xT(opcode), &xt_out, env); \
+ *xt = t; \
do_float_check_status(env, GETPC()); \
}
-VSX_MADD(xsmaddadp, 1, float64, VsrD(0), MADD_FLGS, 1, 1, 0)
-VSX_MADD(xsmaddmdp, 1, float64, VsrD(0), MADD_FLGS, 0, 1, 0)
-VSX_MADD(xsmsubadp, 1, float64, VsrD(0), MSUB_FLGS, 1, 1, 0)
-VSX_MADD(xsmsubmdp, 1, float64, VsrD(0), MSUB_FLGS, 0, 1, 0)
-VSX_MADD(xsnmaddadp, 1, float64, VsrD(0), NMADD_FLGS, 1, 1, 0)
-VSX_MADD(xsnmaddmdp, 1, float64, VsrD(0), NMADD_FLGS, 0, 1, 0)
-VSX_MADD(xsnmsubadp, 1, float64, VsrD(0), NMSUB_FLGS, 1, 1, 0)
-VSX_MADD(xsnmsubmdp, 1, float64, VsrD(0), NMSUB_FLGS, 0, 1, 0)
-
-VSX_MADD(xsmaddasp, 1, float64, VsrD(0), MADD_FLGS, 1, 1, 1)
-VSX_MADD(xsmaddmsp, 1, float64, VsrD(0), MADD_FLGS, 0, 1, 1)
-VSX_MADD(xsmsubasp, 1, float64, VsrD(0), MSUB_FLGS, 1, 1, 1)
-VSX_MADD(xsmsubmsp, 1, float64, VsrD(0), MSUB_FLGS, 0, 1, 1)
-VSX_MADD(xsnmaddasp, 1, float64, VsrD(0), NMADD_FLGS, 1, 1, 1)
-VSX_MADD(xsnmaddmsp, 1, float64, VsrD(0), NMADD_FLGS, 0, 1, 1)
-VSX_MADD(xsnmsubasp, 1, float64, VsrD(0), NMSUB_FLGS, 1, 1, 1)
-VSX_MADD(xsnmsubmsp, 1, float64, VsrD(0), NMSUB_FLGS, 0, 1, 1)
-
-VSX_MADD(xvmaddadp, 2, float64, VsrD(i), MADD_FLGS, 1, 0, 0)
-VSX_MADD(xvmaddmdp, 2, float64, VsrD(i), MADD_FLGS, 0, 0, 0)
-VSX_MADD(xvmsubadp, 2, float64, VsrD(i), MSUB_FLGS, 1, 0, 0)
-VSX_MADD(xvmsubmdp, 2, float64, VsrD(i), MSUB_FLGS, 0, 0, 0)
-VSX_MADD(xvnmaddadp, 2, float64, VsrD(i), NMADD_FLGS, 1, 0, 0)
-VSX_MADD(xvnmaddmdp, 2, float64, VsrD(i), NMADD_FLGS, 0, 0, 0)
-VSX_MADD(xvnmsubadp, 2, float64, VsrD(i), NMSUB_FLGS, 1, 0, 0)
-VSX_MADD(xvnmsubmdp, 2, float64, VsrD(i), NMSUB_FLGS, 0, 0, 0)
-
-VSX_MADD(xvmaddasp, 4, float32, VsrW(i), MADD_FLGS, 1, 0, 0)
-VSX_MADD(xvmaddmsp, 4, float32, VsrW(i), MADD_FLGS, 0, 0, 0)
-VSX_MADD(xvmsubasp, 4, float32, VsrW(i), MSUB_FLGS, 1, 0, 0)
-VSX_MADD(xvmsubmsp, 4, float32, VsrW(i), MSUB_FLGS, 0, 0, 0)
-VSX_MADD(xvnmaddasp, 4, float32, VsrW(i), NMADD_FLGS, 1, 0, 0)
-VSX_MADD(xvnmaddmsp, 4, float32, VsrW(i), NMADD_FLGS, 0, 0, 0)
-VSX_MADD(xvnmsubasp, 4, float32, VsrW(i), NMSUB_FLGS, 1, 0, 0)
-VSX_MADD(xvnmsubmsp, 4, float32, VsrW(i), NMSUB_FLGS, 0, 0, 0)
+VSX_MADD(xsmadddp, 1, float64, VsrD(0), MADD_FLGS, 1, 0)
+VSX_MADD(xsmsubdp, 1, float64, VsrD(0), MSUB_FLGS, 1, 0)
+VSX_MADD(xsnmadddp, 1, float64, VsrD(0), NMADD_FLGS, 1, 0)
+VSX_MADD(xsnmsubdp, 1, float64, VsrD(0), NMSUB_FLGS, 1, 0)
+VSX_MADD(xsmaddsp, 1, float64, VsrD(0), MADD_FLGS, 1, 1)
+VSX_MADD(xsmsubsp, 1, float64, VsrD(0), MSUB_FLGS, 1, 1)
+VSX_MADD(xsnmaddsp, 1, float64, VsrD(0), NMADD_FLGS, 1, 1)
+VSX_MADD(xsnmsubsp, 1, float64, VsrD(0), NMSUB_FLGS, 1, 1)
+
+VSX_MADD(xvmadddp, 2, float64, VsrD(i), MADD_FLGS, 0, 0)
+VSX_MADD(xvmsubdp, 2, float64, VsrD(i), MSUB_FLGS, 0, 0)
+VSX_MADD(xvnmadddp, 2, float64, VsrD(i), NMADD_FLGS, 0, 0)
+VSX_MADD(xvnmsubdp, 2, float64, VsrD(i), NMSUB_FLGS, 0, 0)
+
+VSX_MADD(xvmaddsp, 4, float32, VsrW(i), MADD_FLGS, 0, 0)
+VSX_MADD(xvmsubsp, 4, float32, VsrW(i), MSUB_FLGS, 0, 0)
+VSX_MADD(xvnmaddsp, 4, float32, VsrW(i), NMADD_FLGS, 0, 0)
+VSX_MADD(xvnmsubsp, 4, float32, VsrW(i), NMSUB_FLGS, 0, 0)
/*
* VSX_SCALAR_CMP_DP - VSX scalar floating point compare double precision
* svxvc - set VXVC bit
*/
#define VSX_SCALAR_CMP_DP(op, cmp, exp, svxvc) \
-void helper_##op(CPUPPCState *env, uint32_t opcode) \
+void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, \
+ ppc_vsr_t *xa, ppc_vsr_t *xb) \
{ \
- ppc_vsr_t xt, xa, xb; \
+ ppc_vsr_t t = *xt; \
bool vxsnan_flag = false, vxvc_flag = false, vex_flag = false; \
\
- getVSR(xA(opcode), &xa, env); \
- getVSR(xB(opcode), &xb, env); \
- getVSR(xT(opcode), &xt, env); \
- \
- if (float64_is_signaling_nan(xa.VsrD(0), &env->fp_status) || \
- float64_is_signaling_nan(xb.VsrD(0), &env->fp_status)) { \
+ if (float64_is_signaling_nan(xa->VsrD(0), &env->fp_status) || \
+ float64_is_signaling_nan(xb->VsrD(0), &env->fp_status)) { \
vxsnan_flag = true; \
if (fpscr_ve == 0 && svxvc) { \
vxvc_flag = true; \
} \
} else if (svxvc) { \
- vxvc_flag = float64_is_quiet_nan(xa.VsrD(0), &env->fp_status) || \
- float64_is_quiet_nan(xb.VsrD(0), &env->fp_status); \
+ vxvc_flag = float64_is_quiet_nan(xa->VsrD(0), &env->fp_status) || \
+ float64_is_quiet_nan(xb->VsrD(0), &env->fp_status); \
} \
if (vxsnan_flag) { \
float_invalid_op_vxsnan(env, GETPC()); \
vex_flag = fpscr_ve && (vxvc_flag || vxsnan_flag); \
\
if (!vex_flag) { \
- if (float64_##cmp(xb.VsrD(0), xa.VsrD(0), &env->fp_status) == exp) { \
- xt.VsrD(0) = -1; \
- xt.VsrD(1) = 0; \
+ if (float64_##cmp(xb->VsrD(0), xa->VsrD(0), \
+ &env->fp_status) == exp) { \
+ t.VsrD(0) = -1; \
+ t.VsrD(1) = 0; \
} else { \
- xt.VsrD(0) = 0; \
- xt.VsrD(1) = 0; \
+ t.VsrD(0) = 0; \
+ t.VsrD(1) = 0; \
} \
} \
- putVSR(xT(opcode), &xt, env); \
+ *xt = t; \
do_float_check_status(env, GETPC()); \
}
VSX_SCALAR_CMP_DP(xscmpgtdp, lt, 1, 1)
VSX_SCALAR_CMP_DP(xscmpnedp, eq, 0, 0)
-void helper_xscmpexpdp(CPUPPCState *env, uint32_t opcode)
+void helper_xscmpexpdp(CPUPPCState *env, uint32_t opcode,
+ ppc_vsr_t *xa, ppc_vsr_t *xb)
{
- ppc_vsr_t xa, xb;
int64_t exp_a, exp_b;
uint32_t cc;
- getVSR(xA(opcode), &xa, env);
- getVSR(xB(opcode), &xb, env);
-
- exp_a = extract64(xa.VsrD(0), 52, 11);
- exp_b = extract64(xb.VsrD(0), 52, 11);
+ exp_a = extract64(xa->VsrD(0), 52, 11);
+ exp_b = extract64(xb->VsrD(0), 52, 11);
- if (unlikely(float64_is_any_nan(xa.VsrD(0)) ||
- float64_is_any_nan(xb.VsrD(0)))) {
+ if (unlikely(float64_is_any_nan(xa->VsrD(0)) ||
+ float64_is_any_nan(xb->VsrD(0)))) {
cc = CRF_SO;
} else {
if (exp_a < exp_b) {
do_float_check_status(env, GETPC());
}
-void helper_xscmpexpqp(CPUPPCState *env, uint32_t opcode)
+void helper_xscmpexpqp(CPUPPCState *env, uint32_t opcode,
+ ppc_vsr_t *xa, ppc_vsr_t *xb)
{
- ppc_vsr_t xa, xb;
int64_t exp_a, exp_b;
uint32_t cc;
- getVSR(rA(opcode) + 32, &xa, env);
- getVSR(rB(opcode) + 32, &xb, env);
+ exp_a = extract64(xa->VsrD(0), 48, 15);
+ exp_b = extract64(xb->VsrD(0), 48, 15);
- exp_a = extract64(xa.VsrD(0), 48, 15);
- exp_b = extract64(xb.VsrD(0), 48, 15);
-
- if (unlikely(float128_is_any_nan(xa.f128) ||
- float128_is_any_nan(xb.f128))) {
+ if (unlikely(float128_is_any_nan(xa->f128) ||
+ float128_is_any_nan(xb->f128))) {
cc = CRF_SO;
} else {
if (exp_a < exp_b) {
}
#define VSX_SCALAR_CMP(op, ordered) \
-void helper_##op(CPUPPCState *env, uint32_t opcode) \
+void helper_##op(CPUPPCState *env, uint32_t opcode, \
+ ppc_vsr_t *xa, ppc_vsr_t *xb) \
{ \
- ppc_vsr_t xa, xb; \
uint32_t cc = 0; \
bool vxsnan_flag = false, vxvc_flag = false; \
\
helper_reset_fpstatus(env); \
- getVSR(xA(opcode), &xa, env); \
- getVSR(xB(opcode), &xb, env); \
\
- if (float64_is_signaling_nan(xa.VsrD(0), &env->fp_status) || \
- float64_is_signaling_nan(xb.VsrD(0), &env->fp_status)) { \
+ if (float64_is_signaling_nan(xa->VsrD(0), &env->fp_status) || \
+ float64_is_signaling_nan(xb->VsrD(0), &env->fp_status)) { \
vxsnan_flag = true; \
cc = CRF_SO; \
if (fpscr_ve == 0 && ordered) { \
vxvc_flag = true; \
} \
- } else if (float64_is_quiet_nan(xa.VsrD(0), &env->fp_status) || \
- float64_is_quiet_nan(xb.VsrD(0), &env->fp_status)) { \
+ } else if (float64_is_quiet_nan(xa->VsrD(0), &env->fp_status) || \
+ float64_is_quiet_nan(xb->VsrD(0), &env->fp_status)) { \
cc = CRF_SO; \
if (ordered) { \
vxvc_flag = true; \
float_invalid_op_vxvc(env, 0, GETPC()); \
} \
\
- if (float64_lt(xa.VsrD(0), xb.VsrD(0), &env->fp_status)) { \
+ if (float64_lt(xa->VsrD(0), xb->VsrD(0), &env->fp_status)) { \
cc |= CRF_LT; \
- } else if (!float64_le(xa.VsrD(0), xb.VsrD(0), &env->fp_status)) { \
+ } else if (!float64_le(xa->VsrD(0), xb->VsrD(0), &env->fp_status)) { \
cc |= CRF_GT; \
} else { \
cc |= CRF_EQ; \
VSX_SCALAR_CMP(xscmpudp, 0)
#define VSX_SCALAR_CMPQ(op, ordered) \
-void helper_##op(CPUPPCState *env, uint32_t opcode) \
+void helper_##op(CPUPPCState *env, uint32_t opcode, \
+ ppc_vsr_t *xa, ppc_vsr_t *xb) \
{ \
- ppc_vsr_t xa, xb; \
uint32_t cc = 0; \
bool vxsnan_flag = false, vxvc_flag = false; \
\
helper_reset_fpstatus(env); \
- getVSR(rA(opcode) + 32, &xa, env); \
- getVSR(rB(opcode) + 32, &xb, env); \
\
- if (float128_is_signaling_nan(xa.f128, &env->fp_status) || \
- float128_is_signaling_nan(xb.f128, &env->fp_status)) { \
+ if (float128_is_signaling_nan(xa->f128, &env->fp_status) || \
+ float128_is_signaling_nan(xb->f128, &env->fp_status)) { \
vxsnan_flag = true; \
cc = CRF_SO; \
if (fpscr_ve == 0 && ordered) { \
vxvc_flag = true; \
} \
- } else if (float128_is_quiet_nan(xa.f128, &env->fp_status) || \
- float128_is_quiet_nan(xb.f128, &env->fp_status)) { \
+ } else if (float128_is_quiet_nan(xa->f128, &env->fp_status) || \
+ float128_is_quiet_nan(xb->f128, &env->fp_status)) { \
cc = CRF_SO; \
if (ordered) { \
vxvc_flag = true; \
float_invalid_op_vxvc(env, 0, GETPC()); \
} \
\
- if (float128_lt(xa.f128, xb.f128, &env->fp_status)) { \
+ if (float128_lt(xa->f128, xb->f128, &env->fp_status)) { \
cc |= CRF_LT; \
- } else if (!float128_le(xa.f128, xb.f128, &env->fp_status)) { \
+ } else if (!float128_le(xa->f128, xb->f128, &env->fp_status)) { \
cc |= CRF_GT; \
} else { \
cc |= CRF_EQ; \
* fld - vsr_t field (VsrD(*) or VsrW(*))
*/
#define VSX_MAX_MIN(name, op, nels, tp, fld) \
-void helper_##name(CPUPPCState *env, uint32_t opcode) \
+void helper_##name(CPUPPCState *env, ppc_vsr_t *xt, \
+ ppc_vsr_t *xa, ppc_vsr_t *xb) \
{ \
- ppc_vsr_t xt, xa, xb; \
+ ppc_vsr_t t = *xt; \
int i; \
\
- getVSR(xA(opcode), &xa, env); \
- getVSR(xB(opcode), &xb, env); \
- getVSR(xT(opcode), &xt, env); \
- \
for (i = 0; i < nels; i++) { \
- xt.fld = tp##_##op(xa.fld, xb.fld, &env->fp_status); \
- if (unlikely(tp##_is_signaling_nan(xa.fld, &env->fp_status) || \
- tp##_is_signaling_nan(xb.fld, &env->fp_status))) { \
+ t.fld = tp##_##op(xa->fld, xb->fld, &env->fp_status); \
+ if (unlikely(tp##_is_signaling_nan(xa->fld, &env->fp_status) || \
+ tp##_is_signaling_nan(xb->fld, &env->fp_status))) { \
float_invalid_op_vxsnan(env, GETPC()); \
} \
} \
\
- putVSR(xT(opcode), &xt, env); \
+ *xt = t; \
do_float_check_status(env, GETPC()); \
}
VSX_MAX_MIN(xvminsp, minnum, 4, float32, VsrW(i))
#define VSX_MAX_MINC(name, max) \
-void helper_##name(CPUPPCState *env, uint32_t opcode) \
+void helper_##name(CPUPPCState *env, uint32_t opcode, \
+ ppc_vsr_t *xt, ppc_vsr_t *xa, ppc_vsr_t *xb) \
{ \
- ppc_vsr_t xt, xa, xb; \
+ ppc_vsr_t t = *xt; \
bool vxsnan_flag = false, vex_flag = false; \
\
- getVSR(rA(opcode) + 32, &xa, env); \
- getVSR(rB(opcode) + 32, &xb, env); \
- getVSR(rD(opcode) + 32, &xt, env); \
- \
- if (unlikely(float64_is_any_nan(xa.VsrD(0)) || \
- float64_is_any_nan(xb.VsrD(0)))) { \
- if (float64_is_signaling_nan(xa.VsrD(0), &env->fp_status) || \
- float64_is_signaling_nan(xb.VsrD(0), &env->fp_status)) { \
+ if (unlikely(float64_is_any_nan(xa->VsrD(0)) || \
+ float64_is_any_nan(xb->VsrD(0)))) { \
+ if (float64_is_signaling_nan(xa->VsrD(0), &env->fp_status) || \
+ float64_is_signaling_nan(xb->VsrD(0), &env->fp_status)) { \
vxsnan_flag = true; \
} \
- xt.VsrD(0) = xb.VsrD(0); \
+ t.VsrD(0) = xb->VsrD(0); \
} else if ((max && \
- !float64_lt(xa.VsrD(0), xb.VsrD(0), &env->fp_status)) || \
+ !float64_lt(xa->VsrD(0), xb->VsrD(0), &env->fp_status)) || \
(!max && \
- float64_lt(xa.VsrD(0), xb.VsrD(0), &env->fp_status))) { \
- xt.VsrD(0) = xa.VsrD(0); \
+ float64_lt(xa->VsrD(0), xb->VsrD(0), &env->fp_status))) { \
+ t.VsrD(0) = xa->VsrD(0); \
} else { \
- xt.VsrD(0) = xb.VsrD(0); \
+ t.VsrD(0) = xb->VsrD(0); \
} \
\
vex_flag = fpscr_ve & vxsnan_flag; \
float_invalid_op_vxsnan(env, GETPC()); \
} \
if (!vex_flag) { \
- putVSR(rD(opcode) + 32, &xt, env); \
+ *xt = t; \
} \
} \
VSX_MAX_MINC(xsmincdp, 0);
#define VSX_MAX_MINJ(name, max) \
-void helper_##name(CPUPPCState *env, uint32_t opcode) \
+void helper_##name(CPUPPCState *env, uint32_t opcode, \
+ ppc_vsr_t *xt, ppc_vsr_t *xa, ppc_vsr_t *xb) \
{ \
- ppc_vsr_t xt, xa, xb; \
+ ppc_vsr_t t = *xt; \
bool vxsnan_flag = false, vex_flag = false; \
\
- getVSR(rA(opcode) + 32, &xa, env); \
- getVSR(rB(opcode) + 32, &xb, env); \
- getVSR(rD(opcode) + 32, &xt, env); \
- \
- if (unlikely(float64_is_any_nan(xa.VsrD(0)))) { \
- if (float64_is_signaling_nan(xa.VsrD(0), &env->fp_status)) { \
+ if (unlikely(float64_is_any_nan(xa->VsrD(0)))) { \
+ if (float64_is_signaling_nan(xa->VsrD(0), &env->fp_status)) { \
vxsnan_flag = true; \
} \
- xt.VsrD(0) = xa.VsrD(0); \
- } else if (unlikely(float64_is_any_nan(xb.VsrD(0)))) { \
- if (float64_is_signaling_nan(xb.VsrD(0), &env->fp_status)) { \
+ t.VsrD(0) = xa->VsrD(0); \
+ } else if (unlikely(float64_is_any_nan(xb->VsrD(0)))) { \
+ if (float64_is_signaling_nan(xb->VsrD(0), &env->fp_status)) { \
vxsnan_flag = true; \
} \
- xt.VsrD(0) = xb.VsrD(0); \
- } else if (float64_is_zero(xa.VsrD(0)) && float64_is_zero(xb.VsrD(0))) { \
+ t.VsrD(0) = xb->VsrD(0); \
+ } else if (float64_is_zero(xa->VsrD(0)) && \
+ float64_is_zero(xb->VsrD(0))) { \
if (max) { \
- if (!float64_is_neg(xa.VsrD(0)) || !float64_is_neg(xb.VsrD(0))) { \
- xt.VsrD(0) = 0ULL; \
+ if (!float64_is_neg(xa->VsrD(0)) || \
+ !float64_is_neg(xb->VsrD(0))) { \
+ t.VsrD(0) = 0ULL; \
} else { \
- xt.VsrD(0) = 0x8000000000000000ULL; \
+ t.VsrD(0) = 0x8000000000000000ULL; \
} \
} else { \
- if (float64_is_neg(xa.VsrD(0)) || float64_is_neg(xb.VsrD(0))) { \
- xt.VsrD(0) = 0x8000000000000000ULL; \
+ if (float64_is_neg(xa->VsrD(0)) || \
+ float64_is_neg(xb->VsrD(0))) { \
+ t.VsrD(0) = 0x8000000000000000ULL; \
} else { \
- xt.VsrD(0) = 0ULL; \
+ t.VsrD(0) = 0ULL; \
} \
} \
} else if ((max && \
- !float64_lt(xa.VsrD(0), xb.VsrD(0), &env->fp_status)) || \
+ !float64_lt(xa->VsrD(0), xb->VsrD(0), &env->fp_status)) || \
(!max && \
- float64_lt(xa.VsrD(0), xb.VsrD(0), &env->fp_status))) { \
- xt.VsrD(0) = xa.VsrD(0); \
+ float64_lt(xa->VsrD(0), xb->VsrD(0), &env->fp_status))) { \
+ t.VsrD(0) = xa->VsrD(0); \
} else { \
- xt.VsrD(0) = xb.VsrD(0); \
+ t.VsrD(0) = xb->VsrD(0); \
} \
\
vex_flag = fpscr_ve & vxsnan_flag; \
float_invalid_op_vxsnan(env, GETPC()); \
} \
if (!vex_flag) { \
- putVSR(rD(opcode) + 32, &xt, env); \
+ *xt = t; \
} \
} \
* exp - expected result of comparison
*/
#define VSX_CMP(op, nels, tp, fld, cmp, svxvc, exp) \
-void helper_##op(CPUPPCState *env, uint32_t opcode) \
+uint32_t helper_##op(CPUPPCState *env, ppc_vsr_t *xt, \
+ ppc_vsr_t *xa, ppc_vsr_t *xb) \
{ \
- ppc_vsr_t xt, xa, xb; \
+ ppc_vsr_t t = *xt; \
+ uint32_t crf6 = 0; \
int i; \
int all_true = 1; \
int all_false = 1; \
\
- getVSR(xA(opcode), &xa, env); \
- getVSR(xB(opcode), &xb, env); \
- getVSR(xT(opcode), &xt, env); \
- \
for (i = 0; i < nels; i++) { \
- if (unlikely(tp##_is_any_nan(xa.fld) || \
- tp##_is_any_nan(xb.fld))) { \
- if (tp##_is_signaling_nan(xa.fld, &env->fp_status) || \
- tp##_is_signaling_nan(xb.fld, &env->fp_status)) { \
+ if (unlikely(tp##_is_any_nan(xa->fld) || \
+ tp##_is_any_nan(xb->fld))) { \
+ if (tp##_is_signaling_nan(xa->fld, &env->fp_status) || \
+ tp##_is_signaling_nan(xb->fld, &env->fp_status)) { \
float_invalid_op_vxsnan(env, GETPC()); \
} \
if (svxvc) { \
float_invalid_op_vxvc(env, 0, GETPC()); \
} \
- xt.fld = 0; \
+ t.fld = 0; \
all_true = 0; \
} else { \
- if (tp##_##cmp(xb.fld, xa.fld, &env->fp_status) == exp) { \
- xt.fld = -1; \
+ if (tp##_##cmp(xb->fld, xa->fld, &env->fp_status) == exp) { \
+ t.fld = -1; \
all_false = 0; \
} else { \
- xt.fld = 0; \
+ t.fld = 0; \
all_true = 0; \
} \
} \
} \
\
- putVSR(xT(opcode), &xt, env); \
- if ((opcode >> (31 - 21)) & 1) { \
- env->crf[6] = (all_true ? 0x8 : 0) | (all_false ? 0x2 : 0); \
- } \
- do_float_check_status(env, GETPC()); \
- }
+ *xt = t; \
+ crf6 = (all_true ? 0x8 : 0) | (all_false ? 0x2 : 0); \
+ return crf6; \
+}
VSX_CMP(xvcmpeqdp, 2, float64, VsrD(i), eq, 0, 1)
VSX_CMP(xvcmpgedp, 2, float64, VsrD(i), le, 1, 1)
* sfprf - set FPRF
*/
#define VSX_CVT_FP_TO_FP(op, nels, stp, ttp, sfld, tfld, sfprf) \
-void helper_##op(CPUPPCState *env, uint32_t opcode) \
+void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, ppc_vsr_t *xb) \
{ \
- ppc_vsr_t xt, xb; \
+ ppc_vsr_t t = *xt; \
int i; \
\
- getVSR(xB(opcode), &xb, env); \
- getVSR(xT(opcode), &xt, env); \
- \
for (i = 0; i < nels; i++) { \
- xt.tfld = stp##_to_##ttp(xb.sfld, &env->fp_status); \
- if (unlikely(stp##_is_signaling_nan(xb.sfld, \
+ t.tfld = stp##_to_##ttp(xb->sfld, &env->fp_status); \
+ if (unlikely(stp##_is_signaling_nan(xb->sfld, \
&env->fp_status))) { \
float_invalid_op_vxsnan(env, GETPC()); \
- xt.tfld = ttp##_snan_to_qnan(xt.tfld); \
+ t.tfld = ttp##_snan_to_qnan(t.tfld); \
} \
if (sfprf) { \
- helper_compute_fprf_##ttp(env, xt.tfld); \
+ helper_compute_fprf_##ttp(env, t.tfld); \
} \
} \
\
- putVSR(xT(opcode), &xt, env); \
+ *xt = t; \
do_float_check_status(env, GETPC()); \
}
* sfprf - set FPRF
*/
#define VSX_CVT_FP_TO_FP_VECTOR(op, nels, stp, ttp, sfld, tfld, sfprf) \
-void helper_##op(CPUPPCState *env, uint32_t opcode) \
+void helper_##op(CPUPPCState *env, uint32_t opcode, \
+ ppc_vsr_t *xt, ppc_vsr_t *xb) \
{ \
- ppc_vsr_t xt, xb; \
+ ppc_vsr_t t = *xt; \
int i; \
\
- getVSR(rB(opcode) + 32, &xb, env); \
- getVSR(rD(opcode) + 32, &xt, env); \
- \
for (i = 0; i < nels; i++) { \
- xt.tfld = stp##_to_##ttp(xb.sfld, &env->fp_status); \
- if (unlikely(stp##_is_signaling_nan(xb.sfld, \
+ t.tfld = stp##_to_##ttp(xb->sfld, &env->fp_status); \
+ if (unlikely(stp##_is_signaling_nan(xb->sfld, \
&env->fp_status))) { \
float_invalid_op_vxsnan(env, GETPC()); \
- xt.tfld = ttp##_snan_to_qnan(xt.tfld); \
+ t.tfld = ttp##_snan_to_qnan(t.tfld); \
} \
if (sfprf) { \
- helper_compute_fprf_##ttp(env, xt.tfld); \
+ helper_compute_fprf_##ttp(env, t.tfld); \
} \
} \
\
- putVSR(rD(opcode) + 32, &xt, env); \
+ *xt = t; \
do_float_check_status(env, GETPC()); \
}
* sfprf - set FPRF
*/
#define VSX_CVT_FP_TO_FP_HP(op, nels, stp, ttp, sfld, tfld, sfprf) \
-void helper_##op(CPUPPCState *env, uint32_t opcode) \
+void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, ppc_vsr_t *xb) \
{ \
- ppc_vsr_t xt, xb; \
+ ppc_vsr_t t = { }; \
int i; \
\
- getVSR(xB(opcode), &xb, env); \
- memset(&xt, 0, sizeof(xt)); \
- \
for (i = 0; i < nels; i++) { \
- xt.tfld = stp##_to_##ttp(xb.sfld, 1, &env->fp_status); \
- if (unlikely(stp##_is_signaling_nan(xb.sfld, \
+ t.tfld = stp##_to_##ttp(xb->sfld, 1, &env->fp_status); \
+ if (unlikely(stp##_is_signaling_nan(xb->sfld, \
&env->fp_status))) { \
float_invalid_op_vxsnan(env, GETPC()); \
- xt.tfld = ttp##_snan_to_qnan(xt.tfld); \
+ t.tfld = ttp##_snan_to_qnan(t.tfld); \
} \
if (sfprf) { \
- helper_compute_fprf_##ttp(env, xt.tfld); \
+ helper_compute_fprf_##ttp(env, t.tfld); \
} \
} \
\
- putVSR(xT(opcode), &xt, env); \
+ *xt = t; \
do_float_check_status(env, GETPC()); \
}
* xscvqpdp isn't using VSX_CVT_FP_TO_FP() because xscvqpdpo will be
* added to this later.
*/
-void helper_xscvqpdp(CPUPPCState *env, uint32_t opcode)
+void helper_xscvqpdp(CPUPPCState *env, uint32_t opcode,
+ ppc_vsr_t *xt, ppc_vsr_t *xb)
{
- ppc_vsr_t xt, xb;
+ ppc_vsr_t t = { };
float_status tstat;
- getVSR(rB(opcode) + 32, &xb, env);
- memset(&xt, 0, sizeof(xt));
-
tstat = env->fp_status;
if (unlikely(Rc(opcode) != 0)) {
tstat.float_rounding_mode = float_round_to_odd;
}
- xt.VsrD(0) = float128_to_float64(xb.f128, &tstat);
+ t.VsrD(0) = float128_to_float64(xb->f128, &tstat);
env->fp_status.float_exception_flags |= tstat.float_exception_flags;
- if (unlikely(float128_is_signaling_nan(xb.f128, &tstat))) {
+ if (unlikely(float128_is_signaling_nan(xb->f128, &tstat))) {
float_invalid_op_vxsnan(env, GETPC());
- xt.VsrD(0) = float64_snan_to_qnan(xt.VsrD(0));
+ t.VsrD(0) = float64_snan_to_qnan(t.VsrD(0));
}
- helper_compute_fprf_float64(env, xt.VsrD(0));
+ helper_compute_fprf_float64(env, t.VsrD(0));
- putVSR(rD(opcode) + 32, &xt, env);
+ *xt = t;
do_float_check_status(env, GETPC());
}
* rnan - resulting NaN
*/
#define VSX_CVT_FP_TO_INT(op, nels, stp, ttp, sfld, tfld, rnan) \
-void helper_##op(CPUPPCState *env, uint32_t opcode) \
+void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, ppc_vsr_t *xb) \
{ \
int all_flags = env->fp_status.float_exception_flags, flags; \
- ppc_vsr_t xt, xb; \
+ ppc_vsr_t t = *xt; \
int i; \
\
- getVSR(xB(opcode), &xb, env); \
- getVSR(xT(opcode), &xt, env); \
- \
for (i = 0; i < nels; i++) { \
env->fp_status.float_exception_flags = 0; \
- xt.tfld = stp##_to_##ttp##_round_to_zero(xb.sfld, &env->fp_status); \
+ t.tfld = stp##_to_##ttp##_round_to_zero(xb->sfld, &env->fp_status); \
flags = env->fp_status.float_exception_flags; \
if (unlikely(flags & float_flag_invalid)) { \
- float_invalid_cvt(env, 0, GETPC(), stp##_classify(xb.sfld)); \
- xt.tfld = rnan; \
+ float_invalid_cvt(env, 0, GETPC(), stp##_classify(xb->sfld)); \
+ t.tfld = rnan; \
} \
all_flags |= flags; \
} \
\
- putVSR(xT(opcode), &xt, env); \
+ *xt = t; \
env->fp_status.float_exception_flags = all_flags; \
do_float_check_status(env, GETPC()); \
}
* rnan - resulting NaN
*/
#define VSX_CVT_FP_TO_INT_VECTOR(op, stp, ttp, sfld, tfld, rnan) \
-void helper_##op(CPUPPCState *env, uint32_t opcode) \
+void helper_##op(CPUPPCState *env, uint32_t opcode, \
+ ppc_vsr_t *xt, ppc_vsr_t *xb) \
{ \
- ppc_vsr_t xt, xb; \
+ ppc_vsr_t t = { }; \
\
- getVSR(rB(opcode) + 32, &xb, env); \
- memset(&xt, 0, sizeof(xt)); \
- \
- xt.tfld = stp##_to_##ttp##_round_to_zero(xb.sfld, &env->fp_status); \
+ t.tfld = stp##_to_##ttp##_round_to_zero(xb->sfld, &env->fp_status); \
if (env->fp_status.float_exception_flags & float_flag_invalid) { \
- float_invalid_cvt(env, 0, GETPC(), stp##_classify(xb.sfld)); \
- xt.tfld = rnan; \
+ float_invalid_cvt(env, 0, GETPC(), stp##_classify(xb->sfld)); \
+ t.tfld = rnan; \
} \
\
- putVSR(rD(opcode) + 32, &xt, env); \
+ *xt = t; \
do_float_check_status(env, GETPC()); \
}
* sfprf - set FPRF
*/
#define VSX_CVT_INT_TO_FP(op, nels, stp, ttp, sfld, tfld, sfprf, r2sp) \
-void helper_##op(CPUPPCState *env, uint32_t opcode) \
+void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, ppc_vsr_t *xb) \
{ \
- ppc_vsr_t xt, xb; \
+ ppc_vsr_t t = *xt; \
int i; \
\
- getVSR(xB(opcode), &xb, env); \
- getVSR(xT(opcode), &xt, env); \
- \
for (i = 0; i < nels; i++) { \
- xt.tfld = stp##_to_##ttp(xb.sfld, &env->fp_status); \
+ t.tfld = stp##_to_##ttp(xb->sfld, &env->fp_status); \
if (r2sp) { \
- xt.tfld = helper_frsp(env, xt.tfld); \
+ t.tfld = helper_frsp(env, t.tfld); \
} \
if (sfprf) { \
- helper_compute_fprf_float64(env, xt.tfld); \
+ helper_compute_fprf_float64(env, t.tfld); \
} \
} \
\
- putVSR(xT(opcode), &xt, env); \
+ *xt = t; \
do_float_check_status(env, GETPC()); \
}
* tfld - target vsr_t field
*/
#define VSX_CVT_INT_TO_FP_VECTOR(op, stp, ttp, sfld, tfld) \
-void helper_##op(CPUPPCState *env, uint32_t opcode) \
+void helper_##op(CPUPPCState *env, uint32_t opcode, \
+ ppc_vsr_t *xt, ppc_vsr_t *xb) \
{ \
- ppc_vsr_t xt, xb; \
+ ppc_vsr_t t = *xt; \
\
- getVSR(rB(opcode) + 32, &xb, env); \
- getVSR(rD(opcode) + 32, &xt, env); \
+ t.tfld = stp##_to_##ttp(xb->sfld, &env->fp_status); \
+ helper_compute_fprf_##ttp(env, t.tfld); \
\
- xt.tfld = stp##_to_##ttp(xb.sfld, &env->fp_status); \
- helper_compute_fprf_##ttp(env, xt.tfld); \
- \
- putVSR(xT(opcode) + 32, &xt, env); \
+ *xt = t; \
do_float_check_status(env, GETPC()); \
}
* sfprf - set FPRF
*/
#define VSX_ROUND(op, nels, tp, fld, rmode, sfprf) \
-void helper_##op(CPUPPCState *env, uint32_t opcode) \
+void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, ppc_vsr_t *xb) \
{ \
- ppc_vsr_t xt, xb; \
+ ppc_vsr_t t = *xt; \
int i; \
- getVSR(xB(opcode), &xb, env); \
- getVSR(xT(opcode), &xt, env); \
\
if (rmode != FLOAT_ROUND_CURRENT) { \
set_float_rounding_mode(rmode, &env->fp_status); \
} \
\
for (i = 0; i < nels; i++) { \
- if (unlikely(tp##_is_signaling_nan(xb.fld, \
+ if (unlikely(tp##_is_signaling_nan(xb->fld, \
&env->fp_status))) { \
float_invalid_op_vxsnan(env, GETPC()); \
- xt.fld = tp##_snan_to_qnan(xb.fld); \
+ t.fld = tp##_snan_to_qnan(xb->fld); \
} else { \
- xt.fld = tp##_round_to_int(xb.fld, &env->fp_status); \
+ t.fld = tp##_round_to_int(xb->fld, &env->fp_status); \
} \
if (sfprf) { \
- helper_compute_fprf_float64(env, xt.fld); \
+ helper_compute_fprf_float64(env, t.fld); \
} \
} \
\
env->fp_status.float_exception_flags &= ~float_flag_inexact; \
} \
\
- putVSR(xT(opcode), &xt, env); \
+ *xt = t; \
do_float_check_status(env, GETPC()); \
}
}
#define VSX_XXPERM(op, indexed) \
-void helper_##op(CPUPPCState *env, uint32_t opcode) \
+void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, \
+ ppc_vsr_t *xa, ppc_vsr_t *pcv) \
{ \
- ppc_vsr_t xt, xa, pcv, xto; \
+ ppc_vsr_t t = *xt; \
int i, idx; \
\
- getVSR(xA(opcode), &xa, env); \
- getVSR(xT(opcode), &xt, env); \
- getVSR(xB(opcode), &pcv, env); \
- \
for (i = 0; i < 16; i++) { \
- idx = pcv.VsrB(i) & 0x1F; \
+ idx = pcv->VsrB(i) & 0x1F; \
if (indexed) { \
idx = 31 - idx; \
} \
- xto.VsrB(i) = (idx <= 15) ? xa.VsrB(idx) : xt.VsrB(idx - 16); \
+ t.VsrB(i) = (idx <= 15) ? xa->VsrB(idx) \
+ : xt->VsrB(idx - 16); \
} \
- putVSR(xT(opcode), &xto, env); \
+ *xt = t; \
}
VSX_XXPERM(xxperm, 0)
VSX_XXPERM(xxpermr, 1)
-void helper_xvxsigsp(CPUPPCState *env, uint32_t opcode)
+void helper_xvxsigsp(CPUPPCState *env, ppc_vsr_t *xt, ppc_vsr_t *xb)
{
- ppc_vsr_t xt, xb;
+ ppc_vsr_t t = { };
uint32_t exp, i, fraction;
- getVSR(xB(opcode), &xb, env);
- memset(&xt, 0, sizeof(xt));
-
for (i = 0; i < 4; i++) {
- exp = (xb.VsrW(i) >> 23) & 0xFF;
- fraction = xb.VsrW(i) & 0x7FFFFF;
+ exp = (xb->VsrW(i) >> 23) & 0xFF;
+ fraction = xb->VsrW(i) & 0x7FFFFF;
if (exp != 0 && exp != 255) {
- xt.VsrW(i) = fraction | 0x00800000;
+ t.VsrW(i) = fraction | 0x00800000;
} else {
- xt.VsrW(i) = fraction;
+ t.VsrW(i) = fraction;
}
}
- putVSR(xT(opcode), &xt, env);
+ *xt = t;
}
/*
#define VSX_TEST_DC(op, nels, xbn, tp, fld, tfld, fld_max, scrf) \
void helper_##op(CPUPPCState *env, uint32_t opcode) \
{ \
- ppc_vsr_t xt, xb; \
+ ppc_vsr_t *xt = &env->vsr[xT(opcode)]; \
+ ppc_vsr_t *xb = &env->vsr[xbn]; \
+ ppc_vsr_t t = { }; \
uint32_t i, sign, dcmx; \
uint32_t cc, match = 0; \
\
- getVSR(xbn, &xb, env); \
if (!scrf) { \
- memset(&xt, 0, sizeof(xt)); \
dcmx = DCMX_XV(opcode); \
} else { \
+ t = *xt; \
dcmx = DCMX(opcode); \
} \
\
for (i = 0; i < nels; i++) { \
- sign = tp##_is_neg(xb.fld); \
- if (tp##_is_any_nan(xb.fld)) { \
+ sign = tp##_is_neg(xb->fld); \
+ if (tp##_is_any_nan(xb->fld)) { \
match = extract32(dcmx, 6, 1); \
- } else if (tp##_is_infinity(xb.fld)) { \
+ } else if (tp##_is_infinity(xb->fld)) { \
match = extract32(dcmx, 4 + !sign, 1); \
- } else if (tp##_is_zero(xb.fld)) { \
+ } else if (tp##_is_zero(xb->fld)) { \
match = extract32(dcmx, 2 + !sign, 1); \
- } else if (tp##_is_zero_or_denormal(xb.fld)) { \
+ } else if (tp##_is_zero_or_denormal(xb->fld)) { \
match = extract32(dcmx, 0 + !sign, 1); \
} \
\
env->fpscr |= cc << FPSCR_FPRF; \
env->crf[BF(opcode)] = cc; \
} else { \
- xt.tfld = match ? fld_max : 0; \
+ t.tfld = match ? fld_max : 0; \
} \
match = 0; \
} \
if (!scrf) { \
- putVSR(xT(opcode), &xt, env); \
+ *xt = t; \
} \
}
VSX_TEST_DC(xststdcdp, 1, xB(opcode), float64, VsrD(0), VsrD(0), 0, 1)
VSX_TEST_DC(xststdcqp, 1, (rB(opcode) + 32), float128, f128, VsrD(0), 0, 1)
-void helper_xststdcsp(CPUPPCState *env, uint32_t opcode)
+void helper_xststdcsp(CPUPPCState *env, uint32_t opcode, ppc_vsr_t *xb)
{
- ppc_vsr_t xb;
uint32_t dcmx, sign, exp;
uint32_t cc, match = 0, not_sp = 0;
- getVSR(xB(opcode), &xb, env);
dcmx = DCMX(opcode);
- exp = (xb.VsrD(0) >> 52) & 0x7FF;
+ exp = (xb->VsrD(0) >> 52) & 0x7FF;
- sign = float64_is_neg(xb.VsrD(0));
- if (float64_is_any_nan(xb.VsrD(0))) {
+ sign = float64_is_neg(xb->VsrD(0));
+ if (float64_is_any_nan(xb->VsrD(0))) {
match = extract32(dcmx, 6, 1);
- } else if (float64_is_infinity(xb.VsrD(0))) {
+ } else if (float64_is_infinity(xb->VsrD(0))) {
match = extract32(dcmx, 4 + !sign, 1);
- } else if (float64_is_zero(xb.VsrD(0))) {
+ } else if (float64_is_zero(xb->VsrD(0))) {
match = extract32(dcmx, 2 + !sign, 1);
- } else if (float64_is_zero_or_denormal(xb.VsrD(0)) ||
+ } else if (float64_is_zero_or_denormal(xb->VsrD(0)) ||
(exp > 0 && exp < 0x381)) {
match = extract32(dcmx, 0 + !sign, 1);
}
- not_sp = !float64_eq(xb.VsrD(0),
+ not_sp = !float64_eq(xb->VsrD(0),
float32_to_float64(
- float64_to_float32(xb.VsrD(0), &env->fp_status),
+ float64_to_float32(xb->VsrD(0), &env->fp_status),
&env->fp_status), &env->fp_status);
cc = sign << CRF_LT_BIT | match << CRF_EQ_BIT | not_sp << CRF_SO_BIT;
env->crf[BF(opcode)] = cc;
}
-void helper_xsrqpi(CPUPPCState *env, uint32_t opcode)
+void helper_xsrqpi(CPUPPCState *env, uint32_t opcode,
+ ppc_vsr_t *xt, ppc_vsr_t *xb)
{
- ppc_vsr_t xb;
- ppc_vsr_t xt;
+ ppc_vsr_t t = { };
uint8_t r = Rrm(opcode);
uint8_t ex = Rc(opcode);
uint8_t rmc = RMC(opcode);
uint8_t rmode = 0;
float_status tstat;
- getVSR(rB(opcode) + 32, &xb, env);
- memset(&xt, 0, sizeof(xt));
helper_reset_fpstatus(env);
if (r == 0 && rmc == 0) {
tstat = env->fp_status;
set_float_exception_flags(0, &tstat);
set_float_rounding_mode(rmode, &tstat);
- xt.f128 = float128_round_to_int(xb.f128, &tstat);
+ t.f128 = float128_round_to_int(xb->f128, &tstat);
env->fp_status.float_exception_flags |= tstat.float_exception_flags;
if (unlikely(tstat.float_exception_flags & float_flag_invalid)) {
- if (float128_is_signaling_nan(xb.f128, &tstat)) {
+ if (float128_is_signaling_nan(xb->f128, &tstat)) {
float_invalid_op_vxsnan(env, GETPC());
- xt.f128 = float128_snan_to_qnan(xt.f128);
+ t.f128 = float128_snan_to_qnan(t.f128);
}
}
env->fp_status.float_exception_flags &= ~float_flag_inexact;
}
- helper_compute_fprf_float128(env, xt.f128);
+ helper_compute_fprf_float128(env, t.f128);
do_float_check_status(env, GETPC());
- putVSR(rD(opcode) + 32, &xt, env);
+ *xt = t;
}
-void helper_xsrqpxp(CPUPPCState *env, uint32_t opcode)
+void helper_xsrqpxp(CPUPPCState *env, uint32_t opcode,
+ ppc_vsr_t *xt, ppc_vsr_t *xb)
{
- ppc_vsr_t xb;
- ppc_vsr_t xt;
+ ppc_vsr_t t = { };
uint8_t r = Rrm(opcode);
uint8_t rmc = RMC(opcode);
uint8_t rmode = 0;
floatx80 round_res;
float_status tstat;
- getVSR(rB(opcode) + 32, &xb, env);
- memset(&xt, 0, sizeof(xt));
helper_reset_fpstatus(env);
if (r == 0 && rmc == 0) {
tstat = env->fp_status;
set_float_exception_flags(0, &tstat);
set_float_rounding_mode(rmode, &tstat);
- round_res = float128_to_floatx80(xb.f128, &tstat);
- xt.f128 = floatx80_to_float128(round_res, &tstat);
+ round_res = float128_to_floatx80(xb->f128, &tstat);
+ t.f128 = floatx80_to_float128(round_res, &tstat);
env->fp_status.float_exception_flags |= tstat.float_exception_flags;
if (unlikely(tstat.float_exception_flags & float_flag_invalid)) {
- if (float128_is_signaling_nan(xb.f128, &tstat)) {
+ if (float128_is_signaling_nan(xb->f128, &tstat)) {
float_invalid_op_vxsnan(env, GETPC());
- xt.f128 = float128_snan_to_qnan(xt.f128);
+ t.f128 = float128_snan_to_qnan(t.f128);
}
}
- helper_compute_fprf_float128(env, xt.f128);
- putVSR(rD(opcode) + 32, &xt, env);
+ helper_compute_fprf_float128(env, t.f128);
+ *xt = t;
do_float_check_status(env, GETPC());
}
-void helper_xssqrtqp(CPUPPCState *env, uint32_t opcode)
+void helper_xssqrtqp(CPUPPCState *env, uint32_t opcode,
+ ppc_vsr_t *xt, ppc_vsr_t *xb)
{
- ppc_vsr_t xb;
- ppc_vsr_t xt;
+ ppc_vsr_t t = { };
float_status tstat;
- getVSR(rB(opcode) + 32, &xb, env);
- memset(&xt, 0, sizeof(xt));
helper_reset_fpstatus(env);
tstat = env->fp_status;
}
set_float_exception_flags(0, &tstat);
- xt.f128 = float128_sqrt(xb.f128, &tstat);
+ t.f128 = float128_sqrt(xb->f128, &tstat);
env->fp_status.float_exception_flags |= tstat.float_exception_flags;
if (unlikely(tstat.float_exception_flags & float_flag_invalid)) {
- if (float128_is_signaling_nan(xb.f128, &tstat)) {
+ if (float128_is_signaling_nan(xb->f128, &tstat)) {
float_invalid_op_vxsnan(env, GETPC());
- xt.f128 = float128_snan_to_qnan(xb.f128);
- } else if (float128_is_quiet_nan(xb.f128, &tstat)) {
- xt.f128 = xb.f128;
- } else if (float128_is_neg(xb.f128) && !float128_is_zero(xb.f128)) {
+ t.f128 = float128_snan_to_qnan(xb->f128);
+ } else if (float128_is_quiet_nan(xb->f128, &tstat)) {
+ t.f128 = xb->f128;
+ } else if (float128_is_neg(xb->f128) && !float128_is_zero(xb->f128)) {
float_invalid_op_vxsqrt(env, 1, GETPC());
- xt.f128 = float128_default_nan(&env->fp_status);
+ t.f128 = float128_default_nan(&env->fp_status);
}
}
- helper_compute_fprf_float128(env, xt.f128);
- putVSR(rD(opcode) + 32, &xt, env);
+ helper_compute_fprf_float128(env, t.f128);
+ *xt = t;
do_float_check_status(env, GETPC());
}
-void helper_xssubqp(CPUPPCState *env, uint32_t opcode)
+void helper_xssubqp(CPUPPCState *env, uint32_t opcode,
+ ppc_vsr_t *xt, ppc_vsr_t *xa, ppc_vsr_t *xb)
{
- ppc_vsr_t xt, xa, xb;
+ ppc_vsr_t t = *xt;
float_status tstat;
- getVSR(rA(opcode) + 32, &xa, env);
- getVSR(rB(opcode) + 32, &xb, env);
- getVSR(rD(opcode) + 32, &xt, env);
helper_reset_fpstatus(env);
tstat = env->fp_status;
}
set_float_exception_flags(0, &tstat);
- xt.f128 = float128_sub(xa.f128, xb.f128, &tstat);
+ t.f128 = float128_sub(xa->f128, xb->f128, &tstat);
env->fp_status.float_exception_flags |= tstat.float_exception_flags;
if (unlikely(tstat.float_exception_flags & float_flag_invalid)) {
float_invalid_op_addsub(env, 1, GETPC(),
- float128_classify(xa.f128) |
- float128_classify(xb.f128));
+ float128_classify(xa->f128) |
+ float128_classify(xb->f128));
}
- helper_compute_fprf_float128(env, xt.f128);
- putVSR(rD(opcode) + 32, &xt, env);
+ helper_compute_fprf_float128(env, t.f128);
+ *xt = t;
do_float_check_status(env, GETPC());
}
#define dh_ctype_avr ppc_avr_t *
#define dh_is_signed_avr dh_is_signed_ptr
+#define dh_alias_vsr ptr
+#define dh_ctype_vsr ppc_vsr_t *
+#define dh_is_signed_vsr dh_is_signed_ptr
+
DEF_HELPER_3(vavgub, void, avr, avr, avr)
DEF_HELPER_3(vavguh, void, avr, avr, avr)
DEF_HELPER_3(vavguw, void, avr, avr, avr)
DEF_HELPER_3(stvehx, void, env, avr, tl)
DEF_HELPER_3(stvewx, void, env, avr, tl)
#if defined(TARGET_PPC64)
-DEF_HELPER_4(lxvl, void, env, tl, tl, tl)
-DEF_HELPER_4(lxvll, void, env, tl, tl, tl)
-DEF_HELPER_4(stxvl, void, env, tl, tl, tl)
-DEF_HELPER_4(stxvll, void, env, tl, tl, tl)
+DEF_HELPER_4(lxvl, void, env, tl, vsr, tl)
+DEF_HELPER_4(lxvll, void, env, tl, vsr, tl)
+DEF_HELPER_4(stxvl, void, env, tl, vsr, tl)
+DEF_HELPER_4(stxvll, void, env, tl, vsr, tl)
#endif
DEF_HELPER_4(vsumsws, void, env, avr, avr, avr)
DEF_HELPER_4(vsum2sws, void, env, avr, avr, avr)
DEF_HELPER_4(bcdtrunc, i32, avr, avr, avr, i32)
DEF_HELPER_4(bcdutrunc, i32, avr, avr, avr, i32)
-DEF_HELPER_2(xsadddp, void, env, i32)
-DEF_HELPER_2(xsaddqp, void, env, i32)
-DEF_HELPER_2(xssubdp, void, env, i32)
-DEF_HELPER_2(xsmuldp, void, env, i32)
-DEF_HELPER_2(xsmulqp, void, env, i32)
-DEF_HELPER_2(xsdivdp, void, env, i32)
-DEF_HELPER_2(xsdivqp, void, env, i32)
-DEF_HELPER_2(xsredp, void, env, i32)
-DEF_HELPER_2(xssqrtdp, void, env, i32)
-DEF_HELPER_2(xsrsqrtedp, void, env, i32)
-DEF_HELPER_2(xstdivdp, void, env, i32)
-DEF_HELPER_2(xstsqrtdp, void, env, i32)
-DEF_HELPER_2(xsmaddadp, void, env, i32)
-DEF_HELPER_2(xsmaddmdp, void, env, i32)
-DEF_HELPER_2(xsmsubadp, void, env, i32)
-DEF_HELPER_2(xsmsubmdp, void, env, i32)
-DEF_HELPER_2(xsnmaddadp, void, env, i32)
-DEF_HELPER_2(xsnmaddmdp, void, env, i32)
-DEF_HELPER_2(xsnmsubadp, void, env, i32)
-DEF_HELPER_2(xsnmsubmdp, void, env, i32)
-DEF_HELPER_2(xscmpeqdp, void, env, i32)
-DEF_HELPER_2(xscmpgtdp, void, env, i32)
-DEF_HELPER_2(xscmpgedp, void, env, i32)
-DEF_HELPER_2(xscmpnedp, void, env, i32)
-DEF_HELPER_2(xscmpexpdp, void, env, i32)
-DEF_HELPER_2(xscmpexpqp, void, env, i32)
-DEF_HELPER_2(xscmpodp, void, env, i32)
-DEF_HELPER_2(xscmpudp, void, env, i32)
-DEF_HELPER_2(xscmpoqp, void, env, i32)
-DEF_HELPER_2(xscmpuqp, void, env, i32)
-DEF_HELPER_2(xsmaxdp, void, env, i32)
-DEF_HELPER_2(xsmindp, void, env, i32)
-DEF_HELPER_2(xsmaxcdp, void, env, i32)
-DEF_HELPER_2(xsmincdp, void, env, i32)
-DEF_HELPER_2(xsmaxjdp, void, env, i32)
-DEF_HELPER_2(xsminjdp, void, env, i32)
-DEF_HELPER_2(xscvdphp, void, env, i32)
-DEF_HELPER_2(xscvdpqp, void, env, i32)
-DEF_HELPER_2(xscvdpsp, void, env, i32)
+DEF_HELPER_4(xsadddp, void, env, vsr, vsr, vsr)
+DEF_HELPER_5(xsaddqp, void, env, i32, vsr, vsr, vsr)
+DEF_HELPER_4(xssubdp, void, env, vsr, vsr, vsr)
+DEF_HELPER_4(xsmuldp, void, env, vsr, vsr, vsr)
+DEF_HELPER_5(xsmulqp, void, env, i32, vsr, vsr, vsr)
+DEF_HELPER_4(xsdivdp, void, env, vsr, vsr, vsr)
+DEF_HELPER_5(xsdivqp, void, env, i32, vsr, vsr, vsr)
+DEF_HELPER_3(xsredp, void, env, vsr, vsr)
+DEF_HELPER_3(xssqrtdp, void, env, vsr, vsr)
+DEF_HELPER_3(xsrsqrtedp, void, env, vsr, vsr)
+DEF_HELPER_4(xstdivdp, void, env, i32, vsr, vsr)
+DEF_HELPER_3(xstsqrtdp, void, env, i32, vsr)
+DEF_HELPER_5(xsmadddp, void, env, vsr, vsr, vsr, vsr)
+DEF_HELPER_5(xsmsubdp, void, env, vsr, vsr, vsr, vsr)
+DEF_HELPER_5(xsnmadddp, void, env, vsr, vsr, vsr, vsr)
+DEF_HELPER_5(xsnmsubdp, void, env, vsr, vsr, vsr, vsr)
+DEF_HELPER_4(xscmpeqdp, void, env, vsr, vsr, vsr)
+DEF_HELPER_4(xscmpgtdp, void, env, vsr, vsr, vsr)
+DEF_HELPER_4(xscmpgedp, void, env, vsr, vsr, vsr)
+DEF_HELPER_4(xscmpnedp, void, env, vsr, vsr, vsr)
+DEF_HELPER_4(xscmpexpdp, void, env, i32, vsr, vsr)
+DEF_HELPER_4(xscmpexpqp, void, env, i32, vsr, vsr)
+DEF_HELPER_4(xscmpodp, void, env, i32, vsr, vsr)
+DEF_HELPER_4(xscmpudp, void, env, i32, vsr, vsr)
+DEF_HELPER_4(xscmpoqp, void, env, i32, vsr, vsr)
+DEF_HELPER_4(xscmpuqp, void, env, i32, vsr, vsr)
+DEF_HELPER_4(xsmaxdp, void, env, vsr, vsr, vsr)
+DEF_HELPER_4(xsmindp, void, env, vsr, vsr, vsr)
+DEF_HELPER_5(xsmaxcdp, void, env, i32, vsr, vsr, vsr)
+DEF_HELPER_5(xsmincdp, void, env, i32, vsr, vsr, vsr)
+DEF_HELPER_5(xsmaxjdp, void, env, i32, vsr, vsr, vsr)
+DEF_HELPER_5(xsminjdp, void, env, i32, vsr, vsr, vsr)
+DEF_HELPER_3(xscvdphp, void, env, vsr, vsr)
+DEF_HELPER_4(xscvdpqp, void, env, i32, vsr, vsr)
+DEF_HELPER_3(xscvdpsp, void, env, vsr, vsr)
DEF_HELPER_2(xscvdpspn, i64, env, i64)
-DEF_HELPER_2(xscvqpdp, void, env, i32)
-DEF_HELPER_2(xscvqpsdz, void, env, i32)
-DEF_HELPER_2(xscvqpswz, void, env, i32)
-DEF_HELPER_2(xscvqpudz, void, env, i32)
-DEF_HELPER_2(xscvqpuwz, void, env, i32)
-DEF_HELPER_2(xscvhpdp, void, env, i32)
-DEF_HELPER_2(xscvsdqp, void, env, i32)
-DEF_HELPER_2(xscvspdp, void, env, i32)
+DEF_HELPER_4(xscvqpdp, void, env, i32, vsr, vsr)
+DEF_HELPER_4(xscvqpsdz, void, env, i32, vsr, vsr)
+DEF_HELPER_4(xscvqpswz, void, env, i32, vsr, vsr)
+DEF_HELPER_4(xscvqpudz, void, env, i32, vsr, vsr)
+DEF_HELPER_4(xscvqpuwz, void, env, i32, vsr, vsr)
+DEF_HELPER_3(xscvhpdp, void, env, vsr, vsr)
+DEF_HELPER_4(xscvsdqp, void, env, i32, vsr, vsr)
+DEF_HELPER_3(xscvspdp, void, env, vsr, vsr)
DEF_HELPER_2(xscvspdpn, i64, env, i64)
-DEF_HELPER_2(xscvdpsxds, void, env, i32)
-DEF_HELPER_2(xscvdpsxws, void, env, i32)
-DEF_HELPER_2(xscvdpuxds, void, env, i32)
-DEF_HELPER_2(xscvdpuxws, void, env, i32)
-DEF_HELPER_2(xscvsxddp, void, env, i32)
-DEF_HELPER_2(xscvuxdsp, void, env, i32)
-DEF_HELPER_2(xscvsxdsp, void, env, i32)
-DEF_HELPER_2(xscvudqp, void, env, i32)
-DEF_HELPER_2(xscvuxddp, void, env, i32)
-DEF_HELPER_2(xststdcsp, void, env, i32)
+DEF_HELPER_3(xscvdpsxds, void, env, vsr, vsr)
+DEF_HELPER_3(xscvdpsxws, void, env, vsr, vsr)
+DEF_HELPER_3(xscvdpuxds, void, env, vsr, vsr)
+DEF_HELPER_3(xscvdpuxws, void, env, vsr, vsr)
+DEF_HELPER_3(xscvsxddp, void, env, vsr, vsr)
+DEF_HELPER_3(xscvuxdsp, void, env, vsr, vsr)
+DEF_HELPER_3(xscvsxdsp, void, env, vsr, vsr)
+DEF_HELPER_4(xscvudqp, void, env, i32, vsr, vsr)
+DEF_HELPER_3(xscvuxddp, void, env, vsr, vsr)
+DEF_HELPER_3(xststdcsp, void, env, i32, vsr)
DEF_HELPER_2(xststdcdp, void, env, i32)
DEF_HELPER_2(xststdcqp, void, env, i32)
-DEF_HELPER_2(xsrdpi, void, env, i32)
-DEF_HELPER_2(xsrdpic, void, env, i32)
-DEF_HELPER_2(xsrdpim, void, env, i32)
-DEF_HELPER_2(xsrdpip, void, env, i32)
-DEF_HELPER_2(xsrdpiz, void, env, i32)
-DEF_HELPER_2(xsrqpi, void, env, i32)
-DEF_HELPER_2(xsrqpxp, void, env, i32)
-DEF_HELPER_2(xssqrtqp, void, env, i32)
-DEF_HELPER_2(xssubqp, void, env, i32)
+DEF_HELPER_3(xsrdpi, void, env, vsr, vsr)
+DEF_HELPER_3(xsrdpic, void, env, vsr, vsr)
+DEF_HELPER_3(xsrdpim, void, env, vsr, vsr)
+DEF_HELPER_3(xsrdpip, void, env, vsr, vsr)
+DEF_HELPER_3(xsrdpiz, void, env, vsr, vsr)
+DEF_HELPER_4(xsrqpi, void, env, i32, vsr, vsr)
+DEF_HELPER_4(xsrqpxp, void, env, i32, vsr, vsr)
+DEF_HELPER_4(xssqrtqp, void, env, i32, vsr, vsr)
+DEF_HELPER_5(xssubqp, void, env, i32, vsr, vsr, vsr)
-DEF_HELPER_2(xsaddsp, void, env, i32)
-DEF_HELPER_2(xssubsp, void, env, i32)
-DEF_HELPER_2(xsmulsp, void, env, i32)
-DEF_HELPER_2(xsdivsp, void, env, i32)
-DEF_HELPER_2(xsresp, void, env, i32)
+DEF_HELPER_4(xsaddsp, void, env, vsr, vsr, vsr)
+DEF_HELPER_4(xssubsp, void, env, vsr, vsr, vsr)
+DEF_HELPER_4(xsmulsp, void, env, vsr, vsr, vsr)
+DEF_HELPER_4(xsdivsp, void, env, vsr, vsr, vsr)
+DEF_HELPER_3(xsresp, void, env, vsr, vsr)
DEF_HELPER_2(xsrsp, i64, env, i64)
-DEF_HELPER_2(xssqrtsp, void, env, i32)
-DEF_HELPER_2(xsrsqrtesp, void, env, i32)
-DEF_HELPER_2(xsmaddasp, void, env, i32)
-DEF_HELPER_2(xsmaddmsp, void, env, i32)
-DEF_HELPER_2(xsmsubasp, void, env, i32)
-DEF_HELPER_2(xsmsubmsp, void, env, i32)
-DEF_HELPER_2(xsnmaddasp, void, env, i32)
-DEF_HELPER_2(xsnmaddmsp, void, env, i32)
-DEF_HELPER_2(xsnmsubasp, void, env, i32)
-DEF_HELPER_2(xsnmsubmsp, void, env, i32)
+DEF_HELPER_3(xssqrtsp, void, env, vsr, vsr)
+DEF_HELPER_3(xsrsqrtesp, void, env, vsr, vsr)
+DEF_HELPER_5(xsmaddsp, void, env, vsr, vsr, vsr, vsr)
+DEF_HELPER_5(xsmsubsp, void, env, vsr, vsr, vsr, vsr)
+DEF_HELPER_5(xsnmaddsp, void, env, vsr, vsr, vsr, vsr)
+DEF_HELPER_5(xsnmsubsp, void, env, vsr, vsr, vsr, vsr)
-DEF_HELPER_2(xvadddp, void, env, i32)
-DEF_HELPER_2(xvsubdp, void, env, i32)
-DEF_HELPER_2(xvmuldp, void, env, i32)
-DEF_HELPER_2(xvdivdp, void, env, i32)
-DEF_HELPER_2(xvredp, void, env, i32)
-DEF_HELPER_2(xvsqrtdp, void, env, i32)
-DEF_HELPER_2(xvrsqrtedp, void, env, i32)
-DEF_HELPER_2(xvtdivdp, void, env, i32)
-DEF_HELPER_2(xvtsqrtdp, void, env, i32)
-DEF_HELPER_2(xvmaddadp, void, env, i32)
-DEF_HELPER_2(xvmaddmdp, void, env, i32)
-DEF_HELPER_2(xvmsubadp, void, env, i32)
-DEF_HELPER_2(xvmsubmdp, void, env, i32)
-DEF_HELPER_2(xvnmaddadp, void, env, i32)
-DEF_HELPER_2(xvnmaddmdp, void, env, i32)
-DEF_HELPER_2(xvnmsubadp, void, env, i32)
-DEF_HELPER_2(xvnmsubmdp, void, env, i32)
-DEF_HELPER_2(xvmaxdp, void, env, i32)
-DEF_HELPER_2(xvmindp, void, env, i32)
-DEF_HELPER_2(xvcmpeqdp, void, env, i32)
-DEF_HELPER_2(xvcmpgedp, void, env, i32)
-DEF_HELPER_2(xvcmpgtdp, void, env, i32)
-DEF_HELPER_2(xvcmpnedp, void, env, i32)
-DEF_HELPER_2(xvcvdpsp, void, env, i32)
-DEF_HELPER_2(xvcvdpsxds, void, env, i32)
-DEF_HELPER_2(xvcvdpsxws, void, env, i32)
-DEF_HELPER_2(xvcvdpuxds, void, env, i32)
-DEF_HELPER_2(xvcvdpuxws, void, env, i32)
-DEF_HELPER_2(xvcvsxddp, void, env, i32)
-DEF_HELPER_2(xvcvuxddp, void, env, i32)
-DEF_HELPER_2(xvcvsxwdp, void, env, i32)
-DEF_HELPER_2(xvcvuxwdp, void, env, i32)
-DEF_HELPER_2(xvrdpi, void, env, i32)
-DEF_HELPER_2(xvrdpic, void, env, i32)
-DEF_HELPER_2(xvrdpim, void, env, i32)
-DEF_HELPER_2(xvrdpip, void, env, i32)
-DEF_HELPER_2(xvrdpiz, void, env, i32)
+DEF_HELPER_4(xvadddp, void, env, vsr, vsr, vsr)
+DEF_HELPER_4(xvsubdp, void, env, vsr, vsr, vsr)
+DEF_HELPER_4(xvmuldp, void, env, vsr, vsr, vsr)
+DEF_HELPER_4(xvdivdp, void, env, vsr, vsr, vsr)
+DEF_HELPER_3(xvredp, void, env, vsr, vsr)
+DEF_HELPER_3(xvsqrtdp, void, env, vsr, vsr)
+DEF_HELPER_3(xvrsqrtedp, void, env, vsr, vsr)
+DEF_HELPER_4(xvtdivdp, void, env, i32, vsr, vsr)
+DEF_HELPER_3(xvtsqrtdp, void, env, i32, vsr)
+DEF_HELPER_5(xvmadddp, void, env, vsr, vsr, vsr, vsr)
+DEF_HELPER_5(xvmsubdp, void, env, vsr, vsr, vsr, vsr)
+DEF_HELPER_5(xvnmadddp, void, env, vsr, vsr, vsr, vsr)
+DEF_HELPER_5(xvnmsubdp, void, env, vsr, vsr, vsr, vsr)
+DEF_HELPER_4(xvmaxdp, void, env, vsr, vsr, vsr)
+DEF_HELPER_4(xvmindp, void, env, vsr, vsr, vsr)
+DEF_HELPER_FLAGS_4(xvcmpeqdp, TCG_CALL_NO_RWG, i32, env, vsr, vsr, vsr)
+DEF_HELPER_FLAGS_4(xvcmpgedp, TCG_CALL_NO_RWG, i32, env, vsr, vsr, vsr)
+DEF_HELPER_FLAGS_4(xvcmpgtdp, TCG_CALL_NO_RWG, i32, env, vsr, vsr, vsr)
+DEF_HELPER_FLAGS_4(xvcmpnedp, TCG_CALL_NO_RWG, i32, env, vsr, vsr, vsr)
+DEF_HELPER_3(xvcvdpsp, void, env, vsr, vsr)
+DEF_HELPER_3(xvcvdpsxds, void, env, vsr, vsr)
+DEF_HELPER_3(xvcvdpsxws, void, env, vsr, vsr)
+DEF_HELPER_3(xvcvdpuxds, void, env, vsr, vsr)
+DEF_HELPER_3(xvcvdpuxws, void, env, vsr, vsr)
+DEF_HELPER_3(xvcvsxddp, void, env, vsr, vsr)
+DEF_HELPER_3(xvcvuxddp, void, env, vsr, vsr)
+DEF_HELPER_3(xvcvsxwdp, void, env, vsr, vsr)
+DEF_HELPER_3(xvcvuxwdp, void, env, vsr, vsr)
+DEF_HELPER_3(xvrdpi, void, env, vsr, vsr)
+DEF_HELPER_3(xvrdpic, void, env, vsr, vsr)
+DEF_HELPER_3(xvrdpim, void, env, vsr, vsr)
+DEF_HELPER_3(xvrdpip, void, env, vsr, vsr)
+DEF_HELPER_3(xvrdpiz, void, env, vsr, vsr)
-DEF_HELPER_2(xvaddsp, void, env, i32)
-DEF_HELPER_2(xvsubsp, void, env, i32)
-DEF_HELPER_2(xvmulsp, void, env, i32)
-DEF_HELPER_2(xvdivsp, void, env, i32)
-DEF_HELPER_2(xvresp, void, env, i32)
-DEF_HELPER_2(xvsqrtsp, void, env, i32)
-DEF_HELPER_2(xvrsqrtesp, void, env, i32)
-DEF_HELPER_2(xvtdivsp, void, env, i32)
-DEF_HELPER_2(xvtsqrtsp, void, env, i32)
-DEF_HELPER_2(xvmaddasp, void, env, i32)
-DEF_HELPER_2(xvmaddmsp, void, env, i32)
-DEF_HELPER_2(xvmsubasp, void, env, i32)
-DEF_HELPER_2(xvmsubmsp, void, env, i32)
-DEF_HELPER_2(xvnmaddasp, void, env, i32)
-DEF_HELPER_2(xvnmaddmsp, void, env, i32)
-DEF_HELPER_2(xvnmsubasp, void, env, i32)
-DEF_HELPER_2(xvnmsubmsp, void, env, i32)
-DEF_HELPER_2(xvmaxsp, void, env, i32)
-DEF_HELPER_2(xvminsp, void, env, i32)
-DEF_HELPER_2(xvcmpeqsp, void, env, i32)
-DEF_HELPER_2(xvcmpgesp, void, env, i32)
-DEF_HELPER_2(xvcmpgtsp, void, env, i32)
-DEF_HELPER_2(xvcmpnesp, void, env, i32)
-DEF_HELPER_2(xvcvspdp, void, env, i32)
-DEF_HELPER_2(xvcvsphp, void, env, i32)
-DEF_HELPER_2(xvcvhpsp, void, env, i32)
-DEF_HELPER_2(xvcvspsxds, void, env, i32)
-DEF_HELPER_2(xvcvspsxws, void, env, i32)
-DEF_HELPER_2(xvcvspuxds, void, env, i32)
-DEF_HELPER_2(xvcvspuxws, void, env, i32)
-DEF_HELPER_2(xvcvsxdsp, void, env, i32)
-DEF_HELPER_2(xvcvuxdsp, void, env, i32)
-DEF_HELPER_2(xvcvsxwsp, void, env, i32)
-DEF_HELPER_2(xvcvuxwsp, void, env, i32)
+DEF_HELPER_4(xvaddsp, void, env, vsr, vsr, vsr)
+DEF_HELPER_4(xvsubsp, void, env, vsr, vsr, vsr)
+DEF_HELPER_4(xvmulsp, void, env, vsr, vsr, vsr)
+DEF_HELPER_4(xvdivsp, void, env, vsr, vsr, vsr)
+DEF_HELPER_3(xvresp, void, env, vsr, vsr)
+DEF_HELPER_3(xvsqrtsp, void, env, vsr, vsr)
+DEF_HELPER_3(xvrsqrtesp, void, env, vsr, vsr)
+DEF_HELPER_4(xvtdivsp, void, env, i32, vsr, vsr)
+DEF_HELPER_3(xvtsqrtsp, void, env, i32, vsr)
+DEF_HELPER_5(xvmaddsp, void, env, vsr, vsr, vsr, vsr)
+DEF_HELPER_5(xvmsubsp, void, env, vsr, vsr, vsr, vsr)
+DEF_HELPER_5(xvnmaddsp, void, env, vsr, vsr, vsr, vsr)
+DEF_HELPER_5(xvnmsubsp, void, env, vsr, vsr, vsr, vsr)
+DEF_HELPER_4(xvmaxsp, void, env, vsr, vsr, vsr)
+DEF_HELPER_4(xvminsp, void, env, vsr, vsr, vsr)
+DEF_HELPER_FLAGS_4(xvcmpeqsp, TCG_CALL_NO_RWG, i32, env, vsr, vsr, vsr)
+DEF_HELPER_FLAGS_4(xvcmpgesp, TCG_CALL_NO_RWG, i32, env, vsr, vsr, vsr)
+DEF_HELPER_FLAGS_4(xvcmpgtsp, TCG_CALL_NO_RWG, i32, env, vsr, vsr, vsr)
+DEF_HELPER_FLAGS_4(xvcmpnesp, TCG_CALL_NO_RWG, i32, env, vsr, vsr, vsr)
+DEF_HELPER_3(xvcvspdp, void, env, vsr, vsr)
+DEF_HELPER_3(xvcvsphp, void, env, vsr, vsr)
+DEF_HELPER_3(xvcvhpsp, void, env, vsr, vsr)
+DEF_HELPER_3(xvcvspsxds, void, env, vsr, vsr)
+DEF_HELPER_3(xvcvspsxws, void, env, vsr, vsr)
+DEF_HELPER_3(xvcvspuxds, void, env, vsr, vsr)
+DEF_HELPER_3(xvcvspuxws, void, env, vsr, vsr)
+DEF_HELPER_3(xvcvsxdsp, void, env, vsr, vsr)
+DEF_HELPER_3(xvcvuxdsp, void, env, vsr, vsr)
+DEF_HELPER_3(xvcvsxwsp, void, env, vsr, vsr)
+DEF_HELPER_3(xvcvuxwsp, void, env, vsr, vsr)
DEF_HELPER_2(xvtstdcsp, void, env, i32)
DEF_HELPER_2(xvtstdcdp, void, env, i32)
-DEF_HELPER_2(xvrspi, void, env, i32)
-DEF_HELPER_2(xvrspic, void, env, i32)
-DEF_HELPER_2(xvrspim, void, env, i32)
-DEF_HELPER_2(xvrspip, void, env, i32)
-DEF_HELPER_2(xvrspiz, void, env, i32)
-DEF_HELPER_2(xxperm, void, env, i32)
-DEF_HELPER_2(xxpermr, void, env, i32)
-DEF_HELPER_4(xxextractuw, void, env, tl, tl, i32)
-DEF_HELPER_4(xxinsertw, void, env, tl, tl, i32)
-DEF_HELPER_2(xvxsigsp, void, env, i32)
+DEF_HELPER_3(xvrspi, void, env, vsr, vsr)
+DEF_HELPER_3(xvrspic, void, env, vsr, vsr)
+DEF_HELPER_3(xvrspim, void, env, vsr, vsr)
+DEF_HELPER_3(xvrspip, void, env, vsr, vsr)
+DEF_HELPER_3(xvrspiz, void, env, vsr, vsr)
+DEF_HELPER_4(xxperm, void, env, vsr, vsr, vsr)
+DEF_HELPER_4(xxpermr, void, env, vsr, vsr, vsr)
+DEF_HELPER_4(xxextractuw, void, env, vsr, vsr, i32)
+DEF_HELPER_4(xxinsertw, void, env, vsr, vsr, i32)
+DEF_HELPER_3(xvxsigsp, void, env, vsr, vsr)
DEF_HELPER_2(efscfsi, i32, env, i32)
DEF_HELPER_2(efscfui, i32, env, i32)
VEXTRACT(d, u64)
#undef VEXTRACT
-void helper_xxextractuw(CPUPPCState *env, target_ulong xtn,
- target_ulong xbn, uint32_t index)
+void helper_xxextractuw(CPUPPCState *env, ppc_vsr_t *xt,
+ ppc_vsr_t *xb, uint32_t index)
{
- ppc_vsr_t xt, xb;
+ ppc_vsr_t t = { };
size_t es = sizeof(uint32_t);
uint32_t ext_index;
int i;
- getVSR(xbn, &xb, env);
- memset(&xt, 0, sizeof(xt));
-
ext_index = index;
for (i = 0; i < es; i++, ext_index++) {
- xt.VsrB(8 - es + i) = xb.VsrB(ext_index % 16);
+ t.VsrB(8 - es + i) = xb->VsrB(ext_index % 16);
}
- putVSR(xtn, &xt, env);
+ *xt = t;
}
-void helper_xxinsertw(CPUPPCState *env, target_ulong xtn,
- target_ulong xbn, uint32_t index)
+void helper_xxinsertw(CPUPPCState *env, ppc_vsr_t *xt,
+ ppc_vsr_t *xb, uint32_t index)
{
- ppc_vsr_t xt, xb;
+ ppc_vsr_t t = *xt;
size_t es = sizeof(uint32_t);
int ins_index, i = 0;
- getVSR(xbn, &xb, env);
- getVSR(xtn, &xt, env);
-
ins_index = index;
for (i = 0; i < es && ins_index < 16; i++, ins_index++) {
- xt.VsrB(ins_index) = xb.VsrB(8 - es + i);
+ t.VsrB(ins_index) = xb->VsrB(8 - es + i);
}
- putVSR(xtn, &xt, env);
+ *xt = t;
}
#define VEXT_SIGNED(name, element, cast) \
EXTRACT_HELPER(DCMX, 16, 7);
EXTRACT_HELPER_SPLIT_3(DCMX_XV, 5, 16, 0, 1, 2, 5, 1, 6, 6);
-static inline void getVSR(int n, ppc_vsr_t *vsr, CPUPPCState *env)
-{
- 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].VsrD(0) = vsr->VsrD(0);
- env->vsr[n].VsrD(1) = vsr->VsrD(1);
-}
-
void helper_compute_fprf_float16(CPUPPCState *env, float16 arg);
void helper_compute_fprf_float32(CPUPPCState *env, float32 arg);
void helper_compute_fprf_float128(CPUPPCState *env, float128 arg);
return -ENOENT;
}
- strncpy(args.name, function, sizeof(args.name));
+ strncpy(args.name, function, sizeof(args.name) - 1);
return kvm_vm_ioctl(kvm_state, KVM_PPC_RTAS_DEFINE_TOKEN, &args);
}
kvm_set_one_reg(cs, KVM_REG_PPC_ONLINE, &online);
}
}
+
+void kvmppc_set_reg_tb_offset(PowerPCCPU *cpu, int64_t tb_offset)
+{
+ CPUState *cs = CPU(cpu);
+
+ if (kvm_enabled()) {
+ kvm_set_one_reg(cs, KVM_REG_PPC_TB_OFFSET, &tb_offset);
+ }
+}
bool kvmppc_hpt_needs_host_contiguous_pages(void);
void kvm_check_mmu(PowerPCCPU *cpu, Error **errp);
void kvmppc_set_reg_ppc_online(PowerPCCPU *cpu, unsigned int online);
+void kvmppc_set_reg_tb_offset(PowerPCCPU *cpu, int64_t tb_offset);
#else
return;
}
+static inline void kvmppc_set_reg_tb_offset(PowerPCCPU *cpu, int64_t tb_offset)
+{
+}
+
#ifndef CONFIG_USER_ONLY
static inline bool kvmppc_spapr_use_multitce(void)
{
return -ENOSYS;
}
+static inline bool kvmppc_pvr_workaround_required(PowerPCCPU *cpu)
+{
+ return false;
+}
+
#endif
#ifndef CONFIG_KVM
* receive the PVR it expects as a workaround.
*
*/
-#if defined(CONFIG_KVM)
if (kvmppc_pvr_workaround_required(cpu)) {
env->spr[SPR_PVR] = env->spr_cb[SPR_PVR].default_value;
}
-#endif
env->lr = env->spr[SPR_LR];
env->ctr = env->spr[SPR_CTR];
#define VSX_LXVL(name, lj) \
void helper_##name(CPUPPCState *env, target_ulong addr, \
- target_ulong xt_num, target_ulong rb) \
+ ppc_vsr_t *xt, target_ulong rb) \
{ \
- int i; \
- ppc_vsr_t xt; \
+ ppc_vsr_t t; \
uint64_t nb = GET_NB(rb); \
+ int i; \
\
- xt.s128 = int128_zero(); \
+ t.s128 = int128_zero(); \
if (nb) { \
nb = (nb >= 16) ? 16 : nb; \
if (msr_le && !lj) { \
for (i = 16; i > 16 - nb; i--) { \
- xt.VsrB(i - 1) = cpu_ldub_data_ra(env, addr, GETPC()); \
+ t.VsrB(i - 1) = cpu_ldub_data_ra(env, addr, GETPC()); \
addr = addr_add(env, addr, 1); \
} \
} else { \
for (i = 0; i < nb; i++) { \
- xt.VsrB(i) = cpu_ldub_data_ra(env, addr, GETPC()); \
+ t.VsrB(i) = cpu_ldub_data_ra(env, addr, GETPC()); \
addr = addr_add(env, addr, 1); \
} \
} \
} \
- putVSR(xt_num, &xt, env); \
+ *xt = t; \
}
VSX_LXVL(lxvl, 0)
#define VSX_STXVL(name, lj) \
void helper_##name(CPUPPCState *env, target_ulong addr, \
- target_ulong xt_num, target_ulong rb) \
+ ppc_vsr_t *xt, target_ulong rb) \
{ \
- int i; \
- ppc_vsr_t xt; \
target_ulong nb = GET_NB(rb); \
+ int i; \
\
if (!nb) { \
return; \
} \
- getVSR(xt_num, &xt, env); \
+ \
nb = (nb >= 16) ? 16 : nb; \
if (msr_le && !lj) { \
for (i = 16; i > 16 - nb; i--) { \
- cpu_stb_data_ra(env, addr, xt.VsrB(i - 1), GETPC()); \
+ cpu_stb_data_ra(env, addr, xt->VsrB(i - 1), GETPC()); \
addr = addr_add(env, addr, 1); \
} \
} else { \
for (i = 0; i < nb; i++) { \
- cpu_stb_data_ra(env, addr, xt.VsrB(i), GETPC()); \
+ cpu_stb_data_ra(env, addr, xt->VsrB(i), GETPC()); \
addr = addr_add(env, addr, 1); \
} \
} \
#include "monitor/monitor.h"
#include "qemu/ctype.h"
#include "monitor/hmp-target.h"
-#include "hmp.h"
+#include "monitor/hmp.h"
static target_long monitor_get_ccr(const struct MonitorDef *md, int val)
{
tcg_gen_st_i64(src, cpu_env, vsr64_offset(n, false));
}
+static inline TCGv_ptr gen_vsr_ptr(int reg)
+{
+ TCGv_ptr r = tcg_temp_new_ptr();
+ tcg_gen_addi_ptr(r, cpu_env, vsr_full_offset(reg));
+ return r;
+}
+
#define VSX_LOAD_SCALAR(name, operation) \
static void gen_##name(DisasContext *ctx) \
{ \
VSX_VECTOR_STORE(stxvx, st_i64, 1)
#ifdef TARGET_PPC64
-#define VSX_VECTOR_LOAD_STORE_LENGTH(name) \
-static void gen_##name(DisasContext *ctx) \
-{ \
- TCGv EA, xt; \
- \
- if (xT(ctx->opcode) < 32) { \
- if (unlikely(!ctx->vsx_enabled)) { \
- gen_exception(ctx, POWERPC_EXCP_VSXU); \
- return; \
- } \
- } else { \
- if (unlikely(!ctx->altivec_enabled)) { \
- gen_exception(ctx, POWERPC_EXCP_VPU); \
- return; \
- } \
- } \
- EA = tcg_temp_new(); \
- xt = tcg_const_tl(xT(ctx->opcode)); \
- gen_set_access_type(ctx, ACCESS_INT); \
- gen_addr_register(ctx, EA); \
- gen_helper_##name(cpu_env, EA, xt, cpu_gpr[rB(ctx->opcode)]); \
- tcg_temp_free(EA); \
- tcg_temp_free(xt); \
+#define VSX_VECTOR_LOAD_STORE_LENGTH(name) \
+static void gen_##name(DisasContext *ctx) \
+{ \
+ TCGv EA; \
+ TCGv_ptr xt; \
+ \
+ if (xT(ctx->opcode) < 32) { \
+ if (unlikely(!ctx->vsx_enabled)) { \
+ gen_exception(ctx, POWERPC_EXCP_VSXU); \
+ return; \
+ } \
+ } else { \
+ if (unlikely(!ctx->altivec_enabled)) { \
+ gen_exception(ctx, POWERPC_EXCP_VPU); \
+ return; \
+ } \
+ } \
+ EA = tcg_temp_new(); \
+ xt = gen_vsr_ptr(xT(ctx->opcode)); \
+ gen_set_access_type(ctx, ACCESS_INT); \
+ gen_addr_register(ctx, EA); \
+ gen_helper_##name(cpu_env, EA, xt, cpu_gpr[rB(ctx->opcode)]); \
+ tcg_temp_free(EA); \
+ tcg_temp_free_ptr(xt); \
}
VSX_VECTOR_LOAD_STORE_LENGTH(lxvl)
VSX_VECTOR_MOVE(xvnegsp, OP_NEG, SGN_MASK_SP)
VSX_VECTOR_MOVE(xvcpsgnsp, OP_CPSGN, SGN_MASK_SP)
+#define VSX_CMP(name, op1, op2, inval, type) \
+static void gen_##name(DisasContext *ctx) \
+{ \
+ TCGv_i32 ignored; \
+ TCGv_ptr xt, xa, xb; \
+ if (unlikely(!ctx->vsx_enabled)) { \
+ gen_exception(ctx, POWERPC_EXCP_VSXU); \
+ return; \
+ } \
+ xt = gen_vsr_ptr(xT(ctx->opcode)); \
+ xa = gen_vsr_ptr(xA(ctx->opcode)); \
+ xb = gen_vsr_ptr(xB(ctx->opcode)); \
+ if ((ctx->opcode >> (31 - 21)) & 1) { \
+ gen_helper_##name(cpu_crf[6], cpu_env, xt, xa, xb); \
+ } else { \
+ ignored = tcg_temp_new_i32(); \
+ gen_helper_##name(ignored, cpu_env, xt, xa, xb); \
+ tcg_temp_free_i32(ignored); \
+ } \
+ gen_helper_float_check_status(cpu_env); \
+ tcg_temp_free_ptr(xt); \
+ tcg_temp_free_ptr(xa); \
+ tcg_temp_free_ptr(xb); \
+}
+
+VSX_CMP(xvcmpeqdp, 0x0C, 0x0C, 0, PPC2_VSX)
+VSX_CMP(xvcmpgedp, 0x0C, 0x0E, 0, PPC2_VSX)
+VSX_CMP(xvcmpgtdp, 0x0C, 0x0D, 0, PPC2_VSX)
+VSX_CMP(xvcmpnedp, 0x0C, 0x0F, 0, PPC2_ISA300)
+VSX_CMP(xvcmpeqsp, 0x0C, 0x08, 0, PPC2_VSX)
+VSX_CMP(xvcmpgesp, 0x0C, 0x0A, 0, PPC2_VSX)
+VSX_CMP(xvcmpgtsp, 0x0C, 0x09, 0, PPC2_VSX)
+VSX_CMP(xvcmpnesp, 0x0C, 0x0B, 0, PPC2_VSX)
+
+static void gen_xscvqpdp(DisasContext *ctx)
+{
+ TCGv_i32 opc;
+ TCGv_ptr xt, xb;
+ if (unlikely(!ctx->vsx_enabled)) {
+ gen_exception(ctx, POWERPC_EXCP_VSXU);
+ return;
+ }
+ opc = tcg_const_i32(ctx->opcode);
+ xt = gen_vsr_ptr(xT(ctx->opcode));
+ xb = gen_vsr_ptr(xB(ctx->opcode));
+ gen_helper_xscvqpdp(cpu_env, opc, xt, xb);
+ tcg_temp_free_i32(opc);
+ tcg_temp_free_ptr(xt);
+ tcg_temp_free_ptr(xb);
+}
+
#define GEN_VSX_HELPER_2(name, op1, op2, inval, type) \
static void gen_##name(DisasContext *ctx) \
{ \
tcg_temp_free_i32(opc); \
}
+#define GEN_VSX_HELPER_X3(name, op1, op2, inval, type) \
+static void gen_##name(DisasContext *ctx) \
+{ \
+ TCGv_ptr xt, xa, xb; \
+ if (unlikely(!ctx->vsx_enabled)) { \
+ gen_exception(ctx, POWERPC_EXCP_VSXU); \
+ return; \
+ } \
+ xt = gen_vsr_ptr(xT(ctx->opcode)); \
+ xa = gen_vsr_ptr(xA(ctx->opcode)); \
+ xb = gen_vsr_ptr(xB(ctx->opcode)); \
+ gen_helper_##name(cpu_env, xt, xa, xb); \
+ tcg_temp_free_ptr(xt); \
+ tcg_temp_free_ptr(xa); \
+ tcg_temp_free_ptr(xb); \
+}
+
+#define GEN_VSX_HELPER_X2(name, op1, op2, inval, type) \
+static void gen_##name(DisasContext *ctx) \
+{ \
+ TCGv_ptr xt, xb; \
+ if (unlikely(!ctx->vsx_enabled)) { \
+ gen_exception(ctx, POWERPC_EXCP_VSXU); \
+ return; \
+ } \
+ xt = gen_vsr_ptr(xT(ctx->opcode)); \
+ xb = gen_vsr_ptr(xB(ctx->opcode)); \
+ gen_helper_##name(cpu_env, xt, xb); \
+ tcg_temp_free_ptr(xt); \
+ tcg_temp_free_ptr(xb); \
+}
+
+#define GEN_VSX_HELPER_X2_AB(name, op1, op2, inval, type) \
+static void gen_##name(DisasContext *ctx) \
+{ \
+ TCGv_i32 opc; \
+ TCGv_ptr xa, xb; \
+ if (unlikely(!ctx->vsx_enabled)) { \
+ gen_exception(ctx, POWERPC_EXCP_VSXU); \
+ return; \
+ } \
+ opc = tcg_const_i32(ctx->opcode); \
+ xa = gen_vsr_ptr(xA(ctx->opcode)); \
+ xb = gen_vsr_ptr(xB(ctx->opcode)); \
+ gen_helper_##name(cpu_env, opc, xa, xb); \
+ tcg_temp_free_i32(opc); \
+ tcg_temp_free_ptr(xa); \
+ tcg_temp_free_ptr(xb); \
+}
+
+#define GEN_VSX_HELPER_X1(name, op1, op2, inval, type) \
+static void gen_##name(DisasContext *ctx) \
+{ \
+ TCGv_i32 opc; \
+ TCGv_ptr xb; \
+ if (unlikely(!ctx->vsx_enabled)) { \
+ gen_exception(ctx, POWERPC_EXCP_VSXU); \
+ return; \
+ } \
+ opc = tcg_const_i32(ctx->opcode); \
+ xb = gen_vsr_ptr(xB(ctx->opcode)); \
+ gen_helper_##name(cpu_env, opc, xb); \
+ tcg_temp_free_i32(opc); \
+ tcg_temp_free_ptr(xb); \
+}
+
+#define GEN_VSX_HELPER_R3(name, op1, op2, inval, type) \
+static void gen_##name(DisasContext *ctx) \
+{ \
+ TCGv_i32 opc; \
+ TCGv_ptr xt, xa, xb; \
+ if (unlikely(!ctx->vsx_enabled)) { \
+ gen_exception(ctx, POWERPC_EXCP_VSXU); \
+ return; \
+ } \
+ opc = tcg_const_i32(ctx->opcode); \
+ xt = gen_vsr_ptr(rD(ctx->opcode) + 32); \
+ xa = gen_vsr_ptr(rA(ctx->opcode) + 32); \
+ xb = gen_vsr_ptr(rB(ctx->opcode) + 32); \
+ gen_helper_##name(cpu_env, opc, xt, xa, xb); \
+ tcg_temp_free_i32(opc); \
+ tcg_temp_free_ptr(xt); \
+ tcg_temp_free_ptr(xa); \
+ tcg_temp_free_ptr(xb); \
+}
+
+#define GEN_VSX_HELPER_R2(name, op1, op2, inval, type) \
+static void gen_##name(DisasContext *ctx) \
+{ \
+ TCGv_i32 opc; \
+ TCGv_ptr xt, xb; \
+ if (unlikely(!ctx->vsx_enabled)) { \
+ gen_exception(ctx, POWERPC_EXCP_VSXU); \
+ return; \
+ } \
+ opc = tcg_const_i32(ctx->opcode); \
+ xt = gen_vsr_ptr(rD(ctx->opcode) + 32); \
+ xb = gen_vsr_ptr(rB(ctx->opcode) + 32); \
+ gen_helper_##name(cpu_env, opc, xt, xb); \
+ tcg_temp_free_i32(opc); \
+ tcg_temp_free_ptr(xt); \
+ tcg_temp_free_ptr(xb); \
+}
+
+#define GEN_VSX_HELPER_R2_AB(name, op1, op2, inval, type) \
+static void gen_##name(DisasContext *ctx) \
+{ \
+ TCGv_i32 opc; \
+ TCGv_ptr xa, xb; \
+ if (unlikely(!ctx->vsx_enabled)) { \
+ gen_exception(ctx, POWERPC_EXCP_VSXU); \
+ return; \
+ } \
+ opc = tcg_const_i32(ctx->opcode); \
+ xa = gen_vsr_ptr(rA(ctx->opcode) + 32); \
+ xb = gen_vsr_ptr(rB(ctx->opcode) + 32); \
+ gen_helper_##name(cpu_env, opc, xa, xb); \
+ tcg_temp_free_i32(opc); \
+ tcg_temp_free_ptr(xa); \
+ tcg_temp_free_ptr(xb); \
+}
+
#define GEN_VSX_HELPER_XT_XB_ENV(name, op1, op2, inval, type) \
static void gen_##name(DisasContext *ctx) \
{ \
tcg_temp_free_i64(t1); \
}
-GEN_VSX_HELPER_2(xsadddp, 0x00, 0x04, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xsaddqp, 0x04, 0x00, 0, PPC2_ISA300)
-GEN_VSX_HELPER_2(xssubdp, 0x00, 0x05, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xsmuldp, 0x00, 0x06, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xsmulqp, 0x04, 0x01, 0, PPC2_ISA300)
-GEN_VSX_HELPER_2(xsdivdp, 0x00, 0x07, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xsdivqp, 0x04, 0x11, 0, PPC2_ISA300)
-GEN_VSX_HELPER_2(xsredp, 0x14, 0x05, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xssqrtdp, 0x16, 0x04, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xsrsqrtedp, 0x14, 0x04, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xstdivdp, 0x14, 0x07, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xstsqrtdp, 0x14, 0x06, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xsmaddadp, 0x04, 0x04, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xsmaddmdp, 0x04, 0x05, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xsmsubadp, 0x04, 0x06, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xsmsubmdp, 0x04, 0x07, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xsnmaddadp, 0x04, 0x14, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xsnmaddmdp, 0x04, 0x15, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xsnmsubadp, 0x04, 0x16, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xsnmsubmdp, 0x04, 0x17, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xscmpeqdp, 0x0C, 0x00, 0, PPC2_ISA300)
-GEN_VSX_HELPER_2(xscmpgtdp, 0x0C, 0x01, 0, PPC2_ISA300)
-GEN_VSX_HELPER_2(xscmpgedp, 0x0C, 0x02, 0, PPC2_ISA300)
-GEN_VSX_HELPER_2(xscmpnedp, 0x0C, 0x03, 0, PPC2_ISA300)
-GEN_VSX_HELPER_2(xscmpexpdp, 0x0C, 0x07, 0, PPC2_ISA300)
-GEN_VSX_HELPER_2(xscmpexpqp, 0x04, 0x05, 0, PPC2_ISA300)
-GEN_VSX_HELPER_2(xscmpodp, 0x0C, 0x05, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xscmpudp, 0x0C, 0x04, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xscmpoqp, 0x04, 0x04, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xscmpuqp, 0x04, 0x14, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xsmaxdp, 0x00, 0x14, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xsmindp, 0x00, 0x15, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xsmaxcdp, 0x00, 0x10, 0, PPC2_ISA300)
-GEN_VSX_HELPER_2(xsmincdp, 0x00, 0x11, 0, PPC2_ISA300)
-GEN_VSX_HELPER_2(xsmaxjdp, 0x00, 0x12, 0, PPC2_ISA300)
-GEN_VSX_HELPER_2(xsminjdp, 0x00, 0x12, 0, PPC2_ISA300)
-GEN_VSX_HELPER_2(xscvdphp, 0x16, 0x15, 0x11, PPC2_ISA300)
-GEN_VSX_HELPER_2(xscvdpsp, 0x12, 0x10, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xscvdpqp, 0x04, 0x1A, 0x16, PPC2_ISA300)
+GEN_VSX_HELPER_X3(xsadddp, 0x00, 0x04, 0, PPC2_VSX)
+GEN_VSX_HELPER_R3(xsaddqp, 0x04, 0x00, 0, PPC2_ISA300)
+GEN_VSX_HELPER_X3(xssubdp, 0x00, 0x05, 0, PPC2_VSX)
+GEN_VSX_HELPER_X3(xsmuldp, 0x00, 0x06, 0, PPC2_VSX)
+GEN_VSX_HELPER_R3(xsmulqp, 0x04, 0x01, 0, PPC2_ISA300)
+GEN_VSX_HELPER_X3(xsdivdp, 0x00, 0x07, 0, PPC2_VSX)
+GEN_VSX_HELPER_R3(xsdivqp, 0x04, 0x11, 0, PPC2_ISA300)
+GEN_VSX_HELPER_X2(xsredp, 0x14, 0x05, 0, PPC2_VSX)
+GEN_VSX_HELPER_X2(xssqrtdp, 0x16, 0x04, 0, PPC2_VSX)
+GEN_VSX_HELPER_X2(xsrsqrtedp, 0x14, 0x04, 0, PPC2_VSX)
+GEN_VSX_HELPER_X2_AB(xstdivdp, 0x14, 0x07, 0, PPC2_VSX)
+GEN_VSX_HELPER_X1(xstsqrtdp, 0x14, 0x06, 0, PPC2_VSX)
+GEN_VSX_HELPER_X3(xscmpeqdp, 0x0C, 0x00, 0, PPC2_ISA300)
+GEN_VSX_HELPER_X3(xscmpgtdp, 0x0C, 0x01, 0, PPC2_ISA300)
+GEN_VSX_HELPER_X3(xscmpgedp, 0x0C, 0x02, 0, PPC2_ISA300)
+GEN_VSX_HELPER_X3(xscmpnedp, 0x0C, 0x03, 0, PPC2_ISA300)
+GEN_VSX_HELPER_X2_AB(xscmpexpdp, 0x0C, 0x07, 0, PPC2_ISA300)
+GEN_VSX_HELPER_R2_AB(xscmpexpqp, 0x04, 0x05, 0, PPC2_ISA300)
+GEN_VSX_HELPER_X2_AB(xscmpodp, 0x0C, 0x05, 0, PPC2_VSX)
+GEN_VSX_HELPER_X2_AB(xscmpudp, 0x0C, 0x04, 0, PPC2_VSX)
+GEN_VSX_HELPER_R2_AB(xscmpoqp, 0x04, 0x04, 0, PPC2_VSX)
+GEN_VSX_HELPER_R2_AB(xscmpuqp, 0x04, 0x14, 0, PPC2_VSX)
+GEN_VSX_HELPER_X3(xsmaxdp, 0x00, 0x14, 0, PPC2_VSX)
+GEN_VSX_HELPER_X3(xsmindp, 0x00, 0x15, 0, PPC2_VSX)
+GEN_VSX_HELPER_R3(xsmaxcdp, 0x00, 0x10, 0, PPC2_ISA300)
+GEN_VSX_HELPER_R3(xsmincdp, 0x00, 0x11, 0, PPC2_ISA300)
+GEN_VSX_HELPER_R3(xsmaxjdp, 0x00, 0x12, 0, PPC2_ISA300)
+GEN_VSX_HELPER_R3(xsminjdp, 0x00, 0x12, 0, PPC2_ISA300)
+GEN_VSX_HELPER_X2(xscvdphp, 0x16, 0x15, 0x11, PPC2_ISA300)
+GEN_VSX_HELPER_X2(xscvdpsp, 0x12, 0x10, 0, PPC2_VSX)
+GEN_VSX_HELPER_R2(xscvdpqp, 0x04, 0x1A, 0x16, PPC2_ISA300)
GEN_VSX_HELPER_XT_XB_ENV(xscvdpspn, 0x16, 0x10, 0, PPC2_VSX207)
-GEN_VSX_HELPER_2(xscvqpdp, 0x04, 0x1A, 0x14, PPC2_ISA300)
-GEN_VSX_HELPER_2(xscvqpsdz, 0x04, 0x1A, 0x19, PPC2_ISA300)
-GEN_VSX_HELPER_2(xscvqpswz, 0x04, 0x1A, 0x09, PPC2_ISA300)
-GEN_VSX_HELPER_2(xscvqpudz, 0x04, 0x1A, 0x11, PPC2_ISA300)
-GEN_VSX_HELPER_2(xscvqpuwz, 0x04, 0x1A, 0x01, PPC2_ISA300)
-GEN_VSX_HELPER_2(xscvhpdp, 0x16, 0x15, 0x10, PPC2_ISA300)
-GEN_VSX_HELPER_2(xscvsdqp, 0x04, 0x1A, 0x0A, PPC2_ISA300)
-GEN_VSX_HELPER_2(xscvspdp, 0x12, 0x14, 0, PPC2_VSX)
+GEN_VSX_HELPER_R2(xscvqpsdz, 0x04, 0x1A, 0x19, PPC2_ISA300)
+GEN_VSX_HELPER_R2(xscvqpswz, 0x04, 0x1A, 0x09, PPC2_ISA300)
+GEN_VSX_HELPER_R2(xscvqpudz, 0x04, 0x1A, 0x11, PPC2_ISA300)
+GEN_VSX_HELPER_R2(xscvqpuwz, 0x04, 0x1A, 0x01, PPC2_ISA300)
+GEN_VSX_HELPER_X2(xscvhpdp, 0x16, 0x15, 0x10, PPC2_ISA300)
+GEN_VSX_HELPER_R2(xscvsdqp, 0x04, 0x1A, 0x0A, PPC2_ISA300)
+GEN_VSX_HELPER_X2(xscvspdp, 0x12, 0x14, 0, PPC2_VSX)
GEN_VSX_HELPER_XT_XB_ENV(xscvspdpn, 0x16, 0x14, 0, PPC2_VSX207)
-GEN_VSX_HELPER_2(xscvdpsxds, 0x10, 0x15, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xscvdpsxws, 0x10, 0x05, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xscvdpuxds, 0x10, 0x14, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xscvdpuxws, 0x10, 0x04, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xscvsxddp, 0x10, 0x17, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xscvudqp, 0x04, 0x1A, 0x02, PPC2_ISA300)
-GEN_VSX_HELPER_2(xscvuxddp, 0x10, 0x16, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xsrdpi, 0x12, 0x04, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xsrdpic, 0x16, 0x06, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xsrdpim, 0x12, 0x07, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xsrdpip, 0x12, 0x06, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xsrdpiz, 0x12, 0x05, 0, PPC2_VSX)
+GEN_VSX_HELPER_X2(xscvdpsxds, 0x10, 0x15, 0, PPC2_VSX)
+GEN_VSX_HELPER_X2(xscvdpsxws, 0x10, 0x05, 0, PPC2_VSX)
+GEN_VSX_HELPER_X2(xscvdpuxds, 0x10, 0x14, 0, PPC2_VSX)
+GEN_VSX_HELPER_X2(xscvdpuxws, 0x10, 0x04, 0, PPC2_VSX)
+GEN_VSX_HELPER_X2(xscvsxddp, 0x10, 0x17, 0, PPC2_VSX)
+GEN_VSX_HELPER_R2(xscvudqp, 0x04, 0x1A, 0x02, PPC2_ISA300)
+GEN_VSX_HELPER_X2(xscvuxddp, 0x10, 0x16, 0, PPC2_VSX)
+GEN_VSX_HELPER_X2(xsrdpi, 0x12, 0x04, 0, PPC2_VSX)
+GEN_VSX_HELPER_X2(xsrdpic, 0x16, 0x06, 0, PPC2_VSX)
+GEN_VSX_HELPER_X2(xsrdpim, 0x12, 0x07, 0, PPC2_VSX)
+GEN_VSX_HELPER_X2(xsrdpip, 0x12, 0x06, 0, PPC2_VSX)
+GEN_VSX_HELPER_X2(xsrdpiz, 0x12, 0x05, 0, PPC2_VSX)
GEN_VSX_HELPER_XT_XB_ENV(xsrsp, 0x12, 0x11, 0, PPC2_VSX207)
-
-GEN_VSX_HELPER_2(xsrqpi, 0x05, 0x00, 0, PPC2_ISA300)
-GEN_VSX_HELPER_2(xsrqpxp, 0x05, 0x01, 0, PPC2_ISA300)
-GEN_VSX_HELPER_2(xssqrtqp, 0x04, 0x19, 0x1B, PPC2_ISA300)
-GEN_VSX_HELPER_2(xssubqp, 0x04, 0x10, 0, PPC2_ISA300)
-
-GEN_VSX_HELPER_2(xsaddsp, 0x00, 0x00, 0, PPC2_VSX207)
-GEN_VSX_HELPER_2(xssubsp, 0x00, 0x01, 0, PPC2_VSX207)
-GEN_VSX_HELPER_2(xsmulsp, 0x00, 0x02, 0, PPC2_VSX207)
-GEN_VSX_HELPER_2(xsdivsp, 0x00, 0x03, 0, PPC2_VSX207)
-GEN_VSX_HELPER_2(xsresp, 0x14, 0x01, 0, PPC2_VSX207)
-GEN_VSX_HELPER_2(xssqrtsp, 0x16, 0x00, 0, PPC2_VSX207)
-GEN_VSX_HELPER_2(xsrsqrtesp, 0x14, 0x00, 0, PPC2_VSX207)
-GEN_VSX_HELPER_2(xsmaddasp, 0x04, 0x00, 0, PPC2_VSX207)
-GEN_VSX_HELPER_2(xsmaddmsp, 0x04, 0x01, 0, PPC2_VSX207)
-GEN_VSX_HELPER_2(xsmsubasp, 0x04, 0x02, 0, PPC2_VSX207)
-GEN_VSX_HELPER_2(xsmsubmsp, 0x04, 0x03, 0, PPC2_VSX207)
-GEN_VSX_HELPER_2(xsnmaddasp, 0x04, 0x10, 0, PPC2_VSX207)
-GEN_VSX_HELPER_2(xsnmaddmsp, 0x04, 0x11, 0, PPC2_VSX207)
-GEN_VSX_HELPER_2(xsnmsubasp, 0x04, 0x12, 0, PPC2_VSX207)
-GEN_VSX_HELPER_2(xsnmsubmsp, 0x04, 0x13, 0, PPC2_VSX207)
-GEN_VSX_HELPER_2(xscvsxdsp, 0x10, 0x13, 0, PPC2_VSX207)
-GEN_VSX_HELPER_2(xscvuxdsp, 0x10, 0x12, 0, PPC2_VSX207)
-GEN_VSX_HELPER_2(xststdcsp, 0x14, 0x12, 0, PPC2_ISA300)
+GEN_VSX_HELPER_R2(xsrqpi, 0x05, 0x00, 0, PPC2_ISA300)
+GEN_VSX_HELPER_R2(xsrqpxp, 0x05, 0x01, 0, PPC2_ISA300)
+GEN_VSX_HELPER_R2(xssqrtqp, 0x04, 0x19, 0x1B, PPC2_ISA300)
+GEN_VSX_HELPER_R3(xssubqp, 0x04, 0x10, 0, PPC2_ISA300)
+GEN_VSX_HELPER_X3(xsaddsp, 0x00, 0x00, 0, PPC2_VSX207)
+GEN_VSX_HELPER_X3(xssubsp, 0x00, 0x01, 0, PPC2_VSX207)
+GEN_VSX_HELPER_X3(xsmulsp, 0x00, 0x02, 0, PPC2_VSX207)
+GEN_VSX_HELPER_X3(xsdivsp, 0x00, 0x03, 0, PPC2_VSX207)
+GEN_VSX_HELPER_X2(xsresp, 0x14, 0x01, 0, PPC2_VSX207)
+GEN_VSX_HELPER_X2(xssqrtsp, 0x16, 0x00, 0, PPC2_VSX207)
+GEN_VSX_HELPER_X2(xsrsqrtesp, 0x14, 0x00, 0, PPC2_VSX207)
+GEN_VSX_HELPER_X2(xscvsxdsp, 0x10, 0x13, 0, PPC2_VSX207)
+GEN_VSX_HELPER_X2(xscvuxdsp, 0x10, 0x12, 0, PPC2_VSX207)
+GEN_VSX_HELPER_X1(xststdcsp, 0x14, 0x12, 0, PPC2_ISA300)
GEN_VSX_HELPER_2(xststdcdp, 0x14, 0x16, 0, PPC2_ISA300)
GEN_VSX_HELPER_2(xststdcqp, 0x04, 0x16, 0, PPC2_ISA300)
-GEN_VSX_HELPER_2(xvadddp, 0x00, 0x0C, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xvsubdp, 0x00, 0x0D, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xvmuldp, 0x00, 0x0E, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xvdivdp, 0x00, 0x0F, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xvredp, 0x14, 0x0D, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xvsqrtdp, 0x16, 0x0C, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xvrsqrtedp, 0x14, 0x0C, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xvtdivdp, 0x14, 0x0F, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xvtsqrtdp, 0x14, 0x0E, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xvmaddadp, 0x04, 0x0C, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xvmaddmdp, 0x04, 0x0D, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xvmsubadp, 0x04, 0x0E, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xvmsubmdp, 0x04, 0x0F, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xvnmaddadp, 0x04, 0x1C, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xvnmaddmdp, 0x04, 0x1D, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xvnmsubadp, 0x04, 0x1E, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xvnmsubmdp, 0x04, 0x1F, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xvmaxdp, 0x00, 0x1C, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xvmindp, 0x00, 0x1D, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xvcmpeqdp, 0x0C, 0x0C, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xvcmpgtdp, 0x0C, 0x0D, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xvcmpgedp, 0x0C, 0x0E, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xvcmpnedp, 0x0C, 0x0F, 0, PPC2_ISA300)
-GEN_VSX_HELPER_2(xvcvdpsp, 0x12, 0x18, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xvcvdpsxds, 0x10, 0x1D, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xvcvdpsxws, 0x10, 0x0D, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xvcvdpuxds, 0x10, 0x1C, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xvcvdpuxws, 0x10, 0x0C, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xvcvsxddp, 0x10, 0x1F, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xvcvuxddp, 0x10, 0x1E, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xvcvsxwdp, 0x10, 0x0F, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xvcvuxwdp, 0x10, 0x0E, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xvrdpi, 0x12, 0x0C, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xvrdpic, 0x16, 0x0E, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xvrdpim, 0x12, 0x0F, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xvrdpip, 0x12, 0x0E, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xvrdpiz, 0x12, 0x0D, 0, PPC2_VSX)
-
-GEN_VSX_HELPER_2(xvaddsp, 0x00, 0x08, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xvsubsp, 0x00, 0x09, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xvmulsp, 0x00, 0x0A, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xvdivsp, 0x00, 0x0B, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xvresp, 0x14, 0x09, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xvsqrtsp, 0x16, 0x08, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xvrsqrtesp, 0x14, 0x08, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xvtdivsp, 0x14, 0x0B, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xvtsqrtsp, 0x14, 0x0A, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xvmaddasp, 0x04, 0x08, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xvmaddmsp, 0x04, 0x09, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xvmsubasp, 0x04, 0x0A, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xvmsubmsp, 0x04, 0x0B, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xvnmaddasp, 0x04, 0x18, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xvnmaddmsp, 0x04, 0x19, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xvnmsubasp, 0x04, 0x1A, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xvnmsubmsp, 0x04, 0x1B, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xvmaxsp, 0x00, 0x18, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xvminsp, 0x00, 0x19, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xvcmpeqsp, 0x0C, 0x08, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xvcmpgtsp, 0x0C, 0x09, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xvcmpgesp, 0x0C, 0x0A, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xvcmpnesp, 0x0C, 0x0B, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xvcvspdp, 0x12, 0x1C, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xvcvhpsp, 0x16, 0x1D, 0x18, PPC2_ISA300)
-GEN_VSX_HELPER_2(xvcvsphp, 0x16, 0x1D, 0x19, PPC2_ISA300)
-GEN_VSX_HELPER_2(xvcvspsxds, 0x10, 0x19, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xvcvspsxws, 0x10, 0x09, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xvcvspuxds, 0x10, 0x18, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xvcvspuxws, 0x10, 0x08, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xvcvsxdsp, 0x10, 0x1B, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xvcvuxdsp, 0x10, 0x1A, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xvcvsxwsp, 0x10, 0x0B, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xvcvuxwsp, 0x10, 0x0A, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xvrspi, 0x12, 0x08, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xvrspic, 0x16, 0x0A, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xvrspim, 0x12, 0x0B, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xvrspip, 0x12, 0x0A, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xvrspiz, 0x12, 0x09, 0, PPC2_VSX)
+GEN_VSX_HELPER_X3(xvadddp, 0x00, 0x0C, 0, PPC2_VSX)
+GEN_VSX_HELPER_X3(xvsubdp, 0x00, 0x0D, 0, PPC2_VSX)
+GEN_VSX_HELPER_X3(xvmuldp, 0x00, 0x0E, 0, PPC2_VSX)
+GEN_VSX_HELPER_X3(xvdivdp, 0x00, 0x0F, 0, PPC2_VSX)
+GEN_VSX_HELPER_X2(xvredp, 0x14, 0x0D, 0, PPC2_VSX)
+GEN_VSX_HELPER_X2(xvsqrtdp, 0x16, 0x0C, 0, PPC2_VSX)
+GEN_VSX_HELPER_X2(xvrsqrtedp, 0x14, 0x0C, 0, PPC2_VSX)
+GEN_VSX_HELPER_X2_AB(xvtdivdp, 0x14, 0x0F, 0, PPC2_VSX)
+GEN_VSX_HELPER_X1(xvtsqrtdp, 0x14, 0x0E, 0, PPC2_VSX)
+GEN_VSX_HELPER_X3(xvmaxdp, 0x00, 0x1C, 0, PPC2_VSX)
+GEN_VSX_HELPER_X3(xvmindp, 0x00, 0x1D, 0, PPC2_VSX)
+GEN_VSX_HELPER_X2(xvcvdpsp, 0x12, 0x18, 0, PPC2_VSX)
+GEN_VSX_HELPER_X2(xvcvdpsxds, 0x10, 0x1D, 0, PPC2_VSX)
+GEN_VSX_HELPER_X2(xvcvdpsxws, 0x10, 0x0D, 0, PPC2_VSX)
+GEN_VSX_HELPER_X2(xvcvdpuxds, 0x10, 0x1C, 0, PPC2_VSX)
+GEN_VSX_HELPER_X2(xvcvdpuxws, 0x10, 0x0C, 0, PPC2_VSX)
+GEN_VSX_HELPER_X2(xvcvsxddp, 0x10, 0x1F, 0, PPC2_VSX)
+GEN_VSX_HELPER_X2(xvcvuxddp, 0x10, 0x1E, 0, PPC2_VSX)
+GEN_VSX_HELPER_X2(xvcvsxwdp, 0x10, 0x0F, 0, PPC2_VSX)
+GEN_VSX_HELPER_X2(xvcvuxwdp, 0x10, 0x0E, 0, PPC2_VSX)
+GEN_VSX_HELPER_X2(xvrdpi, 0x12, 0x0C, 0, PPC2_VSX)
+GEN_VSX_HELPER_X2(xvrdpic, 0x16, 0x0E, 0, PPC2_VSX)
+GEN_VSX_HELPER_X2(xvrdpim, 0x12, 0x0F, 0, PPC2_VSX)
+GEN_VSX_HELPER_X2(xvrdpip, 0x12, 0x0E, 0, PPC2_VSX)
+GEN_VSX_HELPER_X2(xvrdpiz, 0x12, 0x0D, 0, PPC2_VSX)
+
+GEN_VSX_HELPER_X3(xvaddsp, 0x00, 0x08, 0, PPC2_VSX)
+GEN_VSX_HELPER_X3(xvsubsp, 0x00, 0x09, 0, PPC2_VSX)
+GEN_VSX_HELPER_X3(xvmulsp, 0x00, 0x0A, 0, PPC2_VSX)
+GEN_VSX_HELPER_X3(xvdivsp, 0x00, 0x0B, 0, PPC2_VSX)
+GEN_VSX_HELPER_X2(xvresp, 0x14, 0x09, 0, PPC2_VSX)
+GEN_VSX_HELPER_X2(xvsqrtsp, 0x16, 0x08, 0, PPC2_VSX)
+GEN_VSX_HELPER_X2(xvrsqrtesp, 0x14, 0x08, 0, PPC2_VSX)
+GEN_VSX_HELPER_X2_AB(xvtdivsp, 0x14, 0x0B, 0, PPC2_VSX)
+GEN_VSX_HELPER_X1(xvtsqrtsp, 0x14, 0x0A, 0, PPC2_VSX)
+GEN_VSX_HELPER_X3(xvmaxsp, 0x00, 0x18, 0, PPC2_VSX)
+GEN_VSX_HELPER_X3(xvminsp, 0x00, 0x19, 0, PPC2_VSX)
+GEN_VSX_HELPER_X2(xvcvspdp, 0x12, 0x1C, 0, PPC2_VSX)
+GEN_VSX_HELPER_X2(xvcvhpsp, 0x16, 0x1D, 0x18, PPC2_ISA300)
+GEN_VSX_HELPER_X2(xvcvsphp, 0x16, 0x1D, 0x19, PPC2_ISA300)
+GEN_VSX_HELPER_X2(xvcvspsxds, 0x10, 0x19, 0, PPC2_VSX)
+GEN_VSX_HELPER_X2(xvcvspsxws, 0x10, 0x09, 0, PPC2_VSX)
+GEN_VSX_HELPER_X2(xvcvspuxds, 0x10, 0x18, 0, PPC2_VSX)
+GEN_VSX_HELPER_X2(xvcvspuxws, 0x10, 0x08, 0, PPC2_VSX)
+GEN_VSX_HELPER_X2(xvcvsxdsp, 0x10, 0x1B, 0, PPC2_VSX)
+GEN_VSX_HELPER_X2(xvcvuxdsp, 0x10, 0x1A, 0, PPC2_VSX)
+GEN_VSX_HELPER_X2(xvcvsxwsp, 0x10, 0x0B, 0, PPC2_VSX)
+GEN_VSX_HELPER_X2(xvcvuxwsp, 0x10, 0x0A, 0, PPC2_VSX)
+GEN_VSX_HELPER_X2(xvrspi, 0x12, 0x08, 0, PPC2_VSX)
+GEN_VSX_HELPER_X2(xvrspic, 0x16, 0x0A, 0, PPC2_VSX)
+GEN_VSX_HELPER_X2(xvrspim, 0x12, 0x0B, 0, PPC2_VSX)
+GEN_VSX_HELPER_X2(xvrspip, 0x12, 0x0A, 0, PPC2_VSX)
+GEN_VSX_HELPER_X2(xvrspiz, 0x12, 0x09, 0, PPC2_VSX)
GEN_VSX_HELPER_2(xvtstdcsp, 0x14, 0x1A, 0, PPC2_VSX)
GEN_VSX_HELPER_2(xvtstdcdp, 0x14, 0x1E, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xxperm, 0x08, 0x03, 0, PPC2_ISA300)
-GEN_VSX_HELPER_2(xxpermr, 0x08, 0x07, 0, PPC2_ISA300)
+GEN_VSX_HELPER_X3(xxperm, 0x08, 0x03, 0, PPC2_ISA300)
+GEN_VSX_HELPER_X3(xxpermr, 0x08, 0x07, 0, PPC2_ISA300)
+
+#define GEN_VSX_HELPER_VSX_MADD(name, op1, aop, mop, inval, type) \
+static void gen_##name(DisasContext *ctx) \
+{ \
+ TCGv_ptr xt, xa, b, c; \
+ if (unlikely(!ctx->vsx_enabled)) { \
+ gen_exception(ctx, POWERPC_EXCP_VSXU); \
+ return; \
+ } \
+ xt = gen_vsr_ptr(xT(ctx->opcode)); \
+ xa = gen_vsr_ptr(xA(ctx->opcode)); \
+ if (ctx->opcode & PPC_BIT(25)) { \
+ /* \
+ * AxT + B \
+ */ \
+ b = gen_vsr_ptr(xT(ctx->opcode)); \
+ c = gen_vsr_ptr(xB(ctx->opcode)); \
+ } else { \
+ /* \
+ * AxB + T \
+ */ \
+ b = gen_vsr_ptr(xB(ctx->opcode)); \
+ c = gen_vsr_ptr(xT(ctx->opcode)); \
+ } \
+ gen_helper_##name(cpu_env, xt, xa, b, c); \
+ tcg_temp_free_ptr(xt); \
+ tcg_temp_free_ptr(xa); \
+ tcg_temp_free_ptr(b); \
+ tcg_temp_free_ptr(c); \
+}
+
+GEN_VSX_HELPER_VSX_MADD(xsmadddp, 0x04, 0x04, 0x05, 0, PPC2_VSX)
+GEN_VSX_HELPER_VSX_MADD(xsmsubdp, 0x04, 0x06, 0x07, 0, PPC2_VSX)
+GEN_VSX_HELPER_VSX_MADD(xsnmadddp, 0x04, 0x14, 0x15, 0, PPC2_VSX)
+GEN_VSX_HELPER_VSX_MADD(xsnmsubdp, 0x04, 0x16, 0x17, 0, PPC2_VSX)
+GEN_VSX_HELPER_VSX_MADD(xsmaddsp, 0x04, 0x00, 0x01, 0, PPC2_VSX207)
+GEN_VSX_HELPER_VSX_MADD(xsmsubsp, 0x04, 0x02, 0x03, 0, PPC2_VSX207)
+GEN_VSX_HELPER_VSX_MADD(xsnmaddsp, 0x04, 0x10, 0x11, 0, PPC2_VSX207)
+GEN_VSX_HELPER_VSX_MADD(xsnmsubsp, 0x04, 0x12, 0x13, 0, PPC2_VSX207)
+GEN_VSX_HELPER_VSX_MADD(xvmadddp, 0x04, 0x0C, 0x0D, 0, PPC2_VSX)
+GEN_VSX_HELPER_VSX_MADD(xvmsubdp, 0x04, 0x0E, 0x0F, 0, PPC2_VSX)
+GEN_VSX_HELPER_VSX_MADD(xvnmadddp, 0x04, 0x1C, 0x1D, 0, PPC2_VSX)
+GEN_VSX_HELPER_VSX_MADD(xvnmsubdp, 0x04, 0x1E, 0x1F, 0, PPC2_VSX)
+GEN_VSX_HELPER_VSX_MADD(xvmaddsp, 0x04, 0x08, 0x09, 0, PPC2_VSX)
+GEN_VSX_HELPER_VSX_MADD(xvmsubsp, 0x04, 0x0A, 0x0B, 0, PPC2_VSX)
+GEN_VSX_HELPER_VSX_MADD(xvnmaddsp, 0x04, 0x18, 0x19, 0, PPC2_VSX)
+GEN_VSX_HELPER_VSX_MADD(xvnmsubsp, 0x04, 0x1A, 0x1B, 0, PPC2_VSX)
static void gen_xxbrd(DisasContext *ctx)
{
#define VSX_EXTRACT_INSERT(name) \
static void gen_##name(DisasContext *ctx) \
{ \
- TCGv xt, xb; \
+ TCGv_ptr xt, xb; \
TCGv_i32 t0; \
TCGv_i64 t1; \
uint8_t uimm = UIMM4(ctx->opcode); \
gen_exception(ctx, POWERPC_EXCP_VSXU); \
return; \
} \
- xt = tcg_const_tl(xT(ctx->opcode)); \
- xb = tcg_const_tl(xB(ctx->opcode)); \
+ xt = gen_vsr_ptr(xT(ctx->opcode)); \
+ xb = gen_vsr_ptr(xB(ctx->opcode)); \
t0 = tcg_temp_new_i32(); \
t1 = tcg_temp_new_i64(); \
/* \
} \
tcg_gen_movi_i32(t0, uimm); \
gen_helper_##name(cpu_env, xt, xb, t0); \
- tcg_temp_free(xb); \
- tcg_temp_free(xt); \
+ tcg_temp_free_ptr(xb); \
+ tcg_temp_free_ptr(xt); \
tcg_temp_free_i32(t0); \
tcg_temp_free_i64(t1); \
}
tcg_temp_free_i64(xbl);
}
-GEN_VSX_HELPER_2(xvxsigsp, 0x00, 0x04, 0, PPC2_ISA300)
+GEN_VSX_HELPER_X2(xvxsigsp, 0x00, 0x04, 0, PPC2_ISA300)
static void gen_xvxsigdp(DisasContext *ctx)
{
GEN_HANDLER2_E(name, #name, 0x3C, opc2 | 2, opc3, 0, PPC_NONE, fl2), \
GEN_HANDLER2_E(name, #name, 0x3C, opc2 | 3, opc3, 0, PPC_NONE, fl2)
+#define GEN_XX3FORM_NAME(name, opcname, opc2, opc3, fl2) \
+GEN_HANDLER2_E(name, opcname, 0x3C, opc2 | 0, opc3, 0, PPC_NONE, fl2), \
+GEN_HANDLER2_E(name, opcname, 0x3C, opc2 | 1, opc3, 0, PPC_NONE, fl2), \
+GEN_HANDLER2_E(name, opcname, 0x3C, opc2 | 2, opc3, 0, PPC_NONE, fl2), \
+GEN_HANDLER2_E(name, opcname, 0x3C, opc2 | 3, opc3, 0, PPC_NONE, fl2)
+
#define GEN_XX2IFORM(name, opc2, opc3, fl2) \
GEN_HANDLER2_E(name, #name, 0x3C, opc2 | 0, opc3, 1, PPC_NONE, fl2), \
GEN_HANDLER2_E(name, #name, 0x3C, opc2 | 1, opc3, 1, PPC_NONE, fl2), \
GEN_XX2FORM(xsrsqrtedp, 0x14, 0x04, PPC2_VSX),
GEN_XX3FORM(xstdivdp, 0x14, 0x07, PPC2_VSX),
GEN_XX2FORM(xstsqrtdp, 0x14, 0x06, PPC2_VSX),
-GEN_XX3FORM(xsmaddadp, 0x04, 0x04, PPC2_VSX),
-GEN_XX3FORM(xsmaddmdp, 0x04, 0x05, PPC2_VSX),
-GEN_XX3FORM(xsmsubadp, 0x04, 0x06, PPC2_VSX),
-GEN_XX3FORM(xsmsubmdp, 0x04, 0x07, PPC2_VSX),
-GEN_XX3FORM(xsnmaddadp, 0x04, 0x14, PPC2_VSX),
-GEN_XX3FORM(xsnmaddmdp, 0x04, 0x15, PPC2_VSX),
-GEN_XX3FORM(xsnmsubadp, 0x04, 0x16, PPC2_VSX),
-GEN_XX3FORM(xsnmsubmdp, 0x04, 0x17, PPC2_VSX),
+GEN_XX3FORM_NAME(xsmadddp, "xsmaddadp", 0x04, 0x04, PPC2_VSX),
+GEN_XX3FORM_NAME(xsmadddp, "xsmaddmdp", 0x04, 0x05, PPC2_VSX),
+GEN_XX3FORM_NAME(xsmsubdp, "xsmsubadp", 0x04, 0x06, PPC2_VSX),
+GEN_XX3FORM_NAME(xsmsubdp, "xsmsubmdp", 0x04, 0x07, PPC2_VSX),
+GEN_XX3FORM_NAME(xsnmadddp, "xsnmaddadp", 0x04, 0x14, PPC2_VSX),
+GEN_XX3FORM_NAME(xsnmadddp, "xsnmaddmdp", 0x04, 0x15, PPC2_VSX),
+GEN_XX3FORM_NAME(xsnmsubdp, "xsnmsubadp", 0x04, 0x16, PPC2_VSX),
+GEN_XX3FORM_NAME(xsnmsubdp, "xsnmsubmdp", 0x04, 0x17, PPC2_VSX),
GEN_XX3FORM(xscmpeqdp, 0x0C, 0x00, PPC2_ISA300),
GEN_XX3FORM(xscmpgtdp, 0x0C, 0x01, PPC2_ISA300),
GEN_XX3FORM(xscmpgedp, 0x0C, 0x02, PPC2_ISA300),
GEN_XX2FORM(xsrsp, 0x12, 0x11, PPC2_VSX207),
GEN_XX2FORM(xssqrtsp, 0x16, 0x00, PPC2_VSX207),
GEN_XX2FORM(xsrsqrtesp, 0x14, 0x00, PPC2_VSX207),
-GEN_XX3FORM(xsmaddasp, 0x04, 0x00, PPC2_VSX207),
-GEN_XX3FORM(xsmaddmsp, 0x04, 0x01, PPC2_VSX207),
-GEN_XX3FORM(xsmsubasp, 0x04, 0x02, PPC2_VSX207),
-GEN_XX3FORM(xsmsubmsp, 0x04, 0x03, PPC2_VSX207),
-GEN_XX3FORM(xsnmaddasp, 0x04, 0x10, PPC2_VSX207),
-GEN_XX3FORM(xsnmaddmsp, 0x04, 0x11, PPC2_VSX207),
-GEN_XX3FORM(xsnmsubasp, 0x04, 0x12, PPC2_VSX207),
-GEN_XX3FORM(xsnmsubmsp, 0x04, 0x13, PPC2_VSX207),
+GEN_XX3FORM_NAME(xsmaddsp, "xsmaddasp", 0x04, 0x00, PPC2_VSX207),
+GEN_XX3FORM_NAME(xsmaddsp, "xsmaddmsp", 0x04, 0x01, PPC2_VSX207),
+GEN_XX3FORM_NAME(xsmsubsp, "xsmsubasp", 0x04, 0x02, PPC2_VSX207),
+GEN_XX3FORM_NAME(xsmsubsp, "xsmsubmsp", 0x04, 0x03, PPC2_VSX207),
+GEN_XX3FORM_NAME(xsnmaddsp, "xsnmaddasp", 0x04, 0x10, PPC2_VSX207),
+GEN_XX3FORM_NAME(xsnmaddsp, "xsnmaddmsp", 0x04, 0x11, PPC2_VSX207),
+GEN_XX3FORM_NAME(xsnmsubsp, "xsnmsubasp", 0x04, 0x12, PPC2_VSX207),
+GEN_XX3FORM_NAME(xsnmsubsp, "xsnmsubmsp", 0x04, 0x13, PPC2_VSX207),
GEN_XX2FORM(xscvsxdsp, 0x10, 0x13, PPC2_VSX207),
GEN_XX2FORM(xscvuxdsp, 0x10, 0x12, PPC2_VSX207),
GEN_XX2FORM(xvrsqrtedp, 0x14, 0x0C, PPC2_VSX),
GEN_XX3FORM(xvtdivdp, 0x14, 0x0F, PPC2_VSX),
GEN_XX2FORM(xvtsqrtdp, 0x14, 0x0E, PPC2_VSX),
-GEN_XX3FORM(xvmaddadp, 0x04, 0x0C, PPC2_VSX),
-GEN_XX3FORM(xvmaddmdp, 0x04, 0x0D, PPC2_VSX),
-GEN_XX3FORM(xvmsubadp, 0x04, 0x0E, PPC2_VSX),
-GEN_XX3FORM(xvmsubmdp, 0x04, 0x0F, PPC2_VSX),
-GEN_XX3FORM(xvnmaddadp, 0x04, 0x1C, PPC2_VSX),
-GEN_XX3FORM(xvnmaddmdp, 0x04, 0x1D, PPC2_VSX),
-GEN_XX3FORM(xvnmsubadp, 0x04, 0x1E, PPC2_VSX),
-GEN_XX3FORM(xvnmsubmdp, 0x04, 0x1F, PPC2_VSX),
+GEN_XX3FORM_NAME(xvmadddp, "xvmaddadp", 0x04, 0x0C, PPC2_VSX),
+GEN_XX3FORM_NAME(xvmadddp, "xvmaddmdp", 0x04, 0x0D, PPC2_VSX),
+GEN_XX3FORM_NAME(xvmsubdp, "xvmsubadp", 0x04, 0x0E, PPC2_VSX),
+GEN_XX3FORM_NAME(xvmsubdp, "xvmsubmdp", 0x04, 0x0F, PPC2_VSX),
+GEN_XX3FORM_NAME(xvnmadddp, "xvnmaddadp", 0x04, 0x1C, PPC2_VSX),
+GEN_XX3FORM_NAME(xvnmadddp, "xvnmaddmdp", 0x04, 0x1D, PPC2_VSX),
+GEN_XX3FORM_NAME(xvnmsubdp, "xvnmsubadp", 0x04, 0x1E, PPC2_VSX),
+GEN_XX3FORM_NAME(xvnmsubdp, "xvnmsubmdp", 0x04, 0x1F, PPC2_VSX),
GEN_XX3FORM(xvmaxdp, 0x00, 0x1C, PPC2_VSX),
GEN_XX3FORM(xvmindp, 0x00, 0x1D, PPC2_VSX),
GEN_XX3_RC_FORM(xvcmpeqdp, 0x0C, 0x0C, PPC2_VSX),
GEN_XX2FORM(xvrsqrtesp, 0x14, 0x08, PPC2_VSX),
GEN_XX3FORM(xvtdivsp, 0x14, 0x0B, PPC2_VSX),
GEN_XX2FORM(xvtsqrtsp, 0x14, 0x0A, PPC2_VSX),
-GEN_XX3FORM(xvmaddasp, 0x04, 0x08, PPC2_VSX),
-GEN_XX3FORM(xvmaddmsp, 0x04, 0x09, PPC2_VSX),
-GEN_XX3FORM(xvmsubasp, 0x04, 0x0A, PPC2_VSX),
-GEN_XX3FORM(xvmsubmsp, 0x04, 0x0B, PPC2_VSX),
-GEN_XX3FORM(xvnmaddasp, 0x04, 0x18, PPC2_VSX),
-GEN_XX3FORM(xvnmaddmsp, 0x04, 0x19, PPC2_VSX),
-GEN_XX3FORM(xvnmsubasp, 0x04, 0x1A, PPC2_VSX),
-GEN_XX3FORM(xvnmsubmsp, 0x04, 0x1B, PPC2_VSX),
+GEN_XX3FORM_NAME(xvmaddsp, "xvmaddasp", 0x04, 0x08, PPC2_VSX),
+GEN_XX3FORM_NAME(xvmaddsp, "xvmaddmsp", 0x04, 0x09, PPC2_VSX),
+GEN_XX3FORM_NAME(xvmsubsp, "xvmsubasp", 0x04, 0x0A, PPC2_VSX),
+GEN_XX3FORM_NAME(xvmsubsp, "xvmsubmsp", 0x04, 0x0B, PPC2_VSX),
+GEN_XX3FORM_NAME(xvnmaddsp, "xvnmaddasp", 0x04, 0x18, PPC2_VSX),
+GEN_XX3FORM_NAME(xvnmaddsp, "xvnmaddmsp", 0x04, 0x19, PPC2_VSX),
+GEN_XX3FORM_NAME(xvnmsubsp, "xvnmsubasp", 0x04, 0x1A, PPC2_VSX),
+GEN_XX3FORM_NAME(xvnmsubsp, "xvnmsubmsp", 0x04, 0x1B, PPC2_VSX),
GEN_XX3FORM(xvmaxsp, 0x00, 0x18, PPC2_VSX),
GEN_XX3FORM(xvminsp, 0x00, 0x19, PPC2_VSX),
GEN_XX3_RC_FORM(xvcmpeqsp, 0x0C, 0x08, PPC2_VSX),
#include "qemu/cutils.h"
#include "disas/capstone.h"
#include "fpu/softfloat.h"
-#include "qapi/qapi-commands-target.h"
+#include "qapi/qapi-commands-machine-target.h"
/* #define PPC_DUMP_CPU */
/* #define PPC_DEBUG_SPR */
#include "cpu.h"
#include "exec/exec-all.h"
#include "qapi/error.h"
+#include "qemu/error-report.h"
#include "hw/qdev-properties.h"
#include "migration/vmstate.h"
env->misa_mask = env->misa = misa;
}
-static void set_versions(CPURISCVState *env, int user_ver, int priv_ver)
+static void set_priv_version(CPURISCVState *env, int priv_ver)
{
- env->user_ver = user_ver;
env->priv_ver = priv_ver;
}
{
CPURISCVState *env = &RISCV_CPU(obj)->env;
set_misa(env, RVXLEN | RVI | RVM | RVA | RVF | RVD | RVC | RVU);
- set_versions(env, USER_VERSION_2_02_0, PRIV_VERSION_1_10_0);
+ set_priv_version(env, PRIV_VERSION_1_11_0);
set_resetvec(env, DEFAULT_RSTVEC);
}
static void riscv_base32_cpu_init(Object *obj)
{
CPURISCVState *env = &RISCV_CPU(obj)->env;
- set_misa(env, RV32 | RVI | RVM | RVA | RVF | RVD | RVC | RVS | RVU);
+ /* We set this in the realise function */
+ set_misa(env, 0);
}
static void rv32gcsu_priv1_09_1_cpu_init(Object *obj)
{
CPURISCVState *env = &RISCV_CPU(obj)->env;
set_misa(env, RV32 | RVI | RVM | RVA | RVF | RVD | RVC | RVS | RVU);
- set_versions(env, USER_VERSION_2_02_0, PRIV_VERSION_1_09_1);
+ set_priv_version(env, PRIV_VERSION_1_09_1);
set_resetvec(env, DEFAULT_RSTVEC);
set_feature(env, RISCV_FEATURE_MMU);
set_feature(env, RISCV_FEATURE_PMP);
{
CPURISCVState *env = &RISCV_CPU(obj)->env;
set_misa(env, RV32 | RVI | RVM | RVA | RVF | RVD | RVC | RVS | RVU);
- set_versions(env, USER_VERSION_2_02_0, PRIV_VERSION_1_10_0);
+ set_priv_version(env, PRIV_VERSION_1_10_0);
set_resetvec(env, DEFAULT_RSTVEC);
set_feature(env, RISCV_FEATURE_MMU);
set_feature(env, RISCV_FEATURE_PMP);
{
CPURISCVState *env = &RISCV_CPU(obj)->env;
set_misa(env, RV32 | RVI | RVM | RVA | RVC | RVU);
- set_versions(env, USER_VERSION_2_02_0, PRIV_VERSION_1_10_0);
+ set_priv_version(env, PRIV_VERSION_1_10_0);
set_resetvec(env, DEFAULT_RSTVEC);
set_feature(env, RISCV_FEATURE_PMP);
}
static void riscv_base64_cpu_init(Object *obj)
{
CPURISCVState *env = &RISCV_CPU(obj)->env;
- set_misa(env, RV64 | RVI | RVM | RVA | RVF | RVD | RVC | RVS | RVU);
+ /* We set this in the realise function */
+ set_misa(env, 0);
}
static void rv64gcsu_priv1_09_1_cpu_init(Object *obj)
{
CPURISCVState *env = &RISCV_CPU(obj)->env;
set_misa(env, RV64 | RVI | RVM | RVA | RVF | RVD | RVC | RVS | RVU);
- set_versions(env, USER_VERSION_2_02_0, PRIV_VERSION_1_09_1);
+ set_priv_version(env, PRIV_VERSION_1_09_1);
set_resetvec(env, DEFAULT_RSTVEC);
set_feature(env, RISCV_FEATURE_MMU);
set_feature(env, RISCV_FEATURE_PMP);
{
CPURISCVState *env = &RISCV_CPU(obj)->env;
set_misa(env, RV64 | RVI | RVM | RVA | RVF | RVD | RVC | RVS | RVU);
- set_versions(env, USER_VERSION_2_02_0, PRIV_VERSION_1_10_0);
+ set_priv_version(env, PRIV_VERSION_1_10_0);
set_resetvec(env, DEFAULT_RSTVEC);
set_feature(env, RISCV_FEATURE_MMU);
set_feature(env, RISCV_FEATURE_PMP);
{
CPURISCVState *env = &RISCV_CPU(obj)->env;
set_misa(env, RV64 | RVI | RVM | RVA | RVC | RVU);
- set_versions(env, USER_VERSION_2_02_0, PRIV_VERSION_1_10_0);
+ set_priv_version(env, PRIV_VERSION_1_10_0);
set_resetvec(env, DEFAULT_RSTVEC);
set_feature(env, RISCV_FEATURE_PMP);
}
env->pc = env->resetvec;
#endif
cs->exception_index = EXCP_NONE;
+ env->load_res = -1;
set_default_nan_mode(1, &env->fp_status);
}
RISCVCPU *cpu = RISCV_CPU(dev);
CPURISCVState *env = &cpu->env;
RISCVCPUClass *mcc = RISCV_CPU_GET_CLASS(dev);
- int priv_version = PRIV_VERSION_1_10_0;
- int user_version = USER_VERSION_2_02_0;
+ int priv_version = PRIV_VERSION_1_11_0;
+ target_ulong target_misa = 0;
Error *local_err = NULL;
cpu_exec_realizefn(cs, &local_err);
}
if (cpu->cfg.priv_spec) {
- if (!g_strcmp0(cpu->cfg.priv_spec, "v1.10.0")) {
+ if (!g_strcmp0(cpu->cfg.priv_spec, "v1.11.0")) {
+ priv_version = PRIV_VERSION_1_11_0;
+ } else if (!g_strcmp0(cpu->cfg.priv_spec, "v1.10.0")) {
priv_version = PRIV_VERSION_1_10_0;
} else if (!g_strcmp0(cpu->cfg.priv_spec, "v1.9.1")) {
priv_version = PRIV_VERSION_1_09_1;
}
}
- if (cpu->cfg.user_spec) {
- if (!g_strcmp0(cpu->cfg.user_spec, "v2.02.0")) {
- user_version = USER_VERSION_2_02_0;
- } else {
- error_setg(errp,
- "Unsupported user spec version '%s'",
- cpu->cfg.user_spec);
- return;
- }
- }
-
- set_versions(env, user_version, priv_version);
+ set_priv_version(env, priv_version);
set_resetvec(env, DEFAULT_RSTVEC);
if (cpu->cfg.mmu) {
set_feature(env, RISCV_FEATURE_PMP);
}
+ /* If misa isn't set (rv32 and rv64 machines) set it here */
+ if (!env->misa) {
+ /* Do some ISA extension error checking */
+ if (cpu->cfg.ext_i && cpu->cfg.ext_e) {
+ error_setg(errp,
+ "I and E extensions are incompatible");
+ return;
+ }
+
+ if (!cpu->cfg.ext_i && !cpu->cfg.ext_e) {
+ error_setg(errp,
+ "Either I or E extension must be set");
+ return;
+ }
+
+ if (cpu->cfg.ext_g && !(cpu->cfg.ext_i & cpu->cfg.ext_m &
+ cpu->cfg.ext_a & cpu->cfg.ext_f &
+ cpu->cfg.ext_d)) {
+ warn_report("Setting G will also set IMAFD");
+ cpu->cfg.ext_i = true;
+ cpu->cfg.ext_m = true;
+ cpu->cfg.ext_a = true;
+ cpu->cfg.ext_f = true;
+ cpu->cfg.ext_d = true;
+ }
+
+ /* Set the ISA extensions, checks should have happened above */
+ if (cpu->cfg.ext_i) {
+ target_misa |= RVI;
+ }
+ if (cpu->cfg.ext_e) {
+ target_misa |= RVE;
+ }
+ if (cpu->cfg.ext_m) {
+ target_misa |= RVM;
+ }
+ if (cpu->cfg.ext_a) {
+ target_misa |= RVA;
+ }
+ if (cpu->cfg.ext_f) {
+ target_misa |= RVF;
+ }
+ if (cpu->cfg.ext_d) {
+ target_misa |= RVD;
+ }
+ if (cpu->cfg.ext_c) {
+ target_misa |= RVC;
+ }
+ if (cpu->cfg.ext_s) {
+ target_misa |= RVS;
+ }
+ if (cpu->cfg.ext_u) {
+ target_misa |= RVU;
+ }
+
+ set_misa(env, RVXLEN | target_misa);
+ }
+
riscv_cpu_register_gdb_regs_for_features(cs);
qemu_init_vcpu(cs);
};
static Property riscv_cpu_properties[] = {
+ DEFINE_PROP_BOOL("i", RISCVCPU, cfg.ext_i, true),
+ DEFINE_PROP_BOOL("e", RISCVCPU, cfg.ext_e, false),
+ DEFINE_PROP_BOOL("g", RISCVCPU, cfg.ext_g, true),
+ DEFINE_PROP_BOOL("m", RISCVCPU, cfg.ext_m, true),
+ DEFINE_PROP_BOOL("a", RISCVCPU, cfg.ext_a, true),
+ DEFINE_PROP_BOOL("f", RISCVCPU, cfg.ext_f, true),
+ DEFINE_PROP_BOOL("d", RISCVCPU, cfg.ext_d, true),
+ DEFINE_PROP_BOOL("c", RISCVCPU, cfg.ext_c, true),
+ DEFINE_PROP_BOOL("s", RISCVCPU, cfg.ext_s, true),
+ DEFINE_PROP_BOOL("u", RISCVCPU, cfg.ext_u, true),
+ DEFINE_PROP_BOOL("Counters", RISCVCPU, cfg.ext_counters, true),
+ DEFINE_PROP_BOOL("Zifencei", RISCVCPU, cfg.ext_ifencei, true),
+ DEFINE_PROP_BOOL("Zicsr", RISCVCPU, cfg.ext_icsr, true),
DEFINE_PROP_STRING("priv_spec", RISCVCPU, cfg.priv_spec),
- DEFINE_PROP_STRING("user_spec", RISCVCPU, cfg.user_spec),
DEFINE_PROP_BOOL("mmu", RISCVCPU, cfg.mmu, true),
DEFINE_PROP_BOOL("pmp", RISCVCPU, cfg.pmp, true),
DEFINE_PROP_END_OF_LIST(),
cc->gdb_stop_before_watchpoint = true;
cc->disas_set_info = riscv_cpu_disas_set_info;
#ifndef CONFIG_USER_ONLY
+ cc->do_unassigned_access = riscv_cpu_unassigned_access;
cc->do_unaligned_access = riscv_cpu_do_unaligned_access;
cc->get_phys_page_debug = riscv_cpu_get_phys_page_debug;
#endif
DEFINE_CPU(TYPE_RISCV_CPU_ANY, riscv_any_cpu_init),
#if defined(TARGET_RISCV32)
DEFINE_CPU(TYPE_RISCV_CPU_BASE32, riscv_base32_cpu_init),
- DEFINE_CPU(TYPE_RISCV_CPU_RV32GCSU_V1_09_1, rv32gcsu_priv1_09_1_cpu_init),
- DEFINE_CPU(TYPE_RISCV_CPU_RV32GCSU_V1_10_0, rv32gcsu_priv1_10_0_cpu_init),
- DEFINE_CPU(TYPE_RISCV_CPU_RV32IMACU_NOMMU, rv32imacu_nommu_cpu_init),
DEFINE_CPU(TYPE_RISCV_CPU_SIFIVE_E31, rv32imacu_nommu_cpu_init),
- DEFINE_CPU(TYPE_RISCV_CPU_SIFIVE_U34, rv32gcsu_priv1_10_0_cpu_init)
+ DEFINE_CPU(TYPE_RISCV_CPU_SIFIVE_U34, rv32gcsu_priv1_10_0_cpu_init),
+ /* Depreacted */
+ DEFINE_CPU(TYPE_RISCV_CPU_RV32IMACU_NOMMU, rv32imacu_nommu_cpu_init),
+ DEFINE_CPU(TYPE_RISCV_CPU_RV32GCSU_V1_09_1, rv32gcsu_priv1_09_1_cpu_init),
+ DEFINE_CPU(TYPE_RISCV_CPU_RV32GCSU_V1_10_0, rv32gcsu_priv1_10_0_cpu_init)
#elif defined(TARGET_RISCV64)
DEFINE_CPU(TYPE_RISCV_CPU_BASE64, riscv_base64_cpu_init),
- DEFINE_CPU(TYPE_RISCV_CPU_RV64GCSU_V1_09_1, rv64gcsu_priv1_09_1_cpu_init),
- DEFINE_CPU(TYPE_RISCV_CPU_RV64GCSU_V1_10_0, rv64gcsu_priv1_10_0_cpu_init),
- DEFINE_CPU(TYPE_RISCV_CPU_RV64IMACU_NOMMU, rv64imacu_nommu_cpu_init),
DEFINE_CPU(TYPE_RISCV_CPU_SIFIVE_E51, rv64imacu_nommu_cpu_init),
- DEFINE_CPU(TYPE_RISCV_CPU_SIFIVE_U54, rv64gcsu_priv1_10_0_cpu_init)
+ DEFINE_CPU(TYPE_RISCV_CPU_SIFIVE_U54, rv64gcsu_priv1_10_0_cpu_init),
+ /* Deprecated */
+ DEFINE_CPU(TYPE_RISCV_CPU_RV64IMACU_NOMMU, rv64imacu_nommu_cpu_init),
+ DEFINE_CPU(TYPE_RISCV_CPU_RV64GCSU_V1_09_1, rv64gcsu_priv1_09_1_cpu_init),
+ DEFINE_CPU(TYPE_RISCV_CPU_RV64GCSU_V1_10_0, rv64gcsu_priv1_10_0_cpu_init)
#endif
};
#define TYPE_RISCV_CPU_ANY RISCV_CPU_TYPE_NAME("any")
#define TYPE_RISCV_CPU_BASE32 RISCV_CPU_TYPE_NAME("rv32")
#define TYPE_RISCV_CPU_BASE64 RISCV_CPU_TYPE_NAME("rv64")
-#define TYPE_RISCV_CPU_RV32GCSU_V1_09_1 RISCV_CPU_TYPE_NAME("rv32gcsu-v1.9.1")
-#define TYPE_RISCV_CPU_RV32GCSU_V1_10_0 RISCV_CPU_TYPE_NAME("rv32gcsu-v1.10.0")
-#define TYPE_RISCV_CPU_RV32IMACU_NOMMU RISCV_CPU_TYPE_NAME("rv32imacu-nommu")
-#define TYPE_RISCV_CPU_RV64GCSU_V1_09_1 RISCV_CPU_TYPE_NAME("rv64gcsu-v1.9.1")
-#define TYPE_RISCV_CPU_RV64GCSU_V1_10_0 RISCV_CPU_TYPE_NAME("rv64gcsu-v1.10.0")
-#define TYPE_RISCV_CPU_RV64IMACU_NOMMU RISCV_CPU_TYPE_NAME("rv64imacu-nommu")
#define TYPE_RISCV_CPU_SIFIVE_E31 RISCV_CPU_TYPE_NAME("sifive-e31")
#define TYPE_RISCV_CPU_SIFIVE_E51 RISCV_CPU_TYPE_NAME("sifive-e51")
#define TYPE_RISCV_CPU_SIFIVE_U34 RISCV_CPU_TYPE_NAME("sifive-u34")
#define TYPE_RISCV_CPU_SIFIVE_U54 RISCV_CPU_TYPE_NAME("sifive-u54")
+/* Deprecated */
+#define TYPE_RISCV_CPU_RV32IMACU_NOMMU RISCV_CPU_TYPE_NAME("rv32imacu-nommu")
+#define TYPE_RISCV_CPU_RV32GCSU_V1_09_1 RISCV_CPU_TYPE_NAME("rv32gcsu-v1.9.1")
+#define TYPE_RISCV_CPU_RV32GCSU_V1_10_0 RISCV_CPU_TYPE_NAME("rv32gcsu-v1.10.0")
+#define TYPE_RISCV_CPU_RV64IMACU_NOMMU RISCV_CPU_TYPE_NAME("rv64imacu-nommu")
+#define TYPE_RISCV_CPU_RV64GCSU_V1_09_1 RISCV_CPU_TYPE_NAME("rv64gcsu-v1.9.1")
+#define TYPE_RISCV_CPU_RV64GCSU_V1_10_0 RISCV_CPU_TYPE_NAME("rv64gcsu-v1.10.0")
#define RV32 ((target_ulong)1 << (TARGET_LONG_BITS - 2))
#define RV64 ((target_ulong)2 << (TARGET_LONG_BITS - 2))
RISCV_FEATURE_MISA
};
-#define USER_VERSION_2_02_0 0x00020200
#define PRIV_VERSION_1_09_1 0x00010901
#define PRIV_VERSION_1_10_0 0x00011000
+#define PRIV_VERSION_1_11_0 0x00011100
+#define TRANSLATE_PMP_FAIL 2
#define TRANSLATE_FAIL 1
#define TRANSLATE_SUCCESS 0
#define MMU_USER_IDX 3
target_ulong badaddr;
- target_ulong user_ver;
target_ulong priv_ver;
target_ulong misa;
target_ulong misa_mask;
/* Configuration Settings */
struct {
+ bool ext_i;
+ bool ext_e;
+ bool ext_g;
+ bool ext_m;
+ bool ext_a;
+ bool ext_f;
+ bool ext_d;
+ bool ext_c;
+ bool ext_s;
+ bool ext_u;
+ bool ext_counters;
+ bool ext_ifencei;
+ bool ext_icsr;
+
char *priv_spec;
char *user_spec;
bool mmu;
bool riscv_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
MMUAccessType access_type, int mmu_idx,
bool probe, uintptr_t retaddr);
+void riscv_cpu_unassigned_access(CPUState *cpu, hwaddr addr, bool is_write,
+ bool is_exec, int unused, unsigned size);
char *riscv_isa_string(RISCVCPU *cpu);
void riscv_cpu_list(void);
#define CSR_MCOUNTEREN 0x306
/* Legacy Counter Setup (priv v1.9.1) */
+/* Update to #define CSR_MCOUNTINHIBIT 0x320 for 1.11.0 */
#define CSR_MUCOUNTEREN 0x320
#define CSR_MSCOUNTEREN 0x321
#define CSR_MHCOUNTEREN 0x322
}
/* tlb_flush is unnecessary as mode is contained in mmu_idx */
env->priv = newpriv;
+
+ /*
+ * Clear the load reservation - otherwise a reservation placed in one
+ * context/process can be used by another, resulting in an SC succeeding
+ * incorrectly. Version 2.2 of the ISA specification explicitly requires
+ * this behaviour, while later revisions say that the kernel "should" use
+ * an SC instruction to force the yielding of a load reservation on a
+ * preemptive context switch. As a result, do both.
+ */
+ env->load_res = -1;
}
/* get_physical_address - get the physical address for this virtual address
/* check that physical address of PTE is legal */
target_ulong pte_addr = base + idx * ptesize;
+
+ if (riscv_feature(env, RISCV_FEATURE_PMP) &&
+ !pmp_hart_has_privs(env, pte_addr, sizeof(target_ulong),
+ 1 << MMU_DATA_LOAD, PRV_S)) {
+ return TRANSLATE_PMP_FAIL;
+ }
#if defined(TARGET_RISCV32)
target_ulong pte = ldl_phys(cs->as, pte_addr);
#elif defined(TARGET_RISCV64)
}
static void raise_mmu_exception(CPURISCVState *env, target_ulong address,
- MMUAccessType access_type)
+ MMUAccessType access_type, bool pmp_violation)
{
CPUState *cs = env_cpu(env);
int page_fault_exceptions =
(env->priv_ver >= PRIV_VERSION_1_10_0) &&
- get_field(env->satp, SATP_MODE) != VM_1_10_MBARE;
+ get_field(env->satp, SATP_MODE) != VM_1_10_MBARE &&
+ !pmp_violation;
switch (access_type) {
case MMU_INST_FETCH:
cs->exception_index = page_fault_exceptions ?
return phys_addr;
}
+void riscv_cpu_unassigned_access(CPUState *cs, hwaddr addr, bool is_write,
+ bool is_exec, int unused, unsigned size)
+{
+ RISCVCPU *cpu = RISCV_CPU(cs);
+ CPURISCVState *env = &cpu->env;
+
+ if (is_write) {
+ cs->exception_index = RISCV_EXCP_STORE_AMO_ACCESS_FAULT;
+ } else {
+ cs->exception_index = RISCV_EXCP_LOAD_ACCESS_FAULT;
+ }
+
+ env->badaddr = addr;
+ riscv_raise_exception(&cpu->env, cs->exception_index, GETPC());
+}
+
void riscv_cpu_do_unaligned_access(CPUState *cs, vaddr addr,
MMUAccessType access_type, int mmu_idx,
uintptr_t retaddr)
CPURISCVState *env = &cpu->env;
hwaddr pa = 0;
int prot;
+ bool pmp_violation = false;
int ret = TRANSLATE_FAIL;
+ int mode = mmu_idx;
qemu_log_mask(CPU_LOG_MMU, "%s ad %" VADDR_PRIx " rw %d mmu_idx %d\n",
__func__, address, access_type, mmu_idx);
ret = get_physical_address(env, &pa, &prot, address, access_type, mmu_idx);
+ if (mode == PRV_M && access_type != MMU_INST_FETCH) {
+ if (get_field(env->mstatus, MSTATUS_MPRV)) {
+ mode = get_field(env->mstatus, MSTATUS_MPP);
+ }
+ }
+
qemu_log_mask(CPU_LOG_MMU,
"%s address=%" VADDR_PRIx " ret %d physical " TARGET_FMT_plx
" prot %d\n", __func__, address, ret, pa, prot);
if (riscv_feature(env, RISCV_FEATURE_PMP) &&
- !pmp_hart_has_privs(env, pa, TARGET_PAGE_SIZE, 1 << access_type)) {
- ret = TRANSLATE_FAIL;
+ (ret == TRANSLATE_SUCCESS) &&
+ !pmp_hart_has_privs(env, pa, size, 1 << access_type, mode)) {
+ ret = TRANSLATE_PMP_FAIL;
+ }
+ if (ret == TRANSLATE_PMP_FAIL) {
+ pmp_violation = true;
}
if (ret == TRANSLATE_SUCCESS) {
tlb_set_page(cs, address & TARGET_PAGE_MASK, pa & TARGET_PAGE_MASK,
} else if (probe) {
return false;
} else {
- raise_mmu_exception(env, address, access_type);
+ raise_mmu_exception(env, address, access_type, pmp_violation);
riscv_raise_exception(env, cs->exception_index, retaddr);
}
#else
static int ctr(CPURISCVState *env, int csrno)
{
#if !defined(CONFIG_USER_ONLY)
+ CPUState *cs = env_cpu(env);
+ RISCVCPU *cpu = RISCV_CPU(cs);
uint32_t ctr_en = ~0u;
+ if (!cpu->cfg.ext_counters) {
+ /* The Counters extensions is not enabled */
+ return -1;
+ }
+
+ /*
+ * The counters are always enabled at run time on newer priv specs, as the
+ * CSR has changed from controlling that the counters can be read to
+ * controlling that the counters increment.
+ */
+ if (env->priv_ver > PRIV_VERSION_1_09_1) {
+ return 0;
+ }
+
if (env->priv < PRV_M) {
ctr_en &= env->mcounteren;
}
return 0;
}
+/* This regiser is replaced with CSR_MCOUNTINHIBIT in 1.11.0 */
static int read_mscounteren(CPURISCVState *env, int csrno, target_ulong *val)
{
- if (env->priv_ver > PRIV_VERSION_1_09_1) {
+ if (env->priv_ver > PRIV_VERSION_1_09_1
+ && env->priv_ver < PRIV_VERSION_1_11_0) {
return -1;
}
*val = env->mcounteren;
return 0;
}
+/* This regiser is replaced with CSR_MCOUNTINHIBIT in 1.11.0 */
static int write_mscounteren(CPURISCVState *env, int csrno, target_ulong val)
{
- if (env->priv_ver > PRIV_VERSION_1_09_1) {
+ if (env->priv_ver > PRIV_VERSION_1_09_1
+ && env->priv_ver < PRIV_VERSION_1_11_0) {
return -1;
}
env->mcounteren = val;
{
int ret;
target_ulong old_value;
+ RISCVCPU *cpu = env_archcpu(env);
/* check privileges and return -1 if check fails */
#if !defined(CONFIG_USER_ONLY)
}
#endif
+ /* ensure the CSR extension is enabled. */
+ if (!cpu->cfg.ext_icsr) {
+ return -1;
+ }
+
/* check predicate */
if (!csr_ops[csrno].predicate || csr_ops[csrno].predicate(env, csrno) < 0) {
return -1;
static bool trans_sfence_vma(DisasContext *ctx, arg_sfence_vma *a)
{
#ifndef CONFIG_USER_ONLY
- if (ctx->priv_ver == PRIV_VERSION_1_10_0) {
+ if (ctx->priv_ver >= PRIV_VERSION_1_10_0) {
gen_helper_tlb_flush(cpu_env);
return true;
}
gen_set_label(l1);
/*
- * Address comparion failure. However, we still need to
+ * Address comparison 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);
gen_set_gpr(a->rd, dat);
gen_set_label(l2);
+ /*
+ * Clear the load reservation, since an SC must fail if there is
+ * an SC to any address, in between an LR and SC pair.
+ */
+ tcg_gen_movi_tl(load_res, -1);
+
tcg_temp_free(dat);
tcg_temp_free(src1);
tcg_temp_free(src2);
static bool trans_fence_i(DisasContext *ctx, arg_fence_i *a)
{
+ if (!ctx->ext_ifencei) {
+ return false;
+ }
+
/*
* FENCE_I is a no-op in QEMU,
* however we need to end the translation block
* Check if the address has required RWX privs to complete desired operation
*/
bool pmp_hart_has_privs(CPURISCVState *env, target_ulong addr,
- target_ulong size, pmp_priv_t privs)
+ target_ulong size, pmp_priv_t privs, target_ulong mode)
{
int i = 0;
int ret = -1;
from low to high */
for (i = 0; i < MAX_RISCV_PMPS; i++) {
s = pmp_is_in_range(env, i, addr);
- e = pmp_is_in_range(env, i, addr + size);
+ e = pmp_is_in_range(env, i, addr + size - 1);
/* partially inside */
if ((s + e) == 1) {
/* fully inside */
const uint8_t a_field =
pmp_get_a_field(env->pmp_state.pmp[i].cfg_reg);
- if ((s + e) == 2) {
- if (PMP_AMATCH_OFF == a_field) {
- return 1;
- }
+ /*
+ * If the PMP entry is not off and the address is in range, do the priv
+ * check
+ */
+ if (((s + e) == 2) && (PMP_AMATCH_OFF != a_field)) {
allowed_privs = PMP_READ | PMP_WRITE | PMP_EXEC;
- if ((env->priv != PRV_M) || pmp_is_locked(env, i)) {
+ if ((mode != PRV_M) || pmp_is_locked(env, i)) {
allowed_privs &= env->pmp_state.pmp[i].cfg_reg;
}
/* No rule matched */
if (ret == -1) {
- if (env->priv == PRV_M) {
+ if (mode == PRV_M) {
ret = 1; /* Privileged spec v1.10 states if no PMP entry matches an
* M-Mode access, the access succeeds */
} else {
target_ulong val);
target_ulong pmpaddr_csr_read(CPURISCVState *env, uint32_t addr_index);
bool pmp_hart_has_privs(CPURISCVState *env, target_ulong addr,
- target_ulong size, pmp_priv_t priv);
+ target_ulong size, pmp_priv_t priv, target_ulong mode);
#endif
to any system register, which includes CSR_FRM, so we do not have
to reset this known value. */
int frm;
+ bool ext_ifencei;
} DisasContext;
#ifdef TARGET_RISCV64
{
DisasContext *ctx = container_of(dcbase, DisasContext, base);
CPURISCVState *env = cs->env_ptr;
+ RISCVCPU *cpu = RISCV_CPU(cs);
ctx->pc_succ_insn = ctx->base.pc_first;
ctx->mem_idx = ctx->base.tb->flags & TB_FLAGS_MMU_MASK;
ctx->priv_ver = env->priv_ver;
ctx->misa = env->misa;
ctx->frm = -1; /* unknown rounding mode */
+ ctx->ext_ifencei = cpu->cfg.ext_ifencei;
}
static void riscv_tr_tb_start(DisasContextBase *db, CPUState *cpu)
#include "qemu/module.h"
#include "trace.h"
#include "qapi/visitor.h"
-#include "qapi/qapi-visit-misc.h"
+#include "qapi/qapi-types-machine.h"
#include "qapi/qapi-visit-run-state.h"
#include "sysemu/hw_accel.h"
#include "hw/qdev-properties.h"
* CPU features/facilities for s390x
*
* Copyright IBM Corp. 2016, 2018
+ * Copyright Red Hat, Inc. 2019
*
- * Author(s): David Hildenbrand <dahi@linux.vnet.ibm.com>
+ * Author(s): David Hildenbrand <david@redhat.com>
*
* This work is licensed under the terms of the GNU GPL, version 2 or (at
* your option) any later version. See the COPYING file in the top-level
#include "qemu/module.h"
#include "cpu_features.h"
-#define FEAT_INIT(_name, _type, _bit, _desc) \
- { \
- .name = _name, \
- .type = _type, \
- .bit = _bit, \
- .desc = _desc, \
- }
-
-/* S390FeatDef.bit is not applicable as there is no feature block. */
-#define FEAT_INIT_MISC(_name, _desc) \
- FEAT_INIT(_name, S390_FEAT_TYPE_MISC, 0, _desc)
-
-/* indexed by feature number for easy lookup */
-static const S390FeatDef s390_features[] = {
- FEAT_INIT("esan3", S390_FEAT_TYPE_STFL, 0, "Instructions marked as n3"),
- FEAT_INIT("zarch", S390_FEAT_TYPE_STFL, 1, "z/Architecture architectural mode"),
- FEAT_INIT("dateh", S390_FEAT_TYPE_STFL, 3, "DAT-enhancement facility"),
- FEAT_INIT("idtes", S390_FEAT_TYPE_STFL, 4, "IDTE selective TLB segment-table clearing"),
- FEAT_INIT("idter", S390_FEAT_TYPE_STFL, 5, "IDTE selective TLB region-table clearing"),
- FEAT_INIT("asnlxr", S390_FEAT_TYPE_STFL, 6, "ASN-and-LX reuse facility"),
- FEAT_INIT("stfle", S390_FEAT_TYPE_STFL, 7, "Store-facility-list-extended facility"),
- FEAT_INIT("edat", S390_FEAT_TYPE_STFL, 8, "Enhanced-DAT facility"),
- FEAT_INIT("srs", S390_FEAT_TYPE_STFL, 9, "Sense-running-status facility"),
- FEAT_INIT("csske", S390_FEAT_TYPE_STFL, 10, "Conditional-SSKE facility"),
- FEAT_INIT("ctop", S390_FEAT_TYPE_STFL, 11, "Configuration-topology facility"),
- FEAT_INIT("apqci", S390_FEAT_TYPE_STFL, 12, "Query AP Configuration Information facility"),
- FEAT_INIT("ipter", S390_FEAT_TYPE_STFL, 13, "IPTE-range facility"),
- FEAT_INIT("nonqks", S390_FEAT_TYPE_STFL, 14, "Nonquiescing key-setting facility"),
- FEAT_INIT("apft", S390_FEAT_TYPE_STFL, 15, "AP Facilities Test facility"),
- FEAT_INIT("etf2", S390_FEAT_TYPE_STFL, 16, "Extended-translation facility 2"),
- FEAT_INIT("msa-base", S390_FEAT_TYPE_STFL, 17, "Message-security-assist facility (excluding subfunctions)"),
- FEAT_INIT("ldisp", S390_FEAT_TYPE_STFL, 18, "Long-displacement facility"),
- FEAT_INIT("ldisphp", S390_FEAT_TYPE_STFL, 19, "Long-displacement facility has high performance"),
- FEAT_INIT("hfpm", S390_FEAT_TYPE_STFL, 20, "HFP-multiply-add/subtract facility"),
- FEAT_INIT("eimm", S390_FEAT_TYPE_STFL, 21, "Extended-immediate facility"),
- FEAT_INIT("etf3", S390_FEAT_TYPE_STFL, 22, "Extended-translation facility 3"),
- FEAT_INIT("hfpue", S390_FEAT_TYPE_STFL, 23, "HFP-unnormalized-extension facility"),
- FEAT_INIT("etf2eh", S390_FEAT_TYPE_STFL, 24, "ETF2-enhancement facility"),
- FEAT_INIT("stckf", S390_FEAT_TYPE_STFL, 25, "Store-clock-fast facility"),
- FEAT_INIT("parseh", S390_FEAT_TYPE_STFL, 26, "Parsing-enhancement facility"),
- FEAT_INIT("mvcos", S390_FEAT_TYPE_STFL, 27, "Move-with-optional-specification facility"),
- FEAT_INIT("tods-base", S390_FEAT_TYPE_STFL, 28, "TOD-clock-steering facility (excluding subfunctions)"),
- FEAT_INIT("etf3eh", S390_FEAT_TYPE_STFL, 30, "ETF3-enhancement facility"),
- FEAT_INIT("ectg", S390_FEAT_TYPE_STFL, 31, "Extract-CPU-time facility"),
- FEAT_INIT("csst", S390_FEAT_TYPE_STFL, 32, "Compare-and-swap-and-store facility"),
- FEAT_INIT("csst2", S390_FEAT_TYPE_STFL, 33, "Compare-and-swap-and-store facility 2"),
- FEAT_INIT("ginste", S390_FEAT_TYPE_STFL, 34, "General-instructions-extension facility"),
- FEAT_INIT("exrl", S390_FEAT_TYPE_STFL, 35, "Execute-extensions facility"),
- FEAT_INIT("emon", S390_FEAT_TYPE_STFL, 36, "Enhanced-monitor facility"),
- FEAT_INIT("fpe", S390_FEAT_TYPE_STFL, 37, "Floating-point extension facility"),
- FEAT_INIT("opc", S390_FEAT_TYPE_STFL, 38, "Order Preserving Compression facility"),
- FEAT_INIT("sprogp", S390_FEAT_TYPE_STFL, 40, "Set-program-parameters facility"),
- FEAT_INIT("fpseh", S390_FEAT_TYPE_STFL, 41, "Floating-point-support-enhancement facilities"),
- FEAT_INIT("dfp", S390_FEAT_TYPE_STFL, 42, "DFP (decimal-floating-point) facility"),
- FEAT_INIT("dfphp", S390_FEAT_TYPE_STFL, 43, "DFP (decimal-floating-point) facility has high performance"),
- FEAT_INIT("pfpo", S390_FEAT_TYPE_STFL, 44, "PFPO instruction"),
- FEAT_INIT("stfle45", S390_FEAT_TYPE_STFL, 45, "Various facilities introduced with z196"),
- FEAT_INIT("cmpsceh", S390_FEAT_TYPE_STFL, 47, "CMPSC-enhancement facility"),
- FEAT_INIT("dfpzc", S390_FEAT_TYPE_STFL, 48, "Decimal-floating-point zoned-conversion facility"),
- FEAT_INIT("stfle49", S390_FEAT_TYPE_STFL, 49, "Various facilities introduced with zEC12"),
- FEAT_INIT("cte", S390_FEAT_TYPE_STFL, 50, "Constrained transactional-execution facility"),
- FEAT_INIT("ltlbc", S390_FEAT_TYPE_STFL, 51, "Local-TLB-clearing facility"),
- FEAT_INIT("iacc2", S390_FEAT_TYPE_STFL, 52, "Interlocked-access facility 2"),
- FEAT_INIT("stfle53", S390_FEAT_TYPE_STFL, 53, "Various facilities introduced with z13"),
- FEAT_INIT("eec", S390_FEAT_TYPE_STFL, 54, "Entropy encoding compression facility"),
- FEAT_INIT("msa5-base", S390_FEAT_TYPE_STFL, 57, "Message-security-assist-extension-5 facility (excluding subfunctions)"),
- FEAT_INIT("minste2", S390_FEAT_TYPE_STFL, 58, "Miscellaneous-instruction-extensions facility 2"),
- FEAT_INIT("sema", S390_FEAT_TYPE_STFL, 59, "Semaphore-assist facility"),
- FEAT_INIT("tsi", S390_FEAT_TYPE_STFL, 60, "Time-slice Instrumentation facility"),
- FEAT_INIT("minste3", S390_FEAT_TYPE_STFL, 61, "Miscellaneous-Instruction-Extensions Facility 3"),
- FEAT_INIT("ri", S390_FEAT_TYPE_STFL, 64, "CPU runtime-instrumentation facility"),
- FEAT_INIT("zpci", S390_FEAT_TYPE_STFL, 69, "z/PCI facility"),
- FEAT_INIT("aen", S390_FEAT_TYPE_STFL, 71, "General-purpose-adapter-event-notification facility"),
- FEAT_INIT("ais", S390_FEAT_TYPE_STFL, 72, "General-purpose-adapter-interruption-suppression facility"),
- FEAT_INIT("te", S390_FEAT_TYPE_STFL, 73, "Transactional-execution facility"),
- FEAT_INIT("sthyi", S390_FEAT_TYPE_STFL, 74, "Store-hypervisor-information facility"),
- FEAT_INIT("aefsi", S390_FEAT_TYPE_STFL, 75, "Access-exception-fetch/store-indication facility"),
- FEAT_INIT("msa3-base", S390_FEAT_TYPE_STFL, 76, "Message-security-assist-extension-3 facility (excluding subfunctions)"),
- FEAT_INIT("msa4-base", S390_FEAT_TYPE_STFL, 77, "Message-security-assist-extension-4 facility (excluding subfunctions)"),
- FEAT_INIT("edat2", S390_FEAT_TYPE_STFL, 78, "Enhanced-DAT facility 2"),
- FEAT_INIT("dfppc", S390_FEAT_TYPE_STFL, 80, "Decimal-floating-point packed-conversion facility"),
- FEAT_INIT("ppa15", S390_FEAT_TYPE_STFL, 81, "PPA15 is installed"),
- FEAT_INIT("bpb", S390_FEAT_TYPE_STFL, 82, "Branch prediction blocking"),
- FEAT_INIT("vx", S390_FEAT_TYPE_STFL, 129, "Vector facility"),
- FEAT_INIT("iep", S390_FEAT_TYPE_STFL, 130, "Instruction-execution-protection facility"),
- FEAT_INIT("sea_esop2", S390_FEAT_TYPE_STFL, 131, "Side-effect-access facility and Enhanced-suppression-on-protection facility 2"),
- FEAT_INIT("gs", S390_FEAT_TYPE_STFL, 133, "Guarded-storage facility"),
- FEAT_INIT("vxpd", S390_FEAT_TYPE_STFL, 134, "Vector packed decimal facility"),
- FEAT_INIT("vxeh", S390_FEAT_TYPE_STFL, 135, "Vector enhancements facility"),
- FEAT_INIT("mepoch", S390_FEAT_TYPE_STFL, 139, "Multiple-epoch facility"),
- FEAT_INIT("tpei", S390_FEAT_TYPE_STFL, 144, "Test-pending-external-interruption facility"),
- FEAT_INIT("irbm", S390_FEAT_TYPE_STFL, 145, "Insert-reference-bits-multiple facility"),
- FEAT_INIT("msa8-base", S390_FEAT_TYPE_STFL, 146, "Message-security-assist-extension-8 facility (excluding subfunctions)"),
- FEAT_INIT("cmmnt", S390_FEAT_TYPE_STFL, 147, "CMM: ESSA-enhancement (no translate) facility"),
- FEAT_INIT("vxeh2", S390_FEAT_TYPE_STFL, 148, "Vector Enhancements facility 2"),
- FEAT_INIT("esort-base", S390_FEAT_TYPE_STFL, 150, "Enhanced-sort facility (excluding subfunctions)"),
- FEAT_INIT("deflate-base", S390_FEAT_TYPE_STFL, 151, "Deflate-conversion facility (excluding subfunctions)"),
- FEAT_INIT("vxbeh", S390_FEAT_TYPE_STFL, 152, "Vector BCD enhancements facility 1"),
- FEAT_INIT("msa9-base", S390_FEAT_TYPE_STFL, 155, "Message-security-assist-extension-9 facility (excluding subfunctions)"),
- FEAT_INIT("etoken", S390_FEAT_TYPE_STFL, 156, "Etoken facility"),
-
- /* SCLP SCCB Byte 80 - 98 (bit numbers relative to byte-80) */
- FEAT_INIT("gsls", S390_FEAT_TYPE_SCLP_CONF_CHAR, 40, "SIE: Guest-storage-limit-suppression facility"),
- FEAT_INIT("esop", S390_FEAT_TYPE_SCLP_CONF_CHAR, 46, "Enhanced-suppression-on-protection facility"),
- FEAT_INIT("hpma2", S390_FEAT_TYPE_SCLP_CONF_CHAR, 90, "Host page management assist 2 Facility"), /* 91-2 */
- FEAT_INIT("kss", S390_FEAT_TYPE_SCLP_CONF_CHAR, 151, "SIE: Keyless-subset facility"), /* 98-7 */
-
- /* SCLP SCCB Byte 116 - 119 (bit numbers relative to byte-116) */
- FEAT_INIT("64bscao", S390_FEAT_TYPE_SCLP_CONF_CHAR_EXT, 0, "SIE: 64-bit-SCAO facility"),
- FEAT_INIT("cmma", S390_FEAT_TYPE_SCLP_CONF_CHAR_EXT, 1, "SIE: Collaborative-memory-management assist"),
- FEAT_INIT("pfmfi", S390_FEAT_TYPE_SCLP_CONF_CHAR_EXT, 9, "SIE: PFMF interpretation facility"),
- FEAT_INIT("ibs", S390_FEAT_TYPE_SCLP_CONF_CHAR_EXT, 10, "SIE: Interlock-and-broadcast-suppression facility"),
-
- FEAT_INIT("sief2", S390_FEAT_TYPE_SCLP_CPU, 4, "SIE: interception format 2 (Virtual SIE)"),
- FEAT_INIT("skey", S390_FEAT_TYPE_SCLP_CPU, 5, "SIE: Storage-key facility"),
- FEAT_INIT("gpereh", S390_FEAT_TYPE_SCLP_CPU, 10, "SIE: Guest-PER enhancement facility"),
- FEAT_INIT("siif", S390_FEAT_TYPE_SCLP_CPU, 11, "SIE: Shared IPTE-interlock facility"),
- FEAT_INIT("sigpif", S390_FEAT_TYPE_SCLP_CPU, 12, "SIE: SIGP interpretation facility"),
- FEAT_INIT("ib", S390_FEAT_TYPE_SCLP_CPU, 42, "SIE: Intervention bypass facility"),
- FEAT_INIT("cei", S390_FEAT_TYPE_SCLP_CPU, 43, "SIE: Conditional-external-interception facility"),
-
- FEAT_INIT_MISC("dateh2", "DAT-enhancement facility 2"),
- FEAT_INIT_MISC("cmm", "Collaborative-memory-management facility"),
- FEAT_INIT_MISC("ap", "AP instructions installed"),
-
- FEAT_INIT("plo-cl", S390_FEAT_TYPE_PLO, 0, "PLO Compare and load (32 bit in general registers)"),
- FEAT_INIT("plo-clg", S390_FEAT_TYPE_PLO, 1, "PLO Compare and load (64 bit in parameter list)"),
- FEAT_INIT("plo-clgr", S390_FEAT_TYPE_PLO, 2, "PLO Compare and load (32 bit in general registers)"),
- FEAT_INIT("plo-clx", S390_FEAT_TYPE_PLO, 3, "PLO Compare and load (128 bit in parameter list)"),
- FEAT_INIT("plo-cs", S390_FEAT_TYPE_PLO, 4, "PLO Compare and swap (32 bit in general registers)"),
- FEAT_INIT("plo-csg", S390_FEAT_TYPE_PLO, 5, "PLO Compare and swap (64 bit in parameter list)"),
- FEAT_INIT("plo-csgr", S390_FEAT_TYPE_PLO, 6, "PLO Compare and swap (32 bit in general registers)"),
- FEAT_INIT("plo-csx", S390_FEAT_TYPE_PLO, 7, "PLO Compare and swap (128 bit in parameter list)"),
- FEAT_INIT("plo-dcs", S390_FEAT_TYPE_PLO, 8, "PLO Double compare and swap (32 bit in general registers)"),
- FEAT_INIT("plo-dcsg", S390_FEAT_TYPE_PLO, 9, "PLO Double compare and swap (64 bit in parameter list)"),
- FEAT_INIT("plo-dcsgr", S390_FEAT_TYPE_PLO, 10, "PLO Double compare and swap (32 bit in general registers)"),
- FEAT_INIT("plo-dcsx", S390_FEAT_TYPE_PLO, 11, "PLO Double compare and swap (128 bit in parameter list)"),
- FEAT_INIT("plo-csst", S390_FEAT_TYPE_PLO, 12, "PLO Compare and swap and store (32 bit in general registers)"),
- FEAT_INIT("plo-csstg", S390_FEAT_TYPE_PLO, 13, "PLO Compare and swap and store (64 bit in parameter list)"),
- FEAT_INIT("plo-csstgr", S390_FEAT_TYPE_PLO, 14, "PLO Compare and swap and store (32 bit in general registers)"),
- FEAT_INIT("plo-csstx", S390_FEAT_TYPE_PLO, 15, "PLO Compare and swap and store (128 bit in parameter list)"),
- FEAT_INIT("plo-csdst", S390_FEAT_TYPE_PLO, 16, "PLO Compare and swap and double store (32 bit in general registers)"),
- FEAT_INIT("plo-csdstg", S390_FEAT_TYPE_PLO, 17, "PLO Compare and swap and double store (64 bit in parameter list)"),
- FEAT_INIT("plo-csdstgr", S390_FEAT_TYPE_PLO, 18, "PLO Compare and swap and double store (32 bit in general registers)"),
- FEAT_INIT("plo-csdstx", S390_FEAT_TYPE_PLO, 19, "PLO Compare and swap and double store (128 bit in parameter list)"),
- FEAT_INIT("plo-cstst", S390_FEAT_TYPE_PLO, 20, "PLO Compare and swap and triple store (32 bit in general registers)"),
- FEAT_INIT("plo-cststg", S390_FEAT_TYPE_PLO, 21, "PLO Compare and swap and triple store (64 bit in parameter list)"),
- FEAT_INIT("plo-cststgr", S390_FEAT_TYPE_PLO, 22, "PLO Compare and swap and triple store (32 bit in general registers)"),
- FEAT_INIT("plo-cststx", S390_FEAT_TYPE_PLO, 23, "PLO Compare and swap and triple store (128 bit in parameter list)"),
-
- FEAT_INIT("ptff-qto", S390_FEAT_TYPE_PTFF, 1, "PTFF Query TOD Offset"),
- FEAT_INIT("ptff-qsi", S390_FEAT_TYPE_PTFF, 2, "PTFF Query Steering Information"),
- FEAT_INIT("ptff-qpc", S390_FEAT_TYPE_PTFF, 3, "PTFF Query Physical Clock"),
- FEAT_INIT("ptff-qui", S390_FEAT_TYPE_PTFF, 4, "PTFF Query UTC Information"),
- FEAT_INIT("ptff-qtou", S390_FEAT_TYPE_PTFF, 5, "PTFF Query TOD Offset User"),
- FEAT_INIT("ptff-qsie", S390_FEAT_TYPE_PTFF, 10, "PTFF Query Steering Information Extended"),
- FEAT_INIT("ptff-qtoue", S390_FEAT_TYPE_PTFF, 13, "PTFF Query TOD Offset User Extended"),
- FEAT_INIT("ptff-sto", S390_FEAT_TYPE_PTFF, 65, "PTFF Set TOD Offset"),
- FEAT_INIT("ptff-stou", S390_FEAT_TYPE_PTFF, 69, "PTFF Set TOD Offset User"),
- FEAT_INIT("ptff-stoe", S390_FEAT_TYPE_PTFF, 73, "PTFF Set TOD Offset Extended"),
- FEAT_INIT("ptff-stoue", S390_FEAT_TYPE_PTFF, 77, "PTFF Set TOD Offset User Extended"),
-
- FEAT_INIT("kmac-dea", S390_FEAT_TYPE_KMAC, 1, "KMAC DEA"),
- FEAT_INIT("kmac-tdea-128", S390_FEAT_TYPE_KMAC, 2, "KMAC TDEA-128"),
- FEAT_INIT("kmac-tdea-192", S390_FEAT_TYPE_KMAC, 3, "KMAC TDEA-192"),
- FEAT_INIT("kmac-edea", S390_FEAT_TYPE_KMAC, 9, "KMAC Encrypted-DEA"),
- FEAT_INIT("kmac-etdea-128", S390_FEAT_TYPE_KMAC, 10, "KMAC Encrypted-TDEA-128"),
- FEAT_INIT("kmac-etdea-192", S390_FEAT_TYPE_KMAC, 11, "KMAC Encrypted-TDEA-192"),
- FEAT_INIT("kmac-aes-128", S390_FEAT_TYPE_KMAC, 18, "KMAC AES-128"),
- FEAT_INIT("kmac-aes-192", S390_FEAT_TYPE_KMAC, 19, "KMAC AES-192"),
- FEAT_INIT("kmac-aes-256", S390_FEAT_TYPE_KMAC, 20, "KMAC AES-256"),
- FEAT_INIT("kmac-eaes-128", S390_FEAT_TYPE_KMAC, 26, "KMAC Encrypted-AES-128"),
- FEAT_INIT("kmac-eaes-192", S390_FEAT_TYPE_KMAC, 27, "KMAC Encrypted-AES-192"),
- FEAT_INIT("kmac-eaes-256", S390_FEAT_TYPE_KMAC, 28, "KMAC Encrypted-AES-256"),
-
- FEAT_INIT("kmc-dea", S390_FEAT_TYPE_KMC, 1, "KMC DEA"),
- FEAT_INIT("kmc-tdea-128", S390_FEAT_TYPE_KMC, 2, "KMC TDEA-128"),
- FEAT_INIT("kmc-tdea-192", S390_FEAT_TYPE_KMC, 3, "KMC TDEA-192"),
- FEAT_INIT("kmc-edea", S390_FEAT_TYPE_KMC, 9, "KMC Encrypted-DEA"),
- FEAT_INIT("kmc-etdea-128", S390_FEAT_TYPE_KMC, 10, "KMC Encrypted-TDEA-128"),
- FEAT_INIT("kmc-etdea-192", S390_FEAT_TYPE_KMC, 11, "KMC Encrypted-TDEA-192"),
- FEAT_INIT("kmc-aes-128", S390_FEAT_TYPE_KMC, 18, "KMC AES-128"),
- FEAT_INIT("kmc-aes-192", S390_FEAT_TYPE_KMC, 19, "KMC AES-192"),
- FEAT_INIT("kmc-aes-256", S390_FEAT_TYPE_KMC, 20, "KMC AES-256"),
- FEAT_INIT("kmc-eaes-128", S390_FEAT_TYPE_KMC, 26, "KMC Encrypted-AES-128"),
- FEAT_INIT("kmc-eaes-192", S390_FEAT_TYPE_KMC, 27, "KMC Encrypted-AES-192"),
- FEAT_INIT("kmc-eaes-256", S390_FEAT_TYPE_KMC, 28, "KMC Encrypted-AES-256"),
- FEAT_INIT("kmc-prng", S390_FEAT_TYPE_KMC, 67, "KMC PRNG"),
-
- FEAT_INIT("km-dea", S390_FEAT_TYPE_KM, 1, "KM DEA"),
- FEAT_INIT("km-tdea-128", S390_FEAT_TYPE_KM, 2, "KM TDEA-128"),
- FEAT_INIT("km-tdea-192", S390_FEAT_TYPE_KM, 3, "KM TDEA-192"),
- FEAT_INIT("km-edea", S390_FEAT_TYPE_KM, 9, "KM Encrypted-DEA"),
- FEAT_INIT("km-etdea-128", S390_FEAT_TYPE_KM, 10, "KM Encrypted-TDEA-128"),
- FEAT_INIT("km-etdea-192", S390_FEAT_TYPE_KM, 11, "KM Encrypted-TDEA-192"),
- FEAT_INIT("km-aes-128", S390_FEAT_TYPE_KM, 18, "KM AES-128"),
- FEAT_INIT("km-aes-192", S390_FEAT_TYPE_KM, 19, "KM AES-192"),
- FEAT_INIT("km-aes-256", S390_FEAT_TYPE_KM, 20, "KM AES-256"),
- FEAT_INIT("km-eaes-128", S390_FEAT_TYPE_KM, 26, "KM Encrypted-AES-128"),
- FEAT_INIT("km-eaes-192", S390_FEAT_TYPE_KM, 27, "KM Encrypted-AES-192"),
- FEAT_INIT("km-eaes-256", S390_FEAT_TYPE_KM, 28, "KM Encrypted-AES-256"),
- FEAT_INIT("km-xts-aes-128", S390_FEAT_TYPE_KM, 50, "KM XTS-AES-128"),
- FEAT_INIT("km-xts-aes-256", S390_FEAT_TYPE_KM, 52, "KM XTS-AES-256"),
- FEAT_INIT("km-xts-eaes-128", S390_FEAT_TYPE_KM, 58, "KM XTS-Encrypted-AES-128"),
- FEAT_INIT("km-xts-eaes-256", S390_FEAT_TYPE_KM, 60, "KM XTS-Encrypted-AES-256"),
-
- FEAT_INIT("kimd-sha-1", S390_FEAT_TYPE_KIMD, 1, "KIMD SHA-1"),
- FEAT_INIT("kimd-sha-256", S390_FEAT_TYPE_KIMD, 2, "KIMD SHA-256"),
- FEAT_INIT("kimd-sha-512", S390_FEAT_TYPE_KIMD, 3, "KIMD SHA-512"),
- FEAT_INIT("kimd-sha3-224", S390_FEAT_TYPE_KIMD, 32, "KIMD SHA3-224"),
- FEAT_INIT("kimd-sha3-256", S390_FEAT_TYPE_KIMD, 33, "KIMD SHA3-256"),
- FEAT_INIT("kimd-sha3-384", S390_FEAT_TYPE_KIMD, 34, "KIMD SHA3-384"),
- FEAT_INIT("kimd-sha3-512", S390_FEAT_TYPE_KIMD, 35, "KIMD SHA3-512"),
- FEAT_INIT("kimd-shake-128", S390_FEAT_TYPE_KIMD, 36, "KIMD SHAKE-128"),
- FEAT_INIT("kimd-shake-256", S390_FEAT_TYPE_KIMD, 37, "KIMD SHAKE-256"),
- FEAT_INIT("kimd-ghash", S390_FEAT_TYPE_KIMD, 65, "KIMD GHASH"),
-
- FEAT_INIT("klmd-sha-1", S390_FEAT_TYPE_KLMD, 1, "KLMD SHA-1"),
- FEAT_INIT("klmd-sha-256", S390_FEAT_TYPE_KLMD, 2, "KLMD SHA-256"),
- FEAT_INIT("klmd-sha-512", S390_FEAT_TYPE_KLMD, 3, "KLMD SHA-512"),
- FEAT_INIT("klmd-sha3-224", S390_FEAT_TYPE_KLMD, 32, "KLMD SHA3-224"),
- FEAT_INIT("klmd-sha3-256", S390_FEAT_TYPE_KLMD, 33, "KLMD SHA3-256"),
- FEAT_INIT("klmd-sha3-384", S390_FEAT_TYPE_KLMD, 34, "KLMD SHA3-384"),
- FEAT_INIT("klmd-sha3-512", S390_FEAT_TYPE_KLMD, 35, "KLMD SHA3-512"),
- FEAT_INIT("klmd-shake-128", S390_FEAT_TYPE_KLMD, 36, "KLMD SHAKE-128"),
- FEAT_INIT("klmd-shake-256", S390_FEAT_TYPE_KLMD, 37, "KLMD SHAKE-256"),
-
- FEAT_INIT("pckmo-edea", S390_FEAT_TYPE_PCKMO, 1, "PCKMO Encrypted-DEA-Key"),
- FEAT_INIT("pckmo-etdea-128", S390_FEAT_TYPE_PCKMO, 2, "PCKMO Encrypted-TDEA-128-Key"),
- FEAT_INIT("pckmo-etdea-192", S390_FEAT_TYPE_PCKMO, 3, "PCKMO Encrypted-TDEA-192-Key"),
- FEAT_INIT("pckmo-aes-128", S390_FEAT_TYPE_PCKMO, 18, "PCKMO Encrypted-AES-128-Key"),
- FEAT_INIT("pckmo-aes-192", S390_FEAT_TYPE_PCKMO, 19, "PCKMO Encrypted-AES-192-Key"),
- FEAT_INIT("pckmo-aes-256", S390_FEAT_TYPE_PCKMO, 20, "PCKMO Encrypted-AES-256-Key"),
- FEAT_INIT("pckmo-ecc-p256", S390_FEAT_TYPE_PCKMO, 32, "PCKMO Encrypt-ECC-P256-Key"),
- FEAT_INIT("pckmo-ecc-p384", S390_FEAT_TYPE_PCKMO, 33, "PCKMO Encrypt-ECC-P384-Key"),
- FEAT_INIT("pckmo-ecc-p521", S390_FEAT_TYPE_PCKMO, 34, "PCKMO Encrypt-ECC-P521-Key"),
- FEAT_INIT("pckmo-ecc-ed25519", S390_FEAT_TYPE_PCKMO, 40 , "PCKMO Encrypt-ECC-Ed25519-Key"),
- FEAT_INIT("pckmo-ecc-ed448", S390_FEAT_TYPE_PCKMO, 41 , "PCKMO Encrypt-ECC-Ed448-Key"),
-
- FEAT_INIT("kmctr-dea", S390_FEAT_TYPE_KMCTR, 1, "KMCTR DEA"),
- FEAT_INIT("kmctr-tdea-128", S390_FEAT_TYPE_KMCTR, 2, "KMCTR TDEA-128"),
- FEAT_INIT("kmctr-tdea-192", S390_FEAT_TYPE_KMCTR, 3, "KMCTR TDEA-192"),
- FEAT_INIT("kmctr-edea", S390_FEAT_TYPE_KMCTR, 9, "KMCTR Encrypted-DEA"),
- FEAT_INIT("kmctr-etdea-128", S390_FEAT_TYPE_KMCTR, 10, "KMCTR Encrypted-TDEA-128"),
- FEAT_INIT("kmctr-etdea-192", S390_FEAT_TYPE_KMCTR, 11, "KMCTR Encrypted-TDEA-192"),
- FEAT_INIT("kmctr-aes-128", S390_FEAT_TYPE_KMCTR, 18, "KMCTR AES-128"),
- FEAT_INIT("kmctr-aes-192", S390_FEAT_TYPE_KMCTR, 19, "KMCTR AES-192"),
- FEAT_INIT("kmctr-aes-256", S390_FEAT_TYPE_KMCTR, 20, "KMCTR AES-256"),
- FEAT_INIT("kmctr-eaes-128", S390_FEAT_TYPE_KMCTR, 26, "KMCTR Encrypted-AES-128"),
- FEAT_INIT("kmctr-eaes-192", S390_FEAT_TYPE_KMCTR, 27, "KMCTR Encrypted-AES-192"),
- FEAT_INIT("kmctr-eaes-256", S390_FEAT_TYPE_KMCTR, 28, "KMCTR Encrypted-AES-256"),
-
- FEAT_INIT("kmf-dea", S390_FEAT_TYPE_KMF, 1, "KMF DEA"),
- FEAT_INIT("kmf-tdea-128", S390_FEAT_TYPE_KMF, 2, "KMF TDEA-128"),
- FEAT_INIT("kmf-tdea-192", S390_FEAT_TYPE_KMF, 3, "KMF TDEA-192"),
- FEAT_INIT("kmf-edea", S390_FEAT_TYPE_KMF, 9, "KMF Encrypted-DEA"),
- FEAT_INIT("kmf-etdea-128", S390_FEAT_TYPE_KMF, 10, "KMF Encrypted-TDEA-128"),
- FEAT_INIT("kmf-etdea-192", S390_FEAT_TYPE_KMF, 11, "KMF Encrypted-TDEA-192"),
- FEAT_INIT("kmf-aes-128", S390_FEAT_TYPE_KMF, 18, "KMF AES-128"),
- FEAT_INIT("kmf-aes-192", S390_FEAT_TYPE_KMF, 19, "KMF AES-192"),
- FEAT_INIT("kmf-aes-256", S390_FEAT_TYPE_KMF, 20, "KMF AES-256"),
- FEAT_INIT("kmf-eaes-128", S390_FEAT_TYPE_KMF, 26, "KMF Encrypted-AES-128"),
- FEAT_INIT("kmf-eaes-192", S390_FEAT_TYPE_KMF, 27, "KMF Encrypted-AES-192"),
- FEAT_INIT("kmf-eaes-256", S390_FEAT_TYPE_KMF, 28, "KMF Encrypted-AES-256"),
-
- FEAT_INIT("kmo-dea", S390_FEAT_TYPE_KMO, 1, "KMO DEA"),
- FEAT_INIT("kmo-tdea-128", S390_FEAT_TYPE_KMO, 2, "KMO TDEA-128"),
- FEAT_INIT("kmo-tdea-192", S390_FEAT_TYPE_KMO, 3, "KMO TDEA-192"),
- FEAT_INIT("kmo-edea", S390_FEAT_TYPE_KMO, 9, "KMO Encrypted-DEA"),
- FEAT_INIT("kmo-etdea-128", S390_FEAT_TYPE_KMO, 10, "KMO Encrypted-TDEA-128"),
- FEAT_INIT("kmo-etdea-192", S390_FEAT_TYPE_KMO, 11, "KMO Encrypted-TDEA-192"),
- FEAT_INIT("kmo-aes-128", S390_FEAT_TYPE_KMO, 18, "KMO AES-128"),
- FEAT_INIT("kmo-aes-192", S390_FEAT_TYPE_KMO, 19, "KMO AES-192"),
- FEAT_INIT("kmo-aes-256", S390_FEAT_TYPE_KMO, 20, "KMO AES-256"),
- FEAT_INIT("kmo-eaes-128", S390_FEAT_TYPE_KMO, 26, "KMO Encrypted-AES-128"),
- FEAT_INIT("kmo-eaes-192", S390_FEAT_TYPE_KMO, 27, "KMO Encrypted-AES-192"),
- FEAT_INIT("kmo-eaes-256", S390_FEAT_TYPE_KMO, 28, "KMO Encrypted-AES-256"),
-
- FEAT_INIT("pcc-cmac-dea", S390_FEAT_TYPE_PCC, 1, "PCC Compute-Last-Block-CMAC-Using-DEA"),
- FEAT_INIT("pcc-cmac-tdea-128", S390_FEAT_TYPE_PCC, 2, "PCC Compute-Last-Block-CMAC-Using-TDEA-128"),
- FEAT_INIT("pcc-cmac-tdea-192", S390_FEAT_TYPE_PCC, 3, "PCC Compute-Last-Block-CMAC-Using-TDEA-192"),
- FEAT_INIT("pcc-cmac-edea", S390_FEAT_TYPE_PCC, 9, "PCC Compute-Last-Block-CMAC-Using-Encrypted-DEA"),
- FEAT_INIT("pcc-cmac-etdea-128", S390_FEAT_TYPE_PCC, 10, "PCC Compute-Last-Block-CMAC-Using-Encrypted-TDEA-128"),
- FEAT_INIT("pcc-cmac-etdea-192", S390_FEAT_TYPE_PCC, 11, "PCC Compute-Last-Block-CMAC-Using-EncryptedTDEA-192"),
- FEAT_INIT("pcc-cmac-aes-128", S390_FEAT_TYPE_PCC, 18, "PCC Compute-Last-Block-CMAC-Using-AES-128"),
- FEAT_INIT("pcc-cmac-aes-192", S390_FEAT_TYPE_PCC, 19, "PCC Compute-Last-Block-CMAC-Using-AES-192"),
- FEAT_INIT("pcc-cmac-eaes-256", S390_FEAT_TYPE_PCC, 20, "PCC Compute-Last-Block-CMAC-Using-AES-256"),
- FEAT_INIT("pcc-cmac-eaes-128", S390_FEAT_TYPE_PCC, 26, "PCC Compute-Last-Block-CMAC-Using-Encrypted-AES-128"),
- FEAT_INIT("pcc-cmac-eaes-192", S390_FEAT_TYPE_PCC, 27, "PCC Compute-Last-Block-CMAC-Using-Encrypted-AES-192"),
- FEAT_INIT("pcc-cmac-eaes-256", S390_FEAT_TYPE_PCC, 28, "PCC Compute-Last-Block-CMAC-Using-Encrypted-AES-256"),
- FEAT_INIT("pcc-xts-aes-128", S390_FEAT_TYPE_PCC, 50, "PCC Compute-XTS-Parameter-Using-AES-128"),
- FEAT_INIT("pcc-xts-aes-256", S390_FEAT_TYPE_PCC, 52, "PCC Compute-XTS-Parameter-Using-AES-256"),
- FEAT_INIT("pcc-xts-eaes-128", S390_FEAT_TYPE_PCC, 58, "PCC Compute-XTS-Parameter-Using-Encrypted-AES-128"),
- FEAT_INIT("pcc-xts-eaes-256", S390_FEAT_TYPE_PCC, 60, "PCC Compute-XTS-Parameter-Using-Encrypted-AES-256"),
- FEAT_INIT("pcc-scalar-mult-p256", S390_FEAT_TYPE_PCC, 64, "PCC Scalar-Multiply-P256"),
- FEAT_INIT("pcc-scalar-mult-p384", S390_FEAT_TYPE_PCC, 65, "PCC Scalar-Multiply-P384"),
- FEAT_INIT("pcc-scalar-mult-p521", S390_FEAT_TYPE_PCC, 66, "PCC Scalar-Multiply-P521"),
- FEAT_INIT("pcc-scalar-mult-ed25519", S390_FEAT_TYPE_PCC, 72, "PCC Scalar-Multiply-Ed25519"),
- FEAT_INIT("pcc-scalar-mult-ed448", S390_FEAT_TYPE_PCC, 73, "PCC Scalar-Multiply-Ed448"),
- FEAT_INIT("pcc-scalar-mult-x25519", S390_FEAT_TYPE_PCC, 80, "PCC Scalar-Multiply-X25519"),
- FEAT_INIT("pcc-scalar-mult-x448", S390_FEAT_TYPE_PCC, 81, "PCC Scalar-Multiply-X448"),
-
- FEAT_INIT("ppno-sha-512-drng", S390_FEAT_TYPE_PPNO, 3, "PPNO SHA-512-DRNG"),
- FEAT_INIT("prno-trng-qrtcr", S390_FEAT_TYPE_PPNO, 112, "PRNO TRNG-Query-Raw-to-Conditioned-Ratio"),
- FEAT_INIT("prno-trng", S390_FEAT_TYPE_PPNO, 114, "PRNO TRNG"),
-
- FEAT_INIT("kma-gcm-aes-128", S390_FEAT_TYPE_KMA, 18, "KMA GCM-AES-128"),
- FEAT_INIT("kma-gcm-aes-192", S390_FEAT_TYPE_KMA, 19, "KMA GCM-AES-192"),
- FEAT_INIT("kma-gcm-aes-256", S390_FEAT_TYPE_KMA, 20, "KMA GCM-AES-256"),
- FEAT_INIT("kma-gcm-eaes-128", S390_FEAT_TYPE_KMA, 26, "KMA GCM-Encrypted-AES-128"),
- FEAT_INIT("kma-gcm-eaes-192", S390_FEAT_TYPE_KMA, 27, "KMA GCM-Encrypted-AES-192"),
- FEAT_INIT("kma-gcm-eaes-256", S390_FEAT_TYPE_KMA, 28, "KMA GCM-Encrypted-AES-256"),
-
- FEAT_INIT("kdsa-ecdsa-verify-p256", S390_FEAT_TYPE_KDSA, 1, "KDSA ECDSA-Verify-P256"),
- FEAT_INIT("kdsa-ecdsa-verify-p384", S390_FEAT_TYPE_KDSA, 2, "KDSA ECDSA-Verify-P384"),
- FEAT_INIT("kdsa-ecdsa-verify-p521", S390_FEAT_TYPE_KDSA, 3, "KDSA ECDSA-Verify-P521"),
- FEAT_INIT("kdsa-ecdsa-sign-p256", S390_FEAT_TYPE_KDSA, 9, "KDSA ECDSA-Sign-P256"),
- FEAT_INIT("kdsa-ecdsa-sign-p384", S390_FEAT_TYPE_KDSA, 10, "KDSA ECDSA-Sign-P384"),
- FEAT_INIT("kdsa-ecdsa-sign-p521", S390_FEAT_TYPE_KDSA, 11, "KDSA ECDSA-Sign-P521"),
- FEAT_INIT("kdsa-eecdsa-sign-p256", S390_FEAT_TYPE_KDSA, 17, "KDSA Encrypted-ECDSA-Sign-P256"),
- FEAT_INIT("kdsa-eecdsa-sign-p384", S390_FEAT_TYPE_KDSA, 18, "KDSA Encrypted-ECDSA-Sign-P384"),
- FEAT_INIT("kdsa-eecdsa-sign-p521", S390_FEAT_TYPE_KDSA, 19, "KDSA Encrypted-ECDSA-Sign-P521"),
- FEAT_INIT("kdsa-eddsa-verify-ed25519", S390_FEAT_TYPE_KDSA, 32, "KDSA EdDSA-Verify-Ed25519"),
- FEAT_INIT("kdsa-eddsa-verify-ed448", S390_FEAT_TYPE_KDSA, 36, "KDSA EdDSA-Verify-Ed448"),
- FEAT_INIT("kdsa-eddsa-sign-ed25519", S390_FEAT_TYPE_KDSA, 40, "KDSA EdDSA-Sign-Ed25519"),
- FEAT_INIT("kdsa-eddsa-sign-ed448", S390_FEAT_TYPE_KDSA, 44, "KDSA EdDSA-Sign-Ed448"),
- FEAT_INIT("kdsa-eeddsa-sign-ed25519", S390_FEAT_TYPE_KDSA, 48, "KDSA Encrypted-EdDSA-Sign-Ed25519"),
- FEAT_INIT("kdsa-eeddsa-sign-ed448", S390_FEAT_TYPE_KDSA, 52, "KDSA Encrypted-EdDSA-Sign-Ed448"),
-
- FEAT_INIT("sortl-sflr", S390_FEAT_TYPE_SORTL, 1, "SORTL SFLR"),
- FEAT_INIT("sortl-svlr", S390_FEAT_TYPE_SORTL, 2, "SORTL SVLR"),
- FEAT_INIT("sortl-32", S390_FEAT_TYPE_SORTL, 130, "SORTL 32 input lists"),
- FEAT_INIT("sortl-128", S390_FEAT_TYPE_SORTL, 132, "SORTL 128 input lists"),
- FEAT_INIT("sortl-f0", S390_FEAT_TYPE_SORTL, 192, "SORTL format 0 parameter-block"),
-
- FEAT_INIT("dfltcc-gdht", S390_FEAT_TYPE_DFLTCC, 1, "DFLTCC GDHT"),
- FEAT_INIT("dfltcc-cmpr", S390_FEAT_TYPE_DFLTCC, 2, "DFLTCC CMPR"),
- FEAT_INIT("dfltcc-xpnd", S390_FEAT_TYPE_DFLTCC, 4, "DFLTCC XPND"),
- FEAT_INIT("dfltcc-f0", S390_FEAT_TYPE_DFLTCC, 192, "DFLTCC format 0 parameter-block"),
+#define DEF_FEAT(_FEAT, _NAME, _TYPE, _BIT, _DESC) \
+ [S390_FEAT_##_FEAT] = { \
+ .name = _NAME, \
+ .type = S390_FEAT_TYPE_##_TYPE, \
+ .bit = _BIT, \
+ .desc = _DESC, \
+ },
+static const S390FeatDef s390_features[S390_FEAT_MAX] = {
+ #include "cpu_features_def.inc.h"
};
+#undef DEF_FEAT
const S390FeatDef *s390_feat_def(S390Feat feat)
{
* CPU features/facilities for s390
*
* Copyright IBM Corp. 2016, 2018
+ * Copyright Red Hat, Inc. 2019
*
* Author(s): Michael Mueller <mimu@linux.vnet.ibm.com>
- * David Hildenbrand <dahi@linux.vnet.ibm.com>
+ * David Hildenbrand <david@redhat.com>
*
* This work is licensed under the terms of the GNU GPL, version 2 or (at
* your option) any later version. See the COPYING file in the top-level
#ifndef TARGET_S390X_CPU_FEATURES_DEF_H
#define TARGET_S390X_CPU_FEATURES_DEF_H
+#define DEF_FEAT(_FEAT, ...) S390_FEAT_##_FEAT,
typedef enum {
- /* Stfle */
- S390_FEAT_ESAN3 = 0,
- S390_FEAT_ZARCH,
- S390_FEAT_DAT_ENH,
- S390_FEAT_IDTE_SEGMENT,
- S390_FEAT_IDTE_REGION,
- S390_FEAT_ASN_LX_REUSE,
- S390_FEAT_STFLE,
- S390_FEAT_EDAT,
- S390_FEAT_SENSE_RUNNING_STATUS,
- S390_FEAT_CONDITIONAL_SSKE,
- S390_FEAT_CONFIGURATION_TOPOLOGY,
- S390_FEAT_AP_QUERY_CONFIG_INFO,
- S390_FEAT_IPTE_RANGE,
- S390_FEAT_NONQ_KEY_SETTING,
- S390_FEAT_AP_FACILITIES_TEST,
- S390_FEAT_EXTENDED_TRANSLATION_2,
- S390_FEAT_MSA,
- S390_FEAT_LONG_DISPLACEMENT,
- S390_FEAT_LONG_DISPLACEMENT_FAST,
- S390_FEAT_HFP_MADDSUB,
- S390_FEAT_EXTENDED_IMMEDIATE,
- S390_FEAT_EXTENDED_TRANSLATION_3,
- S390_FEAT_HFP_UNNORMALIZED_EXT,
- S390_FEAT_ETF2_ENH,
- S390_FEAT_STORE_CLOCK_FAST,
- S390_FEAT_PARSING_ENH,
- S390_FEAT_MOVE_WITH_OPTIONAL_SPEC,
- S390_FEAT_TOD_CLOCK_STEERING,
- S390_FEAT_ETF3_ENH,
- S390_FEAT_EXTRACT_CPU_TIME,
- S390_FEAT_COMPARE_AND_SWAP_AND_STORE,
- S390_FEAT_COMPARE_AND_SWAP_AND_STORE_2,
- S390_FEAT_GENERAL_INSTRUCTIONS_EXT,
- S390_FEAT_EXECUTE_EXT,
- S390_FEAT_ENHANCED_MONITOR,
- S390_FEAT_FLOATING_POINT_EXT,
- S390_FEAT_ORDER_PRESERVING_COMPRESSION,
- S390_FEAT_SET_PROGRAM_PARAMETERS,
- S390_FEAT_FLOATING_POINT_SUPPPORT_ENH,
- S390_FEAT_DFP,
- S390_FEAT_DFP_FAST,
- S390_FEAT_PFPO,
- S390_FEAT_STFLE_45,
- S390_FEAT_CMPSC_ENH,
- S390_FEAT_DFP_ZONED_CONVERSION,
- S390_FEAT_STFLE_49,
- S390_FEAT_CONSTRAINT_TRANSACTIONAL_EXE,
- S390_FEAT_LOCAL_TLB_CLEARING,
- S390_FEAT_INTERLOCKED_ACCESS_2,
- S390_FEAT_STFLE_53,
- S390_FEAT_ENTROPY_ENC_COMP,
- S390_FEAT_MSA_EXT_5,
- S390_FEAT_MISC_INSTRUCTION_EXT,
- S390_FEAT_SEMAPHORE_ASSIST,
- S390_FEAT_TIME_SLICE_INSTRUMENTATION,
- S390_FEAT_MISC_INSTRUCTION_EXT3,
- S390_FEAT_RUNTIME_INSTRUMENTATION,
- S390_FEAT_ZPCI,
- S390_FEAT_ADAPTER_EVENT_NOTIFICATION,
- S390_FEAT_ADAPTER_INT_SUPPRESSION,
- S390_FEAT_TRANSACTIONAL_EXE,
- S390_FEAT_STORE_HYPERVISOR_INFO,
- S390_FEAT_ACCESS_EXCEPTION_FS_INDICATION,
- S390_FEAT_MSA_EXT_3,
- S390_FEAT_MSA_EXT_4,
- S390_FEAT_EDAT_2,
- S390_FEAT_DFP_PACKED_CONVERSION,
- S390_FEAT_PPA15,
- S390_FEAT_BPB,
- S390_FEAT_VECTOR,
- S390_FEAT_INSTRUCTION_EXEC_PROT,
- S390_FEAT_SIDE_EFFECT_ACCESS_ESOP2,
- S390_FEAT_GUARDED_STORAGE,
- S390_FEAT_VECTOR_PACKED_DECIMAL,
- S390_FEAT_VECTOR_ENH,
- S390_FEAT_MULTIPLE_EPOCH,
- S390_FEAT_TEST_PENDING_EXT_INTERRUPTION,
- S390_FEAT_INSERT_REFERENCE_BITS_MULT,
- S390_FEAT_MSA_EXT_8,
- S390_FEAT_CMM_NT,
- S390_FEAT_VECTOR_ENH2,
- S390_FEAT_ESORT_BASE,
- S390_FEAT_DEFLATE_BASE,
- S390_FEAT_VECTOR_BCD_ENH,
- S390_FEAT_MSA_EXT_9,
- S390_FEAT_ETOKEN,
-
- /* Sclp Conf Char */
- S390_FEAT_SIE_GSLS,
- S390_FEAT_ESOP,
- S390_FEAT_HPMA2,
- S390_FEAT_SIE_KSS,
-
- /* Sclp Conf Char Ext */
- S390_FEAT_SIE_64BSCAO,
- S390_FEAT_SIE_CMMA,
- S390_FEAT_SIE_PFMFI,
- S390_FEAT_SIE_IBS,
-
- /* Sclp Cpu */
- S390_FEAT_SIE_F2,
- S390_FEAT_SIE_SKEY,
- S390_FEAT_SIE_GPERE,
- S390_FEAT_SIE_SIIF,
- S390_FEAT_SIE_SIGPIF,
- S390_FEAT_SIE_IB,
- S390_FEAT_SIE_CEI,
-
- /* Misc */
- S390_FEAT_DAT_ENH_2,
- S390_FEAT_CMM,
- S390_FEAT_AP,
-
- /* PLO */
- S390_FEAT_PLO_CL,
- S390_FEAT_PLO_CLG,
- S390_FEAT_PLO_CLGR,
- S390_FEAT_PLO_CLX,
- S390_FEAT_PLO_CS,
- S390_FEAT_PLO_CSG,
- S390_FEAT_PLO_CSGR,
- S390_FEAT_PLO_CSX,
- S390_FEAT_PLO_DCS,
- S390_FEAT_PLO_DCSG,
- S390_FEAT_PLO_DCSGR,
- S390_FEAT_PLO_DCSX,
- S390_FEAT_PLO_CSST,
- S390_FEAT_PLO_CSSTG,
- S390_FEAT_PLO_CSSTGR,
- S390_FEAT_PLO_CSSTX,
- S390_FEAT_PLO_CSDST,
- S390_FEAT_PLO_CSDSTG,
- S390_FEAT_PLO_CSDSTGR,
- S390_FEAT_PLO_CSDSTX,
- S390_FEAT_PLO_CSTST,
- S390_FEAT_PLO_CSTSTG,
- S390_FEAT_PLO_CSTSTGR,
- S390_FEAT_PLO_CSTSTX,
-
- /* PTFF */
- S390_FEAT_PTFF_QTO,
- S390_FEAT_PTFF_QSI,
- S390_FEAT_PTFF_QPT,
- S390_FEAT_PTFF_QUI,
- S390_FEAT_PTFF_QTOU,
- S390_FEAT_PTFF_QSIE,
- S390_FEAT_PTFF_QTOUE,
- S390_FEAT_PTFF_STO,
- S390_FEAT_PTFF_STOU,
- S390_FEAT_PTFF_STOE,
- S390_FEAT_PTFF_STOUE,
-
- /* KMAC */
- S390_FEAT_KMAC_DEA,
- S390_FEAT_KMAC_TDEA_128,
- S390_FEAT_KMAC_TDEA_192,
- S390_FEAT_KMAC_EDEA,
- S390_FEAT_KMAC_ETDEA_128,
- S390_FEAT_KMAC_ETDEA_192,
- S390_FEAT_KMAC_AES_128,
- S390_FEAT_KMAC_AES_192,
- S390_FEAT_KMAC_AES_256,
- S390_FEAT_KMAC_EAES_128,
- S390_FEAT_KMAC_EAES_192,
- S390_FEAT_KMAC_EAES_256,
-
- /* KMC */
- S390_FEAT_KMC_DEA,
- S390_FEAT_KMC_TDEA_128,
- S390_FEAT_KMC_TDEA_192,
- S390_FEAT_KMC_EDEA,
- S390_FEAT_KMC_ETDEA_128,
- S390_FEAT_KMC_ETDEA_192,
- S390_FEAT_KMC_AES_128,
- S390_FEAT_KMC_AES_192,
- S390_FEAT_KMC_AES_256,
- S390_FEAT_KMC_EAES_128,
- S390_FEAT_KMC_EAES_192,
- S390_FEAT_KMC_EAES_256,
- S390_FEAT_KMC_PRNG,
-
- /* KM */
- S390_FEAT_KM_DEA,
- S390_FEAT_KM_TDEA_128,
- S390_FEAT_KM_TDEA_192,
- S390_FEAT_KM_EDEA,
- S390_FEAT_KM_ETDEA_128,
- S390_FEAT_KM_ETDEA_192,
- S390_FEAT_KM_AES_128,
- S390_FEAT_KM_AES_192,
- S390_FEAT_KM_AES_256,
- S390_FEAT_KM_EAES_128,
- S390_FEAT_KM_EAES_192,
- S390_FEAT_KM_EAES_256,
- S390_FEAT_KM_XTS_AES_128,
- S390_FEAT_KM_XTS_AES_256,
- S390_FEAT_KM_XTS_EAES_128,
- S390_FEAT_KM_XTS_EAES_256,
-
- /* KIMD */
- S390_FEAT_KIMD_SHA_1,
- S390_FEAT_KIMD_SHA_256,
- S390_FEAT_KIMD_SHA_512,
- S390_FEAT_KIMD_SHA3_224,
- S390_FEAT_KIMD_SHA3_256,
- S390_FEAT_KIMD_SHA3_384,
- S390_FEAT_KIMD_SHA3_512,
- S390_FEAT_KIMD_SHAKE_128,
- S390_FEAT_KIMD_SHAKE_256,
- S390_FEAT_KIMD_GHASH,
-
- /* KLMD */
- S390_FEAT_KLMD_SHA_1,
- S390_FEAT_KLMD_SHA_256,
- S390_FEAT_KLMD_SHA_512,
- S390_FEAT_KLMD_SHA3_224,
- S390_FEAT_KLMD_SHA3_256,
- S390_FEAT_KLMD_SHA3_384,
- S390_FEAT_KLMD_SHA3_512,
- S390_FEAT_KLMD_SHAKE_128,
- S390_FEAT_KLMD_SHAKE_256,
-
- /* PCKMO */
- S390_FEAT_PCKMO_EDEA,
- S390_FEAT_PCKMO_ETDEA_128,
- S390_FEAT_PCKMO_ETDEA_256,
- S390_FEAT_PCKMO_AES_128,
- S390_FEAT_PCKMO_AES_192,
- S390_FEAT_PCKMO_AES_256,
- S390_FEAT_PCKMO_ECC_P256,
- S390_FEAT_PCKMO_ECC_P384,
- S390_FEAT_PCKMO_ECC_P521,
- S390_FEAT_PCKMO_ECC_ED25519,
- S390_FEAT_PCKMO_ECC_ED448,
-
- /* KMCTR */
- S390_FEAT_KMCTR_DEA,
- S390_FEAT_KMCTR_TDEA_128,
- S390_FEAT_KMCTR_TDEA_192,
- S390_FEAT_KMCTR_EDEA,
- S390_FEAT_KMCTR_ETDEA_128,
- S390_FEAT_KMCTR_ETDEA_192,
- S390_FEAT_KMCTR_AES_128,
- S390_FEAT_KMCTR_AES_192,
- S390_FEAT_KMCTR_AES_256,
- S390_FEAT_KMCTR_EAES_128,
- S390_FEAT_KMCTR_EAES_192,
- S390_FEAT_KMCTR_EAES_256,
-
- /* KMF */
- S390_FEAT_KMF_DEA,
- S390_FEAT_KMF_TDEA_128,
- S390_FEAT_KMF_TDEA_192,
- S390_FEAT_KMF_EDEA,
- S390_FEAT_KMF_ETDEA_128,
- S390_FEAT_KMF_ETDEA_192,
- S390_FEAT_KMF_AES_128,
- S390_FEAT_KMF_AES_192,
- S390_FEAT_KMF_AES_256,
- S390_FEAT_KMF_EAES_128,
- S390_FEAT_KMF_EAES_192,
- S390_FEAT_KMF_EAES_256,
-
- /* KMO */
- S390_FEAT_KMO_DEA,
- S390_FEAT_KMO_TDEA_128,
- S390_FEAT_KMO_TDEA_192,
- S390_FEAT_KMO_EDEA,
- S390_FEAT_KMO_ETDEA_128,
- S390_FEAT_KMO_ETDEA_192,
- S390_FEAT_KMO_AES_128,
- S390_FEAT_KMO_AES_192,
- S390_FEAT_KMO_AES_256,
- S390_FEAT_KMO_EAES_128,
- S390_FEAT_KMO_EAES_192,
- S390_FEAT_KMO_EAES_256,
-
- /* PCC */
- S390_FEAT_PCC_CMAC_DEA,
- S390_FEAT_PCC_CMAC_TDEA_128,
- S390_FEAT_PCC_CMAC_TDEA_192,
- S390_FEAT_PCC_CMAC_ETDEA_128,
- S390_FEAT_PCC_CMAC_ETDEA_192,
- S390_FEAT_PCC_CMAC_TDEA,
- S390_FEAT_PCC_CMAC_AES_128,
- S390_FEAT_PCC_CMAC_AES_192,
- S390_FEAT_PCC_CMAC_AES_256,
- S390_FEAT_PCC_CMAC_EAES_128,
- S390_FEAT_PCC_CMAC_EAES_192,
- S390_FEAT_PCC_CMAC_EAES_256,
- S390_FEAT_PCC_XTS_AES_128,
- S390_FEAT_PCC_XTS_AES_256,
- S390_FEAT_PCC_XTS_EAES_128,
- S390_FEAT_PCC_XTS_EAES_256,
- S390_FEAT_PCC_SCALAR_MULT_P256,
- S390_FEAT_PCC_SCALAR_MULT_P384,
- S390_FEAT_PCC_SCALAR_MULT_P512,
- S390_FEAT_PCC_SCALAR_MULT_ED25519,
- S390_FEAT_PCC_SCALAR_MULT_ED448,
- S390_FEAT_PCC_SCALAR_MULT_X25519,
- S390_FEAT_PCC_SCALAR_MULT_X448,
-
- /* PPNO/PRNO */
- S390_FEAT_PPNO_SHA_512_DRNG,
- S390_FEAT_PRNO_TRNG_QRTCR,
- S390_FEAT_PRNO_TRNG,
-
- /* KMA */
- S390_FEAT_KMA_GCM_AES_128,
- S390_FEAT_KMA_GCM_AES_192,
- S390_FEAT_KMA_GCM_AES_256 ,
- S390_FEAT_KMA_GCM_EAES_128,
- S390_FEAT_KMA_GCM_EAES_192,
- S390_FEAT_KMA_GCM_EAES_256,
-
- /* KDSA */
- S390_FEAT_ECDSA_VERIFY_P256,
- S390_FEAT_ECDSA_VERIFY_P384,
- S390_FEAT_ECDSA_VERIFY_P512,
- S390_FEAT_ECDSA_SIGN_P256,
- S390_FEAT_ECDSA_SIGN_P384,
- S390_FEAT_ECDSA_SIGN_P512,
- S390_FEAT_EECDSA_SIGN_P256,
- S390_FEAT_EECDSA_SIGN_P384,
- S390_FEAT_EECDSA_SIGN_P512,
- S390_FEAT_EDDSA_VERIFY_ED25519,
- S390_FEAT_EDDSA_VERIFY_ED448,
- S390_FEAT_EDDSA_SIGN_ED25519,
- S390_FEAT_EDDSA_SIGN_ED448,
- S390_FEAT_EEDDSA_SIGN_ED25519,
- S390_FEAT_EEDDSA_SIGN_ED448,
-
- /* SORTL */
- S390_FEAT_SORTL_SFLR,
- S390_FEAT_SORTL_SVLR,
- S390_FEAT_SORTL_32,
- S390_FEAT_SORTL_128,
- S390_FEAT_SORTL_F0,
-
- /* DEFLATE */
- S390_FEAT_DEFLATE_GHDT,
- S390_FEAT_DEFLATE_CMPR,
- S390_FEAT_DEFLATE_XPND,
- S390_FEAT_DEFLATE_F0,
-
+ #include "cpu_features_def.inc.h"
S390_FEAT_MAX,
} S390Feat;
+#undef DEF_FEAT
#endif /* TARGET_S390X_CPU_FEATURES_DEF_H */
--- /dev/null
+/*
+ * RAW s390x CPU feature definitions:
+ *
+ * DEF_FEAT(_FEAT, _NAME, _TYPE, _BIT, _DESC):
+ * - _FEAT: Feature (enum) name used internally (S390_FEAT_##_FEAT)
+ * - _NAME: Feature name exposed to the user.
+ * - _TYPE: Feature type (S390_FEAT_TYPE_##_TYPE).
+ * - _BIT: Feature bit number within feature type block (unused for MISC).
+ * - _DESC: Feature description, exposed to the user.
+ *
+ * Copyright IBM Corp. 2016, 2018
+ * Copyright Red Hat, Inc. 2019
+ *
+ * Author(s): Michael Mueller <mimu@linux.vnet.ibm.com>
+ * David Hildenbrand <david@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or (at
+ * your option) any later version. See the COPYING file in the top-level
+ * directory.
+ */
+
+/* Features exposed via the STFL(E) instruction. */
+DEF_FEAT(ESAN3, "esan3", STFL, 0, "Instructions marked as n3")
+DEF_FEAT(ZARCH, "zarch", STFL, 1, "z/Architecture architectural mode")
+DEF_FEAT(DAT_ENH, "dateh", STFL, 3, "DAT-enhancement facility")
+DEF_FEAT(IDTE_SEGMENT, "idtes", STFL, 4, "IDTE selective TLB segment-table clearing")
+DEF_FEAT(IDTE_REGION, "idter", STFL, 5, "IDTE selective TLB region-table clearing")
+DEF_FEAT(ASN_LX_REUSE, "asnlxr", STFL, 6, "ASN-and-LX reuse facility")
+DEF_FEAT(STFLE, "stfle", STFL, 7, "Store-facility-list-extended facility")
+DEF_FEAT(EDAT, "edat", STFL, 8, "Enhanced-DAT facility")
+DEF_FEAT(SENSE_RUNNING_STATUS, "srs", STFL, 9, "Sense-running-status facility")
+DEF_FEAT(CONDITIONAL_SSKE, "csske", STFL, 10, "Conditional-SSKE facility")
+DEF_FEAT(CONFIGURATION_TOPOLOGY, "ctop", STFL, 11, "Configuration-topology facility")
+DEF_FEAT(AP_QUERY_CONFIG_INFO, "apqci", STFL, 12, "Query AP Configuration Information facility")
+DEF_FEAT(IPTE_RANGE, "ipter", STFL, 13, "IPTE-range facility")
+DEF_FEAT(NONQ_KEY_SETTING, "nonqks", STFL, 14, "Nonquiescing key-setting facility")
+DEF_FEAT(AP_FACILITIES_TEST, "apft", STFL, 15, "AP Facilities Test facility")
+DEF_FEAT(EXTENDED_TRANSLATION_2, "etf2", STFL, 16, "Extended-translation facility 2")
+DEF_FEAT(MSA, "msa-base", STFL, 17, "Message-security-assist facility (excluding subfunctions)")
+DEF_FEAT(LONG_DISPLACEMENT, "ldisp", STFL, 18, "Long-displacement facility")
+DEF_FEAT(LONG_DISPLACEMENT_FAST, "ldisphp", STFL, 19, "Long-displacement facility has high performance")
+DEF_FEAT(HFP_MADDSUB, "hfpm", STFL, 20, "HFP-multiply-add/subtract facility")
+DEF_FEAT(EXTENDED_IMMEDIATE, "eimm", STFL, 21, "Extended-immediate facility")
+DEF_FEAT(EXTENDED_TRANSLATION_3, "etf3", STFL, 22, "Extended-translation facility 3")
+DEF_FEAT(HFP_UNNORMALIZED_EXT, "hfpue", STFL, 23, "HFP-unnormalized-extension facility")
+DEF_FEAT(ETF2_ENH, "etf2eh", STFL, 24, "ETF2-enhancement facility")
+DEF_FEAT(STORE_CLOCK_FAST, "stckf", STFL, 25, "Store-clock-fast facility")
+DEF_FEAT(PARSING_ENH, "parseh", STFL, 26, "Parsing-enhancement facility")
+DEF_FEAT(MOVE_WITH_OPTIONAL_SPEC, "mvcos", STFL, 27, "Move-with-optional-specification facility")
+DEF_FEAT(TOD_CLOCK_STEERING, "tods-base", STFL, 28, "TOD-clock-steering facility (excluding subfunctions)")
+DEF_FEAT(ETF3_ENH, "etf3eh", STFL, 30, "ETF3-enhancement facility")
+DEF_FEAT(EXTRACT_CPU_TIME, "ectg", STFL, 31, "Extract-CPU-time facility")
+DEF_FEAT(COMPARE_AND_SWAP_AND_STORE, "csst", STFL, 32, "Compare-and-swap-and-store facility")
+DEF_FEAT(COMPARE_AND_SWAP_AND_STORE_2, "csst2", STFL, 33, "Compare-and-swap-and-store facility 2")
+DEF_FEAT(GENERAL_INSTRUCTIONS_EXT, "ginste", STFL, 34, "General-instructions-extension facility")
+DEF_FEAT(EXECUTE_EXT, "exrl", STFL, 35, "Execute-extensions facility")
+DEF_FEAT(ENHANCED_MONITOR, "emon", STFL, 36, "Enhanced-monitor facility")
+DEF_FEAT(FLOATING_POINT_EXT, "fpe", STFL, 37, "Floating-point extension facility")
+DEF_FEAT(ORDER_PRESERVING_COMPRESSION, "opc", STFL, 38, "Order Preserving Compression facility")
+DEF_FEAT(SET_PROGRAM_PARAMETERS, "sprogp", STFL, 40, "Set-program-parameters facility")
+DEF_FEAT(FLOATING_POINT_SUPPPORT_ENH, "fpseh", STFL, 41, "Floating-point-support-enhancement facilities")
+DEF_FEAT(DFP, "dfp", STFL, 42, "DFP (decimal-floating-point) facility")
+DEF_FEAT(DFP_FAST, "dfphp", STFL, 43, "DFP (decimal-floating-point) facility has high performance")
+DEF_FEAT(PFPO, "pfpo", STFL, 44, "PFPO instruction")
+DEF_FEAT(STFLE_45, "stfle45", STFL, 45, "Various facilities introduced with z196")
+DEF_FEAT(CMPSC_ENH, "cmpsceh", STFL, 47, "CMPSC-enhancement facility")
+DEF_FEAT(DFP_ZONED_CONVERSION, "dfpzc", STFL, 48, "Decimal-floating-point zoned-conversion facility")
+DEF_FEAT(STFLE_49, "stfle49", STFL, 49, "Various facilities introduced with zEC12")
+DEF_FEAT(CONSTRAINT_TRANSACTIONAL_EXE, "cte", STFL, 50, "Constrained transactional-execution facility")
+DEF_FEAT(LOCAL_TLB_CLEARING, "ltlbc", STFL, 51, "Local-TLB-clearing facility")
+DEF_FEAT(INTERLOCKED_ACCESS_2, "iacc2", STFL, 52, "Interlocked-access facility 2")
+DEF_FEAT(STFLE_53, "stfle53", STFL, 53, "Various facilities introduced with z13")
+DEF_FEAT(ENTROPY_ENC_COMP, "eec", STFL, 54, "Entropy encoding compression facility")
+DEF_FEAT(MSA_EXT_5, "msa5-base", STFL, 57, "Message-security-assist-extension-5 facility (excluding subfunctions)")
+DEF_FEAT(MISC_INSTRUCTION_EXT, "minste2", STFL, 58, "Miscellaneous-instruction-extensions facility 2")
+DEF_FEAT(SEMAPHORE_ASSIST, "sema", STFL, 59, "Semaphore-assist facility")
+DEF_FEAT(TIME_SLICE_INSTRUMENTATION, "tsi", STFL, 60, "Time-slice Instrumentation facility")
+DEF_FEAT(MISC_INSTRUCTION_EXT3, "minste3", STFL, 61, "Miscellaneous-Instruction-Extensions Facility 3")
+DEF_FEAT(RUNTIME_INSTRUMENTATION, "ri", STFL, 64, "CPU runtime-instrumentation facility")
+DEF_FEAT(ZPCI, "zpci", STFL, 69, "z/PCI facility")
+DEF_FEAT(ADAPTER_EVENT_NOTIFICATION, "aen", STFL, 71, "General-purpose-adapter-event-notification facility")
+DEF_FEAT(ADAPTER_INT_SUPPRESSION, "ais", STFL, 72, "General-purpose-adapter-interruption-suppression facility")
+DEF_FEAT(TRANSACTIONAL_EXE, "te", STFL, 73, "Transactional-execution facility")
+DEF_FEAT(STORE_HYPERVISOR_INFO, "sthyi", STFL, 74, "Store-hypervisor-information facility")
+DEF_FEAT(ACCESS_EXCEPTION_FS_INDICATION, "aefsi", STFL, 75, "Access-exception-fetch/store-indication facility")
+DEF_FEAT(MSA_EXT_3, "msa3-base", STFL, 76, "Message-security-assist-extension-3 facility (excluding subfunctions)")
+DEF_FEAT(MSA_EXT_4, "msa4-base", STFL, 77, "Message-security-assist-extension-4 facility (excluding subfunctions)")
+DEF_FEAT(EDAT_2, "edat2", STFL, 78, "Enhanced-DAT facility 2")
+DEF_FEAT(DFP_PACKED_CONVERSION, "dfppc", STFL, 80, "Decimal-floating-point packed-conversion facility")
+DEF_FEAT(PPA15, "ppa15", STFL, 81, "PPA15 is installed")
+DEF_FEAT(BPB, "bpb", STFL, 82, "Branch prediction blocking")
+DEF_FEAT(VECTOR, "vx", STFL, 129, "Vector facility")
+DEF_FEAT(INSTRUCTION_EXEC_PROT, "iep", STFL, 130, "Instruction-execution-protection facility")
+DEF_FEAT(SIDE_EFFECT_ACCESS_ESOP2, "sea_esop2", STFL, 131, "Side-effect-access facility and Enhanced-suppression-on-protection facility 2")
+DEF_FEAT(GUARDED_STORAGE, "gs", STFL, 133, "Guarded-storage facility")
+DEF_FEAT(VECTOR_PACKED_DECIMAL, "vxpd", STFL, 134, "Vector packed decimal facility")
+DEF_FEAT(VECTOR_ENH, "vxeh", STFL, 135, "Vector enhancements facility")
+DEF_FEAT(MULTIPLE_EPOCH, "mepoch", STFL, 139, "Multiple-epoch facility")
+DEF_FEAT(TEST_PENDING_EXT_INTERRUPTION, "tpei", STFL, 144, "Test-pending-external-interruption facility")
+DEF_FEAT(INSERT_REFERENCE_BITS_MULT, "irbm", STFL, 145, "Insert-reference-bits-multiple facility")
+DEF_FEAT(MSA_EXT_8, "msa8-base", STFL, 146, "Message-security-assist-extension-8 facility (excluding subfunctions)")
+DEF_FEAT(CMM_NT, "cmmnt", STFL, 147, "CMM: ESSA-enhancement (no translate) facility")
+DEF_FEAT(VECTOR_ENH2, "vxeh2", STFL, 148, "Vector Enhancements facility 2")
+DEF_FEAT(ESORT_BASE, "esort-base", STFL, 150, "Enhanced-sort facility (excluding subfunctions)")
+DEF_FEAT(DEFLATE_BASE, "deflate-base", STFL, 151, "Deflate-conversion facility (excluding subfunctions)")
+DEF_FEAT(VECTOR_BCD_ENH, "vxbeh", STFL, 152, "Vector BCD enhancements facility 1")
+DEF_FEAT(MSA_EXT_9, "msa9-base", STFL, 155, "Message-security-assist-extension-9 facility (excluding subfunctions)")
+DEF_FEAT(ETOKEN, "etoken", STFL, 156, "Etoken facility")
+
+/* Features exposed via SCLP SCCB Byte 80 - 98 (bit numbers relative to byte-80) */
+DEF_FEAT(SIE_GSLS, "gsls", SCLP_CONF_CHAR, 40, "SIE: Guest-storage-limit-suppression facility")
+DEF_FEAT(ESOP, "esop", SCLP_CONF_CHAR, 46, "Enhanced-suppression-on-protection facility")
+DEF_FEAT(HPMA2, "hpma2", SCLP_CONF_CHAR, 90, "Host page management assist 2 Facility") /* 91-2 */
+DEF_FEAT(SIE_KSS, "kss", SCLP_CONF_CHAR, 151, "SIE: Keyless-subset facility") /* 98-7 */
+
+/* Features exposed via SCLP SCCB Byte 116 - 119 (bit numbers relative to byte-116) */
+DEF_FEAT(SIE_64BSCAO, "64bscao", SCLP_CONF_CHAR_EXT, 0, "SIE: 64-bit-SCAO facility")
+DEF_FEAT(SIE_CMMA, "cmma", SCLP_CONF_CHAR_EXT, 1, "SIE: Collaborative-memory-management assist")
+DEF_FEAT(SIE_PFMFI, "pfmfi", SCLP_CONF_CHAR_EXT, 9, "SIE: PFMF interpretation facility")
+DEF_FEAT(SIE_IBS, "ibs", SCLP_CONF_CHAR_EXT, 10, "SIE: Interlock-and-broadcast-suppression facility")
+
+/* Features exposed via SCLP CPU info. */
+DEF_FEAT(SIE_F2, "sief2", SCLP_CPU, 4, "SIE: interception format 2 (Virtual SIE)")
+DEF_FEAT(SIE_SKEY, "skey", SCLP_CPU, 5, "SIE: Storage-key facility")
+DEF_FEAT(SIE_GPERE, "gpereh", SCLP_CPU, 10, "SIE: Guest-PER enhancement facility")
+DEF_FEAT(SIE_SIIF, "siif", SCLP_CPU, 11, "SIE: Shared IPTE-interlock facility")
+DEF_FEAT(SIE_SIGPIF, "sigpif", SCLP_CPU, 12, "SIE: SIGP interpretation facility")
+DEF_FEAT(SIE_IB, "ib", SCLP_CPU, 42, "SIE: Intervention bypass facility")
+DEF_FEAT(SIE_CEI, "cei", SCLP_CPU, 43, "SIE: Conditional-external-interception facility")
+
+/*
+ * Features exposed via no feature bit (but e.g., instruction sensing)
+ * -> the feature bit number is irrelavant
+ */
+DEF_FEAT(DAT_ENH_2, "dateh2", MISC, 0, "DAT-enhancement facility 2")
+DEF_FEAT(CMM, "cmm", MISC, 0, "Collaborative-memory-management facility")
+DEF_FEAT(AP, "ap", MISC, 0, "AP instructions installed")
+
+/* Features exposed via the PLO instruction. */
+DEF_FEAT(PLO_CL, "plo-cl", PLO, 0, "PLO Compare and load (32 bit in general registers)")
+DEF_FEAT(PLO_CLG, "plo-clg", PLO, 1, "PLO Compare and load (64 bit in parameter list)")
+DEF_FEAT(PLO_CLGR, "plo-clgr", PLO, 2, "PLO Compare and load (32 bit in general registers)")
+DEF_FEAT(PLO_CLX, "plo-clx", PLO, 3, "PLO Compare and load (128 bit in parameter list)")
+DEF_FEAT(PLO_CS, "plo-cs", PLO, 4, "PLO Compare and swap (32 bit in general registers)")
+DEF_FEAT(PLO_CSG, "plo-csg", PLO, 5, "PLO Compare and swap (64 bit in parameter list)")
+DEF_FEAT(PLO_CSGR, "plo-csgr", PLO, 6, "PLO Compare and swap (32 bit in general registers)")
+DEF_FEAT(PLO_CSX, "plo-csx", PLO, 7, "PLO Compare and swap (128 bit in parameter list)")
+DEF_FEAT(PLO_DCS, "plo-dcs", PLO, 8, "PLO Double compare and swap (32 bit in general registers)")
+DEF_FEAT(PLO_DCSG, "plo-dcsg", PLO, 9, "PLO Double compare and swap (64 bit in parameter list)")
+DEF_FEAT(PLO_DCSGR, "plo-dcsgr", PLO, 10, "PLO Double compare and swap (32 bit in general registers)")
+DEF_FEAT(PLO_DCSX, "plo-dcsx", PLO, 11, "PLO Double compare and swap (128 bit in parameter list)")
+DEF_FEAT(PLO_CSST, "plo-csst", PLO, 12, "PLO Compare and swap and store (32 bit in general registers)")
+DEF_FEAT(PLO_CSSTG, "plo-csstg", PLO, 13, "PLO Compare and swap and store (64 bit in parameter list)")
+DEF_FEAT(PLO_CSSTGR, "plo-csstgr", PLO, 14, "PLO Compare and swap and store (32 bit in general registers)")
+DEF_FEAT(PLO_CSSTX, "plo-csstx", PLO, 15, "PLO Compare and swap and store (128 bit in parameter list)")
+DEF_FEAT(PLO_CSDST, "plo-csdst", PLO, 16, "PLO Compare and swap and double store (32 bit in general registers)")
+DEF_FEAT(PLO_CSDSTG, "plo-csdstg", PLO, 17, "PLO Compare and swap and double store (64 bit in parameter list)")
+DEF_FEAT(PLO_CSDSTGR, "plo-csdstgr", PLO, 18, "PLO Compare and swap and double store (32 bit in general registers)")
+DEF_FEAT(PLO_CSDSTX, "plo-csdstx", PLO, 19, "PLO Compare and swap and double store (128 bit in parameter list)")
+DEF_FEAT(PLO_CSTST, "plo-cstst", PLO, 20, "PLO Compare and swap and triple store (32 bit in general registers)")
+DEF_FEAT(PLO_CSTSTG, "plo-cststg", PLO, 21, "PLO Compare and swap and triple store (64 bit in parameter list)")
+DEF_FEAT(PLO_CSTSTGR, "plo-cststgr", PLO, 22, "PLO Compare and swap and triple store (32 bit in general registers)")
+DEF_FEAT(PLO_CSTSTX, "plo-cststx", PLO, 23, "PLO Compare and swap and triple store (128 bit in parameter list)")
+
+/* Features exposed via the PTFF instruction. */
+DEF_FEAT(PTFF_QTO, "ptff-qto", PTFF, 1, "PTFF Query TOD Offset")
+DEF_FEAT(PTFF_QSI, "ptff-qsi", PTFF, 2, "PTFF Query Steering Information")
+DEF_FEAT(PTFF_QPT, "ptff-qpc", PTFF, 3, "PTFF Query Physical Clock")
+DEF_FEAT(PTFF_QUI, "ptff-qui", PTFF, 4, "PTFF Query UTC Information")
+DEF_FEAT(PTFF_QTOU, "ptff-qtou", PTFF, 5, "PTFF Query TOD Offset User")
+DEF_FEAT(PTFF_QSIE, "ptff-qsie", PTFF, 10, "PTFF Query Steering Information Extended")
+DEF_FEAT(PTFF_QTOUE, "ptff-qtoue", PTFF, 13, "PTFF Query TOD Offset User Extended")
+DEF_FEAT(PTFF_STO, "ptff-sto", PTFF, 65, "PTFF Set TOD Offset")
+DEF_FEAT(PTFF_STOU, "ptff-stou", PTFF, 69, "PTFF Set TOD Offset User")
+DEF_FEAT(PTFF_STOE, "ptff-stoe", PTFF, 73, "PTFF Set TOD Offset Extended")
+DEF_FEAT(PTFF_STOUE, "ptff-stoue", PTFF, 77, "PTFF Set TOD Offset User Extended")
+
+/* Features exposed via the KMAC instruction. */
+DEF_FEAT(KMAC_DEA, "kmac-dea", KMAC, 1, "KMAC DEA")
+DEF_FEAT(KMAC_TDEA_128, "kmac-tdea-128", KMAC, 2, "KMAC TDEA-128")
+DEF_FEAT(KMAC_TDEA_192, "kmac-tdea-192", KMAC, 3, "KMAC TDEA-192")
+DEF_FEAT(KMAC_EDEA, "kmac-edea", KMAC, 9, "KMAC Encrypted-DEA")
+DEF_FEAT(KMAC_ETDEA_128, "kmac-etdea-128", KMAC, 10, "KMAC Encrypted-TDEA-128")
+DEF_FEAT(KMAC_ETDEA_192, "kmac-etdea-192", KMAC, 11, "KMAC Encrypted-TDEA-192")
+DEF_FEAT(KMAC_AES_128, "kmac-aes-128", KMAC, 18, "KMAC AES-128")
+DEF_FEAT(KMAC_AES_192, "kmac-aes-192", KMAC, 19, "KMAC AES-192")
+DEF_FEAT(KMAC_AES_256, "kmac-aes-256", KMAC, 20, "KMAC AES-256")
+DEF_FEAT(KMAC_EAES_128, "kmac-eaes-128", KMAC, 26, "KMAC Encrypted-AES-128")
+DEF_FEAT(KMAC_EAES_192, "kmac-eaes-192", KMAC, 27, "KMAC Encrypted-AES-192")
+DEF_FEAT(KMAC_EAES_256, "kmac-eaes-256", KMAC, 28, "KMAC Encrypted-AES-256")
+
+/* Features exposed via the KMC instruction. */
+DEF_FEAT(KMC_DEA, "kmc-dea", KMC, 1, "KMC DEA")
+DEF_FEAT(KMC_TDEA_128, "kmc-tdea-128", KMC, 2, "KMC TDEA-128")
+DEF_FEAT(KMC_TDEA_192, "kmc-tdea-192", KMC, 3, "KMC TDEA-192")
+DEF_FEAT(KMC_EDEA, "kmc-edea", KMC, 9, "KMC Encrypted-DEA")
+DEF_FEAT(KMC_ETDEA_128, "kmc-etdea-128", KMC, 10, "KMC Encrypted-TDEA-128")
+DEF_FEAT(KMC_ETDEA_192, "kmc-etdea-192", KMC, 11, "KMC Encrypted-TDEA-192")
+DEF_FEAT(KMC_AES_128, "kmc-aes-128", KMC, 18, "KMC AES-128")
+DEF_FEAT(KMC_AES_192, "kmc-aes-192", KMC, 19, "KMC AES-192")
+DEF_FEAT(KMC_AES_256, "kmc-aes-256", KMC, 20, "KMC AES-256")
+DEF_FEAT(KMC_EAES_128, "kmc-eaes-128", KMC, 26, "KMC Encrypted-AES-128")
+DEF_FEAT(KMC_EAES_192, "kmc-eaes-192", KMC, 27, "KMC Encrypted-AES-192")
+DEF_FEAT(KMC_EAES_256, "kmc-eaes-256", KMC, 28, "KMC Encrypted-AES-256")
+DEF_FEAT(KMC_PRNG, "kmc-prng", KMC, 67, "KMC PRNG")
+
+/* Features exposed via the KM instruction. */
+DEF_FEAT(KM_DEA, "km-dea", KM, 1, "KM DEA")
+DEF_FEAT(KM_TDEA_128, "km-tdea-128", KM, 2, "KM TDEA-128")
+DEF_FEAT(KM_TDEA_192, "km-tdea-192", KM, 3, "KM TDEA-192")
+DEF_FEAT(KM_EDEA, "km-edea", KM, 9, "KM Encrypted-DEA")
+DEF_FEAT(KM_ETDEA_128, "km-etdea-128", KM, 10, "KM Encrypted-TDEA-128")
+DEF_FEAT(KM_ETDEA_192, "km-etdea-192", KM, 11, "KM Encrypted-TDEA-192")
+DEF_FEAT(KM_AES_128, "km-aes-128", KM, 18, "KM AES-128")
+DEF_FEAT(KM_AES_192, "km-aes-192", KM, 19, "KM AES-192")
+DEF_FEAT(KM_AES_256, "km-aes-256", KM, 20, "KM AES-256")
+DEF_FEAT(KM_EAES_128, "km-eaes-128", KM, 26, "KM Encrypted-AES-128")
+DEF_FEAT(KM_EAES_192, "km-eaes-192", KM, 27, "KM Encrypted-AES-192")
+DEF_FEAT(KM_EAES_256, "km-eaes-256", KM, 28, "KM Encrypted-AES-256")
+DEF_FEAT(KM_XTS_AES_128, "km-xts-aes-128", KM, 50, "KM XTS-AES-128")
+DEF_FEAT(KM_XTS_AES_256, "km-xts-aes-256", KM, 52, "KM XTS-AES-256")
+DEF_FEAT(KM_XTS_EAES_128, "km-xts-eaes-128", KM, 58, "KM XTS-Encrypted-AES-128")
+DEF_FEAT(KM_XTS_EAES_256, "km-xts-eaes-256", KM, 60, "KM XTS-Encrypted-AES-256")
+
+/* Features exposed via the KIMD instruction. */
+DEF_FEAT(KIMD_SHA_1, "kimd-sha-1", KIMD, 1, "KIMD SHA-1")
+DEF_FEAT(KIMD_SHA_256, "kimd-sha-256", KIMD, 2, "KIMD SHA-256")
+DEF_FEAT(KIMD_SHA_512, "kimd-sha-512", KIMD, 3, "KIMD SHA-512")
+DEF_FEAT(KIMD_SHA3_224, "kimd-sha3-224", KIMD, 32, "KIMD SHA3-224")
+DEF_FEAT(KIMD_SHA3_256, "kimd-sha3-256", KIMD, 33, "KIMD SHA3-256")
+DEF_FEAT(KIMD_SHA3_384, "kimd-sha3-384", KIMD, 34, "KIMD SHA3-384")
+DEF_FEAT(KIMD_SHA3_512, "kimd-sha3-512", KIMD, 35, "KIMD SHA3-512")
+DEF_FEAT(KIMD_SHAKE_128, "kimd-shake-128", KIMD, 36, "KIMD SHAKE-128")
+DEF_FEAT(KIMD_SHAKE_256, "kimd-shake-256", KIMD, 37, "KIMD SHAKE-256")
+DEF_FEAT(KIMD_GHASH, "kimd-ghash", KIMD, 65, "KIMD GHASH")
+
+/* Features exposed via the KLMD instruction. */
+DEF_FEAT(KLMD_SHA_1, "klmd-sha-1", KLMD, 1, "KLMD SHA-1")
+DEF_FEAT(KLMD_SHA_256, "klmd-sha-256", KLMD, 2, "KLMD SHA-256")
+DEF_FEAT(KLMD_SHA_512, "klmd-sha-512", KLMD, 3, "KLMD SHA-512")
+DEF_FEAT(KLMD_SHA3_224, "klmd-sha3-224", KLMD, 32, "KLMD SHA3-224")
+DEF_FEAT(KLMD_SHA3_256, "klmd-sha3-256", KLMD, 33, "KLMD SHA3-256")
+DEF_FEAT(KLMD_SHA3_384, "klmd-sha3-384", KLMD, 34, "KLMD SHA3-384")
+DEF_FEAT(KLMD_SHA3_512, "klmd-sha3-512", KLMD, 35, "KLMD SHA3-512")
+DEF_FEAT(KLMD_SHAKE_128, "klmd-shake-128", KLMD, 36, "KLMD SHAKE-128")
+DEF_FEAT(KLMD_SHAKE_256, "klmd-shake-256", KLMD, 37, "KLMD SHAKE-256")
+
+/* Features exposed via the PCKMO instruction. */
+DEF_FEAT(PCKMO_EDEA, "pckmo-edea", PCKMO, 1, "PCKMO Encrypted-DEA-Key")
+DEF_FEAT(PCKMO_ETDEA_128, "pckmo-etdea-128", PCKMO, 2, "PCKMO Encrypted-TDEA-128-Key")
+DEF_FEAT(PCKMO_ETDEA_256, "pckmo-etdea-192", PCKMO, 3, "PCKMO Encrypted-TDEA-192-Key")
+DEF_FEAT(PCKMO_AES_128, "pckmo-aes-128", PCKMO, 18, "PCKMO Encrypted-AES-128-Key")
+DEF_FEAT(PCKMO_AES_192, "pckmo-aes-192", PCKMO, 19, "PCKMO Encrypted-AES-192-Key")
+DEF_FEAT(PCKMO_AES_256, "pckmo-aes-256", PCKMO, 20, "PCKMO Encrypted-AES-256-Key")
+DEF_FEAT(PCKMO_ECC_P256, "pckmo-ecc-p256", PCKMO, 32, "PCKMO Encrypt-ECC-P256-Key")
+DEF_FEAT(PCKMO_ECC_P384, "pckmo-ecc-p384", PCKMO, 33, "PCKMO Encrypt-ECC-P384-Key")
+DEF_FEAT(PCKMO_ECC_P521, "pckmo-ecc-p521", PCKMO, 34, "PCKMO Encrypt-ECC-P521-Key")
+DEF_FEAT(PCKMO_ECC_ED25519, "pckmo-ecc-ed25519", PCKMO, 40 , "PCKMO Encrypt-ECC-Ed25519-Key")
+DEF_FEAT(PCKMO_ECC_ED448, "pckmo-ecc-ed448", PCKMO, 41 , "PCKMO Encrypt-ECC-Ed448-Key")
+
+/* Features exposed via the KMCTR instruction. */
+DEF_FEAT(KMCTR_DEA, "kmctr-dea", KMCTR, 1, "KMCTR DEA")
+DEF_FEAT(KMCTR_TDEA_128, "kmctr-tdea-128", KMCTR, 2, "KMCTR TDEA-128")
+DEF_FEAT(KMCTR_TDEA_192, "kmctr-tdea-192", KMCTR, 3, "KMCTR TDEA-192")
+DEF_FEAT(KMCTR_EDEA, "kmctr-edea", KMCTR, 9, "KMCTR Encrypted-DEA")
+DEF_FEAT(KMCTR_ETDEA_128, "kmctr-etdea-128", KMCTR, 10, "KMCTR Encrypted-TDEA-128")
+DEF_FEAT(KMCTR_ETDEA_192, "kmctr-etdea-192", KMCTR, 11, "KMCTR Encrypted-TDEA-192")
+DEF_FEAT(KMCTR_AES_128, "kmctr-aes-128", KMCTR, 18, "KMCTR AES-128")
+DEF_FEAT(KMCTR_AES_192, "kmctr-aes-192", KMCTR, 19, "KMCTR AES-192")
+DEF_FEAT(KMCTR_AES_256, "kmctr-aes-256", KMCTR, 20, "KMCTR AES-256")
+DEF_FEAT(KMCTR_EAES_128, "kmctr-eaes-128", KMCTR, 26, "KMCTR Encrypted-AES-128")
+DEF_FEAT(KMCTR_EAES_192, "kmctr-eaes-192", KMCTR, 27, "KMCTR Encrypted-AES-192")
+DEF_FEAT(KMCTR_EAES_256, "kmctr-eaes-256", KMCTR, 28, "KMCTR Encrypted-AES-256")
+
+/* Features exposed via the KMF instruction. */
+DEF_FEAT(KMF_DEA, "kmf-dea", KMF, 1, "KMF DEA")
+DEF_FEAT(KMF_TDEA_128, "kmf-tdea-128", KMF, 2, "KMF TDEA-128")
+DEF_FEAT(KMF_TDEA_192, "kmf-tdea-192", KMF, 3, "KMF TDEA-192")
+DEF_FEAT(KMF_EDEA, "kmf-edea", KMF, 9, "KMF Encrypted-DEA")
+DEF_FEAT(KMF_ETDEA_128, "kmf-etdea-128", KMF, 10, "KMF Encrypted-TDEA-128")
+DEF_FEAT(KMF_ETDEA_192, "kmf-etdea-192", KMF, 11, "KMF Encrypted-TDEA-192")
+DEF_FEAT(KMF_AES_128, "kmf-aes-128", KMF, 18, "KMF AES-128")
+DEF_FEAT(KMF_AES_192, "kmf-aes-192", KMF, 19, "KMF AES-192")
+DEF_FEAT(KMF_AES_256, "kmf-aes-256", KMF, 20, "KMF AES-256")
+DEF_FEAT(KMF_EAES_128, "kmf-eaes-128", KMF, 26, "KMF Encrypted-AES-128")
+DEF_FEAT(KMF_EAES_192, "kmf-eaes-192", KMF, 27, "KMF Encrypted-AES-192")
+DEF_FEAT(KMF_EAES_256, "kmf-eaes-256", KMF, 28, "KMF Encrypted-AES-256")
+
+/* Features exposed via the KMO instruction. */
+DEF_FEAT(KMO_DEA, "kmo-dea", KMO, 1, "KMO DEA")
+DEF_FEAT(KMO_TDEA_128, "kmo-tdea-128", KMO, 2, "KMO TDEA-128")
+DEF_FEAT(KMO_TDEA_192, "kmo-tdea-192", KMO, 3, "KMO TDEA-192")
+DEF_FEAT(KMO_EDEA, "kmo-edea", KMO, 9, "KMO Encrypted-DEA")
+DEF_FEAT(KMO_ETDEA_128, "kmo-etdea-128", KMO, 10, "KMO Encrypted-TDEA-128")
+DEF_FEAT(KMO_ETDEA_192, "kmo-etdea-192", KMO, 11, "KMO Encrypted-TDEA-192")
+DEF_FEAT(KMO_AES_128, "kmo-aes-128", KMO, 18, "KMO AES-128")
+DEF_FEAT(KMO_AES_192, "kmo-aes-192", KMO, 19, "KMO AES-192")
+DEF_FEAT(KMO_AES_256, "kmo-aes-256", KMO, 20, "KMO AES-256")
+DEF_FEAT(KMO_EAES_128, "kmo-eaes-128", KMO, 26, "KMO Encrypted-AES-128")
+DEF_FEAT(KMO_EAES_192, "kmo-eaes-192", KMO, 27, "KMO Encrypted-AES-192")
+DEF_FEAT(KMO_EAES_256, "kmo-eaes-256", KMO, 28, "KMO Encrypted-AES-256")
+
+/* Features exposed via the PCC instruction. */
+DEF_FEAT(PCC_CMAC_DEA, "pcc-cmac-dea", PCC, 1, "PCC Compute-Last-Block-CMAC-Using-DEA")
+DEF_FEAT(PCC_CMAC_TDEA_128, "pcc-cmac-tdea-128", PCC, 2, "PCC Compute-Last-Block-CMAC-Using-TDEA-128")
+DEF_FEAT(PCC_CMAC_TDEA_192, "pcc-cmac-tdea-192", PCC, 3, "PCC Compute-Last-Block-CMAC-Using-TDEA-192")
+DEF_FEAT(PCC_CMAC_ETDEA_128, "pcc-cmac-edea", PCC, 9, "PCC Compute-Last-Block-CMAC-Using-Encrypted-DEA")
+DEF_FEAT(PCC_CMAC_ETDEA_192, "pcc-cmac-etdea-128", PCC, 10, "PCC Compute-Last-Block-CMAC-Using-Encrypted-TDEA-128")
+DEF_FEAT(PCC_CMAC_TDEA, "pcc-cmac-etdea-192", PCC, 11, "PCC Compute-Last-Block-CMAC-Using-EncryptedTDEA-192")
+DEF_FEAT(PCC_CMAC_AES_128, "pcc-cmac-aes-128", PCC, 18, "PCC Compute-Last-Block-CMAC-Using-AES-128")
+DEF_FEAT(PCC_CMAC_AES_192, "pcc-cmac-aes-192", PCC, 19, "PCC Compute-Last-Block-CMAC-Using-AES-192")
+DEF_FEAT(PCC_CMAC_AES_256, "pcc-cmac-eaes-256", PCC, 20, "PCC Compute-Last-Block-CMAC-Using-AES-256")
+DEF_FEAT(PCC_CMAC_EAES_128, "pcc-cmac-eaes-128", PCC, 26, "PCC Compute-Last-Block-CMAC-Using-Encrypted-AES-128")
+DEF_FEAT(PCC_CMAC_EAES_192, "pcc-cmac-eaes-192", PCC, 27, "PCC Compute-Last-Block-CMAC-Using-Encrypted-AES-192")
+DEF_FEAT(PCC_CMAC_EAES_256, "pcc-cmac-eaes-256", PCC, 28, "PCC Compute-Last-Block-CMAC-Using-Encrypted-AES-256")
+DEF_FEAT(PCC_XTS_AES_128, "pcc-xts-aes-128", PCC, 50, "PCC Compute-XTS-Parameter-Using-AES-128")
+DEF_FEAT(PCC_XTS_AES_256, "pcc-xts-aes-256", PCC, 52, "PCC Compute-XTS-Parameter-Using-AES-256")
+DEF_FEAT(PCC_XTS_EAES_128, "pcc-xts-eaes-128", PCC, 58, "PCC Compute-XTS-Parameter-Using-Encrypted-AES-128")
+DEF_FEAT(PCC_XTS_EAES_256, "pcc-xts-eaes-256", PCC, 60, "PCC Compute-XTS-Parameter-Using-Encrypted-AES-256")
+DEF_FEAT(PCC_SCALAR_MULT_P256, "pcc-scalar-mult-p256", PCC, 64, "PCC Scalar-Multiply-P256")
+DEF_FEAT(PCC_SCALAR_MULT_P384, "pcc-scalar-mult-p384", PCC, 65, "PCC Scalar-Multiply-P384")
+DEF_FEAT(PCC_SCALAR_MULT_P512, "pcc-scalar-mult-p521", PCC, 66, "PCC Scalar-Multiply-P521")
+DEF_FEAT(PCC_SCALAR_MULT_ED25519, "pcc-scalar-mult-ed25519", PCC, 72, "PCC Scalar-Multiply-Ed25519")
+DEF_FEAT(PCC_SCALAR_MULT_ED448, "pcc-scalar-mult-ed448", PCC, 73, "PCC Scalar-Multiply-Ed448")
+DEF_FEAT(PCC_SCALAR_MULT_X25519, "pcc-scalar-mult-x25519", PCC, 80, "PCC Scalar-Multiply-X25519")
+DEF_FEAT(PCC_SCALAR_MULT_X448, "pcc-scalar-mult-x448", PCC, 81, "PCC Scalar-Multiply-X448")
+
+/* Features exposed via the PPNO/PRNO instruction. */
+DEF_FEAT(PPNO_SHA_512_DRNG, "ppno-sha-512-drng", PPNO, 3, "PPNO SHA-512-DRNG")
+DEF_FEAT(PRNO_TRNG_QRTCR, "prno-trng-qrtcr", PPNO, 112, "PRNO TRNG-Query-Raw-to-Conditioned-Ratio")
+DEF_FEAT(PRNO_TRNG, "prno-trng", PPNO, 114, "PRNO TRNG")
+
+/* Features exposed via the KMA instruction. */
+DEF_FEAT(KMA_GCM_AES_128, "kma-gcm-aes-128", KMA, 18, "KMA GCM-AES-128")
+DEF_FEAT(KMA_GCM_AES_192, "kma-gcm-aes-192", KMA, 19, "KMA GCM-AES-192")
+DEF_FEAT(KMA_GCM_AES_256, "kma-gcm-aes-256", KMA, 20, "KMA GCM-AES-256")
+DEF_FEAT(KMA_GCM_EAES_128, "kma-gcm-eaes-128", KMA, 26, "KMA GCM-Encrypted-AES-128")
+DEF_FEAT(KMA_GCM_EAES_192, "kma-gcm-eaes-192", KMA, 27, "KMA GCM-Encrypted-AES-192")
+DEF_FEAT(KMA_GCM_EAES_256, "kma-gcm-eaes-256", KMA, 28, "KMA GCM-Encrypted-AES-256")
+
+/* Features exposed via the KDSA instruction. */
+DEF_FEAT(KDSA_ECDSA_VERIFY_P256, "kdsa-ecdsa-verify-p256", KDSA, 1, "KDSA ECDSA-Verify-P256")
+DEF_FEAT(KDSA_ECDSA_VERIFY_P384, "kdsa-ecdsa-verify-p384", KDSA, 2, "KDSA ECDSA-Verify-P384")
+DEF_FEAT(KDSA_ECDSA_VERIFY_P512, "kdsa-ecdsa-verify-p521", KDSA, 3, "KDSA ECDSA-Verify-P521")
+DEF_FEAT(KDSA_ECDSA_SIGN_P256, "kdsa-ecdsa-sign-p256", KDSA, 9, "KDSA ECDSA-Sign-P256")
+DEF_FEAT(KDSA_ECDSA_SIGN_P384, "kdsa-ecdsa-sign-p384", KDSA, 10, "KDSA ECDSA-Sign-P384")
+DEF_FEAT(KDSA_ECDSA_SIGN_P512, "kdsa-ecdsa-sign-p521", KDSA, 11, "KDSA ECDSA-Sign-P521")
+DEF_FEAT(KDSA_EECDSA_SIGN_P256, "kdsa-eecdsa-sign-p256", KDSA, 17, "KDSA Encrypted-ECDSA-Sign-P256")
+DEF_FEAT(KDSA_EECDSA_SIGN_P384, "kdsa-eecdsa-sign-p384", KDSA, 18, "KDSA Encrypted-ECDSA-Sign-P384")
+DEF_FEAT(KDSA_EECDSA_SIGN_P512, "kdsa-eecdsa-sign-p521", KDSA, 19, "KDSA Encrypted-ECDSA-Sign-P521")
+DEF_FEAT(KDSA_EDDSA_VERIFY_ED25519, "kdsa-eddsa-verify-ed25519", KDSA, 32, "KDSA EdDSA-Verify-Ed25519")
+DEF_FEAT(KDSA_EDDSA_VERIFY_ED448, "kdsa-eddsa-verify-ed448", KDSA, 36, "KDSA EdDSA-Verify-Ed448")
+DEF_FEAT(KDSA_EDDSA_SIGN_ED25519, "kdsa-eddsa-sign-ed25519", KDSA, 40, "KDSA EdDSA-Sign-Ed25519")
+DEF_FEAT(KDSA_EDDSA_SIGN_ED448, "kdsa-eddsa-sign-ed448", KDSA, 44, "KDSA EdDSA-Sign-Ed448")
+DEF_FEAT(KDSA_EEDDSA_SIGN_ED25519, "kdsa-eeddsa-sign-ed25519", KDSA, 48, "KDSA Encrypted-EdDSA-Sign-Ed25519")
+DEF_FEAT(KDSA_EEDDSA_SIGN_ED448, "kdsa-eeddsa-sign-ed448", KDSA, 52, "KDSA Encrypted-EdDSA-Sign-Ed448")
+
+/* Features exposed via the SORTL instruction. */
+DEF_FEAT(SORTL_SFLR, "sortl-sflr", SORTL, 1, "SORTL SFLR")
+DEF_FEAT(SORTL_SVLR, "sortl-svlr", SORTL, 2, "SORTL SVLR")
+DEF_FEAT(SORTL_32, "sortl-32", SORTL, 130, "SORTL 32 input lists")
+DEF_FEAT(SORTL_128, "sortl-128", SORTL, 132, "SORTL 128 input lists")
+DEF_FEAT(SORTL_F0, "sortl-f0", SORTL, 192, "SORTL format 0 parameter-block")
+
+/* Features exposed via the DEFLATE instruction. */
+DEF_FEAT(DEFLATE_GHDT, "dfltcc-gdht", DFLTCC, 1, "DFLTCC GDHT")
+DEF_FEAT(DEFLATE_CMPR, "dfltcc-cmpr", DFLTCC, 2, "DFLTCC CMPR")
+DEF_FEAT(DEFLATE_XPND, "dfltcc-xpnd", DFLTCC, 4, "DFLTCC XPND")
+DEF_FEAT(DEFLATE_F0, "dfltcc-f0", DFLTCC, 192, "DFLTCC format 0 parameter-block")
#include "sysemu/arch_init.h"
#include "hw/pci/pci.h"
#endif
-#include "qapi/qapi-commands-target.h"
+#include "qapi/qapi-commands-machine-target.h"
#define CPUDEF_INIT(_type, _gen, _ec_ga, _mha_pow, _hmfai, _name, _desc) \
{ \
#define S390_FEAT_GROUP_MSA_EXT_9 \
S390_FEAT_MSA_EXT_9, \
- S390_FEAT_ECDSA_VERIFY_P256, \
- S390_FEAT_ECDSA_VERIFY_P384, \
- S390_FEAT_ECDSA_VERIFY_P512, \
- S390_FEAT_ECDSA_SIGN_P256, \
- S390_FEAT_ECDSA_SIGN_P384, \
- S390_FEAT_ECDSA_SIGN_P512, \
- S390_FEAT_EECDSA_SIGN_P256, \
- S390_FEAT_EECDSA_SIGN_P384, \
- S390_FEAT_EECDSA_SIGN_P512, \
- S390_FEAT_EDDSA_VERIFY_ED25519, \
- S390_FEAT_EDDSA_VERIFY_ED448, \
- S390_FEAT_EDDSA_SIGN_ED25519, \
- S390_FEAT_EDDSA_SIGN_ED448, \
- S390_FEAT_EEDDSA_SIGN_ED25519, \
- S390_FEAT_EEDDSA_SIGN_ED448, \
+ S390_FEAT_KDSA_ECDSA_VERIFY_P256, \
+ S390_FEAT_KDSA_ECDSA_VERIFY_P384, \
+ S390_FEAT_KDSA_ECDSA_VERIFY_P512, \
+ S390_FEAT_KDSA_ECDSA_SIGN_P256, \
+ S390_FEAT_KDSA_ECDSA_SIGN_P384, \
+ S390_FEAT_KDSA_ECDSA_SIGN_P512, \
+ S390_FEAT_KDSA_EECDSA_SIGN_P256, \
+ S390_FEAT_KDSA_EECDSA_SIGN_P384, \
+ S390_FEAT_KDSA_EECDSA_SIGN_P512, \
+ S390_FEAT_KDSA_EDDSA_VERIFY_ED25519, \
+ S390_FEAT_KDSA_EDDSA_VERIFY_ED448, \
+ S390_FEAT_KDSA_EDDSA_SIGN_ED25519, \
+ S390_FEAT_KDSA_EDDSA_SIGN_ED448, \
+ S390_FEAT_KDSA_EEDDSA_SIGN_ED25519, \
+ S390_FEAT_KDSA_EEDDSA_SIGN_ED448, \
S390_FEAT_PCC_SCALAR_MULT_P256, \
S390_FEAT_PCC_SCALAR_MULT_P384, \
S390_FEAT_PCC_SCALAR_MULT_P512, \
#include "sysemu/sysemu.h"
#include "sysemu/tcg.h"
#include "trace.h"
-#include "qapi/qapi-types-misc.h"
+#include "qapi/qapi-types-machine.h"
QemuMutex qemu_sigp_mutex;
#include "cpu.h"
#include "monitor/monitor.h"
#include "monitor/hmp-target.h"
-#include "hmp.h"
+#include "monitor/hmp.h"
static void print_tlb(Monitor *mon, int idx, tlb_t *tlb)
{
#include "cpu.h"
#include "monitor/monitor.h"
#include "monitor/hmp-target.h"
-#include "hmp.h"
+#include "monitor/hmp.h"
void hmp_info_tlb(Monitor *mon, const QDict *qdict)
#include "cpu.h"
#include "monitor/monitor.h"
#include "monitor/hmp-target.h"
-#include "hmp.h"
+#include "monitor/hmp.h"
void hmp_info_tlb(Monitor *mon, const QDict *qdict)
{
+# -*- Mode: makefile -*-
.PHONY: check-help
check-help:
check-qtest-arm-y += tests/test-arm-mptimer$(EXESUF)
check-qtest-arm-y += tests/boot-serial-test$(EXESUF)
check-qtest-arm-y += tests/hexloader-test$(EXESUF)
+check-qtest-arm-$(CONFIG_PFLASH_CFI02) += tests/pflash-cfi02-test$(EXESUF)
check-qtest-aarch64-y = tests/numa-test$(EXESUF)
check-qtest-aarch64-y += tests/boot-serial-test$(EXESUF)
tests/rtc-test$(EXESUF): tests/rtc-test.o
tests/m48t59-test$(EXESUF): tests/m48t59-test.o
tests/hexloader-test$(EXESUF): tests/hexloader-test.o
+tests/pflash-cfi02$(EXESUF): tests/pflash-cfi02-test.o
tests/endianness-test$(EXESUF): tests/endianness-test.o
tests/prom-env-test$(EXESUF): tests/prom-env-test.o $(libqos-obj-y)
tests/rtas-test$(EXESUF): tests/rtas-test.o $(libqos-spapr-obj-y)
endef
.PHONY: $(patsubst %, check-qtest-%, $(QTEST_TARGETS))
-$(patsubst %, check-qtest-%, $(QTEST_TARGETS)): check-qtest-%: subdir-%-softmmu $(check-qtest-y)
+$(patsubst %, check-qtest-%, $(QTEST_TARGETS)): check-qtest-%: %-softmmu/all $(check-qtest-y)
$(call do_test_human,$(check-qtest-$*-y) $(check-qtest-generic-y), \
QTEST_QEMU_BINARY=$*-softmmu/qemu-system-$* \
QTEST_QEMU_IMG=qemu-img$(EXESUF))
# gtester tests with TAP output
-$(patsubst %, check-report-qtest-%.tap, $(QTEST_TARGETS)): check-report-qtest-%.tap: subdir-%-softmmu $(check-qtest-y)
+$(patsubst %, check-report-qtest-%.tap, $(QTEST_TARGETS)): check-report-qtest-%.tap: %-softmmu/all $(check-qtest-y)
$(call do_test_tap, $(check-qtest-$*-y) $(check-qtest-generic-y), \
QTEST_QEMU_BINARY=$*-softmmu/qemu-system-$* \
QTEST_QEMU_IMG=qemu-img$(EXESUF))
SRC_ROOT_DIR = os.path.join(os.path.dirname(__file__), '..', '..', '..')
sys.path.append(os.path.join(SRC_ROOT_DIR, 'python'))
-from qemu import QEMUMachine
+from qemu.machine import QEMUMachine
def is_readable_executable_file(path):
return os.path.isfile(path) and os.access(path, os.R_OK | os.X_OK)
import os
sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..', 'python'))
-from qemu import QEMUMachine
+from qemu.machine import QEMUMachine
from avocado_qemu import Test
# Virtio Device IDs:
/* FIXME: { "microblaze", "any" }, doesn't work with -M none -cpu any */
/* FIXME: { "microblazeel", "any" }, doesn't work with -M none -cpu any */
{ "mips", "4Kc" },
- { "mipsel", "4Kc" },
+ { "mipsel", "I7200" },
{ "mips64", "20Kc" },
- { "mips64el", "20Kc" },
+ { "mips64el", "I6500" },
{ "moxie", "MoxieLite" },
{ "nios2", "FIXME" },
{ "or1k", "or1200" },
sys.path.append(os.path.join(os.path.dirname(__file__),
'..', '..', '..', 'python'))
-import qemu
+from qemu.machine import QEMUMachine
class Engine(object):
dstmonaddr = "/var/tmp/qemu-dst-%d-monitor.sock" % os.getpid()
srcmonaddr = "/var/tmp/qemu-src-%d-monitor.sock" % os.getpid()
- src = qemu.QEMUMachine(self._binary,
- args=self._get_src_args(hardware),
- wrapper=self._get_src_wrapper(hardware),
- name="qemu-src-%d" % os.getpid(),
- monitor_address=srcmonaddr)
-
- dst = qemu.QEMUMachine(self._binary,
- args=self._get_dst_args(hardware, uri),
- wrapper=self._get_dst_wrapper(hardware),
- name="qemu-dst-%d" % os.getpid(),
- monitor_address=dstmonaddr)
+ src = QEMUMachine(self._binary,
+ args=self._get_src_args(hardware),
+ wrapper=self._get_src_wrapper(hardware),
+ name="qemu-src-%d" % os.getpid(),
+ monitor_address=srcmonaddr)
+
+ dst = QEMUMachine(self._binary,
+ args=self._get_dst_args(hardware, uri),
+ wrapper=self._get_dst_wrapper(hardware),
+ name="qemu-dst-%d" % os.getpid(),
+ monitor_address=dstmonaddr)
try:
src.launch()
--- /dev/null
+/*
+ * QTest testcase for parallel flash with AMD command set
+ *
+ * Copyright (c) 2019 Stephen Checkoway
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include "qemu/osdep.h"
+#include "libqtest.h"
+
+/*
+ * To test the pflash_cfi02 device, we run QEMU with the musicpal machine with
+ * a pflash drive. This enables us to test some flash configurations, but not
+ * all. In particular, we're limited to a 16-bit wide flash device.
+ */
+
+#define MP_FLASH_SIZE_MAX (32 * 1024 * 1024)
+#define BASE_ADDR (0x100000000ULL - MP_FLASH_SIZE_MAX)
+
+#define UNIFORM_FLASH_SIZE (8 * 1024 * 1024)
+#define UNIFORM_FLASH_SECTOR_SIZE (64 * 1024)
+
+/* Use a newtype to keep flash addresses separate from byte addresses. */
+typedef struct {
+ uint64_t addr;
+} faddr;
+#define FLASH_ADDR(x) ((faddr) { .addr = (x) })
+
+#define CFI_ADDR FLASH_ADDR(0x55)
+#define UNLOCK0_ADDR FLASH_ADDR(0x555)
+#define UNLOCK1_ADDR FLASH_ADDR(0x2AA)
+
+#define CFI_CMD 0x98
+#define UNLOCK0_CMD 0xAA
+#define UNLOCK1_CMD 0x55
+#define SECOND_UNLOCK_CMD 0x80
+#define AUTOSELECT_CMD 0x90
+#define RESET_CMD 0xF0
+#define PROGRAM_CMD 0xA0
+#define SECTOR_ERASE_CMD 0x30
+#define CHIP_ERASE_CMD 0x10
+#define UNLOCK_BYPASS_CMD 0x20
+#define UNLOCK_BYPASS_RESET_CMD 0x00
+#define ERASE_SUSPEND_CMD 0xB0
+#define ERASE_RESUME_CMD SECTOR_ERASE_CMD
+
+typedef struct {
+ int bank_width;
+
+ /* Nonuniform block size. */
+ int nb_blocs[4];
+ int sector_len[4];
+
+ QTestState *qtest;
+} FlashConfig;
+
+static char image_path[] = "/tmp/qtest.XXXXXX";
+
+/*
+ * The pflash implementation allows some parameters to be unspecified. We want
+ * to test those configurations but we also need to know the real values in
+ * our testing code. So after we launch qemu, we'll need a new FlashConfig
+ * with the correct values filled in.
+ */
+static FlashConfig expand_config_defaults(const FlashConfig *c)
+{
+ FlashConfig ret = *c;
+
+ if (ret.bank_width == 0) {
+ ret.bank_width = 2;
+ }
+ if (ret.nb_blocs[0] == 0 && ret.sector_len[0] == 0) {
+ ret.sector_len[0] = UNIFORM_FLASH_SECTOR_SIZE;
+ ret.nb_blocs[0] = UNIFORM_FLASH_SIZE / UNIFORM_FLASH_SECTOR_SIZE;
+ }
+
+ /* XXX: Limitations of test harness. */
+ assert(ret.bank_width == 2);
+ return ret;
+}
+
+/*
+ * Return a bit mask suitable for extracting the least significant
+ * status/query response from an interleaved response.
+ */
+static inline uint64_t device_mask(const FlashConfig *c)
+{
+ return (uint64_t)-1;
+}
+
+/*
+ * Return a bit mask exactly as long as the bank_width.
+ */
+static inline uint64_t bank_mask(const FlashConfig *c)
+{
+ if (c->bank_width == 8) {
+ return (uint64_t)-1;
+ }
+ return (1ULL << (c->bank_width * 8)) - 1ULL;
+}
+
+static inline void flash_write(const FlashConfig *c, uint64_t byte_addr,
+ uint64_t data)
+{
+ /* Sanity check our tests. */
+ assert((data & ~bank_mask(c)) == 0);
+ uint64_t addr = BASE_ADDR + byte_addr;
+ switch (c->bank_width) {
+ case 1:
+ qtest_writeb(c->qtest, addr, data);
+ break;
+ case 2:
+ qtest_writew(c->qtest, addr, data);
+ break;
+ case 4:
+ qtest_writel(c->qtest, addr, data);
+ break;
+ case 8:
+ qtest_writeq(c->qtest, addr, data);
+ break;
+ default:
+ abort();
+ }
+}
+
+static inline uint64_t flash_read(const FlashConfig *c, uint64_t byte_addr)
+{
+ uint64_t addr = BASE_ADDR + byte_addr;
+ switch (c->bank_width) {
+ case 1:
+ return qtest_readb(c->qtest, addr);
+ case 2:
+ return qtest_readw(c->qtest, addr);
+ case 4:
+ return qtest_readl(c->qtest, addr);
+ case 8:
+ return qtest_readq(c->qtest, addr);
+ default:
+ abort();
+ }
+}
+
+/*
+ * Convert a flash address expressed in the maximum width of the device as a
+ * byte address.
+ */
+static inline uint64_t as_byte_addr(const FlashConfig *c, faddr flash_addr)
+{
+ /*
+ * Command addresses are always given as addresses in the maximum
+ * supported bus size for the flash chip. So an x8/x16 chip in x8 mode
+ * uses addresses 0xAAA and 0x555 to unlock because the least significant
+ * bit is ignored. (0x555 rather than 0x554 is traditional.)
+ *
+ * In general we need to multiply by the maximum device width.
+ */
+ return flash_addr.addr * c->bank_width;
+}
+
+/*
+ * Return the command value or expected status replicated across all devices.
+ */
+static inline uint64_t replicate(const FlashConfig *c, uint64_t data)
+{
+ /* Sanity check our tests. */
+ assert((data & ~device_mask(c)) == 0);
+ return data;
+}
+
+static inline void flash_cmd(const FlashConfig *c, faddr cmd_addr,
+ uint8_t cmd)
+{
+ flash_write(c, as_byte_addr(c, cmd_addr), replicate(c, cmd));
+}
+
+static inline uint64_t flash_query(const FlashConfig *c, faddr query_addr)
+{
+ return flash_read(c, as_byte_addr(c, query_addr));
+}
+
+static inline uint64_t flash_query_1(const FlashConfig *c, faddr query_addr)
+{
+ return flash_query(c, query_addr) & device_mask(c);
+}
+
+static void unlock(const FlashConfig *c)
+{
+ flash_cmd(c, UNLOCK0_ADDR, UNLOCK0_CMD);
+ flash_cmd(c, UNLOCK1_ADDR, UNLOCK1_CMD);
+}
+
+static void reset(const FlashConfig *c)
+{
+ flash_cmd(c, FLASH_ADDR(0), RESET_CMD);
+}
+
+static void sector_erase(const FlashConfig *c, uint64_t byte_addr)
+{
+ unlock(c);
+ flash_cmd(c, UNLOCK0_ADDR, SECOND_UNLOCK_CMD);
+ unlock(c);
+ flash_write(c, byte_addr, replicate(c, SECTOR_ERASE_CMD));
+}
+
+static void wait_for_completion(const FlashConfig *c, uint64_t byte_addr)
+{
+ /* If DQ6 is toggling, step the clock and ensure the toggle stops. */
+ const uint64_t dq6 = replicate(c, 0x40);
+ if ((flash_read(c, byte_addr) & dq6) ^ (flash_read(c, byte_addr) & dq6)) {
+ /* Wait for erase or program to finish. */
+ qtest_clock_step_next(c->qtest);
+ /* Ensure that DQ6 has stopped toggling. */
+ g_assert_cmphex(flash_read(c, byte_addr), ==, flash_read(c, byte_addr));
+ }
+}
+
+static void bypass_program(const FlashConfig *c, uint64_t byte_addr,
+ uint16_t data)
+{
+ flash_cmd(c, UNLOCK0_ADDR, PROGRAM_CMD);
+ flash_write(c, byte_addr, data);
+ /*
+ * Data isn't valid until DQ6 stops toggling. We don't model this as
+ * writes are immediate, but if this changes in the future, we can wait
+ * until the program is complete.
+ */
+ wait_for_completion(c, byte_addr);
+}
+
+static void program(const FlashConfig *c, uint64_t byte_addr, uint16_t data)
+{
+ unlock(c);
+ bypass_program(c, byte_addr, data);
+}
+
+static void chip_erase(const FlashConfig *c)
+{
+ unlock(c);
+ flash_cmd(c, UNLOCK0_ADDR, SECOND_UNLOCK_CMD);
+ unlock(c);
+ flash_cmd(c, UNLOCK0_ADDR, CHIP_ERASE_CMD);
+}
+
+static void erase_suspend(const FlashConfig *c)
+{
+ flash_cmd(c, FLASH_ADDR(0), ERASE_SUSPEND_CMD);
+}
+
+static void erase_resume(const FlashConfig *c)
+{
+ flash_cmd(c, FLASH_ADDR(0), ERASE_RESUME_CMD);
+}
+
+/*
+ * Test flash commands with a variety of device geometry.
+ */
+static void test_geometry(const void *opaque)
+{
+ const FlashConfig *config = opaque;
+ QTestState *qtest;
+ qtest = qtest_initf("-M musicpal,accel=qtest"
+ " -drive if=pflash,file=%s,format=raw,copy-on-read"
+ /* Device geometry properties. */
+ " -global driver=cfi.pflash02,"
+ "property=num-blocks0,value=%d"
+ " -global driver=cfi.pflash02,"
+ "property=sector-length0,value=%d"
+ " -global driver=cfi.pflash02,"
+ "property=num-blocks1,value=%d"
+ " -global driver=cfi.pflash02,"
+ "property=sector-length1,value=%d"
+ " -global driver=cfi.pflash02,"
+ "property=num-blocks2,value=%d"
+ " -global driver=cfi.pflash02,"
+ "property=sector-length2,value=%d"
+ " -global driver=cfi.pflash02,"
+ "property=num-blocks3,value=%d"
+ " -global driver=cfi.pflash02,"
+ "property=sector-length3,value=%d",
+ image_path,
+ config->nb_blocs[0],
+ config->sector_len[0],
+ config->nb_blocs[1],
+ config->sector_len[1],
+ config->nb_blocs[2],
+ config->sector_len[2],
+ config->nb_blocs[3],
+ config->sector_len[3]);
+ FlashConfig explicit_config = expand_config_defaults(config);
+ explicit_config.qtest = qtest;
+ const FlashConfig *c = &explicit_config;
+
+ /* Check the IDs. */
+ unlock(c);
+ flash_cmd(c, UNLOCK0_ADDR, AUTOSELECT_CMD);
+ g_assert_cmphex(flash_query(c, FLASH_ADDR(0)), ==, replicate(c, 0xBF));
+ if (c->bank_width >= 2) {
+ /*
+ * XXX: The ID returned by the musicpal flash chip is 16 bits which
+ * wouldn't happen with an 8-bit device. It would probably be best to
+ * prohibit addresses larger than the device width in pflash_cfi02.c,
+ * but then we couldn't test smaller device widths at all.
+ */
+ g_assert_cmphex(flash_query(c, FLASH_ADDR(1)), ==,
+ replicate(c, 0x236D));
+ }
+ reset(c);
+
+ /* Check the erase blocks. */
+ flash_cmd(c, CFI_ADDR, CFI_CMD);
+ g_assert_cmphex(flash_query(c, FLASH_ADDR(0x10)), ==, replicate(c, 'Q'));
+ g_assert_cmphex(flash_query(c, FLASH_ADDR(0x11)), ==, replicate(c, 'R'));
+ g_assert_cmphex(flash_query(c, FLASH_ADDR(0x12)), ==, replicate(c, 'Y'));
+
+ /* Num erase regions. */
+ int nb_erase_regions = flash_query_1(c, FLASH_ADDR(0x2C));
+ g_assert_cmphex(nb_erase_regions, ==,
+ !!c->nb_blocs[0] + !!c->nb_blocs[1] + !!c->nb_blocs[2] +
+ !!c->nb_blocs[3]);
+
+ /* Check device length. */
+ uint32_t device_len = 1 << flash_query_1(c, FLASH_ADDR(0x27));
+ g_assert_cmphex(device_len, ==, UNIFORM_FLASH_SIZE);
+
+ /* Check that erase suspend to read/write is supported. */
+ uint16_t pri = flash_query_1(c, FLASH_ADDR(0x15)) +
+ (flash_query_1(c, FLASH_ADDR(0x16)) << 8);
+ g_assert_cmpint(pri, >=, 0x2D + 4 * nb_erase_regions);
+ g_assert_cmpint(flash_query(c, FLASH_ADDR(pri + 0)), ==, replicate(c, 'P'));
+ g_assert_cmpint(flash_query(c, FLASH_ADDR(pri + 1)), ==, replicate(c, 'R'));
+ g_assert_cmpint(flash_query(c, FLASH_ADDR(pri + 2)), ==, replicate(c, 'I'));
+ g_assert_cmpint(flash_query_1(c, FLASH_ADDR(pri + 6)), ==, 2); /* R/W */
+ reset(c);
+
+ const uint64_t dq7 = replicate(c, 0x80);
+ const uint64_t dq6 = replicate(c, 0x40);
+ const uint64_t dq3 = replicate(c, 0x08);
+ const uint64_t dq2 = replicate(c, 0x04);
+
+ uint64_t byte_addr = 0;
+ for (int region = 0; region < nb_erase_regions; ++region) {
+ uint64_t base = 0x2D + 4 * region;
+ flash_cmd(c, CFI_ADDR, CFI_CMD);
+ uint32_t nb_sectors = flash_query_1(c, FLASH_ADDR(base + 0)) +
+ (flash_query_1(c, FLASH_ADDR(base + 1)) << 8) + 1;
+ uint32_t sector_len = (flash_query_1(c, FLASH_ADDR(base + 2)) << 8) +
+ (flash_query_1(c, FLASH_ADDR(base + 3)) << 16);
+ g_assert_cmphex(nb_sectors, ==, c->nb_blocs[region]);
+ g_assert_cmphex(sector_len, ==, c->sector_len[region]);
+ reset(c);
+
+ /* Erase and program sector. */
+ for (uint32_t i = 0; i < nb_sectors; ++i) {
+ sector_erase(c, byte_addr);
+
+ /* Check that DQ3 is 0. */
+ g_assert_cmphex(flash_read(c, byte_addr) & dq3, ==, 0);
+ qtest_clock_step_next(c->qtest); /* Step over the 50 us timeout. */
+
+ /* Check that DQ3 is 1. */
+ uint64_t status0 = flash_read(c, byte_addr);
+ g_assert_cmphex(status0 & dq3, ==, dq3);
+
+ /* DQ7 is 0 during an erase. */
+ g_assert_cmphex(status0 & dq7, ==, 0);
+ uint64_t status1 = flash_read(c, byte_addr);
+
+ /* DQ6 toggles during an erase. */
+ g_assert_cmphex(status0 & dq6, ==, ~status1 & dq6);
+
+ /* Wait for erase to complete. */
+ wait_for_completion(c, byte_addr);
+
+ /* Ensure DQ6 has stopped toggling. */
+ g_assert_cmphex(flash_read(c, byte_addr), ==,
+ flash_read(c, byte_addr));
+
+ /* Now the data should be valid. */
+ g_assert_cmphex(flash_read(c, byte_addr), ==, bank_mask(c));
+
+ /* Program a bit pattern. */
+ program(c, byte_addr, 0x55);
+ g_assert_cmphex(flash_read(c, byte_addr) & 0xFF, ==, 0x55);
+ program(c, byte_addr, 0xA5);
+ g_assert_cmphex(flash_read(c, byte_addr) & 0xFF, ==, 0x05);
+ byte_addr += sector_len;
+ }
+ }
+
+ /* Erase the chip. */
+ chip_erase(c);
+ /* Read toggle. */
+ uint64_t status0 = flash_read(c, 0);
+ /* DQ7 is 0 during an erase. */
+ g_assert_cmphex(status0 & dq7, ==, 0);
+ uint64_t status1 = flash_read(c, 0);
+ /* DQ6 toggles during an erase. */
+ g_assert_cmphex(status0 & dq6, ==, ~status1 & dq6);
+ /* Wait for erase to complete. */
+ qtest_clock_step_next(c->qtest);
+ /* Ensure DQ6 has stopped toggling. */
+ g_assert_cmphex(flash_read(c, 0), ==, flash_read(c, 0));
+ /* Now the data should be valid. */
+
+ for (int region = 0; region < nb_erase_regions; ++region) {
+ for (uint32_t i = 0; i < c->nb_blocs[region]; ++i) {
+ uint64_t byte_addr = i * c->sector_len[region];
+ g_assert_cmphex(flash_read(c, byte_addr), ==, bank_mask(c));
+ }
+ }
+
+ /* Unlock bypass */
+ unlock(c);
+ flash_cmd(c, UNLOCK0_ADDR, UNLOCK_BYPASS_CMD);
+ bypass_program(c, 0 * c->bank_width, 0x01);
+ bypass_program(c, 1 * c->bank_width, 0x23);
+ bypass_program(c, 2 * c->bank_width, 0x45);
+ /*
+ * Test that bypass programming, unlike normal programming can use any
+ * address for the PROGRAM_CMD.
+ */
+ flash_cmd(c, FLASH_ADDR(3 * c->bank_width), PROGRAM_CMD);
+ flash_write(c, 3 * c->bank_width, 0x67);
+ wait_for_completion(c, 3 * c->bank_width);
+ flash_cmd(c, FLASH_ADDR(0), UNLOCK_BYPASS_RESET_CMD);
+ bypass_program(c, 4 * c->bank_width, 0x89); /* Should fail. */
+ g_assert_cmphex(flash_read(c, 0 * c->bank_width), ==, 0x01);
+ g_assert_cmphex(flash_read(c, 1 * c->bank_width), ==, 0x23);
+ g_assert_cmphex(flash_read(c, 2 * c->bank_width), ==, 0x45);
+ g_assert_cmphex(flash_read(c, 3 * c->bank_width), ==, 0x67);
+ g_assert_cmphex(flash_read(c, 4 * c->bank_width), ==, bank_mask(c));
+
+ /* Test ignored high order bits of address. */
+ flash_cmd(c, FLASH_ADDR(0x5555), UNLOCK0_CMD);
+ flash_cmd(c, FLASH_ADDR(0x2AAA), UNLOCK1_CMD);
+ flash_cmd(c, FLASH_ADDR(0x5555), AUTOSELECT_CMD);
+ g_assert_cmphex(flash_query(c, FLASH_ADDR(0)), ==, replicate(c, 0xBF));
+ reset(c);
+
+ /*
+ * Program a word on each sector, erase one or two sectors per region, and
+ * verify that all of those, and only those, are erased.
+ */
+ byte_addr = 0;
+ for (int region = 0; region < nb_erase_regions; ++region) {
+ for (int i = 0; i < config->nb_blocs[region]; ++i) {
+ program(c, byte_addr, 0);
+ byte_addr += config->sector_len[region];
+ }
+ }
+ unlock(c);
+ flash_cmd(c, UNLOCK0_ADDR, SECOND_UNLOCK_CMD);
+ unlock(c);
+ byte_addr = 0;
+ const uint64_t erase_cmd = replicate(c, SECTOR_ERASE_CMD);
+ for (int region = 0; region < nb_erase_regions; ++region) {
+ flash_write(c, byte_addr, erase_cmd);
+ if (c->nb_blocs[region] > 1) {
+ flash_write(c, byte_addr + c->sector_len[region], erase_cmd);
+ }
+ byte_addr += c->sector_len[region] * c->nb_blocs[region];
+ }
+
+ qtest_clock_step_next(c->qtest); /* Step over the 50 us timeout. */
+ wait_for_completion(c, 0);
+ byte_addr = 0;
+ for (int region = 0; region < nb_erase_regions; ++region) {
+ for (int i = 0; i < config->nb_blocs[region]; ++i) {
+ if (i < 2) {
+ g_assert_cmphex(flash_read(c, byte_addr), ==, bank_mask(c));
+ } else {
+ g_assert_cmphex(flash_read(c, byte_addr), ==, 0);
+ }
+ byte_addr += config->sector_len[region];
+ }
+ }
+
+ /* Test erase suspend/resume during erase timeout. */
+ sector_erase(c, 0);
+ /*
+ * Check that DQ 3 is 0 and DQ6 and DQ2 are toggling in the sector being
+ * erased as well as in a sector not being erased.
+ */
+ byte_addr = c->sector_len[0];
+ status0 = flash_read(c, 0);
+ status1 = flash_read(c, 0);
+ g_assert_cmpint(status0 & dq3, ==, 0);
+ g_assert_cmpint(status0 & dq6, ==, ~status1 & dq6);
+ g_assert_cmpint(status0 & dq2, ==, ~status1 & dq2);
+ status0 = flash_read(c, byte_addr);
+ status1 = flash_read(c, byte_addr);
+ g_assert_cmpint(status0 & dq3, ==, 0);
+ g_assert_cmpint(status0 & dq6, ==, ~status1 & dq6);
+ g_assert_cmpint(status0 & dq2, ==, ~status1 & dq2);
+
+ /*
+ * Check that after suspending, DQ6 does not toggle but DQ2 does toggle in
+ * an erase suspended sector but that neither toggle (we should be
+ * getting data) in a sector not being erased.
+ */
+ erase_suspend(c);
+ status0 = flash_read(c, 0);
+ status1 = flash_read(c, 0);
+ g_assert_cmpint(status0 & dq6, ==, status1 & dq6);
+ g_assert_cmpint(status0 & dq2, ==, ~status1 & dq2);
+ g_assert_cmpint(flash_read(c, byte_addr), ==, flash_read(c, byte_addr));
+
+ /* Check that after resuming, DQ3 is 1 and DQ6 and DQ2 toggle. */
+ erase_resume(c);
+ status0 = flash_read(c, 0);
+ status1 = flash_read(c, 0);
+ g_assert_cmpint(status0 & dq3, ==, dq3);
+ g_assert_cmpint(status0 & dq6, ==, ~status1 & dq6);
+ g_assert_cmpint(status0 & dq2, ==, ~status1 & dq2);
+ status0 = flash_read(c, byte_addr);
+ status1 = flash_read(c, byte_addr);
+ g_assert_cmpint(status0 & dq3, ==, dq3);
+ g_assert_cmpint(status0 & dq6, ==, ~status1 & dq6);
+ g_assert_cmpint(status0 & dq2, ==, ~status1 & dq2);
+ wait_for_completion(c, 0);
+
+ /* Repeat this process but this time suspend after the timeout. */
+ sector_erase(c, 0);
+ qtest_clock_step_next(c->qtest);
+ /*
+ * Check that DQ 3 is 1 and DQ6 and DQ2 are toggling in the sector being
+ * erased as well as in a sector not being erased.
+ */
+ byte_addr = c->sector_len[0];
+ status0 = flash_read(c, 0);
+ status1 = flash_read(c, 0);
+ g_assert_cmpint(status0 & dq3, ==, dq3);
+ g_assert_cmpint(status0 & dq6, ==, ~status1 & dq6);
+ g_assert_cmpint(status0 & dq2, ==, ~status1 & dq2);
+ status0 = flash_read(c, byte_addr);
+ status1 = flash_read(c, byte_addr);
+ g_assert_cmpint(status0 & dq3, ==, dq3);
+ g_assert_cmpint(status0 & dq6, ==, ~status1 & dq6);
+ g_assert_cmpint(status0 & dq2, ==, ~status1 & dq2);
+
+ /*
+ * Check that after suspending, DQ6 does not toggle but DQ2 does toggle in
+ * an erase suspended sector but that neither toggle (we should be
+ * getting data) in a sector not being erased.
+ */
+ erase_suspend(c);
+ status0 = flash_read(c, 0);
+ status1 = flash_read(c, 0);
+ g_assert_cmpint(status0 & dq6, ==, status1 & dq6);
+ g_assert_cmpint(status0 & dq2, ==, ~status1 & dq2);
+ g_assert_cmpint(flash_read(c, byte_addr), ==, flash_read(c, byte_addr));
+
+ /* Check that after resuming, DQ3 is 1 and DQ6 and DQ2 toggle. */
+ erase_resume(c);
+ status0 = flash_read(c, 0);
+ status1 = flash_read(c, 0);
+ g_assert_cmpint(status0 & dq3, ==, dq3);
+ g_assert_cmpint(status0 & dq6, ==, ~status1 & dq6);
+ g_assert_cmpint(status0 & dq2, ==, ~status1 & dq2);
+ status0 = flash_read(c, byte_addr);
+ status1 = flash_read(c, byte_addr);
+ g_assert_cmpint(status0 & dq3, ==, dq3);
+ g_assert_cmpint(status0 & dq6, ==, ~status1 & dq6);
+ g_assert_cmpint(status0 & dq2, ==, ~status1 & dq2);
+ wait_for_completion(c, 0);
+
+ qtest_quit(qtest);
+}
+
+/*
+ * Test that
+ * 1. enter autoselect mode;
+ * 2. enter CFI mode; and then
+ * 3. exit CFI mode
+ * leaves the flash device in autoselect mode.
+ */
+static void test_cfi_in_autoselect(const void *opaque)
+{
+ const FlashConfig *config = opaque;
+ QTestState *qtest;
+ qtest = qtest_initf("-M musicpal,accel=qtest"
+ " -drive if=pflash,file=%s,format=raw,copy-on-read",
+ image_path);
+ FlashConfig explicit_config = expand_config_defaults(config);
+ explicit_config.qtest = qtest;
+ const FlashConfig *c = &explicit_config;
+
+ /* 1. Enter autoselect. */
+ unlock(c);
+ flash_cmd(c, UNLOCK0_ADDR, AUTOSELECT_CMD);
+ g_assert_cmphex(flash_query(c, FLASH_ADDR(0)), ==, replicate(c, 0xBF));
+
+ /* 2. Enter CFI. */
+ flash_cmd(c, CFI_ADDR, CFI_CMD);
+ g_assert_cmphex(flash_query(c, FLASH_ADDR(0x10)), ==, replicate(c, 'Q'));
+ g_assert_cmphex(flash_query(c, FLASH_ADDR(0x11)), ==, replicate(c, 'R'));
+ g_assert_cmphex(flash_query(c, FLASH_ADDR(0x12)), ==, replicate(c, 'Y'));
+
+ /* 3. Exit CFI. */
+ reset(c);
+ g_assert_cmphex(flash_query(c, FLASH_ADDR(0)), ==, replicate(c, 0xBF));
+
+ qtest_quit(qtest);
+}
+
+static void cleanup(void *opaque)
+{
+ unlink(image_path);
+}
+
+/*
+ * XXX: Tests are limited to bank_width = 2 for now because that's what
+ * hw/arm/musicpal.c has.
+ */
+static const FlashConfig configuration[] = {
+ /* One x16 device. */
+ {
+ .bank_width = 2,
+ },
+ /* Nonuniform sectors (top boot). */
+ {
+ .bank_width = 2,
+ .nb_blocs = { 127, 1, 2, 1 },
+ .sector_len = { 0x10000, 0x08000, 0x02000, 0x04000 },
+ },
+ /* Nonuniform sectors (bottom boot). */
+ {
+ .bank_width = 2,
+ .nb_blocs = { 1, 2, 1, 127 },
+ .sector_len = { 0x04000, 0x02000, 0x08000, 0x10000 },
+ },
+};
+
+int main(int argc, char **argv)
+{
+ int fd = mkstemp(image_path);
+ if (fd == -1) {
+ g_printerr("Failed to create temporary file %s: %s\n", image_path,
+ strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+ if (ftruncate(fd, UNIFORM_FLASH_SIZE) < 0) {
+ int error_code = errno;
+ close(fd);
+ unlink(image_path);
+ g_printerr("Failed to truncate file %s to %u MB: %s\n", image_path,
+ UNIFORM_FLASH_SIZE, strerror(error_code));
+ exit(EXIT_FAILURE);
+ }
+ close(fd);
+
+ qtest_add_abrt_handler(cleanup, NULL);
+ g_test_init(&argc, &argv, NULL);
+
+ size_t nb_configurations = sizeof configuration / sizeof configuration[0];
+ for (size_t i = 0; i < nb_configurations; ++i) {
+ const FlashConfig *config = &configuration[i];
+ char *path = g_strdup_printf("pflash-cfi02"
+ "/geometry/%dx%x-%dx%x-%dx%x-%dx%x"
+ "/%d",
+ config->nb_blocs[0],
+ config->sector_len[0],
+ config->nb_blocs[1],
+ config->sector_len[1],
+ config->nb_blocs[2],
+ config->sector_len[2],
+ config->nb_blocs[3],
+ config->sector_len[3],
+ config->bank_width);
+ qtest_add_data_func(path, config, test_geometry);
+ g_free(path);
+ }
+
+ qtest_add_data_func("pflash-cfi02/cfi-in-autoselect", &configuration[0],
+ test_cfi_in_autoselect);
+ int result = g_test_run();
+ cleanup(NULL);
+ return result;
+}
sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..', 'python'))
-from qemu import QEMUMachine
+from qemu.machine import QEMUMachine
# Note:
# This test was added to check that mirror dead-lock was fixed (see previous
auto_finalize = False)
self.assert_qmp(result, 'return', {})
- # We can't remove hd2 while the stream job is ongoing
+ # We can remove hd2 while the stream job is ongoing
opts['backing']['backing'] = None
- self.reopen(opts, {}, "Cannot change 'backing' link from 'hd1' to 'hd2'")
+ self.reopen(opts, {})
# We can't remove hd1 while the stream job is ongoing
opts['backing'] = None
*/
DO_MSA__WD__WS_WT(MADD_Q_H, madd_q.h)
+DO_MSA__WD__WD_WT(MADD_Q_H__DDT, madd_q.h)
+DO_MSA__WD__WS_WD(MADD_Q_H__DSD, madd_q.h)
DO_MSA__WD__WS_WT(MADD_Q_W, madd_q.w)
+DO_MSA__WD__WD_WT(MADD_Q_W__DDT, madd_q.w)
+DO_MSA__WD__WS_WD(MADD_Q_W__DSD, madd_q.w)
DO_MSA__WD__WS_WT(MADDR_Q_H, maddr_q.h)
+DO_MSA__WD__WD_WT(MADDR_Q_H__DDT, maddr_q.h)
+DO_MSA__WD__WS_WD(MADDR_Q_H__DSD, maddr_q.h)
DO_MSA__WD__WS_WT(MADDR_Q_W, maddr_q.w)
+DO_MSA__WD__WD_WT(MADDR_Q_W__DDT, maddr_q.w)
+DO_MSA__WD__WS_WD(MADDR_Q_W__DSD, maddr_q.w)
DO_MSA__WD__WS_WT(MSUB_Q_H, msub_q.h)
+DO_MSA__WD__WD_WT(MSUB_Q_H__DDT, msub_q.h)
+DO_MSA__WD__WS_WD(MSUB_Q_H__DSD, msub_q.h)
DO_MSA__WD__WS_WT(MSUB_Q_W, msub_q.w)
+DO_MSA__WD__WD_WT(MSUB_Q_W__DDT, msub_q.w)
+DO_MSA__WD__WS_WD(MSUB_Q_W__DSD, msub_q.w)
DO_MSA__WD__WS_WT(MSUBR_Q_H, msubr_q.h)
+DO_MSA__WD__WD_WT(MSUBR_Q_H__DDT, msubr_q.h)
+DO_MSA__WD__WS_WD(MSUBR_Q_H__DSD, msubr_q.h)
DO_MSA__WD__WS_WT(MSUBR_Q_W, msubr_q.w)
+DO_MSA__WD__WD_WT(MSUBR_Q_W__DDT, msubr_q.w)
+DO_MSA__WD__WS_WD(MSUBR_Q_W__DSD, msubr_q.w)
DO_MSA__WD__WS_WT(MUL_Q_H, mul_q.h)
DO_MSA__WD__WS_WT(MUL_Q_W, mul_q.w)
--- /dev/null
+/*
+ * Test program for MSA instruction MADD_Q.H
+ *
+ * Copyright (C) 2019 Wave Computing, Inc.
+ * Copyright (C) 2019 Aleksandar Markovic <amarkovic@wavecomp.com>
+ * Copyright (C) 2019 RT-RK Computer Based Systems LLC
+ * Copyright (C) 2019 Mateja Marjanovic <mateja.marjanovic@rt-rk.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 <https://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <sys/time.h>
+#include <stdint.h>
+
+#include "../../../../include/wrappers_msa.h"
+#include "../../../../include/test_inputs_128.h"
+#include "../../../../include/test_utils_128.h"
+
+#define TEST_COUNT_TOTAL ( \
+ (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \
+ 3 * (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT))
+
+
+int32_t main(void)
+{
+ char *isa_ase_name = "MSA";
+ char *group_name = "Fixed Multiply";
+ char *instruction_name = "MADD_Q.H";
+ int32_t ret;
+ uint32_t i, j;
+ struct timeval start, end;
+ double elapsed_time;
+
+ uint64_t b128_result[TEST_COUNT_TOTAL][2];
+ uint64_t b128_expect[TEST_COUNT_TOTAL][2] = {
+ { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 0 */
+ { 0x0000000000000000ULL, 0x0000000000000000ULL, },
+ { 0x0000000000000000ULL, 0x0000000000000000ULL, },
+ { 0xffffffffffffffffULL, 0xffffffffffffffffULL, },
+ { 0xffffffffffffffffULL, 0xffffffffffffffffULL, },
+ { 0xfffefffefffefffeULL, 0xfffefffefffefffeULL, },
+ { 0xfffefffdfffefffeULL, 0xfffdfffefffefffdULL, },
+ { 0xfffdfffdfffdfffdULL, 0xfffdfffdfffdfffdULL, },
+ { 0xfffdfffdfffdfffdULL, 0xfffdfffdfffdfffdULL, }, /* 8 */
+ { 0xfffdfffdfffdfffdULL, 0xfffdfffdfffdfffdULL, },
+ { 0xfffdfffdfffdfffdULL, 0xfffdfffdfffdfffdULL, },
+ { 0xfffdfffdfffdfffdULL, 0xfffdfffdfffdfffdULL, },
+ { 0xfffdfffdfffdfffdULL, 0xfffdfffdfffdfffdULL, },
+ { 0xfffdfffdfffdfffdULL, 0xfffdfffdfffdfffdULL, },
+ { 0xfffdfffdfffdfffdULL, 0xfffdfffdfffdfffdULL, },
+ { 0xfffdfffdfffdfffdULL, 0xfffdfffdfffdfffdULL, },
+ { 0xfffdfffdfffdfffdULL, 0xfffdfffdfffdfffdULL, }, /* 16 */
+ { 0xfffdfffdfffdfffdULL, 0xfffdfffdfffdfffdULL, },
+ { 0x38e138e138e138e1ULL, 0x38e138e138e138e1ULL, },
+ { 0xfffdfffdfffdfffdULL, 0xfffdfffdfffdfffdULL, },
+ { 0x221f221f221f221fULL, 0x221f221f221f221fULL, },
+ { 0xfffcfffcfffcfffcULL, 0xfffcfffcfffcfffcULL, },
+ { 0x12f2da0f4bd712f2ULL, 0xda0f4bd712f2da0fULL, },
+ { 0xfffbfffcfffcfffbULL, 0xfffcfffcfffbfffcULL, },
+ { 0xfffafffbfffbfffaULL, 0xfffbfffbfffafffbULL, }, /* 24 */
+ { 0xfffafffbfffbfffaULL, 0xfffbfffbfffafffbULL, },
+ { 0xc716c717c717c716ULL, 0xc717c717c716c717ULL, },
+ { 0xfff9fffafffafff9ULL, 0xfffafffafff9fffaULL, },
+ { 0xddd6ddd7ddd7ddd6ULL, 0xddd7ddd7ddd6ddd7ULL, },
+ { 0xfff7fff8fff8fff7ULL, 0xfff8fff8fff7fff8ULL, },
+ { 0xed0025e4b41ded00ULL, 0x25e4b41ded0025e4ULL, },
+ { 0xfff5fff6fff6fff5ULL, 0xfff6fff6fff5fff6ULL, },
+ { 0xfff5fff6fff6fff5ULL, 0xfff6fff6fff5fff6ULL, }, /* 32 */
+ { 0xfff5fff6fff6fff5ULL, 0xfff6fff6fff5fff6ULL, },
+ { 0x2217221822182217ULL, 0x2218221822172218ULL, },
+ { 0xfff4fff5fff5fff4ULL, 0xfff5fff5fff4fff5ULL, },
+ { 0x146f14701470146fULL, 0x14701470146f1470ULL, },
+ { 0xfff3fff4fff4fff3ULL, 0xfff4fff4fff3fff4ULL, },
+ { 0x0b53e9322d770b53ULL, 0xe9322d770b53e932ULL, },
+ { 0xfff2fff3fff3fff2ULL, 0xfff3fff3fff2fff3ULL, },
+ { 0xfff1fff2fff2fff1ULL, 0xfff2fff2fff1fff2ULL, }, /* 40 */
+ { 0xfff1fff2fff2fff1ULL, 0xfff2fff2fff1fff2ULL, },
+ { 0xddceddcfddcfddceULL, 0xddcfddcfddceddcfULL, },
+ { 0xffeffff0fff0ffefULL, 0xfff0fff0ffeffff0ULL, },
+ { 0xeb73eb74eb74eb73ULL, 0xeb74eb74eb73eb74ULL, },
+ { 0xffedffeeffeeffedULL, 0xffeeffeeffedffeeULL, },
+ { 0xf48c16afd26af48cULL, 0x16afd26af48c16afULL, },
+ { 0xffecffedffecffecULL, 0xffedffecffecffedULL, },
+ { 0xffecffecffecffecULL, 0xffecffecffecffecULL, }, /* 48 */
+ { 0xffecffecffecffecULL, 0xffecffecffecffecULL, },
+ { 0x12e2d9ff4bc712e2ULL, 0xd9ff4bc712e2d9ffULL, },
+ { 0xffebffebffecffebULL, 0xffebffecffebffebULL, },
+ { 0x0b4be9292d6f0b4bULL, 0xe9292d6f0b4be929ULL, },
+ { 0xffeaffeaffebffeaULL, 0xffeaffebffeaffeaULL, },
+ { 0x063c1932650f063cULL, 0x1932650f063c1932ULL, },
+ { 0xffe9ffe9ffebffe9ULL, 0xffe9ffebffe9ffe9ULL, },
+ { 0xffe8ffe9ffeaffe8ULL, 0xffe9ffeaffe8ffe9ULL, }, /* 56 */
+ { 0xffe8ffe9ffeaffe8ULL, 0xffe9ffeaffe8ffe9ULL, },
+ { 0xecf125d6b40fecf1ULL, 0x25d6b40fecf125d6ULL, },
+ { 0xffe6ffe8ffe8ffe6ULL, 0xffe8ffe8ffe6ffe8ULL, },
+ { 0xf48516a9d264f485ULL, 0x16a9d264f48516a9ULL, },
+ { 0xffe5ffe7ffe6ffe5ULL, 0xffe7ffe6ffe5ffe7ULL, },
+ { 0xf992e69e9ac2f992ULL, 0xe69e9ac2f992e69eULL, },
+ { 0xffe3ffe7ffe4ffe3ULL, 0xffe7ffe4ffe3ffe7ULL, },
+ { 0x6f9c04dd0ca138aaULL, 0x2c5200e6ffe731d8ULL, }, /* 64 */
+ { 0x739604c9251a12b8ULL, 0x377dfac7ffa6fe02ULL, },
+ { 0x7fff14cc0ef4c520ULL, 0x4ef5f5b700a7e6d8ULL, },
+ { 0x171110672cabb158ULL, 0x0bc4eb2201aef931ULL, },
+ { 0x1b0b105345248b66ULL, 0x16efe503016dc55bULL, },
+ { 0x1b2f10537427a4c0ULL, 0x19be0a1804f3fb27ULL, },
+ { 0x1df71014499cd899ULL, 0x1fa528c6f6de1330ULL, },
+ { 0x1a3a10257fffe5d0ULL, 0x0ebe68e9e8780024ULL, },
+ { 0x6860202869d99838ULL, 0x263663d9e979e8faULL, }, /* 72 */
+ { 0x6b281fe93f4ecc11ULL, 0x2c1d7fffdb640103ULL, },
+ { 0x7fff539865cb3619ULL, 0x38847fff139c0bc0ULL, },
+ { 0x369a456c32245120ULL, 0x15027fff4d19033dULL, },
+ { 0xcdac41074fdb3d58ULL, 0xd1d1756a4e201596ULL, },
+ { 0xc9ef41187fff4a8fULL, 0xc0ea7fff3fba028aULL, },
+ { 0x808a32ec4c586596ULL, 0x9d687fff7937fa07ULL, },
+ { 0xe31436ce7fff6c79ULL, 0x030a7fff7fff00c4ULL, },
+ { 0xfe192c037fff7fffULL, 0x04d47fff7e7a0049ULL, }, /* 80 */
+ { 0xfe292c257fff4707ULL, 0x058b3b197fff0078ULL, },
+ { 0xff5c101739ce0661ULL, 0x074420c72b2a009aULL, },
+ { 0xfecc12e4645704e6ULL, 0x00ca02430de90076ULL, },
+ { 0xffeb0f2b7fff0829ULL, 0x014002760dbe002cULL, },
+ { 0xffeb0f367fff0487ULL, 0x016f012210050048ULL, },
+ { 0xfff8058b39ce0068ULL, 0x01e100a00567005cULL, },
+ { 0xfff006826457004fULL, 0x0034000b01bd0046ULL, },
+ { 0xfffe05397fff0083ULL, 0x0052000b01b7001aULL, }, /* 88 */
+ { 0xfffe053d7fff0048ULL, 0x005e000501ff002aULL, },
+ { 0xffff01e839ce0006ULL, 0x007b000200ac0036ULL, },
+ { 0xfffe023d64570004ULL, 0x000d000000370029ULL, },
+ { 0xffff01cc7fff0006ULL, 0x001400000036000fULL, },
+ { 0xffff01cd7fff0003ULL, 0x00160000003e0018ULL, },
+ { 0xffff00a839ce0000ULL, 0x001c00000014001eULL, },
+ { 0xfffe00c564570000ULL, 0x0003000000060017ULL, },
+ { 0xffff009e7fff0000ULL, 0x0004000000050008ULL, }, /* 96 */
+ { 0xffff007e7fff0000ULL, 0x0006000000040003ULL, },
+ { 0xffff00657fff0000ULL, 0x0009000000030001ULL, },
+ { 0xffff00517fff0000ULL, 0x000e000000020000ULL, },
+ { 0xffff00517fff0000ULL, 0x0010000000020000ULL, },
+ { 0xffff00517fff0000ULL, 0x0012000000020000ULL, },
+ { 0xffff00517fff0000ULL, 0x0014000000020000ULL, },
+ { 0xffff00517fff0000ULL, 0x0016000000020000ULL, },
+ { 0xffff001d39ce0000ULL, 0x001c000000000000ULL, }, /* 104 */
+ { 0xffff000a1a1b0000ULL, 0x0024000000000000ULL, },
+ { 0xffff00030bca0000ULL, 0x002f000000000000ULL, },
+ { 0xffff000105530000ULL, 0x003d000000000000ULL, },
+ { 0xfffe0001093d0000ULL, 0x0006000000000000ULL, },
+ { 0xfffc000110090000ULL, 0x0000000000000000ULL, },
+ { 0xfff800011bd50000ULL, 0x0000000000000000ULL, },
+ { 0xfff0000130500000ULL, 0x0000000000000000ULL, },
+};
+
+ reset_msa_registers();
+
+ gettimeofday(&start, NULL);
+
+ for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) {
+ for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) {
+ do_msa_MADD_Q_H(b128_pattern[i], b128_pattern[j],
+ b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]);
+ }
+ }
+
+ for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) {
+ for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) {
+ do_msa_MADD_Q_H(b128_random[i], b128_random[j],
+ b128_result[((PATTERN_INPUTS_SHORT_COUNT) *
+ (PATTERN_INPUTS_SHORT_COUNT)) +
+ RANDOM_INPUTS_SHORT_COUNT * i + j]);
+ }
+ }
+
+ for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) {
+ for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) {
+ do_msa_MADD_Q_H__DDT(b128_random[i], b128_random[j],
+ b128_result[
+ ((PATTERN_INPUTS_SHORT_COUNT) *
+ (PATTERN_INPUTS_SHORT_COUNT)) +
+ ((RANDOM_INPUTS_SHORT_COUNT) *
+ (RANDOM_INPUTS_SHORT_COUNT)) +
+ RANDOM_INPUTS_SHORT_COUNT * i + j]);
+ }
+ }
+
+ for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) {
+ for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) {
+ do_msa_MADD_Q_H__DSD(b128_random[i], b128_random[j],
+ b128_result[
+ ((PATTERN_INPUTS_SHORT_COUNT) *
+ (PATTERN_INPUTS_SHORT_COUNT)) +
+ (2 * (RANDOM_INPUTS_SHORT_COUNT) *
+ (RANDOM_INPUTS_SHORT_COUNT)) +
+ RANDOM_INPUTS_SHORT_COUNT * i + j]);
+ }
+ }
+
+ gettimeofday(&end, NULL);
+
+ elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0;
+ elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0;
+
+ ret = check_results_128(isa_ase_name, group_name, instruction_name,
+ TEST_COUNT_TOTAL, elapsed_time,
+ &b128_result[0][0], &b128_expect[0][0]);
+
+ return ret;
+}
--- /dev/null
+/*
+ * Test program for MSA instruction MADD_Q.W
+ *
+ * Copyright (C) 2019 Wave Computing, Inc.
+ * Copyright (C) 2019 Aleksandar Markovic <amarkovic@wavecomp.com>
+ * Copyright (C) 2019 RT-RK Computer Based Systems LLC
+ * Copyright (C) 2019 Mateja Marjanovic <mateja.marjanovic@rt-rk.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 <https://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <sys/time.h>
+#include <stdint.h>
+
+#include "../../../../include/wrappers_msa.h"
+#include "../../../../include/test_inputs_128.h"
+#include "../../../../include/test_utils_128.h"
+
+#define TEST_COUNT_TOTAL ( \
+ (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \
+ 3 * (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT))
+
+
+int32_t main(void)
+{
+ char *isa_ase_name = "MSA";
+ char *group_name = "Fixed Multiply";
+ char *instruction_name = "MADD_Q.W";
+ int32_t ret;
+ uint32_t i, j;
+ struct timeval start, end;
+ double elapsed_time;
+
+ uint64_t b128_result[TEST_COUNT_TOTAL][2];
+ uint64_t b128_expect[TEST_COUNT_TOTAL][2] = {
+ { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 0 */
+ { 0x0000000000000000ULL, 0x0000000000000000ULL, },
+ { 0x0000000000000000ULL, 0x0000000000000000ULL, },
+ { 0xffffffffffffffffULL, 0xffffffffffffffffULL, },
+ { 0xffffffffffffffffULL, 0xffffffffffffffffULL, },
+ { 0xfffffffefffffffeULL, 0xfffffffefffffffeULL, },
+ { 0xfffffffefffffffeULL, 0xfffffffdfffffffeULL, },
+ { 0xfffffffdfffffffdULL, 0xfffffffdfffffffdULL, },
+ { 0xfffffffdfffffffdULL, 0xfffffffdfffffffdULL, }, /* 8 */
+ { 0xfffffffdfffffffdULL, 0xfffffffdfffffffdULL, },
+ { 0xfffffffdfffffffdULL, 0xfffffffdfffffffdULL, },
+ { 0xfffffffdfffffffdULL, 0xfffffffdfffffffdULL, },
+ { 0xfffffffdfffffffdULL, 0xfffffffdfffffffdULL, },
+ { 0xfffffffdfffffffdULL, 0xfffffffdfffffffdULL, },
+ { 0xfffffffdfffffffdULL, 0xfffffffdfffffffdULL, },
+ { 0xfffffffdfffffffdULL, 0xfffffffdfffffffdULL, },
+ { 0xfffffffdfffffffdULL, 0xfffffffdfffffffdULL, }, /* 16 */
+ { 0xfffffffdfffffffdULL, 0xfffffffdfffffffdULL, },
+ { 0x38e38e3638e38e36ULL, 0x38e38e3638e38e36ULL, },
+ { 0xfffffffcfffffffcULL, 0xfffffffcfffffffcULL, },
+ { 0x2222221e2222221eULL, 0x2222221e2222221eULL, },
+ { 0xfffffffbfffffffbULL, 0xfffffffbfffffffbULL, },
+ { 0x12f684b94bda12f2ULL, 0xda12f68012f684b9ULL, },
+ { 0xfffffffbfffffffbULL, 0xfffffffbfffffffbULL, },
+ { 0xfffffffafffffffaULL, 0xfffffffafffffffaULL, }, /* 24 */
+ { 0xfffffffafffffffaULL, 0xfffffffafffffffaULL, },
+ { 0xc71c71c0c71c71c0ULL, 0xc71c71c0c71c71c0ULL, },
+ { 0xfffffff8fffffff8ULL, 0xfffffff8fffffff8ULL, },
+ { 0xddddddd5ddddddd5ULL, 0xddddddd5ddddddd5ULL, },
+ { 0xfffffff6fffffff6ULL, 0xfffffff6fffffff6ULL, },
+ { 0xed097b38b425ecffULL, 0x25ed0970ed097b38ULL, },
+ { 0xfffffff5fffffff4ULL, 0xfffffff4fffffff5ULL, },
+ { 0xfffffff5fffffff4ULL, 0xfffffff4fffffff5ULL, }, /* 32 */
+ { 0xfffffff5fffffff4ULL, 0xfffffff4fffffff5ULL, },
+ { 0x2222221722222216ULL, 0x2222221622222217ULL, },
+ { 0xfffffff4fffffff3ULL, 0xfffffff3fffffff4ULL, },
+ { 0x147ae13c147ae13bULL, 0x147ae13b147ae13cULL, },
+ { 0xfffffff4fffffff3ULL, 0xfffffff3fffffff4ULL, },
+ { 0x0b60b5ff2d82d821ULL, 0xe93e93dc0b60b5ffULL, },
+ { 0xfffffff3fffffff3ULL, 0xfffffff3fffffff3ULL, },
+ { 0xfffffff2fffffff2ULL, 0xfffffff2fffffff2ULL, }, /* 40 */
+ { 0xfffffff2fffffff2ULL, 0xfffffff2fffffff2ULL, },
+ { 0xddddddcfddddddcfULL, 0xddddddcfddddddcfULL, },
+ { 0xfffffff0fffffff0ULL, 0xfffffff0fffffff0ULL, },
+ { 0xeb851ea8eb851ea8ULL, 0xeb851ea8eb851ea8ULL, },
+ { 0xffffffefffffffefULL, 0xffffffefffffffefULL, },
+ { 0xf49f49e3d27d27c1ULL, 0x16c16c05f49f49e3ULL, },
+ { 0xffffffeeffffffeeULL, 0xffffffeeffffffeeULL, },
+ { 0xffffffeeffffffeeULL, 0xffffffedffffffeeULL, }, /* 48 */
+ { 0xffffffeeffffffeeULL, 0xffffffedffffffeeULL, },
+ { 0x12f684ac4bda12e5ULL, 0xda12f67212f684acULL, },
+ { 0xffffffeeffffffeeULL, 0xffffffecffffffeeULL, },
+ { 0x0b60b5f92d82d81cULL, 0xe93e93d50b60b5f9ULL, },
+ { 0xffffffedffffffeeULL, 0xffffffebffffffedULL, },
+ { 0x06522c2c6522c3e1ULL, 0x1948b0e706522c2cULL, },
+ { 0xffffffecffffffeeULL, 0xffffffeaffffffecULL, },
+ { 0xffffffebffffffedULL, 0xffffffeaffffffebULL, }, /* 56 */
+ { 0xffffffebffffffedULL, 0xffffffeaffffffebULL, },
+ { 0xed097b2db425ecf6ULL, 0x25ed0965ed097b2dULL, },
+ { 0xffffffeaffffffebULL, 0xffffffe9ffffffeaULL, },
+ { 0xf49f49ded27d27bdULL, 0x16c16c00f49f49deULL, },
+ { 0xffffffe9ffffffeaULL, 0xffffffe9ffffffe9ULL, },
+ { 0xf9add3a99add3bf7ULL, 0xe6b74eecf9add3a9ULL, },
+ { 0xffffffe8ffffffe8ULL, 0xffffffe8ffffffe8ULL, },
+ { 0x6fb7e8710cbdc0baULL, 0x2c6b142e000499ecULL, }, /* 64 */
+ { 0x73b239bf253787bbULL, 0x379780d7ffc424b2ULL, },
+ { 0x7fffffff0f12777aULL, 0x4f10996a00c57ee6ULL, },
+ { 0x1713a7162cca6b1fULL, 0x0be04dd301cca255ULL, },
+ { 0x1b0df86445443220ULL, 0x170cba7c018c2d1bULL, },
+ { 0x1b323a657448a831ULL, 0x19dc4690051313a9ULL, },
+ { 0x1dfa85ec49be7952ULL, 0x1fc3e11af6fe2ffbULL, },
+ { 0x1a3e24c87fffffffULL, 0x0edd19b6e8983fd8ULL, },
+ { 0x6863454e69daefbeULL, 0x26563249e9999a0cULL, }, /* 72 */
+ { 0x6b2b90d53f50c0dfULL, 0x2c3dccd3db84b65eULL, },
+ { 0x7fffffff65cdd2a2ULL, 0x38a5553713bd77aaULL, },
+ { 0x369baa383226e26fULL, 0x1523c32e4d39d083ULL, },
+ { 0xcdaf514f4fded614ULL, 0xd1f377974e40f3f2ULL, },
+ { 0xc9f2f02b7fffffffULL, 0xc10cb0333fdb03cfULL, },
+ { 0x808e9a644c590fccULL, 0x9d8b1e2a79575ca8ULL, },
+ { 0xe31932487fffffffULL, 0x032ce40b7fffffffULL, },
+ { 0xfe196fe57fffffffULL, 0x050bc0117e7bb00bULL, }, /* 80 */
+ { 0xfe299f467fffffffULL, 0x05cb2b207fffffffULL, },
+ { 0xff5d018239cf8b7fULL, 0x0798e21e2b2b2513ULL, },
+ { 0xfecdfe1e645a7d99ULL, 0x00d3dcf00dea608dULL, },
+ { 0xffebe0507fffffffULL, 0x0150aaf30dc02967ULL, },
+ { 0xffec8bad7fffffffULL, 0x01828e9310087db0ULL, },
+ { 0xfff9423b39cf8b7fULL, 0x01fae4ad056841b8ULL, },
+ { 0xfff35804645a7d99ULL, 0x003737ba01be3861ULL, },
+ { 0xffff2aee7fffffffULL, 0x0057bed401b8eeafULL, }, /* 88 */
+ { 0xffff32047fffffffULL, 0x0064bf7c02021ffbULL, },
+ { 0xffffb89f39cf8b7fULL, 0x00841c7300ad6409ULL, },
+ { 0xffff79fe645a7d99ULL, 0x000e642e0037e4a5ULL, },
+ { 0xfffff72f7fffffffULL, 0x0016de7600373b15ULL, },
+ { 0xfffff77a7fffffffULL, 0x001a420100406619ULL, },
+ { 0xfffffd0b39cf8b7fULL, 0x00226e950015b801ULL, },
+ { 0xfffffa72645a7d99ULL, 0x0003c03400070049ULL, },
+ { 0xffffffa27fffffffULL, 0x0005f5d70006eb0bULL, }, /* 96 */
+ { 0xfffffff97fffffffULL, 0x000978af0006d60eULL, },
+ { 0xffffffff7fffffffULL, 0x000f0d050006c150ULL, },
+ { 0xffffffff7fffffffULL, 0x0017eac30006acd1ULL, },
+ { 0xffffffff7fffffffULL, 0x001b76100007c878ULL, },
+ { 0xffffffff7fffffffULL, 0x001f87d000091335ULL, },
+ { 0xffffffff7fffffffULL, 0x002433ef000a94d9ULL, },
+ { 0xffffffff7fffffffULL, 0x0029914d000c5680ULL, },
+ { 0xffffffff39cf8b7fULL, 0x003681f800042937ULL, }, /* 104 */
+ { 0xffffffff1a1c28c3ULL, 0x004779e10001673fULL, },
+ { 0xffffffff0bcae025ULL, 0x005dba1000007928ULL, },
+ { 0xffffffff055376c1ULL, 0x007ae77c000028dcULL, },
+ { 0xfffffffe093ed554ULL, 0x000d636d00000d2bULL, },
+ { 0xfffffffc100c9463ULL, 0x0001755c0000043eULL, },
+ { 0xfffffff81bdc128cULL, 0x000028ab0000015eULL, },
+ { 0xfffffff0305c8babULL, 0x0000046e00000070ULL, },
+};
+
+ reset_msa_registers();
+
+ gettimeofday(&start, NULL);
+
+ for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) {
+ for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) {
+ do_msa_MADD_Q_W(b128_pattern[i], b128_pattern[j],
+ b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]);
+ }
+ }
+
+ for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) {
+ for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) {
+ do_msa_MADD_Q_W(b128_random[i], b128_random[j],
+ b128_result[((PATTERN_INPUTS_SHORT_COUNT) *
+ (PATTERN_INPUTS_SHORT_COUNT)) +
+ RANDOM_INPUTS_SHORT_COUNT * i + j]);
+ }
+ }
+
+ for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) {
+ for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) {
+ do_msa_MADD_Q_W__DDT(b128_random[i], b128_random[j],
+ b128_result[
+ ((PATTERN_INPUTS_SHORT_COUNT) *
+ (PATTERN_INPUTS_SHORT_COUNT)) +
+ ((RANDOM_INPUTS_SHORT_COUNT) *
+ (RANDOM_INPUTS_SHORT_COUNT)) +
+ RANDOM_INPUTS_SHORT_COUNT * i + j]);
+ }
+ }
+
+ for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) {
+ for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) {
+ do_msa_MADD_Q_W__DSD(b128_random[i], b128_random[j],
+ b128_result[
+ ((PATTERN_INPUTS_SHORT_COUNT) *
+ (PATTERN_INPUTS_SHORT_COUNT)) +
+ (2 * (RANDOM_INPUTS_SHORT_COUNT) *
+ (RANDOM_INPUTS_SHORT_COUNT)) +
+ RANDOM_INPUTS_SHORT_COUNT * i + j]);
+ }
+ }
+
+ gettimeofday(&end, NULL);
+
+ elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0;
+ elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0;
+
+ ret = check_results_128(isa_ase_name, group_name, instruction_name,
+ TEST_COUNT_TOTAL, elapsed_time,
+ &b128_result[0][0], &b128_expect[0][0]);
+
+ return ret;
+}
--- /dev/null
+/*
+ * Test program for MSA instruction MADDR_Q.H
+ *
+ * Copyright (C) 2019 Wave Computing, Inc.
+ * Copyright (C) 2019 Aleksandar Markovic <amarkovic@wavecomp.com>
+ * Copyright (C) 2019 RT-RK Computer Based Systems LLC
+ * Copyright (C) 2019 Mateja Marjanovic <mateja.marjanovic@rt-rk.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 <https://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <sys/time.h>
+#include <stdint.h>
+
+#include "../../../../include/wrappers_msa.h"
+#include "../../../../include/test_inputs_128.h"
+#include "../../../../include/test_utils_128.h"
+
+#define TEST_COUNT_TOTAL ( \
+ (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \
+ 3 * (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT))
+
+
+int32_t main(void)
+{
+ char *isa_ase_name = "MSA";
+ char *group_name = "Fixed Multiply";
+ char *instruction_name = "MADDR_Q.H";
+ int32_t ret;
+ uint32_t i, j;
+ struct timeval start, end;
+ double elapsed_time;
+
+ uint64_t b128_result[TEST_COUNT_TOTAL][2];
+ uint64_t b128_expect[TEST_COUNT_TOTAL][2] = {
+ { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 0 */
+ { 0x0000000000000000ULL, 0x0000000000000000ULL, },
+ { 0x0001000100010001ULL, 0x0001000100010001ULL, },
+ { 0x0000000000000000ULL, 0x0000000000000000ULL, },
+ { 0x0000000000000000ULL, 0x0000000000000000ULL, },
+ { 0x0000000000000000ULL, 0x0000000000000000ULL, },
+ { 0x0000000000010000ULL, 0x0000000100000000ULL, },
+ { 0x0000000000000000ULL, 0x0000000000000000ULL, },
+ { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 8 */
+ { 0x0000000000000000ULL, 0x0000000000000000ULL, },
+ { 0x0000000000000000ULL, 0x0000000000000000ULL, },
+ { 0x0000000000000000ULL, 0x0000000000000000ULL, },
+ { 0x0000000000000000ULL, 0x0000000000000000ULL, },
+ { 0x0000000000000000ULL, 0x0000000000000000ULL, },
+ { 0x0000000000000000ULL, 0x0000000000000000ULL, },
+ { 0x0000000000000000ULL, 0x0000000000000000ULL, },
+ { 0x0001000100010001ULL, 0x0001000100010001ULL, }, /* 16 */
+ { 0x0001000100010001ULL, 0x0001000100010001ULL, },
+ { 0x38e538e538e538e5ULL, 0x38e538e538e538e5ULL, },
+ { 0x0001000100010001ULL, 0x0001000100010001ULL, },
+ { 0x2224222422242224ULL, 0x2224222422242224ULL, },
+ { 0x0002000200020002ULL, 0x0002000200020002ULL, },
+ { 0x12f9da154bdd12f9ULL, 0xda154bdd12f9da15ULL, },
+ { 0x0003000300020003ULL, 0x0003000200030003ULL, },
+ { 0x0002000200010002ULL, 0x0002000100020002ULL, }, /* 24 */
+ { 0x0002000200010002ULL, 0x0002000100020002ULL, },
+ { 0xc71ec71ec71dc71eULL, 0xc71ec71dc71ec71eULL, },
+ { 0x0001000100000001ULL, 0x0001000000010001ULL, },
+ { 0xdddedddedddddddeULL, 0xdddedddddddedddeULL, },
+ { 0x00000000ffff0000ULL, 0x0000ffff00000000ULL, },
+ { 0xed0925edb425ed09ULL, 0x25edb425ed0925edULL, },
+ { 0xffff0000ffffffffULL, 0x0000ffffffff0000ULL, },
+ { 0xffff0000ffffffffULL, 0x0000ffffffff0000ULL, }, /* 32 */
+ { 0xffff0000ffffffffULL, 0x0000ffffffff0000ULL, },
+ { 0x2222222322222222ULL, 0x2223222222222223ULL, },
+ { 0xffff0000ffffffffULL, 0x0000ffffffff0000ULL, },
+ { 0x147b147c147b147bULL, 0x147c147b147b147cULL, },
+ { 0x0000000100000000ULL, 0x0001000000000001ULL, },
+ { 0x0b61e93f2d840b61ULL, 0xe93f2d840b61e93fULL, },
+ { 0x0000000100000000ULL, 0x0001000000000001ULL, },
+ { 0x0000000100000000ULL, 0x0001000000000001ULL, }, /* 40 */
+ { 0x0000000100000000ULL, 0x0001000000000001ULL, },
+ { 0xdddedddfdddedddeULL, 0xdddfdddedddedddfULL, },
+ { 0x0000000100000000ULL, 0x0001000000000001ULL, },
+ { 0xeb85eb86eb85eb85ULL, 0xeb86eb85eb85eb86ULL, },
+ { 0x0000000100000000ULL, 0x0001000000000001ULL, },
+ { 0xf49f16c2d27df49fULL, 0x16c2d27df49f16c2ULL, },
+ { 0xffff00000000ffffULL, 0x00000000ffff0000ULL, },
+ { 0xffff00000001ffffULL, 0x00000001ffff0000ULL, }, /* 48 */
+ { 0xffff00000001ffffULL, 0x00000001ffff0000ULL, },
+ { 0x12f6da134bdc12f6ULL, 0xda134bdc12f6da13ULL, },
+ { 0xffff00000002ffffULL, 0x00000002ffff0000ULL, },
+ { 0x0b60e93e2d860b60ULL, 0xe93e2d860b60e93eULL, },
+ { 0xffffffff0003ffffULL, 0xffff0003ffffffffULL, },
+ { 0x0651194765270651ULL, 0x1947652706511947ULL, },
+ { 0xfffffffe0004ffffULL, 0xfffe0004fffffffeULL, },
+ { 0xfffffffe0003ffffULL, 0xfffe0003fffffffeULL, }, /* 56 */
+ { 0xfffffffe0003ffffULL, 0xfffe0003fffffffeULL, },
+ { 0xed0925ecb428ed09ULL, 0x25ecb428ed0925ecULL, },
+ { 0xffffffff0002ffffULL, 0xffff0002ffffffffULL, },
+ { 0xf49e16c1d27ef49eULL, 0x16c1d27ef49e16c1ULL, },
+ { 0xfffeffff0001fffeULL, 0xffff0001fffeffffULL, },
+ { 0xf9ace6b69adef9acULL, 0xe6b69adef9ace6b6ULL, },
+ { 0xfffeffff0001fffeULL, 0xffff0001fffeffffULL, },
+ { 0x6fb804f50cbf38c5ULL, 0x2c6a0103000331f0ULL, }, /* 64 */
+ { 0x73b204e2253812d4ULL, 0x3796fae5ffc2fe1aULL, },
+ { 0x7fff14e60f13c53dULL, 0x4f0ff5d500c4e6f1ULL, },
+ { 0x171210822ccab176ULL, 0x0bdeeb4001ccf94aULL, },
+ { 0x1b0c106f45438b85ULL, 0x170ae522018bc574ULL, },
+ { 0x1b30106f7447a4e0ULL, 0x19d90a380512fb41ULL, },
+ { 0x1df8103049bdd8baULL, 0x1fc028e7f6fd134bULL, },
+ { 0x1a3c10417fffe5f1ULL, 0x0eda690ae8970040ULL, },
+ { 0x6862204569da985aULL, 0x265363fae999e917ULL, }, /* 72 */
+ { 0x6b2a20063f50cc34ULL, 0x2c3a7fffdb840121ULL, },
+ { 0x7fff53b565ce363dULL, 0x38a17fff13bd0bdfULL, },
+ { 0x369a458932275144ULL, 0x15207fff4d3a035dULL, },
+ { 0xcdad41254fde3d7dULL, 0xd1ef756a4e4215b6ULL, },
+ { 0xc9f141367fff4ab4ULL, 0xc1097fff3fdc02abULL, },
+ { 0x808c330a4c5865bbULL, 0x9d887fff7959fa29ULL, },
+ { 0xe31636ed7fff6c9fULL, 0x032b7fff7fff00e7ULL, },
+ { 0xfe192c1c7fff7fffULL, 0x05097fff7e7a0057ULL, }, /* 80 */
+ { 0xfe292c3e7fff4707ULL, 0x05c83b1a7fff008fULL, },
+ { 0xff5d102139cf0662ULL, 0x079520c82b2b00b8ULL, },
+ { 0xfece12f0645904e7ULL, 0x00d302440dea008eULL, },
+ { 0xffec0f357fff082bULL, 0x014f02780dc00035ULL, },
+ { 0xffed0f417fff0488ULL, 0x0181012410080057ULL, },
+ { 0xfff9059039cf0068ULL, 0x01f900a205680070ULL, },
+ { 0xfff3068864590050ULL, 0x0037000b01be0056ULL, },
+ { 0xffff053f7fff0085ULL, 0x0057000c01b90020ULL, }, /* 88 */
+ { 0xffff05437fff004aULL, 0x0064000602020035ULL, },
+ { 0x000001eb39cf0007ULL, 0x0083000300ad0044ULL, },
+ { 0x0000024164590005ULL, 0x000e000000380034ULL, },
+ { 0x000001cf7fff0008ULL, 0x0016000000370014ULL, },
+ { 0x000001d07fff0004ULL, 0x0019000000400021ULL, },
+ { 0x000000a939cf0000ULL, 0x002100000016002bULL, },
+ { 0x000000c664590000ULL, 0x0004000000070021ULL, },
+ { 0x0000009f7fff0000ULL, 0x000600000007000cULL, }, /* 96 */
+ { 0x000000807fff0000ULL, 0x000a000000070005ULL, },
+ { 0x000000677fff0000ULL, 0x0010000000070002ULL, },
+ { 0x000000537fff0000ULL, 0x0019000000070001ULL, },
+ { 0x000000537fff0000ULL, 0x001d000000080002ULL, },
+ { 0x000000537fff0000ULL, 0x0021000000090003ULL, },
+ { 0x000000537fff0000ULL, 0x00260000000a0005ULL, },
+ { 0x000000537fff0000ULL, 0x002c0000000c0008ULL, },
+ { 0x0000001e39cf0000ULL, 0x003a00000004000aULL, }, /* 104 */
+ { 0x0000000b1a1c0000ULL, 0x004c00000001000dULL, },
+ { 0x000000040bcb0000ULL, 0x0064000000000011ULL, },
+ { 0x0000000105530000ULL, 0x0083000000000016ULL, },
+ { 0x00000001093e0000ULL, 0x000e000000000011ULL, },
+ { 0x00000001100b0000ULL, 0x000200000000000dULL, },
+ { 0x000000011bd90000ULL, 0x000000000000000aULL, },
+ { 0x0000000130570000ULL, 0x0000000000000008ULL, },
+};
+
+ reset_msa_registers();
+
+ gettimeofday(&start, NULL);
+
+ for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) {
+ for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) {
+ do_msa_MADDR_Q_H(b128_pattern[i], b128_pattern[j],
+ b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]);
+ }
+ }
+
+ for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) {
+ for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) {
+ do_msa_MADDR_Q_H(b128_random[i], b128_random[j],
+ b128_result[((PATTERN_INPUTS_SHORT_COUNT) *
+ (PATTERN_INPUTS_SHORT_COUNT)) +
+ RANDOM_INPUTS_SHORT_COUNT * i + j]);
+ }
+ }
+
+ for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) {
+ for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) {
+ do_msa_MADDR_Q_H__DDT(b128_random[i], b128_random[j],
+ b128_result[
+ ((PATTERN_INPUTS_SHORT_COUNT) *
+ (PATTERN_INPUTS_SHORT_COUNT)) +
+ ((RANDOM_INPUTS_SHORT_COUNT) *
+ (RANDOM_INPUTS_SHORT_COUNT)) +
+ RANDOM_INPUTS_SHORT_COUNT * i + j]);
+ }
+ }
+
+ for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) {
+ for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) {
+ do_msa_MADDR_Q_H__DSD(b128_random[i], b128_random[j],
+ b128_result[
+ ((PATTERN_INPUTS_SHORT_COUNT) *
+ (PATTERN_INPUTS_SHORT_COUNT)) +
+ (2 * (RANDOM_INPUTS_SHORT_COUNT) *
+ (RANDOM_INPUTS_SHORT_COUNT)) +
+ RANDOM_INPUTS_SHORT_COUNT * i + j]);
+ }
+ }
+
+ gettimeofday(&end, NULL);
+
+ elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0;
+ elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0;
+
+ ret = check_results_128(isa_ase_name, group_name, instruction_name,
+ TEST_COUNT_TOTAL, elapsed_time,
+ &b128_result[0][0], &b128_expect[0][0]);
+
+ return ret;
+}
--- /dev/null
+/*
+ * Test program for MSA instruction MADDR_Q.W
+ *
+ * Copyright (C) 2019 Wave Computing, Inc.
+ * Copyright (C) 2019 Aleksandar Markovic <amarkovic@wavecomp.com>
+ * Copyright (C) 2019 RT-RK Computer Based Systems LLC
+ * Copyright (C) 2019 Mateja Marjanovic <mateja.marjanovic@rt-rk.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 <https://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <sys/time.h>
+#include <stdint.h>
+
+#include "../../../../include/wrappers_msa.h"
+#include "../../../../include/test_inputs_128.h"
+#include "../../../../include/test_utils_128.h"
+
+#define TEST_COUNT_TOTAL ( \
+ (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \
+ 3 * (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT))
+
+
+int32_t main(void)
+{
+ char *isa_ase_name = "MSA";
+ char *group_name = "Fixed Multiply";
+ char *instruction_name = "MADDR_Q.W";
+ int32_t ret;
+ uint32_t i, j;
+ struct timeval start, end;
+ double elapsed_time;
+
+ uint64_t b128_result[TEST_COUNT_TOTAL][2];
+ uint64_t b128_expect[TEST_COUNT_TOTAL][2] = {
+ { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 0 */
+ { 0x0000000000000000ULL, 0x0000000000000000ULL, },
+ { 0x0000000100000001ULL, 0x0000000100000001ULL, },
+ { 0x0000000000000000ULL, 0x0000000000000000ULL, },
+ { 0x0000000000000000ULL, 0x0000000000000000ULL, },
+ { 0x0000000000000000ULL, 0x0000000000000000ULL, },
+ { 0x0000000000000001ULL, 0x0000000000000000ULL, },
+ { 0x0000000000000000ULL, 0x0000000000000000ULL, },
+ { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 8 */
+ { 0x0000000000000000ULL, 0x0000000000000000ULL, },
+ { 0x0000000000000000ULL, 0x0000000000000000ULL, },
+ { 0x0000000000000000ULL, 0x0000000000000000ULL, },
+ { 0x0000000000000000ULL, 0x0000000000000000ULL, },
+ { 0x0000000000000000ULL, 0x0000000000000000ULL, },
+ { 0x0000000000000000ULL, 0x0000000000000000ULL, },
+ { 0x0000000000000000ULL, 0x0000000000000000ULL, },
+ { 0x0000000100000001ULL, 0x0000000100000001ULL, }, /* 16 */
+ { 0x0000000100000001ULL, 0x0000000100000001ULL, },
+ { 0x38e38e3b38e38e3bULL, 0x38e38e3b38e38e3bULL, },
+ { 0x0000000200000002ULL, 0x0000000200000002ULL, },
+ { 0x2222222522222225ULL, 0x2222222522222225ULL, },
+ { 0x0000000300000003ULL, 0x0000000300000003ULL, },
+ { 0x12f684c14bda12faULL, 0xda12f68812f684c1ULL, },
+ { 0x0000000400000003ULL, 0x0000000400000004ULL, },
+ { 0x0000000300000002ULL, 0x0000000300000003ULL, }, /* 24 */
+ { 0x0000000300000002ULL, 0x0000000300000003ULL, },
+ { 0xc71c71cac71c71c9ULL, 0xc71c71cac71c71caULL, },
+ { 0x0000000200000001ULL, 0x0000000200000002ULL, },
+ { 0xdddddddfdddddddeULL, 0xdddddddfdddddddfULL, },
+ { 0x0000000100000000ULL, 0x0000000100000001ULL, },
+ { 0xed097b43b425ed0aULL, 0x25ed097ced097b43ULL, },
+ { 0x0000000000000000ULL, 0x0000000100000000ULL, },
+ { 0x0000000000000000ULL, 0x0000000100000000ULL, }, /* 32 */
+ { 0x0000000000000000ULL, 0x0000000100000000ULL, },
+ { 0x2222222322222223ULL, 0x2222222422222223ULL, },
+ { 0x0000000000000000ULL, 0x0000000100000000ULL, },
+ { 0x147ae148147ae148ULL, 0x147ae149147ae148ULL, },
+ { 0x0000000000000000ULL, 0x0000000100000000ULL, },
+ { 0x0b60b60c2d82d82eULL, 0xe93e93ea0b60b60cULL, },
+ { 0x0000000100000000ULL, 0x0000000100000001ULL, },
+ { 0x0000000100000000ULL, 0x0000000100000001ULL, }, /* 40 */
+ { 0x0000000100000000ULL, 0x0000000100000001ULL, },
+ { 0xdddddddfdddddddeULL, 0xdddddddfdddddddfULL, },
+ { 0x0000000100000000ULL, 0x0000000100000001ULL, },
+ { 0xeb851eb9eb851eb8ULL, 0xeb851eb9eb851eb9ULL, },
+ { 0x0000000100000000ULL, 0x0000000100000001ULL, },
+ { 0xf49f49f5d27d27d3ULL, 0x16c16c17f49f49f5ULL, },
+ { 0x0000000000000000ULL, 0x0000000000000000ULL, },
+ { 0x0000000000000001ULL, 0x0000000000000000ULL, }, /* 48 */
+ { 0x0000000000000001ULL, 0x0000000000000000ULL, },
+ { 0x12f684be4bda12f8ULL, 0xda12f68512f684beULL, },
+ { 0x0000000000000002ULL, 0x0000000000000000ULL, },
+ { 0x0b60b60c2d82d830ULL, 0xe93e93e90b60b60cULL, },
+ { 0x0000000000000003ULL, 0xffffffff00000000ULL, },
+ { 0x06522c3f6522c3f7ULL, 0x1948b0fb06522c3fULL, },
+ { 0x0000000000000004ULL, 0xffffffff00000000ULL, },
+ { 0x0000000000000003ULL, 0xffffffff00000000ULL, }, /* 56 */
+ { 0x0000000000000003ULL, 0xffffffff00000000ULL, },
+ { 0xed097b43b425ed0cULL, 0x25ed097bed097b43ULL, },
+ { 0x0000000000000002ULL, 0x0000000000000000ULL, },
+ { 0xf49f49f5d27d27d4ULL, 0x16c16c17f49f49f5ULL, },
+ { 0x0000000000000001ULL, 0x0000000000000000ULL, },
+ { 0xf9add3c19add3c0eULL, 0xe6b74f04f9add3c1ULL, },
+ { 0x0000000000000000ULL, 0x0000000100000000ULL, },
+ { 0x6fb7e8890cbdc0d3ULL, 0x2c6b144700049a05ULL, }, /* 64 */
+ { 0x73b239d7253787d5ULL, 0x379780f0ffc424ccULL, },
+ { 0x7fffffff0f127795ULL, 0x4f10998300c57f01ULL, },
+ { 0x1713a7162cca6b3bULL, 0x0be04ded01cca270ULL, },
+ { 0x1b0df8644544323dULL, 0x170cba96018c2d37ULL, },
+ { 0x1b323a657448a84fULL, 0x19dc46aa051313c6ULL, },
+ { 0x1dfa85ed49be7970ULL, 0x1fc3e135f6fe3018ULL, },
+ { 0x1a3e24ca7fffffffULL, 0x0edd19d1e8983ff6ULL, },
+ { 0x6863455169daefbfULL, 0x26563264e9999a2bULL, }, /* 72 */
+ { 0x6b2b90d93f50c0e0ULL, 0x2c3dccefdb84b67dULL, },
+ { 0x7fffffff65cdd2a4ULL, 0x38a5555313bd77c9ULL, },
+ { 0x369baa393226e271ULL, 0x1523c34a4d39d0a3ULL, },
+ { 0xcdaf51504fded617ULL, 0xd1f377b44e40f412ULL, },
+ { 0xc9f2f02d7fffffffULL, 0xc10cb0503fdb03f0ULL, },
+ { 0x808e9a674c590fccULL, 0x9d8b1e4779575ccaULL, },
+ { 0xe319324b7fffffffULL, 0x032ce4297fffffffULL, },
+ { 0xfe196fe67fffffffULL, 0x050bc0417e7bb00bULL, }, /* 80 */
+ { 0xfe299f487fffffffULL, 0x05cb2b577fffffffULL, },
+ { 0xff5d018339cf8b80ULL, 0x0798e2662b2b2514ULL, },
+ { 0xfecdfe20645a7d9bULL, 0x00d3dcf80dea608eULL, },
+ { 0xffebe0517fffffffULL, 0x0150ab000dc02968ULL, },
+ { 0xffec8baf7fffffffULL, 0x01828ea210087db2ULL, },
+ { 0xfff9423c39cf8b80ULL, 0x01fae4c1056841b9ULL, },
+ { 0xfff35806645a7d9bULL, 0x003737bc01be3862ULL, },
+ { 0xffff2aee7fffffffULL, 0x0057bed801b8eeb0ULL, }, /* 88 */
+ { 0xffff32047fffffffULL, 0x0064bf8102021ffcULL, },
+ { 0xffffb89f39cf8b80ULL, 0x00841c7a00ad640aULL, },
+ { 0xffff79fe645a7d9bULL, 0x000e642f0037e4a6ULL, },
+ { 0xfffff7307fffffffULL, 0x0016de7800373b16ULL, },
+ { 0xfffff77b7fffffffULL, 0x001a42040040661aULL, },
+ { 0xfffffd0c39cf8b80ULL, 0x00226e990015b802ULL, },
+ { 0xfffffa75645a7d9bULL, 0x0003c0350007004aULL, },
+ { 0xffffffa37fffffffULL, 0x0005f5d90006eb0dULL, }, /* 96 */
+ { 0xfffffffa7fffffffULL, 0x000978b30006d610ULL, },
+ { 0x000000007fffffffULL, 0x000f0d0c0006c153ULL, },
+ { 0x000000007fffffffULL, 0x0017eacf0006acd5ULL, },
+ { 0x000000007fffffffULL, 0x001b761e0007c87dULL, },
+ { 0x000000007fffffffULL, 0x001f87e00009133bULL, },
+ { 0x000000007fffffffULL, 0x00243402000a94e0ULL, },
+ { 0x000000007fffffffULL, 0x00299164000c5689ULL, },
+ { 0x0000000039cf8b80ULL, 0x003682160004293bULL, }, /* 104 */
+ { 0x000000001a1c28c4ULL, 0x00477a0900016741ULL, },
+ { 0x000000000bcae026ULL, 0x005dba4500007929ULL, },
+ { 0x00000000055376c2ULL, 0x007ae7c2000028ddULL, },
+ { 0x00000000093ed557ULL, 0x000d637500000d2cULL, },
+ { 0x00000000100c9469ULL, 0x0001755d0000043fULL, },
+ { 0x000000001bdc1297ULL, 0x000028ac0000015eULL, },
+ { 0x00000000305c8bbfULL, 0x0000046e00000071ULL, },
+};
+
+ reset_msa_registers();
+
+ gettimeofday(&start, NULL);
+
+ for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) {
+ for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) {
+ do_msa_MADDR_Q_W(b128_pattern[i], b128_pattern[j],
+ b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]);
+ }
+ }
+
+ for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) {
+ for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) {
+ do_msa_MADDR_Q_W(b128_random[i], b128_random[j],
+ b128_result[((PATTERN_INPUTS_SHORT_COUNT) *
+ (PATTERN_INPUTS_SHORT_COUNT)) +
+ RANDOM_INPUTS_SHORT_COUNT * i + j]);
+ }
+ }
+
+ for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) {
+ for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) {
+ do_msa_MADDR_Q_W__DDT(b128_random[i], b128_random[j],
+ b128_result[
+ ((PATTERN_INPUTS_SHORT_COUNT) *
+ (PATTERN_INPUTS_SHORT_COUNT)) +
+ ((RANDOM_INPUTS_SHORT_COUNT) *
+ (RANDOM_INPUTS_SHORT_COUNT)) +
+ RANDOM_INPUTS_SHORT_COUNT * i + j]);
+ }
+ }
+
+ for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) {
+ for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) {
+ do_msa_MADDR_Q_W__DSD(b128_random[i], b128_random[j],
+ b128_result[
+ ((PATTERN_INPUTS_SHORT_COUNT) *
+ (PATTERN_INPUTS_SHORT_COUNT)) +
+ (2 * (RANDOM_INPUTS_SHORT_COUNT) *
+ (RANDOM_INPUTS_SHORT_COUNT)) +
+ RANDOM_INPUTS_SHORT_COUNT * i + j]);
+ }
+ }
+
+ gettimeofday(&end, NULL);
+
+ elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0;
+ elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0;
+
+ ret = check_results_128(isa_ase_name, group_name, instruction_name,
+ TEST_COUNT_TOTAL, elapsed_time,
+ &b128_result[0][0], &b128_expect[0][0]);
+
+ return ret;
+}
--- /dev/null
+/*
+ * Test program for MSA instruction MSUB_Q.H
+ *
+ * Copyright (C) 2019 Wave Computing, Inc.
+ * Copyright (C) 2019 Aleksandar Markovic <amarkovic@wavecomp.com>
+ * Copyright (C) 2019 RT-RK Computer Based Systems LLC
+ * Copyright (C) 2019 Mateja Marjanovic <mateja.marjanovic@rt-rk.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 <https://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <sys/time.h>
+#include <stdint.h>
+
+#include "../../../../include/wrappers_msa.h"
+#include "../../../../include/test_inputs_128.h"
+#include "../../../../include/test_utils_128.h"
+
+#define TEST_COUNT_TOTAL ( \
+ (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \
+ 3 * (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT))
+
+
+int32_t main(void)
+{
+ char *isa_ase_name = "MSA";
+ char *group_name = "Fixed Multiply";
+ char *instruction_name = "MSUB_Q.H";
+ int32_t ret;
+ uint32_t i, j;
+ struct timeval start, end;
+ double elapsed_time;
+
+ uint64_t b128_result[TEST_COUNT_TOTAL][2];
+ uint64_t b128_expect[TEST_COUNT_TOTAL][2] = {
+ { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 0 */
+ { 0xffffffffffffffffULL, 0xffffffffffffffffULL, },
+ { 0xfffefffefffefffeULL, 0xfffefffefffefffeULL, },
+ { 0xfffefffefffefffeULL, 0xfffefffefffefffeULL, },
+ { 0xfffdfffdfffdfffdULL, 0xfffdfffdfffdfffdULL, },
+ { 0xfffdfffdfffdfffdULL, 0xfffdfffdfffdfffdULL, },
+ { 0xfffcfffdfffcfffcULL, 0xfffdfffcfffcfffdULL, },
+ { 0xfffcfffcfffcfffcULL, 0xfffcfffcfffcfffcULL, },
+ { 0xfffcfffcfffcfffcULL, 0xfffcfffcfffcfffcULL, }, /* 8 */
+ { 0xfffcfffcfffcfffcULL, 0xfffcfffcfffcfffcULL, },
+ { 0xfffcfffcfffcfffcULL, 0xfffcfffcfffcfffcULL, },
+ { 0xfffcfffcfffcfffcULL, 0xfffcfffcfffcfffcULL, },
+ { 0xfffcfffcfffcfffcULL, 0xfffcfffcfffcfffcULL, },
+ { 0xfffcfffcfffcfffcULL, 0xfffcfffcfffcfffcULL, },
+ { 0xfffcfffcfffcfffcULL, 0xfffcfffcfffcfffcULL, },
+ { 0xfffcfffcfffcfffcULL, 0xfffcfffcfffcfffcULL, },
+ { 0xfffbfffbfffbfffbULL, 0xfffbfffbfffbfffbULL, }, /* 16 */
+ { 0xfffbfffbfffbfffbULL, 0xfffbfffbfffbfffbULL, },
+ { 0xc716c716c716c716ULL, 0xc716c716c716c716ULL, },
+ { 0xfff9fff9fff9fff9ULL, 0xfff9fff9fff9fff9ULL, },
+ { 0xddd6ddd6ddd6ddd6ULL, 0xddd6ddd6ddd6ddd6ULL, },
+ { 0xfff8fff8fff8fff8ULL, 0xfff8fff8fff8fff8ULL, },
+ { 0xed0125e4b41ced01ULL, 0x25e4b41ced0125e4ULL, },
+ { 0xfff7fff6fff6fff7ULL, 0xfff6fff6fff7fff6ULL, },
+ { 0xfff7fff6fff6fff7ULL, 0xfff6fff6fff7fff6ULL, }, /* 24 */
+ { 0xfff7fff6fff6fff7ULL, 0xfff6fff6fff7fff6ULL, },
+ { 0x38da38d938d938daULL, 0x38d938d938da38d9ULL, },
+ { 0xfff6fff5fff5fff6ULL, 0xfff5fff5fff6fff5ULL, },
+ { 0x2218221722172218ULL, 0x2217221722182217ULL, },
+ { 0xfff6fff5fff5fff6ULL, 0xfff5fff5fff6fff5ULL, },
+ { 0x12ecda084bcf12ecULL, 0xda084bcf12ecda08ULL, },
+ { 0xfff6fff5fff5fff6ULL, 0xfff5fff5fff6fff5ULL, },
+ { 0xfff5fff4fff4fff5ULL, 0xfff4fff4fff5fff4ULL, }, /* 32 */
+ { 0xfff5fff4fff4fff5ULL, 0xfff4fff4fff5fff4ULL, },
+ { 0xddd2ddd1ddd1ddd2ULL, 0xddd1ddd1ddd2ddd1ULL, },
+ { 0xfff4fff3fff3fff4ULL, 0xfff3fff3fff4fff3ULL, },
+ { 0xeb78eb77eb77eb78ULL, 0xeb77eb77eb78eb77ULL, },
+ { 0xfff3fff2fff2fff3ULL, 0xfff2fff2fff3fff2ULL, },
+ { 0xf49216b3d26ef492ULL, 0x16b3d26ef49216b3ULL, },
+ { 0xfff2fff1fff1fff2ULL, 0xfff1fff1fff2fff1ULL, },
+ { 0xfff2fff1fff1fff2ULL, 0xfff1fff1fff2fff1ULL, }, /* 40 */
+ { 0xfff2fff1fff1fff2ULL, 0xfff1fff1fff2fff1ULL, },
+ { 0x2214221322132214ULL, 0x2213221322142213ULL, },
+ { 0xfff2fff1fff1fff2ULL, 0xfff1fff1fff2fff1ULL, },
+ { 0x146d146c146c146dULL, 0x146c146c146d146cULL, },
+ { 0xfff2fff1fff1fff2ULL, 0xfff1fff1fff2fff1ULL, },
+ { 0x0b52e92f2d740b52ULL, 0xe92f2d740b52e92fULL, },
+ { 0xfff1fff0fff1fff1ULL, 0xfff0fff1fff1fff0ULL, },
+ { 0xfff0fff0fff0fff0ULL, 0xfff0fff0fff0fff0ULL, }, /* 48 */
+ { 0xfff0fff0fff0fff0ULL, 0xfff0fff0fff0fff0ULL, },
+ { 0xecf925dcb414ecf9ULL, 0x25dcb414ecf925dcULL, },
+ { 0xffefffefffeeffefULL, 0xffefffeeffefffefULL, },
+ { 0xf48e16b0d26af48eULL, 0x16b0d26af48e16b0ULL, },
+ { 0xffeeffeeffedffeeULL, 0xffeeffedffeeffeeULL, },
+ { 0xf99be6a59ac8f99bULL, 0xe6a59ac8f99be6a5ULL, },
+ { 0xffedffedffebffedULL, 0xffedffebffedffedULL, },
+ { 0xffedffecffebffedULL, 0xffecffebffedffecULL, }, /* 56 */
+ { 0xffedffecffebffedULL, 0xffecffebffedffecULL, },
+ { 0x12e3d9fe4bc512e3ULL, 0xd9fe4bc512e3d9feULL, },
+ { 0xffedffebffebffedULL, 0xffebffebffedffebULL, },
+ { 0x0b4de9292d6e0b4dULL, 0xe9292d6e0b4de929ULL, },
+ { 0xffecffeaffebffecULL, 0xffeaffebffecffeaULL, },
+ { 0x063e1932650e063eULL, 0x1932650e063e1932ULL, },
+ { 0xffecffe8ffebffecULL, 0xffe8ffebffecffe8ULL, },
+ { 0x9032faf1f32dc724ULL, 0xd37cfee8ffe7cdf6ULL, }, /* 64 */
+ { 0x8c37fb04dab3ed15ULL, 0xc8500506002701cbULL, },
+ { 0x8000eb00f0d83aacULL, 0xb0d70a15ff2518f4ULL, },
+ { 0xe8edef64d3204e73ULL, 0xf40714a9fe1d069aULL, },
+ { 0xe4f2ef77baa67464ULL, 0xe8db1ac7fe5d3a6fULL, },
+ { 0xe4cdef768ba25b09ULL, 0xe60bf5b1fad604a2ULL, },
+ { 0xe204efb4b62c272fULL, 0xe023d70208eaec98ULL, },
+ { 0xe5c0efa2800019f7ULL, 0xf10996de174fffa3ULL, },
+ { 0x9799df9e9625678eULL, 0xd9909bed164d16ccULL, }, /* 72 */
+ { 0x94d0dfdcc0af33b4ULL, 0xd3a880002461fec2ULL, },
+ { 0x8000ac2c9a31c9abULL, 0xc7408000ec28f404ULL, },
+ { 0xc964ba57cdd7aea3ULL, 0xeac18000b2aafc86ULL, },
+ { 0x3251bebbb01fc26aULL, 0x2df18a94b1a2ea2cULL, },
+ { 0x360dbea98000b532ULL, 0x3ed78000c007fd37ULL, },
+ { 0x7f71ccd4b3a69a2aULL, 0x62588000868905b9ULL, },
+ { 0x1ce6c8f180009346ULL, 0xfcb580008000fefbULL, },
+ { 0x37e5be19a862dbafULL, 0xfea58b5e8000fe57ULL, }, /* 80 */
+ { 0x39c0be4bdd7bcb85ULL, 0xfed88000953fff6aULL, },
+ { 0x5f7d948aca8d9bc1ULL, 0xff3480008000ff95ULL, },
+ { 0x0bb4a742f1e1847fULL, 0xfe7e80008000ff7cULL, },
+ { 0x16a395c8f655d6c0ULL, 0xff618b5e8000ff29ULL, },
+ { 0x1763961afc30c464ULL, 0xff788000953fffb4ULL, },
+ { 0x26ab8000fa188e23ULL, 0xffa280008000ffcaULL, },
+ { 0x04bd964dfe708000ULL, 0xff4e80008000ffbdULL, },
+ { 0x092a817dfeeed540ULL, 0xffb68b5e8000ff93ULL, }, /* 88 */
+ { 0x097881deff94c239ULL, 0xffc08000953fffd9ULL, },
+ { 0x0fa88000ff5889feULL, 0xffd380008000ffe4ULL, },
+ { 0x01eb964dffd38000ULL, 0xffaa80008000ffddULL, },
+ { 0x03b5817dffe1d540ULL, 0xffdc8b5e8000ffc7ULL, },
+ { 0x03d481defff3c239ULL, 0xffe18000953fffebULL, },
+ { 0x06548000ffeb89feULL, 0xffea80008000fff1ULL, },
+ { 0x00c6964dfffa8000ULL, 0xffd680008000ffedULL, },
+ { 0x017e817dfffbd540ULL, 0xffee8b5e8000ffe1ULL, }, /* 96 */
+ { 0x02e28000fffcf1b8ULL, 0xfff895b98000ffcdULL, },
+ { 0x05938000fffdfb3aULL, 0xfffc9f298000ffadULL, },
+ { 0x0ac88000fffdfe67ULL, 0xfffea7c28000ff79ULL, },
+ { 0x0b238063fffefdb0ULL, 0xfffe8000953fffd0ULL, },
+ { 0x0b8180c5fffffca8ULL, 0xfffe8000a6f7ffefULL, },
+ { 0x0be28127fffffb2bULL, 0xfffe8000b5befffaULL, },
+ { 0x0c478189fffff904ULL, 0xfffe8000c211fffdULL, },
+ { 0x144c8000fffef2a8ULL, 0xfffe80009905fffdULL, }, /* 104 */
+ { 0x218f8000fffce682ULL, 0xfffe80008000fffdULL, },
+ { 0x377d8000fff9cf4eULL, 0xfffe80008000fffdULL, },
+ { 0x5bc08000fff5a2fbULL, 0xfffe80008000fffdULL, },
+ { 0x0b3f964dfffd8d66ULL, 0xfffc80008000fffcULL, },
+ { 0x0160a8b7ffff8000ULL, 0xfff880008000fffbULL, },
+ { 0x002bb7ecffff8000ULL, 0xfff080008000fff9ULL, },
+ { 0x0005c47affff8000ULL, 0xffe180008000fff7ULL, },
+};
+
+ reset_msa_registers();
+
+ gettimeofday(&start, NULL);
+
+ for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) {
+ for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) {
+ do_msa_MSUB_Q_H(b128_pattern[i], b128_pattern[j],
+ b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]);
+ }
+ }
+
+ for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) {
+ for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) {
+ do_msa_MSUB_Q_H(b128_random[i], b128_random[j],
+ b128_result[((PATTERN_INPUTS_SHORT_COUNT) *
+ (PATTERN_INPUTS_SHORT_COUNT)) +
+ RANDOM_INPUTS_SHORT_COUNT * i + j]);
+ }
+ }
+
+ for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) {
+ for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) {
+ do_msa_MSUB_Q_H__DDT(b128_random[i], b128_random[j],
+ b128_result[
+ ((PATTERN_INPUTS_SHORT_COUNT) *
+ (PATTERN_INPUTS_SHORT_COUNT)) +
+ ((RANDOM_INPUTS_SHORT_COUNT) *
+ (RANDOM_INPUTS_SHORT_COUNT)) +
+ RANDOM_INPUTS_SHORT_COUNT * i + j]);
+ }
+ }
+
+ for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) {
+ for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) {
+ do_msa_MSUB_Q_H__DSD(b128_random[i], b128_random[j],
+ b128_result[
+ ((PATTERN_INPUTS_SHORT_COUNT) *
+ (PATTERN_INPUTS_SHORT_COUNT)) +
+ (2 * (RANDOM_INPUTS_SHORT_COUNT) *
+ (RANDOM_INPUTS_SHORT_COUNT)) +
+ RANDOM_INPUTS_SHORT_COUNT * i + j]);
+ }
+ }
+
+ gettimeofday(&end, NULL);
+
+ elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0;
+ elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0;
+
+ ret = check_results_128(isa_ase_name, group_name, instruction_name,
+ TEST_COUNT_TOTAL, elapsed_time,
+ &b128_result[0][0], &b128_expect[0][0]);
+
+ return ret;
+}
--- /dev/null
+/*
+ * Test program for MSA instruction MSUB_Q.W
+ *
+ * Copyright (C) 2019 Wave Computing, Inc.
+ * Copyright (C) 2019 Aleksandar Markovic <amarkovic@wavecomp.com>
+ * Copyright (C) 2019 RT-RK Computer Based Systems LLC
+ * Copyright (C) 2019 Mateja Marjanovic <mateja.marjanovic@rt-rk.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 <https://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <sys/time.h>
+#include <stdint.h>
+
+#include "../../../../include/wrappers_msa.h"
+#include "../../../../include/test_inputs_128.h"
+#include "../../../../include/test_utils_128.h"
+
+#define TEST_COUNT_TOTAL ( \
+ (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \
+ 3 * (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT))
+
+
+int32_t main(void)
+{
+ char *isa_ase_name = "MSA";
+ char *group_name = "Fixed Multiply";
+ char *instruction_name = "MSUB_Q.W";
+ int32_t ret;
+ uint32_t i, j;
+ struct timeval start, end;
+ double elapsed_time;
+
+ uint64_t b128_result[TEST_COUNT_TOTAL][2];
+ uint64_t b128_expect[TEST_COUNT_TOTAL][2] = {
+ { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 0 */
+ { 0xffffffffffffffffULL, 0xffffffffffffffffULL, },
+ { 0xfffffffefffffffeULL, 0xfffffffefffffffeULL, },
+ { 0xfffffffefffffffeULL, 0xfffffffefffffffeULL, },
+ { 0xfffffffdfffffffdULL, 0xfffffffdfffffffdULL, },
+ { 0xfffffffdfffffffdULL, 0xfffffffdfffffffdULL, },
+ { 0xfffffffcfffffffcULL, 0xfffffffdfffffffcULL, },
+ { 0xfffffffcfffffffcULL, 0xfffffffcfffffffcULL, },
+ { 0xfffffffcfffffffcULL, 0xfffffffcfffffffcULL, }, /* 8 */
+ { 0xfffffffcfffffffcULL, 0xfffffffcfffffffcULL, },
+ { 0xfffffffcfffffffcULL, 0xfffffffcfffffffcULL, },
+ { 0xfffffffcfffffffcULL, 0xfffffffcfffffffcULL, },
+ { 0xfffffffcfffffffcULL, 0xfffffffcfffffffcULL, },
+ { 0xfffffffcfffffffcULL, 0xfffffffcfffffffcULL, },
+ { 0xfffffffcfffffffcULL, 0xfffffffcfffffffcULL, },
+ { 0xfffffffcfffffffcULL, 0xfffffffcfffffffcULL, },
+ { 0xfffffffbfffffffbULL, 0xfffffffbfffffffbULL, }, /* 16 */
+ { 0xfffffffbfffffffbULL, 0xfffffffbfffffffbULL, },
+ { 0xc71c71c1c71c71c1ULL, 0xc71c71c1c71c71c1ULL, },
+ { 0xfffffffafffffffaULL, 0xfffffffafffffffaULL, },
+ { 0xddddddd7ddddddd7ULL, 0xddddddd7ddddddd7ULL, },
+ { 0xfffffff9fffffff9ULL, 0xfffffff9fffffff9ULL, },
+ { 0xed097b3ab425ed01ULL, 0x25ed0973ed097b3aULL, },
+ { 0xfffffff7fffffff7ULL, 0xfffffff7fffffff7ULL, },
+ { 0xfffffff7fffffff7ULL, 0xfffffff7fffffff7ULL, }, /* 24 */
+ { 0xfffffff7fffffff7ULL, 0xfffffff7fffffff7ULL, },
+ { 0x38e38e3038e38e30ULL, 0x38e38e3038e38e30ULL, },
+ { 0xfffffff7fffffff7ULL, 0xfffffff7fffffff7ULL, },
+ { 0x2222221922222219ULL, 0x2222221922222219ULL, },
+ { 0xfffffff7fffffff7ULL, 0xfffffff7fffffff7ULL, },
+ { 0x12f684b44bda12edULL, 0xda12f67c12f684b4ULL, },
+ { 0xfffffff6fffffff7ULL, 0xfffffff7fffffff6ULL, },
+ { 0xfffffff5fffffff6ULL, 0xfffffff6fffffff5ULL, }, /* 32 */
+ { 0xfffffff5fffffff6ULL, 0xfffffff6fffffff5ULL, },
+ { 0xddddddd2ddddddd3ULL, 0xddddddd3ddddddd2ULL, },
+ { 0xfffffff4fffffff5ULL, 0xfffffff5fffffff4ULL, },
+ { 0xeb851eabeb851eacULL, 0xeb851eaceb851eabULL, },
+ { 0xfffffff2fffffff3ULL, 0xfffffff3fffffff2ULL, },
+ { 0xf49f49e6d27d27c4ULL, 0x16c16c09f49f49e6ULL, },
+ { 0xfffffff1fffffff1ULL, 0xfffffff1fffffff1ULL, },
+ { 0xfffffff1fffffff1ULL, 0xfffffff1fffffff1ULL, }, /* 40 */
+ { 0xfffffff1fffffff1ULL, 0xfffffff1fffffff1ULL, },
+ { 0x2222221322222213ULL, 0x2222221322222213ULL, },
+ { 0xfffffff1fffffff1ULL, 0xfffffff1fffffff1ULL, },
+ { 0x147ae138147ae138ULL, 0x147ae138147ae138ULL, },
+ { 0xfffffff0fffffff0ULL, 0xfffffff0fffffff0ULL, },
+ { 0x0b60b5fb2d82d81dULL, 0xe93e93d90b60b5fbULL, },
+ { 0xffffffefffffffefULL, 0xffffffefffffffefULL, },
+ { 0xffffffeeffffffeeULL, 0xffffffefffffffeeULL, }, /* 48 */
+ { 0xffffffeeffffffeeULL, 0xffffffefffffffeeULL, },
+ { 0xed097b2fb425ecf6ULL, 0x25ed0969ed097b2fULL, },
+ { 0xffffffecffffffecULL, 0xffffffeeffffffecULL, },
+ { 0xf49f49e0d27d27bdULL, 0x16c16c04f49f49e0ULL, },
+ { 0xffffffebffffffeaULL, 0xffffffedffffffebULL, },
+ { 0xf9add3ab9add3bf6ULL, 0xe6b74ef0f9add3abULL, },
+ { 0xffffffeaffffffe8ULL, 0xffffffecffffffeaULL, },
+ { 0xffffffeaffffffe8ULL, 0xffffffebffffffeaULL, }, /* 56 */
+ { 0xffffffeaffffffe8ULL, 0xffffffebffffffeaULL, },
+ { 0x12f684a74bda12deULL, 0xda12f66f12f684a7ULL, },
+ { 0xffffffe9ffffffe8ULL, 0xffffffeaffffffe9ULL, },
+ { 0x0b60b5f42d82d815ULL, 0xe93e93d20b60b5f4ULL, },
+ { 0xffffffe8ffffffe7ULL, 0xffffffe8ffffffe8ULL, },
+ { 0x06522c276522c3d9ULL, 0x1948b0e406522c27ULL, },
+ { 0xffffffe7ffffffe7ULL, 0xffffffe7ffffffe7ULL, },
+ { 0x9048175df3423f14ULL, 0xd394eba0fffb65e2ULL, }, /* 64 */
+ { 0x8c4dc60edac87812ULL, 0xc8687ef6003bdb1bULL, },
+ { 0x80000000f0ed8852ULL, 0xb0ef6662ff3a80e6ULL, },
+ { 0xe8ec58e8d33594acULL, 0xf41fb1f8fe335d76ULL, },
+ { 0xe4f20799babbcdaaULL, 0xe8f3454efe73d2afULL, },
+ { 0xe4cdc5978bb75798ULL, 0xe623b939faecec20ULL, },
+ { 0xe2057a0fb6418676ULL, 0xe03c1eae0901cfcdULL, },
+ { 0xe5c1db3280000000ULL, 0xf122e6111767bfefULL, },
+ { 0x979cbaab96251040ULL, 0xd9a9cd7d166665baULL, }, /* 72 */
+ { 0x94d46f23c0af3f1eULL, 0xd3c232f2247b4967ULL, },
+ { 0x800000009a322d5aULL, 0xc75aaa8dec42881aULL, },
+ { 0xc96455c6cdd91d8cULL, 0xeadc3c95b2c62f40ULL, },
+ { 0x3250aeaeb02129e6ULL, 0x2e0c882bb1bf0bd0ULL, },
+ { 0x360d0fd180000000ULL, 0x3ef34f8ec024fbf2ULL, },
+ { 0x7f716597b3a6f032ULL, 0x6274e19686a8a318ULL, },
+ { 0x1ce6cdb280000000ULL, 0xfcd31bb480000000ULL, },
+ { 0x37e70b49a8625540ULL, 0xfeb1f7e080000000ULL, }, /* 80 */
+ { 0x39c31699dd7c5546ULL, 0xfee37780953f52fcULL, },
+ { 0x5f82316fca8f431eULL, 0xff3c0af780000000ULL, },
+ { 0x0bb5432ff1e2e177ULL, 0xfe8d6e9580000000ULL, },
+ { 0x16a56af3f656d2b3ULL, 0xff67ba1b80000000ULL, },
+ { 0x17664384fc31bf42ULL, 0xff7e4aa4953f52fcULL, },
+ { 0x26b0cbfdfa1b830bULL, 0xffa6ab9180000000ULL, },
+ { 0x04be31a4fe719ab1ULL, 0xff57124580000000ULL, },
+ { 0x092c8a1ffeef4c68ULL, 0xffba958e80000000ULL, }, /* 88 */
+ { 0x097aa960ff949347ULL, 0xffc4dede953f52fcULL, },
+ { 0x0fac7158ff59ab27ULL, 0xffd7471a80000000ULL, },
+ { 0x01ebdf01ffd41248ULL, 0xffb2fdd380000000ULL, },
+ { 0x03b76546ffe1ee50ULL, 0xffe05b1780000000ULL, },
+ { 0x03d70afdfff427aaULL, 0xffe50b86953f52fcULL, },
+ { 0x065971c1ffeda8dfULL, 0xffed6fa980000000ULL, },
+ { 0x00c741e8fffb2801ULL, 0xffdce50280000000ULL, },
+ { 0x01816947fffcaf39ULL, 0xfff1931580000000ULL, }, /* 96 */
+ { 0x02e97a17fffdbb03ULL, 0xfffa128380000000ULL, },
+ { 0x05a1edf3fffe7250ULL, 0xfffd906f80000000ULL, },
+ { 0x0ae508c5fffeefc8ULL, 0xfffeffc380000000ULL, },
+ { 0x0b41cf1bffff94c3ULL, 0xffff25bb953f52fcULL, },
+ { 0x0ba1ab79ffffd5c1ULL, 0xffff4613a6f7bf69ULL, },
+ { 0x0c04b828ffffef5bULL, 0xffff61a0b5bf25caULL, },
+ { 0x0c6b104efffff971ULL, 0xffff7918c21285a5ULL, },
+ { 0x148886c7fffff5d8ULL, 0xffffa3179907b21bULL, }, /* 104 */
+ { 0x21f39335fffff046ULL, 0xffffc00380000000ULL, },
+ { 0x38235e38ffffe7a6ULL, 0xffffd3ee80000000ULL, },
+ { 0x5cd2ce93ffffda4bULL, 0xffffe1a680000000ULL, },
+ { 0x0b60ff8afffff60aULL, 0xffffc69a80000000ULL, },
+ { 0x01651818fffffd5eULL, 0xffff937480000000ULL, },
+ { 0x002bc65fffffff4dULL, 0xffff32bb80000000ULL, },
+ { 0x00055dbfffffffd0ULL, 0xfffe7bd280000000ULL, },
+};
+
+ reset_msa_registers();
+
+ gettimeofday(&start, NULL);
+
+ for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) {
+ for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) {
+ do_msa_MSUB_Q_W(b128_pattern[i], b128_pattern[j],
+ b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]);
+ }
+ }
+
+ for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) {
+ for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) {
+ do_msa_MSUB_Q_W(b128_random[i], b128_random[j],
+ b128_result[((PATTERN_INPUTS_SHORT_COUNT) *
+ (PATTERN_INPUTS_SHORT_COUNT)) +
+ RANDOM_INPUTS_SHORT_COUNT * i + j]);
+ }
+ }
+
+ for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) {
+ for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) {
+ do_msa_MSUB_Q_W__DDT(b128_random[i], b128_random[j],
+ b128_result[
+ ((PATTERN_INPUTS_SHORT_COUNT) *
+ (PATTERN_INPUTS_SHORT_COUNT)) +
+ ((RANDOM_INPUTS_SHORT_COUNT) *
+ (RANDOM_INPUTS_SHORT_COUNT)) +
+ RANDOM_INPUTS_SHORT_COUNT * i + j]);
+ }
+ }
+
+ for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) {
+ for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) {
+ do_msa_MSUB_Q_W__DSD(b128_random[i], b128_random[j],
+ b128_result[
+ ((PATTERN_INPUTS_SHORT_COUNT) *
+ (PATTERN_INPUTS_SHORT_COUNT)) +
+ (2 * (RANDOM_INPUTS_SHORT_COUNT) *
+ (RANDOM_INPUTS_SHORT_COUNT)) +
+ RANDOM_INPUTS_SHORT_COUNT * i + j]);
+ }
+ }
+
+ gettimeofday(&end, NULL);
+
+ elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0;
+ elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0;
+
+ ret = check_results_128(isa_ase_name, group_name, instruction_name,
+ TEST_COUNT_TOTAL, elapsed_time,
+ &b128_result[0][0], &b128_expect[0][0]);
+
+ return ret;
+}
--- /dev/null
+/*
+ * Test program for MSA instruction MSUBR_Q.H
+ *
+ * Copyright (C) 2019 Wave Computing, Inc.
+ * Copyright (C) 2019 Aleksandar Markovic <amarkovic@wavecomp.com>
+ * Copyright (C) 2019 RT-RK Computer Based Systems LLC
+ * Copyright (C) 2019 Mateja Marjanovic <mateja.marjanovic@rt-rk.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 <https://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <sys/time.h>
+#include <stdint.h>
+
+#include "../../../../include/wrappers_msa.h"
+#include "../../../../include/test_inputs_128.h"
+#include "../../../../include/test_utils_128.h"
+
+#define TEST_COUNT_TOTAL ( \
+ (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \
+ 3 * (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT))
+
+
+int32_t main(void)
+{
+ char *isa_ase_name = "MSA";
+ char *group_name = "Fixed Multiply";
+ char *instruction_name = "MSUBR_Q.H";
+ int32_t ret;
+ uint32_t i, j;
+ struct timeval start, end;
+ double elapsed_time;
+
+ uint64_t b128_result[TEST_COUNT_TOTAL][2];
+ uint64_t b128_expect[TEST_COUNT_TOTAL][2] = {
+ { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 0 */
+ { 0x0000000000000000ULL, 0x0000000000000000ULL, },
+ { 0xffffffffffffffffULL, 0xffffffffffffffffULL, },
+ { 0x0000000000000000ULL, 0x0000000000000000ULL, },
+ { 0x0000000000000000ULL, 0x0000000000000000ULL, },
+ { 0x0000000000000000ULL, 0x0000000000000000ULL, },
+ { 0x00000000ffff0000ULL, 0x0000ffff00000000ULL, },
+ { 0x0000000000000000ULL, 0x0000000000000000ULL, },
+ { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 8 */
+ { 0x0000000000000000ULL, 0x0000000000000000ULL, },
+ { 0x0000000000000000ULL, 0x0000000000000000ULL, },
+ { 0x0000000000000000ULL, 0x0000000000000000ULL, },
+ { 0x0000000000000000ULL, 0x0000000000000000ULL, },
+ { 0x0000000000000000ULL, 0x0000000000000000ULL, },
+ { 0x0000000000000000ULL, 0x0000000000000000ULL, },
+ { 0x0000000000000000ULL, 0x0000000000000000ULL, },
+ { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 16 */
+ { 0xffffffffffffffffULL, 0xffffffffffffffffULL, },
+ { 0xc71bc71bc71bc71bULL, 0xc71bc71bc71bc71bULL, },
+ { 0xffffffffffffffffULL, 0xffffffffffffffffULL, },
+ { 0xdddcdddcdddcdddcULL, 0xdddcdddcdddcdddcULL, },
+ { 0xfffefffefffefffeULL, 0xfffefffefffefffeULL, },
+ { 0xed0725ebb423ed07ULL, 0x25ebb423ed0725ebULL, },
+ { 0xfffdfffdfffefffdULL, 0xfffdfffefffdfffdULL, },
+ { 0xfffefffefffffffeULL, 0xfffefffffffefffeULL, }, /* 24 */
+ { 0xfffefffefffffffeULL, 0xfffefffffffefffeULL, },
+ { 0x38e238e238e338e2ULL, 0x38e238e338e238e2ULL, },
+ { 0xffffffff0000ffffULL, 0xffff0000ffffffffULL, },
+ { 0x2222222222232222ULL, 0x2222222322222222ULL, },
+ { 0x0000000000010000ULL, 0x0000000100000000ULL, },
+ { 0x12f7da134bdb12f7ULL, 0xda134bdb12f7da13ULL, },
+ { 0x0001000000010001ULL, 0x0000000100010000ULL, },
+ { 0x0001000000010001ULL, 0x0000000100010000ULL, }, /* 32 */
+ { 0x0001000000010001ULL, 0x0000000100010000ULL, },
+ { 0xdddedddddddedddeULL, 0xdddddddedddeddddULL, },
+ { 0x0001000000010001ULL, 0x0000000100010000ULL, },
+ { 0xeb85eb84eb85eb85ULL, 0xeb84eb85eb85eb84ULL, },
+ { 0x0000ffff00000000ULL, 0xffff00000000ffffULL, },
+ { 0xf49f16c1d27cf49fULL, 0x16c1d27cf49f16c1ULL, },
+ { 0x0000ffff00000000ULL, 0xffff00000000ffffULL, },
+ { 0x0000ffff00000000ULL, 0xffff00000000ffffULL, }, /* 40 */
+ { 0x0000ffff00000000ULL, 0xffff00000000ffffULL, },
+ { 0x2222222122222222ULL, 0x2221222222222221ULL, },
+ { 0x0000ffff00000000ULL, 0xffff00000000ffffULL, },
+ { 0x147b147a147b147bULL, 0x147a147b147b147aULL, },
+ { 0x0000ffff00000000ULL, 0xffff00000000ffffULL, },
+ { 0x0b61e93e2d830b61ULL, 0xe93e2d830b61e93eULL, },
+ { 0x0001000000000001ULL, 0x0000000000010000ULL, },
+ { 0x00010000ffff0001ULL, 0x0000ffff00010000ULL, }, /* 48 */
+ { 0x00010000ffff0001ULL, 0x0000ffff00010000ULL, },
+ { 0xed0a25edb424ed0aULL, 0x25edb424ed0a25edULL, },
+ { 0x00010000fffe0001ULL, 0x0000fffe00010000ULL, },
+ { 0xf4a016c2d27af4a0ULL, 0x16c2d27af4a016c2ULL, },
+ { 0x00010001fffd0001ULL, 0x0001fffd00010001ULL, },
+ { 0xf9afe6b99ad9f9afULL, 0xe6b99ad9f9afe6b9ULL, },
+ { 0x00010002fffc0001ULL, 0x0002fffc00010002ULL, },
+ { 0x00010002fffd0001ULL, 0x0002fffd00010002ULL, }, /* 56 */
+ { 0x00010002fffd0001ULL, 0x0002fffd00010002ULL, },
+ { 0x12f7da144bd812f7ULL, 0xda144bd812f7da14ULL, },
+ { 0x00010001fffe0001ULL, 0x0001fffe00010001ULL, },
+ { 0x0b62e93f2d820b62ULL, 0xe93f2d820b62e93fULL, },
+ { 0x00020001ffff0002ULL, 0x0001ffff00020001ULL, },
+ { 0x0654194a65220654ULL, 0x194a65220654194aULL, },
+ { 0x00020001ffff0002ULL, 0x0001ffff00020001ULL, },
+ { 0x9048fb0bf341c73bULL, 0xd396fefdfffdce10ULL, }, /* 64 */
+ { 0x8c4efb1edac8ed2cULL, 0xc86a051b003e01e6ULL, },
+ { 0x8000eb1af0ed3ac3ULL, 0xb0f10a2bff3c190fULL, },
+ { 0xe8edef7ed3364e8aULL, 0xf42214c0fe3406b6ULL, },
+ { 0xe4f3ef91babd747bULL, 0xe8f61adefe753a8cULL, },
+ { 0xe4cfef918bb95b20ULL, 0xe627f5c8faee04bfULL, },
+ { 0xe207efd0b6432746ULL, 0xe040d7190903ecb5ULL, },
+ { 0xe5c3efbf80001a0fULL, 0xf12696f61769ffc0ULL, },
+ { 0x979ddfbb962567a6ULL, 0xd9ad9c06166716e9ULL, }, /* 72 */
+ { 0x94d5dffac0af33ccULL, 0xd3c68000247cfedfULL, },
+ { 0x8000ac4b9a31c9c4ULL, 0xc75f8000ec43f421ULL, },
+ { 0xc965ba77cdd8aebdULL, 0xeae08000b2c6fca3ULL, },
+ { 0x3252bedbb021c284ULL, 0x2e118a95b1beea4aULL, },
+ { 0x360ebeca8000b54dULL, 0x3ef78000c024fd55ULL, },
+ { 0x7f73ccf6b3a79a46ULL, 0x6278800086a705d7ULL, },
+ { 0x1ce9c91380009362ULL, 0xfcd580008000ff19ULL, },
+ { 0x37ebbe42a862dbb9ULL, 0xfeb38b5e8000fe89ULL, }, /* 80 */
+ { 0x39c7be75dd7ccb94ULL, 0xfee48000953fff7cULL, },
+ { 0x5f8994cfca8f9bdeULL, 0xff3c80008000ffa2ULL, },
+ { 0x0bb6a77cf1e284a3ULL, 0xfe8d80008000ff8cULL, },
+ { 0x16a7960ef656d6ccULL, 0xff688b5e8000ff44ULL, },
+ { 0x17689660fc31c475ULL, 0xff7f8000953fffbeULL, },
+ { 0x26b48000fa1a8e43ULL, 0xffa780008000ffd1ULL, },
+ { 0x04bf964dfe718000ULL, 0xff5880008000ffc6ULL, },
+ { 0x092e817dfeefd540ULL, 0xffbb8b5e8000ffa2ULL, }, /* 88 */
+ { 0x097c81dfff94c239ULL, 0xffc58000953fffdfULL, },
+ { 0x0faf8000ff5989ffULL, 0xffd780008000ffe9ULL, },
+ { 0x01ec964dffd48000ULL, 0xffb280008000ffe4ULL, },
+ { 0x03b8817dffe2d540ULL, 0xffe08b5e8000ffd3ULL, },
+ { 0x03d881dffff4c239ULL, 0xffe58000953ffff0ULL, },
+ { 0x065b8000ffed89ffULL, 0xffed80008000fff5ULL, },
+ { 0x00c7964dfffb8000ULL, 0xffdc80008000fff2ULL, },
+ { 0x0181817dfffdd540ULL, 0xfff18b5e8000ffe9ULL, }, /* 96 */
+ { 0x02e98000fffef1b9ULL, 0xfffa95ba8000ffdbULL, },
+ { 0x05a18000fffffb3bULL, 0xfffe9f2a8000ffc4ULL, },
+ { 0x0ae38000fffffe68ULL, 0xffffa7c48000ff9fULL, },
+ { 0x0b4080630000fdb2ULL, 0xffff8000953fffdeULL, },
+ { 0x0ba080c60000fcabULL, 0xffff8000a6f7fff4ULL, },
+ { 0x0c0381280000fb2fULL, 0xffff8000b5befffcULL, },
+ { 0x0c69818a0000f90aULL, 0xffff8000c211ffffULL, },
+ { 0x148580000000f2b4ULL, 0xffff80009905ffffULL, }, /* 104 */
+ { 0x21ee80000000e69aULL, 0xffff80008000ffffULL, },
+ { 0x381a80000000cf7cULL, 0xffff80008000ffffULL, },
+ { 0x5cc480000000a354ULL, 0xffff80008000ffffULL, },
+ { 0x0b5f964d00008dd4ULL, 0xfffe80008000ffffULL, },
+ { 0x0165a8b700008000ULL, 0xfffc80008000ffffULL, },
+ { 0x002cb7ec00008000ULL, 0xfff880008000ffffULL, },
+ { 0x0005c47b00008000ULL, 0xfff180008000ffffULL, },
+};
+
+ reset_msa_registers();
+
+ gettimeofday(&start, NULL);
+
+ for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) {
+ for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) {
+ do_msa_MSUBR_Q_H(b128_pattern[i], b128_pattern[j],
+ b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]);
+ }
+ }
+
+ for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) {
+ for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) {
+ do_msa_MSUBR_Q_H(b128_random[i], b128_random[j],
+ b128_result[((PATTERN_INPUTS_SHORT_COUNT) *
+ (PATTERN_INPUTS_SHORT_COUNT)) +
+ RANDOM_INPUTS_SHORT_COUNT * i + j]);
+ }
+ }
+
+ for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) {
+ for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) {
+ do_msa_MSUBR_Q_H__DDT(b128_random[i], b128_random[j],
+ b128_result[
+ ((PATTERN_INPUTS_SHORT_COUNT) *
+ (PATTERN_INPUTS_SHORT_COUNT)) +
+ ((RANDOM_INPUTS_SHORT_COUNT) *
+ (RANDOM_INPUTS_SHORT_COUNT)) +
+ RANDOM_INPUTS_SHORT_COUNT * i + j]);
+ }
+ }
+
+ for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) {
+ for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) {
+ do_msa_MSUBR_Q_H__DSD(b128_random[i], b128_random[j],
+ b128_result[
+ ((PATTERN_INPUTS_SHORT_COUNT) *
+ (PATTERN_INPUTS_SHORT_COUNT)) +
+ (2 * (RANDOM_INPUTS_SHORT_COUNT) *
+ (RANDOM_INPUTS_SHORT_COUNT)) +
+ RANDOM_INPUTS_SHORT_COUNT * i + j]);
+ }
+ }
+
+ gettimeofday(&end, NULL);
+
+ elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0;
+ elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0;
+
+ ret = check_results_128(isa_ase_name, group_name, instruction_name,
+ TEST_COUNT_TOTAL, elapsed_time,
+ &b128_result[0][0], &b128_expect[0][0]);
+
+ return ret;
+}
--- /dev/null
+/*
+ * Test program for MSA instruction MSUBR_Q.W
+ *
+ * Copyright (C) 2019 Wave Computing, Inc.
+ * Copyright (C) 2019 Aleksandar Markovic <amarkovic@wavecomp.com>
+ * Copyright (C) 2019 RT-RK Computer Based Systems LLC
+ * Copyright (C) 2019 Mateja Marjanovic <mateja.marjanovic@rt-rk.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 <https://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <sys/time.h>
+#include <stdint.h>
+
+#include "../../../../include/wrappers_msa.h"
+#include "../../../../include/test_inputs_128.h"
+#include "../../../../include/test_utils_128.h"
+
+#define TEST_COUNT_TOTAL ( \
+ (PATTERN_INPUTS_SHORT_COUNT) * (PATTERN_INPUTS_SHORT_COUNT) + \
+ 3 * (RANDOM_INPUTS_SHORT_COUNT) * (RANDOM_INPUTS_SHORT_COUNT))
+
+
+int32_t main(void)
+{
+ char *isa_ase_name = "MSA";
+ char *group_name = "Fixed Multiply";
+ char *instruction_name = "MSUBR_Q.W";
+ int32_t ret;
+ uint32_t i, j;
+ struct timeval start, end;
+ double elapsed_time;
+
+ uint64_t b128_result[TEST_COUNT_TOTAL][2];
+ uint64_t b128_expect[TEST_COUNT_TOTAL][2] = {
+ { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 0 */
+ { 0x0000000000000000ULL, 0x0000000000000000ULL, },
+ { 0x0000000100000001ULL, 0x0000000100000001ULL, },
+ { 0x0000000000000000ULL, 0x0000000000000000ULL, },
+ { 0x0000000000000000ULL, 0x0000000000000000ULL, },
+ { 0x0000000000000000ULL, 0x0000000000000000ULL, },
+ { 0x0000000000000001ULL, 0x0000000000000000ULL, },
+ { 0x0000000000000000ULL, 0x0000000000000000ULL, },
+ { 0x0000000000000000ULL, 0x0000000000000000ULL, }, /* 8 */
+ { 0x0000000000000000ULL, 0x0000000000000000ULL, },
+ { 0x0000000000000000ULL, 0x0000000000000000ULL, },
+ { 0x0000000000000000ULL, 0x0000000000000000ULL, },
+ { 0x0000000000000000ULL, 0x0000000000000000ULL, },
+ { 0x0000000000000000ULL, 0x0000000000000000ULL, },
+ { 0x0000000000000000ULL, 0x0000000000000000ULL, },
+ { 0x0000000000000000ULL, 0x0000000000000000ULL, },
+ { 0x0000000100000001ULL, 0x0000000100000001ULL, }, /* 16 */
+ { 0x0000000100000001ULL, 0x0000000100000001ULL, },
+ { 0x38e38e3b38e38e3bULL, 0x38e38e3b38e38e3bULL, },
+ { 0x0000000200000002ULL, 0x0000000200000002ULL, },
+ { 0x2222222522222225ULL, 0x2222222522222225ULL, },
+ { 0x0000000300000003ULL, 0x0000000300000003ULL, },
+ { 0x12f684c14bda12faULL, 0xda12f68812f684c1ULL, },
+ { 0x0000000400000003ULL, 0x0000000400000004ULL, },
+ { 0x0000000300000002ULL, 0x0000000300000003ULL, }, /* 24 */
+ { 0x0000000300000002ULL, 0x0000000300000003ULL, },
+ { 0xc71c71cac71c71c9ULL, 0xc71c71cac71c71caULL, },
+ { 0x0000000200000001ULL, 0x0000000200000002ULL, },
+ { 0xdddddddfdddddddeULL, 0xdddddddfdddddddfULL, },
+ { 0x0000000100000000ULL, 0x0000000100000001ULL, },
+ { 0xed097b43b425ed0aULL, 0x25ed097ced097b43ULL, },
+ { 0x0000000000000000ULL, 0x0000000100000000ULL, },
+ { 0x0000000000000000ULL, 0x0000000100000000ULL, }, /* 32 */
+ { 0x0000000000000000ULL, 0x0000000100000000ULL, },
+ { 0x2222222322222223ULL, 0x2222222422222223ULL, },
+ { 0x0000000000000000ULL, 0x0000000100000000ULL, },
+ { 0x147ae148147ae148ULL, 0x147ae149147ae148ULL, },
+ { 0x0000000000000000ULL, 0x0000000100000000ULL, },
+ { 0x0b60b60c2d82d82eULL, 0xe93e93ea0b60b60cULL, },
+ { 0x0000000100000000ULL, 0x0000000100000001ULL, },
+ { 0x0000000100000000ULL, 0x0000000100000001ULL, }, /* 40 */
+ { 0x0000000100000000ULL, 0x0000000100000001ULL, },
+ { 0xdddddddfdddddddeULL, 0xdddddddfdddddddfULL, },
+ { 0x0000000100000000ULL, 0x0000000100000001ULL, },
+ { 0xeb851eb9eb851eb8ULL, 0xeb851eb9eb851eb9ULL, },
+ { 0x0000000100000000ULL, 0x0000000100000001ULL, },
+ { 0xf49f49f5d27d27d3ULL, 0x16c16c17f49f49f5ULL, },
+ { 0x0000000000000000ULL, 0x0000000000000000ULL, },
+ { 0x0000000000000001ULL, 0x0000000000000000ULL, }, /* 48 */
+ { 0x0000000000000001ULL, 0x0000000000000000ULL, },
+ { 0x12f684be4bda12f8ULL, 0xda12f68512f684beULL, },
+ { 0x0000000000000002ULL, 0x0000000000000000ULL, },
+ { 0x0b60b60c2d82d830ULL, 0xe93e93e90b60b60cULL, },
+ { 0x0000000000000003ULL, 0xffffffff00000000ULL, },
+ { 0x06522c3f6522c3f7ULL, 0x1948b0fb06522c3fULL, },
+ { 0x0000000000000004ULL, 0xffffffff00000000ULL, },
+ { 0x0000000000000003ULL, 0xffffffff00000000ULL, }, /* 56 */
+ { 0x0000000000000003ULL, 0xffffffff00000000ULL, },
+ { 0xed097b43b425ed0cULL, 0x25ed097bed097b43ULL, },
+ { 0x0000000000000002ULL, 0x0000000000000000ULL, },
+ { 0xf49f49f5d27d27d4ULL, 0x16c16c17f49f49f5ULL, },
+ { 0x0000000000000001ULL, 0x0000000000000000ULL, },
+ { 0xf9add3c19add3c0eULL, 0xe6b74f04f9add3c1ULL, },
+ { 0x0000000000000000ULL, 0x0000000100000000ULL, },
+ { 0x6fb7e8890cbdc0d3ULL, 0x2c6b144700049a05ULL, }, /* 64 */
+ { 0x73b239d7253787d5ULL, 0x379780f0ffc424ccULL, },
+ { 0x7fffffff0f127795ULL, 0x4f10998300c57f01ULL, },
+ { 0x1713a7162cca6b3bULL, 0x0be04ded01cca270ULL, },
+ { 0x1b0df8644544323dULL, 0x170cba96018c2d37ULL, },
+ { 0x1b323a657448a84fULL, 0x19dc46aa051313c6ULL, },
+ { 0x1dfa85ed49be7970ULL, 0x1fc3e135f6fe3018ULL, },
+ { 0x1a3e24ca7fffffffULL, 0x0edd19d1e8983ff6ULL, },
+ { 0x6863455169daefbfULL, 0x26563264e9999a2bULL, }, /* 72 */
+ { 0x6b2b90d93f50c0e0ULL, 0x2c3dccefdb84b67dULL, },
+ { 0x7fffffff65cdd2a4ULL, 0x38a5555313bd77c9ULL, },
+ { 0x369baa393226e271ULL, 0x1523c34a4d39d0a3ULL, },
+ { 0xcdaf51504fded617ULL, 0xd1f377b44e40f412ULL, },
+ { 0xc9f2f02d7fffffffULL, 0xc10cb0503fdb03f0ULL, },
+ { 0x808e9a674c590fccULL, 0x9d8b1e4779575ccaULL, },
+ { 0xe319324b7fffffffULL, 0x032ce4297fffffffULL, },
+ { 0xfe196fe67fffffffULL, 0x050bc0417e7bb00bULL, }, /* 80 */
+ { 0xfe299f487fffffffULL, 0x05cb2b577fffffffULL, },
+ { 0xff5d018339cf8b80ULL, 0x0798e2662b2b2514ULL, },
+ { 0xfecdfe20645a7d9bULL, 0x00d3dcf80dea608eULL, },
+ { 0xffebe0517fffffffULL, 0x0150ab000dc02968ULL, },
+ { 0xffec8baf7fffffffULL, 0x01828ea210087db2ULL, },
+ { 0xfff9423c39cf8b80ULL, 0x01fae4c1056841b9ULL, },
+ { 0xfff35806645a7d9bULL, 0x003737bc01be3862ULL, },
+ { 0xffff2aee7fffffffULL, 0x0057bed801b8eeb0ULL, }, /* 88 */
+ { 0xffff32047fffffffULL, 0x0064bf8102021ffcULL, },
+ { 0xffffb89f39cf8b80ULL, 0x00841c7a00ad640aULL, },
+ { 0xffff79fe645a7d9bULL, 0x000e642f0037e4a6ULL, },
+ { 0xfffff7307fffffffULL, 0x0016de7800373b16ULL, },
+ { 0xfffff77b7fffffffULL, 0x001a42040040661aULL, },
+ { 0xfffffd0c39cf8b80ULL, 0x00226e990015b802ULL, },
+ { 0xfffffa75645a7d9bULL, 0x0003c0350007004aULL, },
+ { 0xffffffa37fffffffULL, 0x0005f5d90006eb0dULL, }, /* 96 */
+ { 0xfffffffa7fffffffULL, 0x000978b30006d610ULL, },
+ { 0x000000007fffffffULL, 0x000f0d0c0006c153ULL, },
+ { 0x000000007fffffffULL, 0x0017eacf0006acd5ULL, },
+ { 0x000000007fffffffULL, 0x001b761e0007c87dULL, },
+ { 0x000000007fffffffULL, 0x001f87e00009133bULL, },
+ { 0x000000007fffffffULL, 0x00243402000a94e0ULL, },
+ { 0x000000007fffffffULL, 0x00299164000c5689ULL, },
+ { 0x0000000039cf8b80ULL, 0x003682160004293bULL, }, /* 104 */
+ { 0x000000001a1c28c4ULL, 0x00477a0900016741ULL, },
+ { 0x000000000bcae026ULL, 0x005dba4500007929ULL, },
+ { 0x00000000055376c2ULL, 0x007ae7c2000028ddULL, },
+ { 0x00000000093ed557ULL, 0x000d637500000d2cULL, },
+ { 0x00000000100c9469ULL, 0x0001755d0000043fULL, },
+ { 0x000000001bdc1297ULL, 0x000028ac0000015eULL, },
+ { 0x00000000305c8bbfULL, 0x0000046e00000071ULL, },
+};
+
+ reset_msa_registers();
+
+ gettimeofday(&start, NULL);
+
+ for (i = 0; i < PATTERN_INPUTS_SHORT_COUNT; i++) {
+ for (j = 0; j < PATTERN_INPUTS_SHORT_COUNT; j++) {
+ do_msa_MADDR_Q_W(b128_pattern[i], b128_pattern[j],
+ b128_result[PATTERN_INPUTS_SHORT_COUNT * i + j]);
+ }
+ }
+
+ for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) {
+ for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) {
+ do_msa_MADDR_Q_W(b128_random[i], b128_random[j],
+ b128_result[((PATTERN_INPUTS_SHORT_COUNT) *
+ (PATTERN_INPUTS_SHORT_COUNT)) +
+ RANDOM_INPUTS_SHORT_COUNT * i + j]);
+ }
+ }
+
+ for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) {
+ for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) {
+ do_msa_MADDR_Q_W__DDT(b128_random[i], b128_random[j],
+ b128_result[
+ ((PATTERN_INPUTS_SHORT_COUNT) *
+ (PATTERN_INPUTS_SHORT_COUNT)) +
+ ((RANDOM_INPUTS_SHORT_COUNT) *
+ (RANDOM_INPUTS_SHORT_COUNT)) +
+ RANDOM_INPUTS_SHORT_COUNT * i + j]);
+ }
+ }
+
+ for (i = 0; i < RANDOM_INPUTS_SHORT_COUNT; i++) {
+ for (j = 0; j < RANDOM_INPUTS_SHORT_COUNT; j++) {
+ do_msa_MADDR_Q_W__DSD(b128_random[i], b128_random[j],
+ b128_result[
+ ((PATTERN_INPUTS_SHORT_COUNT) *
+ (PATTERN_INPUTS_SHORT_COUNT)) +
+ (2 * (RANDOM_INPUTS_SHORT_COUNT) *
+ (RANDOM_INPUTS_SHORT_COUNT)) +
+ RANDOM_INPUTS_SHORT_COUNT * i + j]);
+ }
+ }
+
+ gettimeofday(&end, NULL);
+
+ elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0;
+ elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0;
+
+ ret = check_results_128(isa_ase_name, group_name, instruction_name,
+ TEST_COUNT_TOTAL, elapsed_time,
+ &b128_result[0][0], &b128_expect[0][0]);
+
+ return ret;
+}
uint64_t b128_result[TEST_COUNT_TOTAL][2];
uint64_t b128_expect[TEST_COUNT_TOTAL][2] = {
- { 0x0000000000000002ULL, 0x0000000000000002ULL, }, /* 0 */
- { 0x0000000000000002ULL, 0x0000000000000002ULL, },
- { 0x00000000aaaaaaaeULL, 0x00000000aaaaaaaeULL, },
- { 0x0000000000000004ULL, 0x0000000000000004ULL, },
- { 0x000000006666666cULL, 0x000000006666666cULL, },
- { 0x0000000000000006ULL, 0x0000000000000006ULL, },
- { 0x000000008e38e395ULL, 0xffffffffe38e38ebULL, },
- { 0x0000000000000008ULL, 0x0000000000000008ULL, },
- { 0x0000000000000008ULL, 0x0000000000000008ULL, }, /* 8 */
- { 0x0000000000000008ULL, 0x0000000000000008ULL, },
- { 0x0000000000000008ULL, 0x0000000000000008ULL, },
- { 0x0000000000000008ULL, 0x0000000000000008ULL, },
- { 0x0000000000000008ULL, 0x0000000000000008ULL, },
- { 0x0000000000000008ULL, 0x0000000000000008ULL, },
- { 0x0000000000000008ULL, 0x0000000000000008ULL, },
- { 0x0000000000000008ULL, 0x0000000000000008ULL, },
- { 0x00000000aaaaaab4ULL, 0x00000000aaaaaab4ULL, }, /* 16 */
- { 0x00000000aaaaaab4ULL, 0x00000000aaaaaab4ULL, },
- { 0x38e38e3a71c71c7cULL, 0x38e38e3a71c71c7cULL, },
- { 0x0000000155555560ULL, 0x0000000155555560ULL, },
- { 0x2222222444444450ULL, 0x2222222444444450ULL, },
- { 0x000000020000000cULL, 0x000000020000000cULL, },
- { 0x2f684bdcb425ed16ULL, 0xf684bda397b425faULL, },
- { 0x00000002aaaaaab8ULL, 0x00000002aaaaaab8ULL, },
- { 0x000000020000000eULL, 0x000000020000000eULL, }, /* 24 */
- { 0x000000020000000eULL, 0x000000020000000eULL, },
- { 0xc71c71c8e38e38f2ULL, 0xc71c71c8e38e38f2ULL, },
- { 0x0000000155555564ULL, 0x0000000155555564ULL, },
- { 0xdddddddeccccccdcULL, 0xdddddddeccccccdcULL, },
- { 0x00000000aaaaaabaULL, 0x00000000aaaaaabaULL, },
- { 0xd097b42684bda13fULL, 0x097b425ef684bdb1ULL, },
- { 0x0000000000000010ULL, 0x0000000000000010ULL, },
- { 0x0000000066666678ULL, 0x0000000066666678ULL, }, /* 32 */
- { 0x0000000066666678ULL, 0x0000000066666678ULL, },
- { 0x2222222355555568ULL, 0x2222222355555568ULL, },
- { 0x00000000cccccce0ULL, 0x00000000cccccce0ULL, },
- { 0x147ae1491eb85200ULL, 0x147ae1491eb85200ULL, },
- { 0x0000000133333348ULL, 0x0000000133333348ULL, },
- { 0x1c71c71e3e93e954ULL, 0xfa4fa4fbb60b60ccULL, },
- { 0x00000001999999b0ULL, 0x00000001999999b0ULL, },
- { 0x000000013333334aULL, 0x000000013333334aULL, }, /* 40 */
- { 0x000000013333334aULL, 0x000000013333334aULL, },
- { 0xdddddddeeeeeef06ULL, 0xdddddddeeeeeef06ULL, },
- { 0x00000000cccccce4ULL, 0x00000000cccccce4ULL, },
- { 0xeb851eb8e147ae2cULL, 0xeb851eb8e147ae2cULL, },
- { 0x000000006666667eULL, 0x000000006666667eULL, },
- { 0xe38e38e3e93e9401ULL, 0x05b05b05c71c71dfULL, },
- { 0x0000000000000018ULL, 0x0000000000000018ULL, },
- { 0x000000008e38e3a7ULL, 0xffffffffe38e38fdULL, }, /* 48 */
- { 0x000000008e38e3a7ULL, 0xffffffffe38e38fdULL, },
- { 0x2f684bdb425ed0b1ULL, 0xf684bda17b425eebULL, },
- { 0x000000011c71c736ULL, 0xffffffffc71c71e2ULL, },
- { 0x1c71c71e27d27d42ULL, 0xfa4fa4fa49f49f66ULL, },
- { 0x00000001aaaaaac5ULL, 0xffffffffaaaaaac7ULL, },
- { 0x35ba781b4587e6d2ULL, 0x0fcd6e9d6b74f050ULL, },
- { 0x0000000238e38e54ULL, 0xffffffff8e38e3acULL, },
- { 0x00000001aaaaaac7ULL, 0xffffffffaaaaaac9ULL, }, /* 56 */
- { 0x00000001aaaaaac7ULL, 0xffffffffaaaaaac9ULL, },
- { 0xd097b427a12f6869ULL, 0x097b425ebda12f87ULL, },
- { 0x000000011c71c73aULL, 0xffffffffc71c71e6ULL, },
- { 0xe38e38e477777796ULL, 0x05b05b05aaaaaacaULL, },
- { 0x000000008e38e3adULL, 0xffffffffe38e3903ULL, },
- { 0xca4587e781948b2fULL, 0xf032916206522c5fULL, },
- { 0x0000000000000020ULL, 0x0000000000000020ULL, },
- { 0x3e3ad4ae1266c2b0ULL, 0x1637d725aebdb734ULL, }, /* 64 */
- { 0x4c74e0d60a3d6d94ULL, 0x1badd2dd9f4dac90ULL, },
- { 0x6874e8f94205b90cULL, 0x27eb0c41af2c3022ULL, },
- { 0x42dab657e16f25e8ULL, 0x06d6782e137656f2ULL, },
- { 0x5114c27fd945d0ccULL, 0x0c4c73e604064c4eULL, },
- { 0x68a91e898c276755ULL, 0x0f77ad378bdfb302ULL, },
- { 0x54c82cde41d1cf13ULL, 0x0b6108a5f38e1598ULL, },
- { 0x6f755d3eddd1234aULL, 0xfbbaace2f5421908ULL, },
- { 0x8b75656215996ec2ULL, 0x07f7e64705209c9aULL, }, /* 72 */
- { 0x779473b6cb43d680ULL, 0x03e141b56cceff30ULL, },
- { 0xa6279a1866fb9f64ULL, 0x2631668db9e53ac1ULL, },
- { 0x67a1f71bd99e4586ULL, 0x312ec9f6206e6e69ULL, },
- { 0x4207c47a7907b262ULL, 0x101a35e284b89539ULL, },
- { 0x5cb4f4db15070699ULL, 0x0073da1f866c98a9ULL, },
- { 0x1e2f51de87a9acbbULL, 0x0b713d87ecf5cc51ULL, },
- { 0x721d49ba5f0acfa8ULL, 0x5ba5bbe9afeae691ULL, },
- { 0x4bcd68690d995de0ULL, 0x771da6b4b6c967ebULL, }, /* 80 */
- { 0x4ea9a2cfbb5acd7bULL, 0x79dd6a73439e6387ULL, },
- { 0x47c800b999dd2371ULL, 0x766d25914ef7a7a0ULL, },
- { 0x41b0fa10eb77cf84ULL, 0x26e85189458965f8ULL, },
- { 0x1fc448ce062c2944ULL, 0x31f490a9422a80e6ULL, },
- { 0x211bdfadfd79770eULL, 0x3b25f4cac5763378ULL, },
- { 0x16fbb87edd87b6f0ULL, 0x57c0b65fabdda20eULL, },
- { 0x14621091eac4a5f6ULL, 0x4d29a25d32fa9ef6ULL, },
- { 0x07832ded1c464b02ULL, 0x6396905709e3cfa4ULL, }, /* 88 */
- { 0x0ff4a84eab8df3b9ULL, 0x6bc9a7d8c6adf2eaULL, },
- { 0x21e53326bfbd0b05ULL, 0x8f8f3b9c679dff5aULL, },
- { 0x191ed6a24e1576f9ULL, 0x9e8c2e402760373aULL, },
- { 0x19b438400fc27751ULL, 0x819c4bbfd3ee6972ULL, },
- { 0x1e0d5dc1094ae999ULL, 0x7496a289f5eff010ULL, },
- { 0x11af620b7bc03943ULL, 0x8a11f229836addc7ULL, },
- { 0x46fa45d0e84440fcULL, 0xe8d2c0211fb042bfULL, },
- { 0x22142516b5a8adbcULL, 0xe1cf1923e186aad1ULL, }, /* 96 */
- { 0x066ebbbb4ff6da44ULL, 0xd918d7e6a7e61877ULL, },
- { 0x100acc9d22839a48ULL, 0xce291932929e367fULL, },
- { 0x0dfe419d62a62f64ULL, 0xc020fe45a8cf7acfULL, },
- { 0x2ba79b6ffbf3c63bULL, 0xb428f52c49fce695ULL, },
- { 0x29b3b85200bdf100ULL, 0xb4ae7ea2f52aa5b9ULL, },
- { 0x293bb84d6360c0b6ULL, 0xae33b26e4c493c49ULL, },
- { 0x46a99fdf54f4862dULL, 0xae790dc5055f6f51ULL, },
- { 0x18480e0fd728c7c3ULL, 0xa000ad7b15f8ebe0ULL, }, /* 104 */
- { 0x1b8b97aa205e1239ULL, 0x89c78b8909c4a8e5ULL, },
- { 0x09abb26b05ef649dULL, 0x74242fa1bd49e740ULL, },
- { 0x04e233bc861d272bULL, 0x9c5343ab30f62f9fULL, },
- { 0xda2da0d0884dc3d1ULL, 0xb824f201640b4147ULL, },
- { 0x9d8b22ee1b9a2e0fULL, 0xb642ddf1edb0747fULL, },
- { 0x7c81956533686a37ULL, 0xdd5181781dc3ad37ULL, },
- { 0xc60b1905717ff25aULL, 0xe2af726e71ad7ad7ULL, },
+ { 0x0101010101010101ULL, 0x0101010101010101ULL, }, /* 0 */
+ { 0x0101010101010101ULL, 0x0101010101010101ULL, },
+ { 0x5757575757575757ULL, 0x5757575757575757ULL, },
+ { 0x0202020202020202ULL, 0x0202020202020202ULL, },
+ { 0x3636363636363636ULL, 0x3636363636363636ULL, },
+ { 0x0303030303030303ULL, 0x0303030303030303ULL, },
+ { 0x2075cb2075cb2075ULL, 0xcb2075cb2075cb20ULL, },
+ { 0x0404040404040404ULL, 0x0404040404040404ULL, },
+ { 0x0404040404040404ULL, 0x0404040404040404ULL, }, /* 8 */
+ { 0x0404040404040404ULL, 0x0404040404040404ULL, },
+ { 0x0404040404040404ULL, 0x0404040404040404ULL, },
+ { 0x0404040404040404ULL, 0x0404040404040404ULL, },
+ { 0x0404040404040404ULL, 0x0404040404040404ULL, },
+ { 0x0404040404040404ULL, 0x0404040404040404ULL, },
+ { 0x0404040404040404ULL, 0x0404040404040404ULL, },
+ { 0x0404040404040404ULL, 0x0404040404040404ULL, },
+ { 0x5a5a5a5a5a5a5a5aULL, 0x5a5a5a5a5a5a5a5aULL, }, /* 16 */
+ { 0x5a5a5a5a5a5a5a5aULL, 0x5a5a5a5a5a5a5a5aULL, },
+ { 0x3e3e3e3e3e3e3e3eULL, 0x3e3e3e3e3e3e3e3eULL, },
+ { 0xb0b0b0b0b0b0b0b0ULL, 0xb0b0b0b0b0b0b0b0ULL, },
+ { 0x2828282828282828ULL, 0x2828282828282828ULL, },
+ { 0x0606060606060606ULL, 0x0606060606060606ULL, },
+ { 0xc45236c45236c452ULL, 0x36c45236c45236c4ULL, },
+ { 0x5c5c5c5c5c5c5c5cULL, 0x5c5c5c5c5c5c5c5cULL, },
+ { 0x0707070707070707ULL, 0x0707070707070707ULL, }, /* 24 */
+ { 0x0707070707070707ULL, 0x0707070707070707ULL, },
+ { 0x7979797979797979ULL, 0x7979797979797979ULL, },
+ { 0xb2b2b2b2b2b2b2b2ULL, 0xb2b2b2b2b2b2b2b2ULL, },
+ { 0x6e6e6e6e6e6e6e6eULL, 0x6e6e6e6e6e6e6e6eULL, },
+ { 0x5d5d5d5d5d5d5d5dULL, 0x5d5d5d5d5d5d5d5dULL, },
+ { 0xbc83f5bc83f5bc83ULL, 0xf5bc83f5bc83f5bcULL, },
+ { 0x0808080808080808ULL, 0x0808080808080808ULL, },
+ { 0x3c3c3c3c3c3c3c3cULL, 0x3c3c3c3c3c3c3c3cULL, }, /* 32 */
+ { 0x3c3c3c3c3c3c3c3cULL, 0x3c3c3c3c3c3c3c3cULL, },
+ { 0xb4b4b4b4b4b4b4b4ULL, 0xb4b4b4b4b4b4b4b4ULL, },
+ { 0x7070707070707070ULL, 0x7070707070707070ULL, },
+ { 0x0000000000000000ULL, 0x0000000000000000ULL, },
+ { 0xa4a4a4a4a4a4a4a4ULL, 0xa4a4a4a4a4a4a4a4ULL, },
+ { 0x88cc4488cc4488ccULL, 0x4488cc4488cc4488ULL, },
+ { 0xd8d8d8d8d8d8d8d8ULL, 0xd8d8d8d8d8d8d8d8ULL, },
+ { 0xa5a5a5a5a5a5a5a5ULL, 0xa5a5a5a5a5a5a5a5ULL, }, /* 40 */
+ { 0xa5a5a5a5a5a5a5a5ULL, 0xa5a5a5a5a5a5a5a5ULL, },
+ { 0x8383838383838383ULL, 0x8383838383838383ULL, },
+ { 0x7272727272727272ULL, 0x7272727272727272ULL, },
+ { 0x1616161616161616ULL, 0x1616161616161616ULL, },
+ { 0x3f3f3f3f3f3f3f3fULL, 0x3f3f3f3f3f3f3f3fULL, },
+ { 0x7889677889677889ULL, 0x6778896778896778ULL, },
+ { 0x0c0c0c0c0c0c0c0cULL, 0x0c0c0c0c0c0c0c0cULL, },
+ { 0x297ed4297ed4297eULL, 0xd4297ed4297ed429ULL, }, /* 48 */
+ { 0x297ed4297ed4297eULL, 0xd4297ed4297ed429ULL, },
+ { 0xe7ca04e7ca04e7caULL, 0x04e7ca04e7ca04e7ULL, },
+ { 0x46f09c46f09c46f0ULL, 0x9c46f09c46f09c46ULL, },
+ { 0x2a183c2a183c2a18ULL, 0x3c2a183c2a183c2aULL, },
+ { 0x6362646362646362ULL, 0x6463626463626463ULL, },
+ { 0xac26a4ac26a4ac26ULL, 0xa4ac26a4ac26a4acULL, },
+ { 0x80d42c80d42c80d4ULL, 0x2c80d42c80d42c80ULL, },
+ { 0x6463656463656463ULL, 0x6564636564636564ULL, }, /* 56 */
+ { 0x6463656463656463ULL, 0x6564636564636564ULL, },
+ { 0xfc6d8bfc6d8bfc6dULL, 0x8bfc6d8bfc6d8bfcULL, },
+ { 0x48f29e48f29e48f2ULL, 0x9e48f29e48f29e48ULL, },
+ { 0x98fe3298fe3298feULL, 0x3298fe3298fe3298ULL, },
+ { 0x2c81d72c81d72c81ULL, 0xd72c81d72c81d72cULL, },
+ { 0x002f5f002f5f002fULL, 0x5f002f5f002f5f00ULL, },
+ { 0x1010101010101010ULL, 0x1010101010101010ULL, },
+ { 0x50f4b4a050944910ULL, 0x09818994142910a0ULL, }, /* 64 */
+ { 0xa8a0b48458da5c10ULL, 0x4fe29220ea6e7070ULL, },
+ { 0x08e408fc40188310ULL, 0xbcca14c29417e060ULL, },
+ { 0x889acc58f0da8d90ULL, 0x0bc1ec1242cd40e0ULL, },
+ { 0xe046cc3cf820a090ULL, 0x5122f59e1812a0b0ULL, },
+ { 0xf94acc85218951d0ULL, 0x95738e42d193e4c0ULL, },
+ { 0x9d16cc43c6665ed0ULL, 0x53db3028d828be70ULL, },
+ { 0x6db8cc0a0c890c40ULL, 0x3d628818b56622f0ULL, },
+ { 0xcdfc2082f4c73340ULL, 0xaa4a0aba5f0f92e0ULL, }, /* 72 */
+ { 0x71c8204099a44040ULL, 0x68b2aca066a46c90ULL, },
+ { 0x016c64244a05b940ULL, 0x59f2d0a19fddc520ULL, },
+ { 0x4132584638a46f40ULL, 0xd44a00c982f36fa0ULL, },
+ { 0xc1e81ca2e86679c0ULL, 0x2341d81930a9cf20ULL, },
+ { 0x918a1c692e892730ULL, 0x0dc830090de733a0ULL, },
+ { 0xd150108b1c28dd30ULL, 0x88206031f0fddd20ULL, },
+ { 0xd1b1f4b4a08961f4ULL, 0x3101a07181016120ULL, },
+ { 0xd9fb2c24a0fb96f4ULL, 0x8c6880ef7f7c11a0ULL, }, /* 80 */
+ { 0x9c452c10c01c3094ULL, 0x64c00035ea008320ULL, },
+ { 0x6c8714b080c04094ULL, 0xa0c00000380072a0ULL, },
+ { 0xac30cca08080c0acULL, 0xc0800000300016a0ULL, },
+ { 0x0c101420808080acULL, 0x00000000d0003620ULL, },
+ { 0xd0f014800000000cULL, 0x00000000e00082a0ULL, },
+ { 0x9050ac800000000cULL, 0x0000000080004c20ULL, },
+ { 0x90007400000000b4ULL, 0x0000000000006420ULL, },
+ { 0x1000ac00000000b4ULL, 0x00000000000024a0ULL, }, /* 88 */
+ { 0xc000ac0000000054ULL, 0x000000000000ac20ULL, },
+ { 0xc000940000000054ULL, 0x00000000000088a0ULL, },
+ { 0xc0004c00000000ecULL, 0x00000000000098a0ULL, },
+ { 0xc0009400000000ecULL, 0x0000000000001820ULL, },
+ { 0x000094000000004cULL, 0x000000000000c8a0ULL, },
+ { 0x00002c000000004cULL, 0x000000000000b020ULL, },
+ { 0x0000f40000000074ULL, 0x0000000000001020ULL, },
+ { 0x00002c0000000074ULL, 0x00000000000010a0ULL, }, /* 96 */
+ { 0x0000b40000000074ULL, 0x0000000000001020ULL, },
+ { 0x00006c0000000074ULL, 0x00000000000010a0ULL, },
+ { 0x0000740000000074ULL, 0x0000000000001020ULL, },
+ { 0x0000740000000014ULL, 0x00000000000030a0ULL, },
+ { 0x00007400000000b4ULL, 0x0000000000009020ULL, },
+ { 0x0000740000000054ULL, 0x000000000000b0a0ULL, },
+ { 0x00007400000000f4ULL, 0x0000000000001020ULL, },
+ { 0x00004c00000000f4ULL, 0x00000000000060a0ULL, }, /* 104 */
+ { 0x0000f400000000f4ULL, 0x0000000000004020ULL, },
+ { 0x0000cc00000000f4ULL, 0x00000000000080a0ULL, },
+ { 0x00007400000000f4ULL, 0x0000000000000020ULL, },
+ { 0x00006c000000004cULL, 0x0000000000000020ULL, },
+ { 0x0000b40000000074ULL, 0x0000000000000020ULL, },
+ { 0x00002c00000000ccULL, 0x0000000000000020ULL, },
+ { 0x0000f400000000f4ULL, 0x0000000000000020ULL, },
};
reset_msa_registers();
uint64_t b128_result[TEST_COUNT_TOTAL][2];
uint64_t b128_expect[TEST_COUNT_TOTAL][2] = {
- { 0x0000000000000002ULL, 0x0000000000000002ULL, }, /* 0 */
+ { 0x0000000000000001ULL, 0x0000000000000001ULL, }, /* 0 */
+ { 0x0000000000000001ULL, 0x0000000000000001ULL, },
+ { 0x5555555555555557ULL, 0x5555555555555557ULL, },
{ 0x0000000000000002ULL, 0x0000000000000002ULL, },
- { 0x00000000aaaaaaaeULL, 0x00000000aaaaaaaeULL, },
+ { 0x3333333333333336ULL, 0x3333333333333336ULL, },
+ { 0x0000000000000003ULL, 0x0000000000000003ULL, },
+ { 0x1c71c71c71c71c75ULL, 0xc71c71c71c71c720ULL, },
{ 0x0000000000000004ULL, 0x0000000000000004ULL, },
- { 0x000000006666666cULL, 0x000000006666666cULL, },
+ { 0x0000000000000004ULL, 0x0000000000000004ULL, }, /* 8 */
+ { 0x0000000000000004ULL, 0x0000000000000004ULL, },
+ { 0x0000000000000004ULL, 0x0000000000000004ULL, },
+ { 0x0000000000000004ULL, 0x0000000000000004ULL, },
+ { 0x0000000000000004ULL, 0x0000000000000004ULL, },
+ { 0x0000000000000004ULL, 0x0000000000000004ULL, },
+ { 0x0000000000000004ULL, 0x0000000000000004ULL, },
+ { 0x0000000000000004ULL, 0x0000000000000004ULL, },
+ { 0x555555555555555aULL, 0x555555555555555aULL, }, /* 16 */
+ { 0x555555555555555aULL, 0x555555555555555aULL, },
+ { 0x8e38e38e38e38e3eULL, 0x8e38e38e38e38e3eULL, },
+ { 0xaaaaaaaaaaaaaab0ULL, 0xaaaaaaaaaaaaaab0ULL, },
+ { 0x2222222222222228ULL, 0x2222222222222228ULL, },
{ 0x0000000000000006ULL, 0x0000000000000006ULL, },
- { 0x000000008e38e395ULL, 0xffffffffe38e38ebULL, },
- { 0x0000000000000008ULL, 0x0000000000000008ULL, },
- { 0x0000000000000008ULL, 0x0000000000000008ULL, }, /* 8 */
- { 0x0000000000000008ULL, 0x0000000000000008ULL, },
- { 0x0000000000000008ULL, 0x0000000000000008ULL, },
- { 0x0000000000000008ULL, 0x0000000000000008ULL, },
- { 0x0000000000000008ULL, 0x0000000000000008ULL, },
- { 0x0000000000000008ULL, 0x0000000000000008ULL, },
- { 0x0000000000000008ULL, 0x0000000000000008ULL, },
+ { 0x12f684bda12f6852ULL, 0x2f684bda12f684c4ULL, },
+ { 0x555555555555555cULL, 0x555555555555555cULL, },
+ { 0x0000000000000007ULL, 0x0000000000000007ULL, }, /* 24 */
+ { 0x0000000000000007ULL, 0x0000000000000007ULL, },
+ { 0x1c71c71c71c71c79ULL, 0x1c71c71c71c71c79ULL, },
+ { 0xaaaaaaaaaaaaaab2ULL, 0xaaaaaaaaaaaaaab2ULL, },
+ { 0x666666666666666eULL, 0x666666666666666eULL, },
+ { 0x555555555555555dULL, 0x555555555555555dULL, },
+ { 0x5ed097b425ed0983ULL, 0xed097b425ed097bcULL, },
{ 0x0000000000000008ULL, 0x0000000000000008ULL, },
- { 0x00000000aaaaaab4ULL, 0x00000000aaaaaab4ULL, }, /* 16 */
- { 0x00000000aaaaaab4ULL, 0x00000000aaaaaab4ULL, },
- { 0x38e38e3a71c71c7cULL, 0x38e38e3a71c71c7cULL, },
- { 0x0000000155555560ULL, 0x0000000155555560ULL, },
- { 0x2222222444444450ULL, 0x2222222444444450ULL, },
- { 0x000000020000000cULL, 0x000000020000000cULL, },
- { 0x2f684bdcb425ed16ULL, 0xf684bda397b425faULL, },
- { 0x00000002aaaaaab8ULL, 0x00000002aaaaaab8ULL, },
- { 0x000000020000000eULL, 0x000000020000000eULL, }, /* 24 */
- { 0x000000020000000eULL, 0x000000020000000eULL, },
- { 0xc71c71c8e38e38f2ULL, 0xc71c71c8e38e38f2ULL, },
- { 0x0000000155555564ULL, 0x0000000155555564ULL, },
- { 0xdddddddeccccccdcULL, 0xdddddddeccccccdcULL, },
- { 0x00000000aaaaaabaULL, 0x00000000aaaaaabaULL, },
- { 0xd097b42684bda13fULL, 0x097b425ef684bdb1ULL, },
+ { 0x333333333333333cULL, 0x333333333333333cULL, }, /* 32 */
+ { 0x333333333333333cULL, 0x333333333333333cULL, },
+ { 0xaaaaaaaaaaaaaab4ULL, 0xaaaaaaaaaaaaaab4ULL, },
+ { 0x6666666666666670ULL, 0x6666666666666670ULL, },
+ { 0x5c28f5c28f5c2900ULL, 0x5c28f5c28f5c2900ULL, },
+ { 0x99999999999999a4ULL, 0x99999999999999a4ULL, },
+ { 0x16c16c16c16c16ccULL, 0xd27d27d27d27d288ULL, },
+ { 0xccccccccccccccd8ULL, 0xccccccccccccccd8ULL, },
+ { 0x99999999999999a5ULL, 0x99999999999999a5ULL, }, /* 40 */
+ { 0x99999999999999a5ULL, 0x99999999999999a5ULL, },
+ { 0x7777777777777783ULL, 0x7777777777777783ULL, },
+ { 0x6666666666666672ULL, 0x6666666666666672ULL, },
+ { 0xa3d70a3d70a3d716ULL, 0xa3d70a3d70a3d716ULL, },
+ { 0x333333333333333fULL, 0x333333333333333fULL, },
+ { 0xd27d27d27d27d289ULL, 0xc16c16c16c16c178ULL, },
+ { 0x000000000000000cULL, 0x000000000000000cULL, },
+ { 0x1c71c71c71c71c7eULL, 0xc71c71c71c71c729ULL, }, /* 48 */
+ { 0x1c71c71c71c71c7eULL, 0xc71c71c71c71c729ULL, },
+ { 0x2f684bda12f684caULL, 0xf684bda12f684be7ULL, },
+ { 0x38e38e38e38e38f0ULL, 0x8e38e38e38e38e46ULL, },
+ { 0xb60b60b60b60b618ULL, 0xc71c71c71c71c72aULL, },
+ { 0x5555555555555562ULL, 0x5555555555555563ULL, },
+ { 0x06522c3f35ba7826ULL, 0xa781948b0fcd6eacULL, },
+ { 0x71c71c71c71c71d4ULL, 0x1c71c71c71c71c80ULL, },
+ { 0x5555555555555563ULL, 0x5555555555555564ULL, }, /* 56 */
+ { 0x5555555555555563ULL, 0x5555555555555564ULL, },
+ { 0x97b425ed097b426dULL, 0x7b425ed097b425fcULL, },
+ { 0x38e38e38e38e38f2ULL, 0x8e38e38e38e38e48ULL, },
+ { 0xeeeeeeeeeeeeeefeULL, 0x8888888888888898ULL, },
+ { 0x1c71c71c71c71c81ULL, 0xc71c71c71c71c72cULL, },
+ { 0x87e6b74f0329162fULL, 0x3c0ca4587e6b7500ULL, },
{ 0x0000000000000010ULL, 0x0000000000000010ULL, },
- { 0x0000000066666678ULL, 0x0000000066666678ULL, }, /* 32 */
- { 0x0000000066666678ULL, 0x0000000066666678ULL, },
- { 0x2222222355555568ULL, 0x2222222355555568ULL, },
- { 0x00000000cccccce0ULL, 0x00000000cccccce0ULL, },
- { 0x147ae1491eb85200ULL, 0x147ae1491eb85200ULL, },
- { 0x0000000133333348ULL, 0x0000000133333348ULL, },
- { 0x1c71c71e3e93e954ULL, 0xfa4fa4fbb60b60ccULL, },
- { 0x00000001999999b0ULL, 0x00000001999999b0ULL, },
- { 0x000000013333334aULL, 0x000000013333334aULL, }, /* 40 */
- { 0x000000013333334aULL, 0x000000013333334aULL, },
- { 0xdddddddeeeeeef06ULL, 0xdddddddeeeeeef06ULL, },
- { 0x00000000cccccce4ULL, 0x00000000cccccce4ULL, },
- { 0xeb851eb8e147ae2cULL, 0xeb851eb8e147ae2cULL, },
- { 0x000000006666667eULL, 0x000000006666667eULL, },
- { 0xe38e38e3e93e9401ULL, 0x05b05b05c71c71dfULL, },
- { 0x0000000000000018ULL, 0x0000000000000018ULL, },
- { 0x000000008e38e3a7ULL, 0xffffffffe38e38fdULL, }, /* 48 */
- { 0x000000008e38e3a7ULL, 0xffffffffe38e38fdULL, },
- { 0x2f684bdb425ed0b1ULL, 0xf684bda17b425eebULL, },
- { 0x000000011c71c736ULL, 0xffffffffc71c71e2ULL, },
- { 0x1c71c71e27d27d42ULL, 0xfa4fa4fa49f49f66ULL, },
- { 0x00000001aaaaaac5ULL, 0xffffffffaaaaaac7ULL, },
- { 0x35ba781b4587e6d2ULL, 0x0fcd6e9d6b74f050ULL, },
- { 0x0000000238e38e54ULL, 0xffffffff8e38e3acULL, },
- { 0x00000001aaaaaac7ULL, 0xffffffffaaaaaac9ULL, }, /* 56 */
- { 0x00000001aaaaaac7ULL, 0xffffffffaaaaaac9ULL, },
- { 0xd097b427a12f6869ULL, 0x097b425ebda12f87ULL, },
- { 0x000000011c71c73aULL, 0xffffffffc71c71e6ULL, },
- { 0xe38e38e477777796ULL, 0x05b05b05aaaaaacaULL, },
- { 0x000000008e38e3adULL, 0xffffffffe38e3903ULL, },
- { 0xca4587e781948b2fULL, 0xf032916206522c5fULL, },
- { 0x0000000000000020ULL, 0x0000000000000020ULL, },
- { 0x3e3ad4ae1266c2b0ULL, 0x1637d725aebdb734ULL, }, /* 64 */
- { 0x4c74e0d60a3d6d94ULL, 0x1badd2dd9f4dac90ULL, },
- { 0x6874e8f94205b90cULL, 0x27eb0c41af2c3022ULL, },
- { 0x42dab657e16f25e8ULL, 0x06d6782e137656f2ULL, },
- { 0x5114c27fd945d0ccULL, 0x0c4c73e604064c4eULL, },
- { 0x68a91e898c276755ULL, 0x0f77ad378bdfb302ULL, },
- { 0x54c82cde41d1cf13ULL, 0x0b6108a5f38e1598ULL, },
- { 0x6f755d3eddd1234aULL, 0xfbbaace2f5421908ULL, },
- { 0x8b75656215996ec2ULL, 0x07f7e64705209c9aULL, }, /* 72 */
- { 0x779473b6cb43d680ULL, 0x03e141b56cceff30ULL, },
- { 0xa6279a1866fb9f64ULL, 0x2631668db9e53ac1ULL, },
- { 0x67a1f71bd99e4586ULL, 0x312ec9f6206e6e69ULL, },
- { 0x4207c47a7907b262ULL, 0x101a35e284b89539ULL, },
- { 0x5cb4f4db15070699ULL, 0x0073da1f866c98a9ULL, },
- { 0x1e2f51de87a9acbbULL, 0x0b713d87ecf5cc51ULL, },
- { 0x721d49ba5f0acfa8ULL, 0x5ba5bbe9afeae691ULL, },
- { 0x4bcd68690d995de0ULL, 0x771da6b4b6c967ebULL, }, /* 80 */
- { 0x4ea9a2cfbb5acd7bULL, 0x79dd6a73439e6387ULL, },
- { 0x47c800b999dd2371ULL, 0x766d25914ef7a7a0ULL, },
- { 0x41b0fa10eb77cf84ULL, 0x26e85189458965f8ULL, },
- { 0x1fc448ce062c2944ULL, 0x31f490a9422a80e6ULL, },
- { 0x211bdfadfd79770eULL, 0x3b25f4cac5763378ULL, },
- { 0x16fbb87edd87b6f0ULL, 0x57c0b65fabdda20eULL, },
- { 0x14621091eac4a5f6ULL, 0x4d29a25d32fa9ef6ULL, },
- { 0x07832ded1c464b02ULL, 0x6396905709e3cfa4ULL, }, /* 88 */
- { 0x0ff4a84eab8df3b9ULL, 0x6bc9a7d8c6adf2eaULL, },
- { 0x21e53326bfbd0b05ULL, 0x8f8f3b9c679dff5aULL, },
- { 0x191ed6a24e1576f9ULL, 0x9e8c2e402760373aULL, },
- { 0x19b438400fc27751ULL, 0x819c4bbfd3ee6972ULL, },
- { 0x1e0d5dc1094ae999ULL, 0x7496a289f5eff010ULL, },
- { 0x11af620b7bc03943ULL, 0x8a11f229836addc7ULL, },
- { 0x46fa45d0e84440fcULL, 0xe8d2c0211fb042bfULL, },
- { 0x22142516b5a8adbcULL, 0xe1cf1923e186aad1ULL, }, /* 96 */
- { 0x066ebbbb4ff6da44ULL, 0xd918d7e6a7e61877ULL, },
- { 0x100acc9d22839a48ULL, 0xce291932929e367fULL, },
- { 0x0dfe419d62a62f64ULL, 0xc020fe45a8cf7acfULL, },
- { 0x2ba79b6ffbf3c63bULL, 0xb428f52c49fce695ULL, },
- { 0x29b3b85200bdf100ULL, 0xb4ae7ea2f52aa5b9ULL, },
- { 0x293bb84d6360c0b6ULL, 0xae33b26e4c493c49ULL, },
- { 0x46a99fdf54f4862dULL, 0xae790dc5055f6f51ULL, },
- { 0x18480e0fd728c7c3ULL, 0xa000ad7b15f8ebe0ULL, }, /* 104 */
- { 0x1b8b97aa205e1239ULL, 0x89c78b8909c4a8e5ULL, },
- { 0x09abb26b05ef649dULL, 0x74242fa1bd49e740ULL, },
- { 0x04e233bc861d272bULL, 0x9c5343ab30f62f9fULL, },
- { 0xda2da0d0884dc3d1ULL, 0xb824f201640b4147ULL, },
- { 0x9d8b22ee1b9a2e0fULL, 0xb642ddf1edb0747fULL, },
- { 0x7c81956533686a37ULL, 0xdd5181781dc3ad37ULL, },
- { 0xc60b1905717ff25aULL, 0xe2af726e71ad7ad7ULL, },
+ { 0xad45be6961639010ULL, 0x3297fdea749880a0ULL, }, /* 64 */
+ { 0x9ced640a487afa10ULL, 0xeaa90809e3b1a470ULL, },
+ { 0xa5b377aa0caf5a10ULL, 0x95c9a7903bd12160ULL, },
+ { 0xa194ffe4fb27d390ULL, 0x17e6ccd3c9a1c0e0ULL, },
+ { 0x913ca585e23f3d90ULL, 0xcff7d6f338bae4b0ULL, },
+ { 0xc8ead0bee02cadd0ULL, 0x381c4d6a83a94cc0ULL, },
+ { 0x33b60e279e9989d0ULL, 0xe7f71f9b97ee3470ULL, },
+ { 0x217580abbfdd3e40ULL, 0x6779436687bc89f0ULL, },
+ { 0x2a3b944b84119e40ULL, 0x1299e2ecdfdc06e0ULL, }, /* 72 */
+ { 0x9506d1b4427e7a40ULL, 0xc274b51df420ee90ULL, },
+ { 0x1b2bb7962782ba40ULL, 0x9bf62dc42637b820ULL, },
+ { 0x91d16316b1663b40ULL, 0x3cf7c824fb128ca0ULL, },
+ { 0x8db2eb519fdeb4c0ULL, 0xbf14ed6888e32c20ULL, },
+ { 0x7b725dd5c1226930ULL, 0x3e97113378b181a0ULL, },
+ { 0xf21809564b05ea30ULL, 0xdf98ab944d8c5620ULL, },
+ { 0x3dcc402bfcefb9f4ULL, 0xf26a7a4530ab3a20ULL, },
+ { 0x81a8956a21043af4ULL, 0xe63ec4a9de07f3a0ULL, }, /* 80 */
+ { 0x14acc7eab115be94ULL, 0xa72fae300e450520ULL, },
+ { 0x4c5c3900181b6494ULL, 0xc26796e561c70ba0ULL, },
+ { 0x513451003792b1acULL, 0x5acad191d5b18fa0ULL, },
+ { 0x0daff27cb51538acULL, 0x31375ce2aea24b20ULL, },
+ { 0xbb9ebee52390b20cULL, 0xd8cfb350af547ea0ULL, },
+ { 0x4df25269204a3c0cULL, 0x07b9241bbd1b8320ULL, },
+ { 0x39b3c4d066371fb4ULL, 0x2a4dc00c264fb720ULL, },
+ { 0xf9aee458846dd0b4ULL, 0x79d838b37c524ca0ULL, }, /* 88 */
+ { 0x115f9e7f00744254ULL, 0x46ec87fe3540fa20ULL, },
+ { 0xb01458f6b0850854ULL, 0xde82246a25db24a0ULL, },
+ { 0xc18097bf5a7bb9ecULL, 0x4155f0da566748a0ULL, },
+ { 0x70c7391b1a7d90ecULL, 0x0400deec0a0cb020ULL, },
+ { 0xf7a41980bd958c4cULL, 0xedfeb14ff6d44fa0ULL, },
+ { 0x7906f19718fcf64cULL, 0x29e471752ecca820ULL, },
+ { 0xb6393967140b1974ULL, 0xbd0ed4c39361fc20ULL, },
+ { 0x74ecb57da4acfa74ULL, 0x36ea3f3dbcafcda0ULL, }, /* 96 */
+ { 0x5b14aa5e3f7c1b74ULL, 0xeb031f17fe2b7120ULL, },
+ { 0x0468573ef6087c74ULL, 0xe8ef35d2e05abea0ULL, },
+ { 0xd69cf5cf0de21d74ULL, 0x39f569701e89ae20ULL, },
+ { 0xf233f7a10f743514ULL, 0xf574fc00c1b755a0ULL, },
+ { 0x873c421a5ed469b4ULL, 0x96f393305dfcdf20ULL, },
+ { 0x17e80b0449fea354ULL, 0x2f05ddb06b40c2a0ULL, },
+ { 0x0741f67f982609f4ULL, 0x9c23f2dbc2b79820ULL, },
+ { 0x530275e3b2de7ff4ULL, 0xc6904e7f6f6c1aa0ULL, }, /* 104 */
+ { 0xf8214644bbe3f5f4ULL, 0xe44a0de01c974f20ULL, },
+ { 0xb59c90c0a8b66bf4ULL, 0x9abcf7a8e1391da0ULL, },
+ { 0xb67d543caed5e1f4ULL, 0x4ce8f72994d78e20ULL, },
+ { 0xcee67f5e9d2e224cULL, 0xba31bdf2ab48a220ULL, },
+ { 0x87acb43db40fad74ULL, 0x8a259794c40e3620ULL, },
+ { 0x45c27495332aeeccULL, 0xe81c4208ecf84a20ULL, },
+ { 0x50a99b794e1bc8f4ULL, 0x17cdf4c275d6de20ULL, },
};
reset_msa_registers();
uint64_t b128_result[TEST_COUNT_TOTAL][2];
uint64_t b128_expect[TEST_COUNT_TOTAL][2] = {
- { 0x0000000000000002ULL, 0x0000000000000002ULL, }, /* 0 */
- { 0x0000000000000002ULL, 0x0000000000000002ULL, },
- { 0x00000000aaaaaaaeULL, 0x00000000aaaaaaaeULL, },
- { 0x0000000000000004ULL, 0x0000000000000004ULL, },
- { 0x000000006666666cULL, 0x000000006666666cULL, },
- { 0x0000000000000006ULL, 0x0000000000000006ULL, },
- { 0x000000008e38e395ULL, 0xffffffffe38e38ebULL, },
- { 0x0000000000000008ULL, 0x0000000000000008ULL, },
- { 0x0000000000000008ULL, 0x0000000000000008ULL, }, /* 8 */
- { 0x0000000000000008ULL, 0x0000000000000008ULL, },
- { 0x0000000000000008ULL, 0x0000000000000008ULL, },
- { 0x0000000000000008ULL, 0x0000000000000008ULL, },
- { 0x0000000000000008ULL, 0x0000000000000008ULL, },
- { 0x0000000000000008ULL, 0x0000000000000008ULL, },
- { 0x0000000000000008ULL, 0x0000000000000008ULL, },
- { 0x0000000000000008ULL, 0x0000000000000008ULL, },
- { 0x00000000aaaaaab4ULL, 0x00000000aaaaaab4ULL, }, /* 16 */
- { 0x00000000aaaaaab4ULL, 0x00000000aaaaaab4ULL, },
- { 0x38e38e3a71c71c7cULL, 0x38e38e3a71c71c7cULL, },
- { 0x0000000155555560ULL, 0x0000000155555560ULL, },
- { 0x2222222444444450ULL, 0x2222222444444450ULL, },
- { 0x000000020000000cULL, 0x000000020000000cULL, },
- { 0x2f684bdcb425ed16ULL, 0xf684bda397b425faULL, },
- { 0x00000002aaaaaab8ULL, 0x00000002aaaaaab8ULL, },
- { 0x000000020000000eULL, 0x000000020000000eULL, }, /* 24 */
- { 0x000000020000000eULL, 0x000000020000000eULL, },
- { 0xc71c71c8e38e38f2ULL, 0xc71c71c8e38e38f2ULL, },
- { 0x0000000155555564ULL, 0x0000000155555564ULL, },
- { 0xdddddddeccccccdcULL, 0xdddddddeccccccdcULL, },
- { 0x00000000aaaaaabaULL, 0x00000000aaaaaabaULL, },
- { 0xd097b42684bda13fULL, 0x097b425ef684bdb1ULL, },
- { 0x0000000000000010ULL, 0x0000000000000010ULL, },
- { 0x0000000066666678ULL, 0x0000000066666678ULL, }, /* 32 */
- { 0x0000000066666678ULL, 0x0000000066666678ULL, },
- { 0x2222222355555568ULL, 0x2222222355555568ULL, },
- { 0x00000000cccccce0ULL, 0x00000000cccccce0ULL, },
- { 0x147ae1491eb85200ULL, 0x147ae1491eb85200ULL, },
- { 0x0000000133333348ULL, 0x0000000133333348ULL, },
- { 0x1c71c71e3e93e954ULL, 0xfa4fa4fbb60b60ccULL, },
- { 0x00000001999999b0ULL, 0x00000001999999b0ULL, },
- { 0x000000013333334aULL, 0x000000013333334aULL, }, /* 40 */
- { 0x000000013333334aULL, 0x000000013333334aULL, },
- { 0xdddddddeeeeeef06ULL, 0xdddddddeeeeeef06ULL, },
- { 0x00000000cccccce4ULL, 0x00000000cccccce4ULL, },
- { 0xeb851eb8e147ae2cULL, 0xeb851eb8e147ae2cULL, },
- { 0x000000006666667eULL, 0x000000006666667eULL, },
- { 0xe38e38e3e93e9401ULL, 0x05b05b05c71c71dfULL, },
- { 0x0000000000000018ULL, 0x0000000000000018ULL, },
- { 0x000000008e38e3a7ULL, 0xffffffffe38e38fdULL, }, /* 48 */
- { 0x000000008e38e3a7ULL, 0xffffffffe38e38fdULL, },
- { 0x2f684bdb425ed0b1ULL, 0xf684bda17b425eebULL, },
- { 0x000000011c71c736ULL, 0xffffffffc71c71e2ULL, },
- { 0x1c71c71e27d27d42ULL, 0xfa4fa4fa49f49f66ULL, },
- { 0x00000001aaaaaac5ULL, 0xffffffffaaaaaac7ULL, },
- { 0x35ba781b4587e6d2ULL, 0x0fcd6e9d6b74f050ULL, },
- { 0x0000000238e38e54ULL, 0xffffffff8e38e3acULL, },
- { 0x00000001aaaaaac7ULL, 0xffffffffaaaaaac9ULL, }, /* 56 */
- { 0x00000001aaaaaac7ULL, 0xffffffffaaaaaac9ULL, },
- { 0xd097b427a12f6869ULL, 0x097b425ebda12f87ULL, },
- { 0x000000011c71c73aULL, 0xffffffffc71c71e6ULL, },
- { 0xe38e38e477777796ULL, 0x05b05b05aaaaaacaULL, },
- { 0x000000008e38e3adULL, 0xffffffffe38e3903ULL, },
- { 0xca4587e781948b2fULL, 0xf032916206522c5fULL, },
- { 0x0000000000000020ULL, 0x0000000000000020ULL, },
- { 0x3e3ad4ae1266c2b0ULL, 0x1637d725aebdb734ULL, }, /* 64 */
- { 0x4c74e0d60a3d6d94ULL, 0x1badd2dd9f4dac90ULL, },
- { 0x6874e8f94205b90cULL, 0x27eb0c41af2c3022ULL, },
- { 0x42dab657e16f25e8ULL, 0x06d6782e137656f2ULL, },
- { 0x5114c27fd945d0ccULL, 0x0c4c73e604064c4eULL, },
- { 0x68a91e898c276755ULL, 0x0f77ad378bdfb302ULL, },
- { 0x54c82cde41d1cf13ULL, 0x0b6108a5f38e1598ULL, },
- { 0x6f755d3eddd1234aULL, 0xfbbaace2f5421908ULL, },
- { 0x8b75656215996ec2ULL, 0x07f7e64705209c9aULL, }, /* 72 */
- { 0x779473b6cb43d680ULL, 0x03e141b56cceff30ULL, },
- { 0xa6279a1866fb9f64ULL, 0x2631668db9e53ac1ULL, },
- { 0x67a1f71bd99e4586ULL, 0x312ec9f6206e6e69ULL, },
- { 0x4207c47a7907b262ULL, 0x101a35e284b89539ULL, },
- { 0x5cb4f4db15070699ULL, 0x0073da1f866c98a9ULL, },
- { 0x1e2f51de87a9acbbULL, 0x0b713d87ecf5cc51ULL, },
- { 0x721d49ba5f0acfa8ULL, 0x5ba5bbe9afeae691ULL, },
- { 0x4bcd68690d995de0ULL, 0x771da6b4b6c967ebULL, }, /* 80 */
- { 0x4ea9a2cfbb5acd7bULL, 0x79dd6a73439e6387ULL, },
- { 0x47c800b999dd2371ULL, 0x766d25914ef7a7a0ULL, },
- { 0x41b0fa10eb77cf84ULL, 0x26e85189458965f8ULL, },
- { 0x1fc448ce062c2944ULL, 0x31f490a9422a80e6ULL, },
- { 0x211bdfadfd79770eULL, 0x3b25f4cac5763378ULL, },
- { 0x16fbb87edd87b6f0ULL, 0x57c0b65fabdda20eULL, },
- { 0x14621091eac4a5f6ULL, 0x4d29a25d32fa9ef6ULL, },
- { 0x07832ded1c464b02ULL, 0x6396905709e3cfa4ULL, }, /* 88 */
- { 0x0ff4a84eab8df3b9ULL, 0x6bc9a7d8c6adf2eaULL, },
- { 0x21e53326bfbd0b05ULL, 0x8f8f3b9c679dff5aULL, },
- { 0x191ed6a24e1576f9ULL, 0x9e8c2e402760373aULL, },
- { 0x19b438400fc27751ULL, 0x819c4bbfd3ee6972ULL, },
- { 0x1e0d5dc1094ae999ULL, 0x7496a289f5eff010ULL, },
- { 0x11af620b7bc03943ULL, 0x8a11f229836addc7ULL, },
- { 0x46fa45d0e84440fcULL, 0xe8d2c0211fb042bfULL, },
- { 0x22142516b5a8adbcULL, 0xe1cf1923e186aad1ULL, }, /* 96 */
- { 0x066ebbbb4ff6da44ULL, 0xd918d7e6a7e61877ULL, },
- { 0x100acc9d22839a48ULL, 0xce291932929e367fULL, },
- { 0x0dfe419d62a62f64ULL, 0xc020fe45a8cf7acfULL, },
- { 0x2ba79b6ffbf3c63bULL, 0xb428f52c49fce695ULL, },
- { 0x29b3b85200bdf100ULL, 0xb4ae7ea2f52aa5b9ULL, },
- { 0x293bb84d6360c0b6ULL, 0xae33b26e4c493c49ULL, },
- { 0x46a99fdf54f4862dULL, 0xae790dc5055f6f51ULL, },
- { 0x18480e0fd728c7c3ULL, 0xa000ad7b15f8ebe0ULL, }, /* 104 */
- { 0x1b8b97aa205e1239ULL, 0x89c78b8909c4a8e5ULL, },
- { 0x09abb26b05ef649dULL, 0x74242fa1bd49e740ULL, },
- { 0x04e233bc861d272bULL, 0x9c5343ab30f62f9fULL, },
- { 0xda2da0d0884dc3d1ULL, 0xb824f201640b4147ULL, },
- { 0x9d8b22ee1b9a2e0fULL, 0xb642ddf1edb0747fULL, },
- { 0x7c81956533686a37ULL, 0xdd5181781dc3ad37ULL, },
- { 0xc60b1905717ff25aULL, 0xe2af726e71ad7ad7ULL, },
+ { 0x0001000100010001ULL, 0x0001000100010001ULL, }, /* 0 */
+ { 0x0001000100010001ULL, 0x0001000100010001ULL, },
+ { 0x5557555755575557ULL, 0x5557555755575557ULL, },
+ { 0x0002000200020002ULL, 0x0002000200020002ULL, },
+ { 0x3336333633363336ULL, 0x3336333633363336ULL, },
+ { 0x0003000300030003ULL, 0x0003000300030003ULL, },
+ { 0x1c75c72071cb1c75ULL, 0xc72071cb1c75c720ULL, },
+ { 0x0004000400040004ULL, 0x0004000400040004ULL, },
+ { 0x0004000400040004ULL, 0x0004000400040004ULL, }, /* 8 */
+ { 0x0004000400040004ULL, 0x0004000400040004ULL, },
+ { 0x0004000400040004ULL, 0x0004000400040004ULL, },
+ { 0x0004000400040004ULL, 0x0004000400040004ULL, },
+ { 0x0004000400040004ULL, 0x0004000400040004ULL, },
+ { 0x0004000400040004ULL, 0x0004000400040004ULL, },
+ { 0x0004000400040004ULL, 0x0004000400040004ULL, },
+ { 0x0004000400040004ULL, 0x0004000400040004ULL, },
+ { 0x555a555a555a555aULL, 0x555a555a555a555aULL, }, /* 16 */
+ { 0x555a555a555a555aULL, 0x555a555a555a555aULL, },
+ { 0x8e3e8e3e8e3e8e3eULL, 0x8e3e8e3e8e3e8e3eULL, },
+ { 0xaab0aab0aab0aab0ULL, 0xaab0aab0aab0aab0ULL, },
+ { 0x2228222822282228ULL, 0x2228222822282228ULL, },
+ { 0x0006000600060006ULL, 0x0006000600060006ULL, },
+ { 0x685284c4a1366852ULL, 0x84c4a136685284c4ULL, },
+ { 0x555c555c555c555cULL, 0x555c555c555c555cULL, },
+ { 0x0007000700070007ULL, 0x0007000700070007ULL, }, /* 24 */
+ { 0x0007000700070007ULL, 0x0007000700070007ULL, },
+ { 0x1c791c791c791c79ULL, 0x1c791c791c791c79ULL, },
+ { 0xaab2aab2aab2aab2ULL, 0xaab2aab2aab2aab2ULL, },
+ { 0x666e666e666e666eULL, 0x666e666e666e666eULL, },
+ { 0x555d555d555d555dULL, 0x555d555d555d555dULL, },
+ { 0x098397bc25f50983ULL, 0x97bc25f5098397bcULL, },
+ { 0x0008000800080008ULL, 0x0008000800080008ULL, },
+ { 0x333c333c333c333cULL, 0x333c333c333c333cULL, }, /* 32 */
+ { 0x333c333c333c333cULL, 0x333c333c333c333cULL, },
+ { 0xaab4aab4aab4aab4ULL, 0xaab4aab4aab4aab4ULL, },
+ { 0x6670667066706670ULL, 0x6670667066706670ULL, },
+ { 0x2900290029002900ULL, 0x2900290029002900ULL, },
+ { 0x99a499a499a499a4ULL, 0x99a499a499a499a4ULL, },
+ { 0x16ccd2888e4416ccULL, 0xd2888e4416ccd288ULL, },
+ { 0xccd8ccd8ccd8ccd8ULL, 0xccd8ccd8ccd8ccd8ULL, },
+ { 0x99a599a599a599a5ULL, 0x99a599a599a599a5ULL, }, /* 40 */
+ { 0x99a599a599a599a5ULL, 0x99a599a599a599a5ULL, },
+ { 0x7783778377837783ULL, 0x7783778377837783ULL, },
+ { 0x6672667266726672ULL, 0x6672667266726672ULL, },
+ { 0xd716d716d716d716ULL, 0xd716d716d716d716ULL, },
+ { 0x333f333f333f333fULL, 0x333f333f333f333fULL, },
+ { 0xd289c178b067d289ULL, 0xc178b067d289c178ULL, },
+ { 0x000c000c000c000cULL, 0x000c000c000c000cULL, },
+ { 0x1c7ec72971d41c7eULL, 0xc72971d41c7ec729ULL, }, /* 48 */
+ { 0x1c7ec72971d41c7eULL, 0xc72971d41c7ec729ULL, },
+ { 0x84ca4be7130484caULL, 0x4be7130484ca4be7ULL, },
+ { 0x38f08e46e39c38f0ULL, 0x8e46e39c38f08e46ULL, },
+ { 0xb618c72ad83cb618ULL, 0xc72ad83cb618c72aULL, },
+ { 0x5562556355645562ULL, 0x5563556455625563ULL, },
+ { 0x78266eac81a47826ULL, 0x6eac81a478266eacULL, },
+ { 0x71d41c80c72c71d4ULL, 0x1c80c72c71d41c80ULL, },
+ { 0x5563556455655563ULL, 0x5564556555635564ULL, }, /* 56 */
+ { 0x5563556455655563ULL, 0x5564556555635564ULL, },
+ { 0x426d25fc098b426dULL, 0x25fc098b426d25fcULL, },
+ { 0x38f28e48e39e38f2ULL, 0x8e48e39e38f28e48ULL, },
+ { 0xeefe88982232eefeULL, 0x88982232eefe8898ULL, },
+ { 0x1c81c72c71d71c81ULL, 0xc72c71d71c81c72cULL, },
+ { 0x162f7500b75f162fULL, 0x7500b75f162f7500ULL, },
+ { 0x0010001000100010ULL, 0x0010001000100010ULL, },
+ { 0xcbf432a0c5949010ULL, 0x838136944f2980a0ULL, }, /* 64 */
+ { 0xf8a073846fdafa10ULL, 0x81e20820066ea470ULL, },
+ { 0x25e45efce9185a10ULL, 0xd1ca0ec2ee172160ULL, },
+ { 0x9e9a52589fdad390ULL, 0x88c19612bccdc0e0ULL, },
+ { 0xcb46933c4a203d90ULL, 0x8722679e7412e4b0ULL, },
+ { 0xec4ab9850c89add0ULL, 0x31736642d9934cc0ULL, },
+ { 0x15164543016689d0ULL, 0xd2dbe12880283470ULL, },
+ { 0xe4b8e50ad4893e40ULL, 0xb8628f18916689f0ULL, },
+ { 0x11fcd0824dc79e40ULL, 0x084a95ba790f06e0ULL, }, /* 72 */
+ { 0x3ac85c4042a47a40ULL, 0xa9b210a01fa4ee90ULL, },
+ { 0x4a6ce5241805ba40ULL, 0x2ff282a198ddb820ULL, },
+ { 0xda320a46aaa43b40ULL, 0xaa4ae1c91cf38ca0ULL, },
+ { 0x52e8fda26166b4c0ULL, 0x61416919eba92c20ULL, },
+ { 0x228a9d6934896930ULL, 0x46c81709fce781a0ULL, },
+ { 0xb250c28bc728ea30ULL, 0xc120763180fd5620ULL, },
+ { 0xeab115b4cc89b9f4ULL, 0x1e01ac71b6013a20ULL, },
+ { 0x1ffb192480fb3af4ULL, 0x7b68d8ef267cf3a0ULL, }, /* 80 */
+ { 0xf545d210101cbe94ULL, 0xdcc07635cb000520ULL, },
+ { 0x8b8730b052c06494ULL, 0x5ec03300e4000ba0ULL, },
+ { 0xaa30f5a0a980b1acULL, 0x51803b00ac008fa0ULL, },
+ { 0xa21071208c8038acULL, 0x9c00e50050004b20ULL, },
+ { 0x99f03080ba00b20cULL, 0x2000270000007ea0ULL, },
+ { 0xf850658020003c0cULL, 0x2000000000008320ULL, },
+ { 0x9900ed0040001fb4ULL, 0x400000000000b720ULL, },
+ { 0xf300c900c000d0b4ULL, 0x0000000000004ca0ULL, }, /* 88 */
+ { 0x4d00840000004254ULL, 0x000000000000fa20ULL, },
+ { 0x5f002c0000000854ULL, 0x00000000000024a0ULL, },
+ { 0xb00068000000b9ecULL, 0x00000000000048a0ULL, },
+ { 0x90004800000090ecULL, 0x000000000000b020ULL, },
+ { 0x7000200000008c4cULL, 0x0000000000004fa0ULL, },
+ { 0xd00060000000f64cULL, 0x000000000000a820ULL, },
+ { 0x0000400000001974ULL, 0x000000000000fc20ULL, },
+ { 0x000040000000fa74ULL, 0x000000000000cda0ULL, }, /* 96 */
+ { 0x0000400000001b74ULL, 0x0000000000007120ULL, },
+ { 0x0000400000007c74ULL, 0x000000000000bea0ULL, },
+ { 0x0000400000001d74ULL, 0x000000000000ae20ULL, },
+ { 0x0000000000003514ULL, 0x00000000000055a0ULL, },
+ { 0x00000000000069b4ULL, 0x000000000000df20ULL, },
+ { 0x000000000000a354ULL, 0x000000000000c2a0ULL, },
+ { 0x00000000000009f4ULL, 0x0000000000009820ULL, },
+ { 0x0000000000007ff4ULL, 0x0000000000001aa0ULL, }, /* 104 */
+ { 0x000000000000f5f4ULL, 0x0000000000004f20ULL, },
+ { 0x0000000000006bf4ULL, 0x0000000000001da0ULL, },
+ { 0x000000000000e1f4ULL, 0x0000000000008e20ULL, },
+ { 0x000000000000224cULL, 0x000000000000a220ULL, },
+ { 0x000000000000ad74ULL, 0x0000000000003620ULL, },
+ { 0x000000000000eeccULL, 0x0000000000004a20ULL, },
+ { 0x000000000000c8f4ULL, 0x000000000000de20ULL, },
};
reset_msa_registers();
uint64_t b128_result[TEST_COUNT_TOTAL][2];
uint64_t b128_expect[TEST_COUNT_TOTAL][2] = {
- { 0x0000000000000002ULL, 0x0000000000000002ULL, }, /* 0 */
- { 0x0000000000000002ULL, 0x0000000000000002ULL, },
- { 0x00000000aaaaaaaeULL, 0x00000000aaaaaaaeULL, },
- { 0x0000000000000004ULL, 0x0000000000000004ULL, },
- { 0x000000006666666cULL, 0x000000006666666cULL, },
- { 0x0000000000000006ULL, 0x0000000000000006ULL, },
- { 0x000000008e38e395ULL, 0xffffffffe38e38ebULL, },
- { 0x0000000000000008ULL, 0x0000000000000008ULL, },
- { 0x0000000000000008ULL, 0x0000000000000008ULL, }, /* 8 */
- { 0x0000000000000008ULL, 0x0000000000000008ULL, },
- { 0x0000000000000008ULL, 0x0000000000000008ULL, },
- { 0x0000000000000008ULL, 0x0000000000000008ULL, },
- { 0x0000000000000008ULL, 0x0000000000000008ULL, },
- { 0x0000000000000008ULL, 0x0000000000000008ULL, },
- { 0x0000000000000008ULL, 0x0000000000000008ULL, },
- { 0x0000000000000008ULL, 0x0000000000000008ULL, },
- { 0x00000000aaaaaab4ULL, 0x00000000aaaaaab4ULL, }, /* 16 */
- { 0x00000000aaaaaab4ULL, 0x00000000aaaaaab4ULL, },
- { 0x38e38e3a71c71c7cULL, 0x38e38e3a71c71c7cULL, },
- { 0x0000000155555560ULL, 0x0000000155555560ULL, },
- { 0x2222222444444450ULL, 0x2222222444444450ULL, },
- { 0x000000020000000cULL, 0x000000020000000cULL, },
- { 0x2f684bdcb425ed16ULL, 0xf684bda397b425faULL, },
- { 0x00000002aaaaaab8ULL, 0x00000002aaaaaab8ULL, },
- { 0x000000020000000eULL, 0x000000020000000eULL, }, /* 24 */
- { 0x000000020000000eULL, 0x000000020000000eULL, },
- { 0xc71c71c8e38e38f2ULL, 0xc71c71c8e38e38f2ULL, },
- { 0x0000000155555564ULL, 0x0000000155555564ULL, },
- { 0xdddddddeccccccdcULL, 0xdddddddeccccccdcULL, },
- { 0x00000000aaaaaabaULL, 0x00000000aaaaaabaULL, },
- { 0xd097b42684bda13fULL, 0x097b425ef684bdb1ULL, },
- { 0x0000000000000010ULL, 0x0000000000000010ULL, },
- { 0x0000000066666678ULL, 0x0000000066666678ULL, }, /* 32 */
- { 0x0000000066666678ULL, 0x0000000066666678ULL, },
- { 0x2222222355555568ULL, 0x2222222355555568ULL, },
- { 0x00000000cccccce0ULL, 0x00000000cccccce0ULL, },
- { 0x147ae1491eb85200ULL, 0x147ae1491eb85200ULL, },
- { 0x0000000133333348ULL, 0x0000000133333348ULL, },
- { 0x1c71c71e3e93e954ULL, 0xfa4fa4fbb60b60ccULL, },
- { 0x00000001999999b0ULL, 0x00000001999999b0ULL, },
- { 0x000000013333334aULL, 0x000000013333334aULL, }, /* 40 */
- { 0x000000013333334aULL, 0x000000013333334aULL, },
- { 0xdddddddeeeeeef06ULL, 0xdddddddeeeeeef06ULL, },
- { 0x00000000cccccce4ULL, 0x00000000cccccce4ULL, },
- { 0xeb851eb8e147ae2cULL, 0xeb851eb8e147ae2cULL, },
- { 0x000000006666667eULL, 0x000000006666667eULL, },
- { 0xe38e38e3e93e9401ULL, 0x05b05b05c71c71dfULL, },
- { 0x0000000000000018ULL, 0x0000000000000018ULL, },
- { 0x000000008e38e3a7ULL, 0xffffffffe38e38fdULL, }, /* 48 */
- { 0x000000008e38e3a7ULL, 0xffffffffe38e38fdULL, },
- { 0x2f684bdb425ed0b1ULL, 0xf684bda17b425eebULL, },
- { 0x000000011c71c736ULL, 0xffffffffc71c71e2ULL, },
- { 0x1c71c71e27d27d42ULL, 0xfa4fa4fa49f49f66ULL, },
- { 0x00000001aaaaaac5ULL, 0xffffffffaaaaaac7ULL, },
- { 0x35ba781b4587e6d2ULL, 0x0fcd6e9d6b74f050ULL, },
- { 0x0000000238e38e54ULL, 0xffffffff8e38e3acULL, },
- { 0x00000001aaaaaac7ULL, 0xffffffffaaaaaac9ULL, }, /* 56 */
- { 0x00000001aaaaaac7ULL, 0xffffffffaaaaaac9ULL, },
- { 0xd097b427a12f6869ULL, 0x097b425ebda12f87ULL, },
- { 0x000000011c71c73aULL, 0xffffffffc71c71e6ULL, },
- { 0xe38e38e477777796ULL, 0x05b05b05aaaaaacaULL, },
- { 0x000000008e38e3adULL, 0xffffffffe38e3903ULL, },
- { 0xca4587e781948b2fULL, 0xf032916206522c5fULL, },
- { 0x0000000000000020ULL, 0x0000000000000020ULL, },
- { 0x3e3ad4ae1266c2b0ULL, 0x1637d725aebdb734ULL, }, /* 64 */
- { 0x4c74e0d60a3d6d94ULL, 0x1badd2dd9f4dac90ULL, },
- { 0x6874e8f94205b90cULL, 0x27eb0c41af2c3022ULL, },
- { 0x42dab657e16f25e8ULL, 0x06d6782e137656f2ULL, },
- { 0x5114c27fd945d0ccULL, 0x0c4c73e604064c4eULL, },
- { 0x68a91e898c276755ULL, 0x0f77ad378bdfb302ULL, },
- { 0x54c82cde41d1cf13ULL, 0x0b6108a5f38e1598ULL, },
- { 0x6f755d3eddd1234aULL, 0xfbbaace2f5421908ULL, },
- { 0x8b75656215996ec2ULL, 0x07f7e64705209c9aULL, }, /* 72 */
- { 0x779473b6cb43d680ULL, 0x03e141b56cceff30ULL, },
- { 0xa6279a1866fb9f64ULL, 0x2631668db9e53ac1ULL, },
- { 0x67a1f71bd99e4586ULL, 0x312ec9f6206e6e69ULL, },
- { 0x4207c47a7907b262ULL, 0x101a35e284b89539ULL, },
- { 0x5cb4f4db15070699ULL, 0x0073da1f866c98a9ULL, },
- { 0x1e2f51de87a9acbbULL, 0x0b713d87ecf5cc51ULL, },
- { 0x721d49ba5f0acfa8ULL, 0x5ba5bbe9afeae691ULL, },
- { 0x4bcd68690d995de0ULL, 0x771da6b4b6c967ebULL, }, /* 80 */
- { 0x4ea9a2cfbb5acd7bULL, 0x79dd6a73439e6387ULL, },
- { 0x47c800b999dd2371ULL, 0x766d25914ef7a7a0ULL, },
- { 0x41b0fa10eb77cf84ULL, 0x26e85189458965f8ULL, },
- { 0x1fc448ce062c2944ULL, 0x31f490a9422a80e6ULL, },
- { 0x211bdfadfd79770eULL, 0x3b25f4cac5763378ULL, },
- { 0x16fbb87edd87b6f0ULL, 0x57c0b65fabdda20eULL, },
- { 0x14621091eac4a5f6ULL, 0x4d29a25d32fa9ef6ULL, },
- { 0x07832ded1c464b02ULL, 0x6396905709e3cfa4ULL, }, /* 88 */
- { 0x0ff4a84eab8df3b9ULL, 0x6bc9a7d8c6adf2eaULL, },
- { 0x21e53326bfbd0b05ULL, 0x8f8f3b9c679dff5aULL, },
- { 0x191ed6a24e1576f9ULL, 0x9e8c2e402760373aULL, },
- { 0x19b438400fc27751ULL, 0x819c4bbfd3ee6972ULL, },
- { 0x1e0d5dc1094ae999ULL, 0x7496a289f5eff010ULL, },
- { 0x11af620b7bc03943ULL, 0x8a11f229836addc7ULL, },
- { 0x46fa45d0e84440fcULL, 0xe8d2c0211fb042bfULL, },
- { 0x22142516b5a8adbcULL, 0xe1cf1923e186aad1ULL, }, /* 96 */
- { 0x066ebbbb4ff6da44ULL, 0xd918d7e6a7e61877ULL, },
- { 0x100acc9d22839a48ULL, 0xce291932929e367fULL, },
- { 0x0dfe419d62a62f64ULL, 0xc020fe45a8cf7acfULL, },
- { 0x2ba79b6ffbf3c63bULL, 0xb428f52c49fce695ULL, },
- { 0x29b3b85200bdf100ULL, 0xb4ae7ea2f52aa5b9ULL, },
- { 0x293bb84d6360c0b6ULL, 0xae33b26e4c493c49ULL, },
- { 0x46a99fdf54f4862dULL, 0xae790dc5055f6f51ULL, },
- { 0x18480e0fd728c7c3ULL, 0xa000ad7b15f8ebe0ULL, }, /* 104 */
- { 0x1b8b97aa205e1239ULL, 0x89c78b8909c4a8e5ULL, },
- { 0x09abb26b05ef649dULL, 0x74242fa1bd49e740ULL, },
- { 0x04e233bc861d272bULL, 0x9c5343ab30f62f9fULL, },
- { 0xda2da0d0884dc3d1ULL, 0xb824f201640b4147ULL, },
- { 0x9d8b22ee1b9a2e0fULL, 0xb642ddf1edb0747fULL, },
- { 0x7c81956533686a37ULL, 0xdd5181781dc3ad37ULL, },
- { 0xc60b1905717ff25aULL, 0xe2af726e71ad7ad7ULL, },
+ { 0x0000000100000001ULL, 0x0000000100000001ULL, }, /* 0 */
+ { 0x0000000100000001ULL, 0x0000000100000001ULL, },
+ { 0x5555555755555557ULL, 0x5555555755555557ULL, },
+ { 0x0000000200000002ULL, 0x0000000200000002ULL, },
+ { 0x3333333633333336ULL, 0x3333333633333336ULL, },
+ { 0x0000000300000003ULL, 0x0000000300000003ULL, },
+ { 0x1c71c72071c71c75ULL, 0xc71c71cb1c71c720ULL, },
+ { 0x0000000400000004ULL, 0x0000000400000004ULL, },
+ { 0x0000000400000004ULL, 0x0000000400000004ULL, }, /* 8 */
+ { 0x0000000400000004ULL, 0x0000000400000004ULL, },
+ { 0x0000000400000004ULL, 0x0000000400000004ULL, },
+ { 0x0000000400000004ULL, 0x0000000400000004ULL, },
+ { 0x0000000400000004ULL, 0x0000000400000004ULL, },
+ { 0x0000000400000004ULL, 0x0000000400000004ULL, },
+ { 0x0000000400000004ULL, 0x0000000400000004ULL, },
+ { 0x0000000400000004ULL, 0x0000000400000004ULL, },
+ { 0x5555555a5555555aULL, 0x5555555a5555555aULL, }, /* 16 */
+ { 0x5555555a5555555aULL, 0x5555555a5555555aULL, },
+ { 0x38e38e3e38e38e3eULL, 0x38e38e3e38e38e3eULL, },
+ { 0xaaaaaab0aaaaaab0ULL, 0xaaaaaab0aaaaaab0ULL, },
+ { 0x2222222822222228ULL, 0x2222222822222228ULL, },
+ { 0x0000000600000006ULL, 0x0000000600000006ULL, },
+ { 0x12f684c4a12f6852ULL, 0x84bda13612f684c4ULL, },
+ { 0x5555555c5555555cULL, 0x5555555c5555555cULL, },
+ { 0x0000000700000007ULL, 0x0000000700000007ULL, }, /* 24 */
+ { 0x0000000700000007ULL, 0x0000000700000007ULL, },
+ { 0x71c71c7971c71c79ULL, 0x71c71c7971c71c79ULL, },
+ { 0xaaaaaab2aaaaaab2ULL, 0xaaaaaab2aaaaaab2ULL, },
+ { 0x6666666e6666666eULL, 0x6666666e6666666eULL, },
+ { 0x5555555d5555555dULL, 0x5555555d5555555dULL, },
+ { 0x5ed097bc25ed0983ULL, 0x97b425f55ed097bcULL, },
+ { 0x0000000800000008ULL, 0x0000000800000008ULL, },
+ { 0x3333333c3333333cULL, 0x3333333c3333333cULL, }, /* 32 */
+ { 0x3333333c3333333cULL, 0x3333333c3333333cULL, },
+ { 0xaaaaaab4aaaaaab4ULL, 0xaaaaaab4aaaaaab4ULL, },
+ { 0x6666667066666670ULL, 0x6666667066666670ULL, },
+ { 0x8f5c29008f5c2900ULL, 0x8f5c29008f5c2900ULL, },
+ { 0x999999a4999999a4ULL, 0x999999a4999999a4ULL, },
+ { 0x7d27d288c16c16ccULL, 0x38e38e447d27d288ULL, },
+ { 0xccccccd8ccccccd8ULL, 0xccccccd8ccccccd8ULL, },
+ { 0x999999a5999999a5ULL, 0x999999a5999999a5ULL, }, /* 40 */
+ { 0x999999a5999999a5ULL, 0x999999a5999999a5ULL, },
+ { 0x7777778377777783ULL, 0x7777778377777783ULL, },
+ { 0x6666667266666672ULL, 0x6666667266666672ULL, },
+ { 0x70a3d71670a3d716ULL, 0x70a3d71670a3d716ULL, },
+ { 0x3333333f3333333fULL, 0x3333333f3333333fULL, },
+ { 0x6c16c1787d27d289ULL, 0x5b05b0676c16c178ULL, },
+ { 0x0000000c0000000cULL, 0x0000000c0000000cULL, },
+ { 0x1c71c72971c71c7eULL, 0xc71c71d41c71c729ULL, }, /* 48 */
+ { 0x1c71c72971c71c7eULL, 0xc71c71d41c71c729ULL, },
+ { 0x2f684be712f684caULL, 0x4bda13042f684be7ULL, },
+ { 0x38e38e46e38e38f0ULL, 0x8e38e39c38e38e46ULL, },
+ { 0x1c71c72a0b60b618ULL, 0x2d82d83c1c71c72aULL, },
+ { 0x5555556355555562ULL, 0x5555556455555563ULL, },
+ { 0x0fcd6eac35ba7826ULL, 0x5ba781a40fcd6eacULL, },
+ { 0x71c71c80c71c71d4ULL, 0x1c71c72c71c71c80ULL, },
+ { 0x5555556455555563ULL, 0x5555556555555564ULL, }, /* 56 */
+ { 0x5555556455555563ULL, 0x5555556555555564ULL, },
+ { 0x97b425fc097b426dULL, 0x25ed098b97b425fcULL, },
+ { 0x38e38e48e38e38f2ULL, 0x8e38e39e38e38e48ULL, },
+ { 0x88888898eeeeeefeULL, 0x2222223288888898ULL, },
+ { 0x1c71c72c71c71c81ULL, 0xc71c71d71c71c72cULL, },
+ { 0x7e6b75000329162fULL, 0x87e6b75f7e6b7500ULL, },
+ { 0x0000001000000010ULL, 0x0000001000000010ULL, },
+ { 0xb10332a061639010ULL, 0x3a253694749880a0ULL, }, /* 64 */
+ { 0xc1c27384487afa10ULL, 0xbb9c0820e3b1a470ULL, },
+ { 0x35565efc0caf5a10ULL, 0x735b0ec23bd12160ULL, },
+ { 0xe6475258fb27d390ULL, 0x49d49612c9a1c0e0ULL, },
+ { 0xf706933ce23f3d90ULL, 0xcb4b679e38bae4b0ULL, },
+ { 0xabfab985e02cadd0ULL, 0x0836664283a94cc0ULL, },
+ { 0xa33845439e9989d0ULL, 0x5b9fe12897ee3470ULL, },
+ { 0x1df3e50abfdd3e40ULL, 0x6d858f1887bc89f0ULL, },
+ { 0x9187d08284119e40ULL, 0x254495badfdc06e0ULL, }, /* 72 */
+ { 0x88c55c40427e7a40ULL, 0x78ae10a0f420ee90ULL, },
+ { 0x3f78e5242782ba40ULL, 0x93ad82a12637b820ULL, },
+ { 0x28380a46b1663b40ULL, 0x255be1c9fb128ca0ULL, },
+ { 0xd928fda29fdeb4c0ULL, 0xfbd5691988e32c20ULL, },
+ { 0x53e49d69c1226930ULL, 0x0dbb170978b181a0ULL, },
+ { 0x3ca3c28b4b05ea30ULL, 0x9f6976314d8c5620ULL, },
+ { 0x621b15b4fcefb9f4ULL, 0x7f3fac7130ab3a20ULL, },
+ { 0x81b8192421043af4ULL, 0x7180d8efde07f3a0ULL, }, /* 80 */
+ { 0xa0a1d210b115be94ULL, 0x33a676350e450520ULL, },
+ { 0xe27e30b0181b6494ULL, 0x359b330061c70ba0ULL, },
+ { 0xe0f1f5a03792b1acULL, 0xe6a63b00d5b18fa0ULL, },
+ { 0x38af7120b51538acULL, 0x7938e500aea24b20ULL, },
+ { 0x7a4830802390b20cULL, 0x4b472700af547ea0ULL, },
+ { 0xcc2f6580204a3c0cULL, 0x37510000bd1b8320ULL, },
+ { 0x9ba9ed0066371fb4ULL, 0xeba90000264fb720ULL, },
+ { 0x7400c900846dd0b4ULL, 0xb6b700007c524ca0ULL, }, /* 88 */
+ { 0x7e4e840000744254ULL, 0xf24d00003540fa20ULL, },
+ { 0x242a2c00b0850854ULL, 0xdb00000025db24a0ULL, },
+ { 0x38a168005a7bb9ecULL, 0xa3000000566748a0ULL, },
+ { 0x6cb048001a7d90ecULL, 0x7d0000000a0cb020ULL, },
+ { 0xe4dc2000bd958c4cULL, 0x2f000000f6d44fa0ULL, },
+ { 0xbcc9600018fcf64cULL, 0x000000002ecca820ULL, },
+ { 0x739b4000140b1974ULL, 0x000000009361fc20ULL, },
+ { 0x8ed24000a4acfa74ULL, 0x00000000bcafcda0ULL, }, /* 96 */
+ { 0xc3dd40003f7c1b74ULL, 0x00000000fe2b7120ULL, },
+ { 0x1fac4000f6087c74ULL, 0x00000000e05abea0ULL, },
+ { 0x9e6f40000de21d74ULL, 0x000000001e89ae20ULL, },
+ { 0x637500000f743514ULL, 0x00000000c1b755a0ULL, },
+ { 0xd9b400005ed469b4ULL, 0x000000005dfcdf20ULL, },
+ { 0x0a50000049fea354ULL, 0x000000006b40c2a0ULL, },
+ { 0x07400000982609f4ULL, 0x00000000c2b79820ULL, },
+ { 0x57c00000b2de7ff4ULL, 0x000000006f6c1aa0ULL, }, /* 104 */
+ { 0x1d400000bbe3f5f4ULL, 0x000000001c974f20ULL, },
+ { 0x09c00000a8b66bf4ULL, 0x00000000e1391da0ULL, },
+ { 0x03400000aed5e1f4ULL, 0x0000000094d78e20ULL, },
+ { 0x7d8000009d2e224cULL, 0x00000000ab48a220ULL, },
+ { 0x3d000000b40fad74ULL, 0x00000000c40e3620ULL, },
+ { 0x96000000332aeeccULL, 0x00000000ecf84a20ULL, },
+ { 0xb40000004e1bc8f4ULL, 0x0000000075d6de20ULL, },
};
reset_msa_registers();
uint64_t b128_result[TEST_COUNT_TOTAL][2];
uint64_t b128_expect[TEST_COUNT_TOTAL][2] = {
- { 0x0000000000000002ULL, 0x0000000000000002ULL, }, /* 0 */
- { 0x0000000000000002ULL, 0x0000000000000002ULL, },
- { 0x00000000aaaaaaaeULL, 0x00000000aaaaaaaeULL, },
- { 0x0000000000000004ULL, 0x0000000000000004ULL, },
- { 0x000000006666666cULL, 0x000000006666666cULL, },
- { 0x0000000000000006ULL, 0x0000000000000006ULL, },
- { 0x000000008e38e395ULL, 0xffffffffe38e38ebULL, },
- { 0x0000000000000008ULL, 0x0000000000000008ULL, },
- { 0x0000000000000008ULL, 0x0000000000000008ULL, }, /* 8 */
- { 0x0000000000000008ULL, 0x0000000000000008ULL, },
- { 0x0000000000000008ULL, 0x0000000000000008ULL, },
- { 0x0000000000000008ULL, 0x0000000000000008ULL, },
- { 0x0000000000000008ULL, 0x0000000000000008ULL, },
- { 0x0000000000000008ULL, 0x0000000000000008ULL, },
- { 0x0000000000000008ULL, 0x0000000000000008ULL, },
- { 0x0000000000000008ULL, 0x0000000000000008ULL, },
- { 0x00000000aaaaaab4ULL, 0x00000000aaaaaab4ULL, }, /* 16 */
- { 0x00000000aaaaaab4ULL, 0x00000000aaaaaab4ULL, },
- { 0x38e38e3a71c71c7cULL, 0x38e38e3a71c71c7cULL, },
- { 0x0000000155555560ULL, 0x0000000155555560ULL, },
- { 0x2222222444444450ULL, 0x2222222444444450ULL, },
- { 0x000000020000000cULL, 0x000000020000000cULL, },
- { 0x2f684bdcb425ed16ULL, 0xf684bda397b425faULL, },
- { 0x00000002aaaaaab8ULL, 0x00000002aaaaaab8ULL, },
- { 0x000000020000000eULL, 0x000000020000000eULL, }, /* 24 */
- { 0x000000020000000eULL, 0x000000020000000eULL, },
- { 0xc71c71c8e38e38f2ULL, 0xc71c71c8e38e38f2ULL, },
- { 0x0000000155555564ULL, 0x0000000155555564ULL, },
- { 0xdddddddeccccccdcULL, 0xdddddddeccccccdcULL, },
- { 0x00000000aaaaaabaULL, 0x00000000aaaaaabaULL, },
- { 0xd097b42684bda13fULL, 0x097b425ef684bdb1ULL, },
- { 0x0000000000000010ULL, 0x0000000000000010ULL, },
- { 0x0000000066666678ULL, 0x0000000066666678ULL, }, /* 32 */
- { 0x0000000066666678ULL, 0x0000000066666678ULL, },
- { 0x2222222355555568ULL, 0x2222222355555568ULL, },
- { 0x00000000cccccce0ULL, 0x00000000cccccce0ULL, },
- { 0x147ae1491eb85200ULL, 0x147ae1491eb85200ULL, },
- { 0x0000000133333348ULL, 0x0000000133333348ULL, },
- { 0x1c71c71e3e93e954ULL, 0xfa4fa4fbb60b60ccULL, },
- { 0x00000001999999b0ULL, 0x00000001999999b0ULL, },
- { 0x000000013333334aULL, 0x000000013333334aULL, }, /* 40 */
- { 0x000000013333334aULL, 0x000000013333334aULL, },
- { 0xdddddddeeeeeef06ULL, 0xdddddddeeeeeef06ULL, },
- { 0x00000000cccccce4ULL, 0x00000000cccccce4ULL, },
- { 0xeb851eb8e147ae2cULL, 0xeb851eb8e147ae2cULL, },
- { 0x000000006666667eULL, 0x000000006666667eULL, },
- { 0xe38e38e3e93e9401ULL, 0x05b05b05c71c71dfULL, },
- { 0x0000000000000018ULL, 0x0000000000000018ULL, },
- { 0x000000008e38e3a7ULL, 0xffffffffe38e38fdULL, }, /* 48 */
- { 0x000000008e38e3a7ULL, 0xffffffffe38e38fdULL, },
- { 0x2f684bdb425ed0b1ULL, 0xf684bda17b425eebULL, },
- { 0x000000011c71c736ULL, 0xffffffffc71c71e2ULL, },
- { 0x1c71c71e27d27d42ULL, 0xfa4fa4fa49f49f66ULL, },
- { 0x00000001aaaaaac5ULL, 0xffffffffaaaaaac7ULL, },
- { 0x35ba781b4587e6d2ULL, 0x0fcd6e9d6b74f050ULL, },
- { 0x0000000238e38e54ULL, 0xffffffff8e38e3acULL, },
- { 0x00000001aaaaaac7ULL, 0xffffffffaaaaaac9ULL, }, /* 56 */
- { 0x00000001aaaaaac7ULL, 0xffffffffaaaaaac9ULL, },
- { 0xd097b427a12f6869ULL, 0x097b425ebda12f87ULL, },
- { 0x000000011c71c73aULL, 0xffffffffc71c71e6ULL, },
- { 0xe38e38e477777796ULL, 0x05b05b05aaaaaacaULL, },
- { 0x000000008e38e3adULL, 0xffffffffe38e3903ULL, },
- { 0xca4587e781948b2fULL, 0xf032916206522c5fULL, },
- { 0x0000000000000020ULL, 0x0000000000000020ULL, },
- { 0x3e3ad4ae1266c2b0ULL, 0x1637d725aebdb734ULL, }, /* 64 */
- { 0x4c74e0d60a3d6d94ULL, 0x1badd2dd9f4dac90ULL, },
- { 0x6874e8f94205b90cULL, 0x27eb0c41af2c3022ULL, },
- { 0x42dab657e16f25e8ULL, 0x06d6782e137656f2ULL, },
- { 0x5114c27fd945d0ccULL, 0x0c4c73e604064c4eULL, },
- { 0x68a91e898c276755ULL, 0x0f77ad378bdfb302ULL, },
- { 0x54c82cde41d1cf13ULL, 0x0b6108a5f38e1598ULL, },
- { 0x6f755d3eddd1234aULL, 0xfbbaace2f5421908ULL, },
- { 0x8b75656215996ec2ULL, 0x07f7e64705209c9aULL, }, /* 72 */
- { 0x779473b6cb43d680ULL, 0x03e141b56cceff30ULL, },
- { 0xa6279a1866fb9f64ULL, 0x2631668db9e53ac1ULL, },
- { 0x67a1f71bd99e4586ULL, 0x312ec9f6206e6e69ULL, },
- { 0x4207c47a7907b262ULL, 0x101a35e284b89539ULL, },
- { 0x5cb4f4db15070699ULL, 0x0073da1f866c98a9ULL, },
- { 0x1e2f51de87a9acbbULL, 0x0b713d87ecf5cc51ULL, },
- { 0x721d49ba5f0acfa8ULL, 0x5ba5bbe9afeae691ULL, },
- { 0x4bcd68690d995de0ULL, 0x771da6b4b6c967ebULL, }, /* 80 */
- { 0x4ea9a2cfbb5acd7bULL, 0x79dd6a73439e6387ULL, },
- { 0x47c800b999dd2371ULL, 0x766d25914ef7a7a0ULL, },
- { 0x41b0fa10eb77cf84ULL, 0x26e85189458965f8ULL, },
- { 0x1fc448ce062c2944ULL, 0x31f490a9422a80e6ULL, },
- { 0x211bdfadfd79770eULL, 0x3b25f4cac5763378ULL, },
- { 0x16fbb87edd87b6f0ULL, 0x57c0b65fabdda20eULL, },
- { 0x14621091eac4a5f6ULL, 0x4d29a25d32fa9ef6ULL, },
- { 0x07832ded1c464b02ULL, 0x6396905709e3cfa4ULL, }, /* 88 */
- { 0x0ff4a84eab8df3b9ULL, 0x6bc9a7d8c6adf2eaULL, },
- { 0x21e53326bfbd0b05ULL, 0x8f8f3b9c679dff5aULL, },
- { 0x191ed6a24e1576f9ULL, 0x9e8c2e402760373aULL, },
- { 0x19b438400fc27751ULL, 0x819c4bbfd3ee6972ULL, },
- { 0x1e0d5dc1094ae999ULL, 0x7496a289f5eff010ULL, },
- { 0x11af620b7bc03943ULL, 0x8a11f229836addc7ULL, },
- { 0x46fa45d0e84440fcULL, 0xe8d2c0211fb042bfULL, },
- { 0x22142516b5a8adbcULL, 0xe1cf1923e186aad1ULL, }, /* 96 */
- { 0x066ebbbb4ff6da44ULL, 0xd918d7e6a7e61877ULL, },
- { 0x100acc9d22839a48ULL, 0xce291932929e367fULL, },
- { 0x0dfe419d62a62f64ULL, 0xc020fe45a8cf7acfULL, },
- { 0x2ba79b6ffbf3c63bULL, 0xb428f52c49fce695ULL, },
- { 0x29b3b85200bdf100ULL, 0xb4ae7ea2f52aa5b9ULL, },
- { 0x293bb84d6360c0b6ULL, 0xae33b26e4c493c49ULL, },
- { 0x46a99fdf54f4862dULL, 0xae790dc5055f6f51ULL, },
- { 0x18480e0fd728c7c3ULL, 0xa000ad7b15f8ebe0ULL, }, /* 104 */
- { 0x1b8b97aa205e1239ULL, 0x89c78b8909c4a8e5ULL, },
- { 0x09abb26b05ef649dULL, 0x74242fa1bd49e740ULL, },
- { 0x04e233bc861d272bULL, 0x9c5343ab30f62f9fULL, },
- { 0xda2da0d0884dc3d1ULL, 0xb824f201640b4147ULL, },
- { 0x9d8b22ee1b9a2e0fULL, 0xb642ddf1edb0747fULL, },
- { 0x7c81956533686a37ULL, 0xdd5181781dc3ad37ULL, },
- { 0xc60b1905717ff25aULL, 0xe2af726e71ad7ad7ULL, },
+ { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 0 */
+ { 0xffffffffffffffffULL, 0xffffffffffffffffULL, },
+ { 0xa9a9a9a9a9a9a9a9ULL, 0xa9a9a9a9a9a9a9a9ULL, },
+ { 0xfefefefefefefefeULL, 0xfefefefefefefefeULL, },
+ { 0xcacacacacacacacaULL, 0xcacacacacacacacaULL, },
+ { 0xfdfdfdfdfdfdfdfdULL, 0xfdfdfdfdfdfdfdfdULL, },
+ { 0xe08b35e08b35e08bULL, 0x35e08b35e08b35e0ULL, },
+ { 0xfcfcfcfcfcfcfcfcULL, 0xfcfcfcfcfcfcfcfcULL, },
+ { 0xfcfcfcfcfcfcfcfcULL, 0xfcfcfcfcfcfcfcfcULL, }, /* 8 */
+ { 0xfcfcfcfcfcfcfcfcULL, 0xfcfcfcfcfcfcfcfcULL, },
+ { 0xfcfcfcfcfcfcfcfcULL, 0xfcfcfcfcfcfcfcfcULL, },
+ { 0xfcfcfcfcfcfcfcfcULL, 0xfcfcfcfcfcfcfcfcULL, },
+ { 0xfcfcfcfcfcfcfcfcULL, 0xfcfcfcfcfcfcfcfcULL, },
+ { 0xfcfcfcfcfcfcfcfcULL, 0xfcfcfcfcfcfcfcfcULL, },
+ { 0xfcfcfcfcfcfcfcfcULL, 0xfcfcfcfcfcfcfcfcULL, },
+ { 0xfcfcfcfcfcfcfcfcULL, 0xfcfcfcfcfcfcfcfcULL, },
+ { 0xa6a6a6a6a6a6a6a6ULL, 0xa6a6a6a6a6a6a6a6ULL, }, /* 16 */
+ { 0xa6a6a6a6a6a6a6a6ULL, 0xa6a6a6a6a6a6a6a6ULL, },
+ { 0xc2c2c2c2c2c2c2c2ULL, 0xc2c2c2c2c2c2c2c2ULL, },
+ { 0x5050505050505050ULL, 0x5050505050505050ULL, },
+ { 0xd8d8d8d8d8d8d8d8ULL, 0xd8d8d8d8d8d8d8d8ULL, },
+ { 0xfafafafafafafafaULL, 0xfafafafafafafafaULL, },
+ { 0x3caeca3caeca3caeULL, 0xca3caeca3caeca3cULL, },
+ { 0xa4a4a4a4a4a4a4a4ULL, 0xa4a4a4a4a4a4a4a4ULL, },
+ { 0xf9f9f9f9f9f9f9f9ULL, 0xf9f9f9f9f9f9f9f9ULL, }, /* 24 */
+ { 0xf9f9f9f9f9f9f9f9ULL, 0xf9f9f9f9f9f9f9f9ULL, },
+ { 0x8787878787878787ULL, 0x8787878787878787ULL, },
+ { 0x4e4e4e4e4e4e4e4eULL, 0x4e4e4e4e4e4e4e4eULL, },
+ { 0x9292929292929292ULL, 0x9292929292929292ULL, },
+ { 0xa3a3a3a3a3a3a3a3ULL, 0xa3a3a3a3a3a3a3a3ULL, },
+ { 0x447d0b447d0b447dULL, 0x0b447d0b447d0b44ULL, },
+ { 0xf8f8f8f8f8f8f8f8ULL, 0xf8f8f8f8f8f8f8f8ULL, },
+ { 0xc4c4c4c4c4c4c4c4ULL, 0xc4c4c4c4c4c4c4c4ULL, }, /* 32 */
+ { 0xc4c4c4c4c4c4c4c4ULL, 0xc4c4c4c4c4c4c4c4ULL, },
+ { 0x4c4c4c4c4c4c4c4cULL, 0x4c4c4c4c4c4c4c4cULL, },
+ { 0x9090909090909090ULL, 0x9090909090909090ULL, },
+ { 0x0000000000000000ULL, 0x0000000000000000ULL, },
+ { 0x5c5c5c5c5c5c5c5cULL, 0x5c5c5c5c5c5c5c5cULL, },
+ { 0x7834bc7834bc7834ULL, 0xbc7834bc7834bc78ULL, },
+ { 0x2828282828282828ULL, 0x2828282828282828ULL, },
+ { 0x5b5b5b5b5b5b5b5bULL, 0x5b5b5b5b5b5b5b5bULL, }, /* 40 */
+ { 0x5b5b5b5b5b5b5b5bULL, 0x5b5b5b5b5b5b5b5bULL, },
+ { 0x7d7d7d7d7d7d7d7dULL, 0x7d7d7d7d7d7d7d7dULL, },
+ { 0x8e8e8e8e8e8e8e8eULL, 0x8e8e8e8e8e8e8e8eULL, },
+ { 0xeaeaeaeaeaeaeaeaULL, 0xeaeaeaeaeaeaeaeaULL, },
+ { 0xc1c1c1c1c1c1c1c1ULL, 0xc1c1c1c1c1c1c1c1ULL, },
+ { 0x8877998877998877ULL, 0x9988779988779988ULL, },
+ { 0xf4f4f4f4f4f4f4f4ULL, 0xf4f4f4f4f4f4f4f4ULL, },
+ { 0xd7822cd7822cd782ULL, 0x2cd7822cd7822cd7ULL, }, /* 48 */
+ { 0xd7822cd7822cd782ULL, 0x2cd7822cd7822cd7ULL, },
+ { 0x1936fc1936fc1936ULL, 0xfc1936fc1936fc19ULL, },
+ { 0xba1064ba1064ba10ULL, 0x64ba1064ba1064baULL, },
+ { 0xd6e8c4d6e8c4d6e8ULL, 0xc4d6e8c4d6e8c4d6ULL, },
+ { 0x9d9e9c9d9e9c9d9eULL, 0x9c9d9e9c9d9e9c9dULL, },
+ { 0x54da5c54da5c54daULL, 0x5c54da5c54da5c54ULL, },
+ { 0x802cd4802cd4802cULL, 0xd4802cd4802cd480ULL, },
+ { 0x9c9d9b9c9d9b9c9dULL, 0x9b9c9d9b9c9d9b9cULL, }, /* 56 */
+ { 0x9c9d9b9c9d9b9c9dULL, 0x9b9c9d9b9c9d9b9cULL, },
+ { 0x0493750493750493ULL, 0x7504937504937504ULL, },
+ { 0xb80e62b80e62b80eULL, 0x62b80e62b80e62b8ULL, },
+ { 0x6802ce6802ce6802ULL, 0xce6802ce6802ce68ULL, },
+ { 0xd47f29d47f29d47fULL, 0x29d47f29d47f29d4ULL, },
+ { 0x00d1a100d1a100d1ULL, 0xa100d1a100d1a100ULL, },
+ { 0xf0f0f0f0f0f0f0f0ULL, 0xf0f0f0f0f0f0f0f0ULL, },
+ { 0xb00c4c60b06cb7f0ULL, 0xf77f776cecd7f060ULL, }, /* 64 */
+ { 0x58604c7ca826a4f0ULL, 0xb11e6ee016929090ULL, },
+ { 0xf81cf804c0e87df0ULL, 0x4436ec3e6ce920a0ULL, },
+ { 0x786634a810267370ULL, 0xf53f14eebe33c020ULL, },
+ { 0x20ba34c408e06070ULL, 0xafde0b62e8ee6050ULL, },
+ { 0x07b6347bdf77af30ULL, 0x6b8d72be2f6d1c40ULL, },
+ { 0x63ea34bd3a9aa230ULL, 0xad25d0d828d84290ULL, },
+ { 0x934834f6f477f4c0ULL, 0xc39e78e84b9ade10ULL, },
+ { 0x3304e07e0c39cdc0ULL, 0x56b6f646a1f16e20ULL, }, /* 72 */
+ { 0x8f38e0c0675cc0c0ULL, 0x984e54609a5c9470ULL, },
+ { 0xff949cdcb6fb47c0ULL, 0xa70e305f61233be0ULL, },
+ { 0xbfcea8bac85c91c0ULL, 0x2cb600377e0d9160ULL, },
+ { 0x3f18e45e189a8740ULL, 0xddbf28e7d05731e0ULL, },
+ { 0x6f76e497d277d9d0ULL, 0xf338d0f7f319cd60ULL, },
+ { 0x2fb0f075e4d823d0ULL, 0x78e0a0cf100323e0ULL, },
+ { 0x2f4f0c4c60779f0cULL, 0xcfff608f7fff9fe0ULL, },
+ { 0x379944bc60e9d40cULL, 0x2a66400d7d7a4f60ULL, }, /* 80 */
+ { 0x4a0b4408801e08acULL, 0x36fc80bb3c7401e0ULL, },
+ { 0x922d0cb800dcb0acULL, 0xfc5c807628f8dc60ULL, },
+ { 0xb24a046000c05044ULL, 0x30c080e6c008a460ULL, },
+ { 0x22a66ce00040c044ULL, 0x208000724030e4e0ULL, },
+ { 0xcc726c4000808024ULL, 0xe00000de0060dc60ULL, },
+ { 0xbc5e04c000000024ULL, 0xc00000bc004010e0ULL, },
+ { 0x7c5cac000000002cULL, 0x0000001c00c0f0e0ULL, },
+ { 0x9c4424000000002cULL, 0x000000d40080f060ULL, }, /* 88 */
+ { 0xa8cc2400000000ccULL, 0x0000004c000010e0ULL, },
+ { 0xc814ac00000000ccULL, 0x000000980000c060ULL, },
+ { 0x48e8e400000000a4ULL, 0x0000005800004060ULL, },
+ { 0x08d80c00000000a4ULL, 0x00000008000040e0ULL, },
+ { 0x30880c0000000084ULL, 0x000000380000c060ULL, },
+ { 0xf0b8e40000000084ULL, 0x00000070000000e0ULL, },
+ { 0xf0f04c000000004cULL, 0x000000f0000000e0ULL, },
+ { 0x709004000000004cULL, 0x000000d000000060ULL, }, /* 96 */
+ { 0xf0f06c000000004cULL, 0x00000070000000e0ULL, },
+ { 0x709064000000004cULL, 0x0000005000000060ULL, },
+ { 0xf0f08c000000004cULL, 0x000000f0000000e0ULL, },
+ { 0xa0d08c00000000ecULL, 0x0000009000000060ULL, },
+ { 0xc0708c000000008cULL, 0x000000f0000000e0ULL, },
+ { 0x80508c000000002cULL, 0x0000009000000060ULL, },
+ { 0x00f08c00000000ccULL, 0x000000f0000000e0ULL, },
+ { 0x00906400000000ccULL, 0x000000e000000060ULL, }, /* 104 */
+ { 0x00f06c00000000ccULL, 0x000000c0000000e0ULL, },
+ { 0x00900400000000ccULL, 0x0000008000000060ULL, },
+ { 0x00f04c00000000ccULL, 0x00000000000000e0ULL, },
+ { 0x00e0c400000000a4ULL, 0x00000000000000e0ULL, },
+ { 0x00c0ec00000000acULL, 0x00000000000000e0ULL, },
+ { 0x0080a40000000044ULL, 0x00000000000000e0ULL, },
+ { 0x00008c000000008cULL, 0x00000000000000e0ULL, },
};
reset_msa_registers();
uint64_t b128_result[TEST_COUNT_TOTAL][2];
uint64_t b128_expect[TEST_COUNT_TOTAL][2] = {
- { 0x0000000000000002ULL, 0x0000000000000002ULL, }, /* 0 */
- { 0x0000000000000002ULL, 0x0000000000000002ULL, },
- { 0x00000000aaaaaaaeULL, 0x00000000aaaaaaaeULL, },
- { 0x0000000000000004ULL, 0x0000000000000004ULL, },
- { 0x000000006666666cULL, 0x000000006666666cULL, },
- { 0x0000000000000006ULL, 0x0000000000000006ULL, },
- { 0x000000008e38e395ULL, 0xffffffffe38e38ebULL, },
- { 0x0000000000000008ULL, 0x0000000000000008ULL, },
- { 0x0000000000000008ULL, 0x0000000000000008ULL, }, /* 8 */
- { 0x0000000000000008ULL, 0x0000000000000008ULL, },
- { 0x0000000000000008ULL, 0x0000000000000008ULL, },
- { 0x0000000000000008ULL, 0x0000000000000008ULL, },
- { 0x0000000000000008ULL, 0x0000000000000008ULL, },
- { 0x0000000000000008ULL, 0x0000000000000008ULL, },
- { 0x0000000000000008ULL, 0x0000000000000008ULL, },
- { 0x0000000000000008ULL, 0x0000000000000008ULL, },
- { 0x00000000aaaaaab4ULL, 0x00000000aaaaaab4ULL, }, /* 16 */
- { 0x00000000aaaaaab4ULL, 0x00000000aaaaaab4ULL, },
- { 0x38e38e3a71c71c7cULL, 0x38e38e3a71c71c7cULL, },
- { 0x0000000155555560ULL, 0x0000000155555560ULL, },
- { 0x2222222444444450ULL, 0x2222222444444450ULL, },
- { 0x000000020000000cULL, 0x000000020000000cULL, },
- { 0x2f684bdcb425ed16ULL, 0xf684bda397b425faULL, },
- { 0x00000002aaaaaab8ULL, 0x00000002aaaaaab8ULL, },
- { 0x000000020000000eULL, 0x000000020000000eULL, }, /* 24 */
- { 0x000000020000000eULL, 0x000000020000000eULL, },
- { 0xc71c71c8e38e38f2ULL, 0xc71c71c8e38e38f2ULL, },
- { 0x0000000155555564ULL, 0x0000000155555564ULL, },
- { 0xdddddddeccccccdcULL, 0xdddddddeccccccdcULL, },
- { 0x00000000aaaaaabaULL, 0x00000000aaaaaabaULL, },
- { 0xd097b42684bda13fULL, 0x097b425ef684bdb1ULL, },
- { 0x0000000000000010ULL, 0x0000000000000010ULL, },
- { 0x0000000066666678ULL, 0x0000000066666678ULL, }, /* 32 */
- { 0x0000000066666678ULL, 0x0000000066666678ULL, },
- { 0x2222222355555568ULL, 0x2222222355555568ULL, },
- { 0x00000000cccccce0ULL, 0x00000000cccccce0ULL, },
- { 0x147ae1491eb85200ULL, 0x147ae1491eb85200ULL, },
- { 0x0000000133333348ULL, 0x0000000133333348ULL, },
- { 0x1c71c71e3e93e954ULL, 0xfa4fa4fbb60b60ccULL, },
- { 0x00000001999999b0ULL, 0x00000001999999b0ULL, },
- { 0x000000013333334aULL, 0x000000013333334aULL, }, /* 40 */
- { 0x000000013333334aULL, 0x000000013333334aULL, },
- { 0xdddddddeeeeeef06ULL, 0xdddddddeeeeeef06ULL, },
- { 0x00000000cccccce4ULL, 0x00000000cccccce4ULL, },
- { 0xeb851eb8e147ae2cULL, 0xeb851eb8e147ae2cULL, },
- { 0x000000006666667eULL, 0x000000006666667eULL, },
- { 0xe38e38e3e93e9401ULL, 0x05b05b05c71c71dfULL, },
- { 0x0000000000000018ULL, 0x0000000000000018ULL, },
- { 0x000000008e38e3a7ULL, 0xffffffffe38e38fdULL, }, /* 48 */
- { 0x000000008e38e3a7ULL, 0xffffffffe38e38fdULL, },
- { 0x2f684bdb425ed0b1ULL, 0xf684bda17b425eebULL, },
- { 0x000000011c71c736ULL, 0xffffffffc71c71e2ULL, },
- { 0x1c71c71e27d27d42ULL, 0xfa4fa4fa49f49f66ULL, },
- { 0x00000001aaaaaac5ULL, 0xffffffffaaaaaac7ULL, },
- { 0x35ba781b4587e6d2ULL, 0x0fcd6e9d6b74f050ULL, },
- { 0x0000000238e38e54ULL, 0xffffffff8e38e3acULL, },
- { 0x00000001aaaaaac7ULL, 0xffffffffaaaaaac9ULL, }, /* 56 */
- { 0x00000001aaaaaac7ULL, 0xffffffffaaaaaac9ULL, },
- { 0xd097b427a12f6869ULL, 0x097b425ebda12f87ULL, },
- { 0x000000011c71c73aULL, 0xffffffffc71c71e6ULL, },
- { 0xe38e38e477777796ULL, 0x05b05b05aaaaaacaULL, },
- { 0x000000008e38e3adULL, 0xffffffffe38e3903ULL, },
- { 0xca4587e781948b2fULL, 0xf032916206522c5fULL, },
- { 0x0000000000000020ULL, 0x0000000000000020ULL, },
- { 0x3e3ad4ae1266c2b0ULL, 0x1637d725aebdb734ULL, }, /* 64 */
- { 0x4c74e0d60a3d6d94ULL, 0x1badd2dd9f4dac90ULL, },
- { 0x6874e8f94205b90cULL, 0x27eb0c41af2c3022ULL, },
- { 0x42dab657e16f25e8ULL, 0x06d6782e137656f2ULL, },
- { 0x5114c27fd945d0ccULL, 0x0c4c73e604064c4eULL, },
- { 0x68a91e898c276755ULL, 0x0f77ad378bdfb302ULL, },
- { 0x54c82cde41d1cf13ULL, 0x0b6108a5f38e1598ULL, },
- { 0x6f755d3eddd1234aULL, 0xfbbaace2f5421908ULL, },
- { 0x8b75656215996ec2ULL, 0x07f7e64705209c9aULL, }, /* 72 */
- { 0x779473b6cb43d680ULL, 0x03e141b56cceff30ULL, },
- { 0xa6279a1866fb9f64ULL, 0x2631668db9e53ac1ULL, },
- { 0x67a1f71bd99e4586ULL, 0x312ec9f6206e6e69ULL, },
- { 0x4207c47a7907b262ULL, 0x101a35e284b89539ULL, },
- { 0x5cb4f4db15070699ULL, 0x0073da1f866c98a9ULL, },
- { 0x1e2f51de87a9acbbULL, 0x0b713d87ecf5cc51ULL, },
- { 0x721d49ba5f0acfa8ULL, 0x5ba5bbe9afeae691ULL, },
- { 0x4bcd68690d995de0ULL, 0x771da6b4b6c967ebULL, }, /* 80 */
- { 0x4ea9a2cfbb5acd7bULL, 0x79dd6a73439e6387ULL, },
- { 0x47c800b999dd2371ULL, 0x766d25914ef7a7a0ULL, },
- { 0x41b0fa10eb77cf84ULL, 0x26e85189458965f8ULL, },
- { 0x1fc448ce062c2944ULL, 0x31f490a9422a80e6ULL, },
- { 0x211bdfadfd79770eULL, 0x3b25f4cac5763378ULL, },
- { 0x16fbb87edd87b6f0ULL, 0x57c0b65fabdda20eULL, },
- { 0x14621091eac4a5f6ULL, 0x4d29a25d32fa9ef6ULL, },
- { 0x07832ded1c464b02ULL, 0x6396905709e3cfa4ULL, }, /* 88 */
- { 0x0ff4a84eab8df3b9ULL, 0x6bc9a7d8c6adf2eaULL, },
- { 0x21e53326bfbd0b05ULL, 0x8f8f3b9c679dff5aULL, },
- { 0x191ed6a24e1576f9ULL, 0x9e8c2e402760373aULL, },
- { 0x19b438400fc27751ULL, 0x819c4bbfd3ee6972ULL, },
- { 0x1e0d5dc1094ae999ULL, 0x7496a289f5eff010ULL, },
- { 0x11af620b7bc03943ULL, 0x8a11f229836addc7ULL, },
- { 0x46fa45d0e84440fcULL, 0xe8d2c0211fb042bfULL, },
- { 0x22142516b5a8adbcULL, 0xe1cf1923e186aad1ULL, }, /* 96 */
- { 0x066ebbbb4ff6da44ULL, 0xd918d7e6a7e61877ULL, },
- { 0x100acc9d22839a48ULL, 0xce291932929e367fULL, },
- { 0x0dfe419d62a62f64ULL, 0xc020fe45a8cf7acfULL, },
- { 0x2ba79b6ffbf3c63bULL, 0xb428f52c49fce695ULL, },
- { 0x29b3b85200bdf100ULL, 0xb4ae7ea2f52aa5b9ULL, },
- { 0x293bb84d6360c0b6ULL, 0xae33b26e4c493c49ULL, },
- { 0x46a99fdf54f4862dULL, 0xae790dc5055f6f51ULL, },
- { 0x18480e0fd728c7c3ULL, 0xa000ad7b15f8ebe0ULL, }, /* 104 */
- { 0x1b8b97aa205e1239ULL, 0x89c78b8909c4a8e5ULL, },
- { 0x09abb26b05ef649dULL, 0x74242fa1bd49e740ULL, },
- { 0x04e233bc861d272bULL, 0x9c5343ab30f62f9fULL, },
- { 0xda2da0d0884dc3d1ULL, 0xb824f201640b4147ULL, },
- { 0x9d8b22ee1b9a2e0fULL, 0xb642ddf1edb0747fULL, },
- { 0x7c81956533686a37ULL, 0xdd5181781dc3ad37ULL, },
- { 0xc60b1905717ff25aULL, 0xe2af726e71ad7ad7ULL, },
+ { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 0 */
+ { 0xffffffffffffffffULL, 0xffffffffffffffffULL, },
+ { 0xaaaaaaaaaaaaaaa9ULL, 0xaaaaaaaaaaaaaaa9ULL, },
+ { 0xfffffffffffffffeULL, 0xfffffffffffffffeULL, },
+ { 0xcccccccccccccccaULL, 0xcccccccccccccccaULL, },
+ { 0xfffffffffffffffdULL, 0xfffffffffffffffdULL, },
+ { 0xe38e38e38e38e38bULL, 0x38e38e38e38e38e0ULL, },
+ { 0xfffffffffffffffcULL, 0xfffffffffffffffcULL, },
+ { 0xfffffffffffffffcULL, 0xfffffffffffffffcULL, }, /* 8 */
+ { 0xfffffffffffffffcULL, 0xfffffffffffffffcULL, },
+ { 0xfffffffffffffffcULL, 0xfffffffffffffffcULL, },
+ { 0xfffffffffffffffcULL, 0xfffffffffffffffcULL, },
+ { 0xfffffffffffffffcULL, 0xfffffffffffffffcULL, },
+ { 0xfffffffffffffffcULL, 0xfffffffffffffffcULL, },
+ { 0xfffffffffffffffcULL, 0xfffffffffffffffcULL, },
+ { 0xfffffffffffffffcULL, 0xfffffffffffffffcULL, },
+ { 0xaaaaaaaaaaaaaaa6ULL, 0xaaaaaaaaaaaaaaa6ULL, }, /* 16 */
+ { 0xaaaaaaaaaaaaaaa6ULL, 0xaaaaaaaaaaaaaaa6ULL, },
+ { 0x71c71c71c71c71c2ULL, 0x71c71c71c71c71c2ULL, },
+ { 0x5555555555555550ULL, 0x5555555555555550ULL, },
+ { 0xddddddddddddddd8ULL, 0xddddddddddddddd8ULL, },
+ { 0xfffffffffffffffaULL, 0xfffffffffffffffaULL, },
+ { 0xed097b425ed097aeULL, 0xd097b425ed097b3cULL, },
+ { 0xaaaaaaaaaaaaaaa4ULL, 0xaaaaaaaaaaaaaaa4ULL, },
+ { 0xfffffffffffffff9ULL, 0xfffffffffffffff9ULL, }, /* 24 */
+ { 0xfffffffffffffff9ULL, 0xfffffffffffffff9ULL, },
+ { 0xe38e38e38e38e387ULL, 0xe38e38e38e38e387ULL, },
+ { 0x555555555555554eULL, 0x555555555555554eULL, },
+ { 0x9999999999999992ULL, 0x9999999999999992ULL, },
+ { 0xaaaaaaaaaaaaaaa3ULL, 0xaaaaaaaaaaaaaaa3ULL, },
+ { 0xa12f684bda12f67dULL, 0x12f684bda12f6844ULL, },
+ { 0xfffffffffffffff8ULL, 0xfffffffffffffff8ULL, },
+ { 0xccccccccccccccc4ULL, 0xccccccccccccccc4ULL, }, /* 32 */
+ { 0xccccccccccccccc4ULL, 0xccccccccccccccc4ULL, },
+ { 0x555555555555554cULL, 0x555555555555554cULL, },
+ { 0x9999999999999990ULL, 0x9999999999999990ULL, },
+ { 0xa3d70a3d70a3d700ULL, 0xa3d70a3d70a3d700ULL, },
+ { 0x666666666666665cULL, 0x666666666666665cULL, },
+ { 0xe93e93e93e93e934ULL, 0x2d82d82d82d82d78ULL, },
+ { 0x3333333333333328ULL, 0x3333333333333328ULL, },
+ { 0x666666666666665bULL, 0x666666666666665bULL, }, /* 40 */
+ { 0x666666666666665bULL, 0x666666666666665bULL, },
+ { 0x888888888888887dULL, 0x888888888888887dULL, },
+ { 0x999999999999998eULL, 0x999999999999998eULL, },
+ { 0x5c28f5c28f5c28eaULL, 0x5c28f5c28f5c28eaULL, },
+ { 0xccccccccccccccc1ULL, 0xccccccccccccccc1ULL, },
+ { 0x2d82d82d82d82d77ULL, 0x3e93e93e93e93e88ULL, },
+ { 0xfffffffffffffff4ULL, 0xfffffffffffffff4ULL, },
+ { 0xe38e38e38e38e382ULL, 0x38e38e38e38e38d7ULL, }, /* 48 */
+ { 0xe38e38e38e38e382ULL, 0x38e38e38e38e38d7ULL, },
+ { 0xd097b425ed097b36ULL, 0x097b425ed097b419ULL, },
+ { 0xc71c71c71c71c710ULL, 0x71c71c71c71c71baULL, },
+ { 0x49f49f49f49f49e8ULL, 0x38e38e38e38e38d6ULL, },
+ { 0xaaaaaaaaaaaaaa9eULL, 0xaaaaaaaaaaaaaa9dULL, },
+ { 0xf9add3c0ca4587daULL, 0x587e6b74f0329154ULL, },
+ { 0x8e38e38e38e38e2cULL, 0xe38e38e38e38e380ULL, },
+ { 0xaaaaaaaaaaaaaa9dULL, 0xaaaaaaaaaaaaaa9cULL, }, /* 56 */
+ { 0xaaaaaaaaaaaaaa9dULL, 0xaaaaaaaaaaaaaa9cULL, },
+ { 0x684bda12f684bd93ULL, 0x84bda12f684bda04ULL, },
+ { 0xc71c71c71c71c70eULL, 0x71c71c71c71c71b8ULL, },
+ { 0x1111111111111102ULL, 0x7777777777777768ULL, },
+ { 0xe38e38e38e38e37fULL, 0x38e38e38e38e38d4ULL, },
+ { 0x781948b0fcd6e9d1ULL, 0xc3f35ba781948b00ULL, },
+ { 0xfffffffffffffff0ULL, 0xfffffffffffffff0ULL, },
+ { 0x52ba41969e9c6ff0ULL, 0xcd6802158b677f60ULL, }, /* 64 */
+ { 0x63129bf5b78505f0ULL, 0x1556f7f61c4e5b90ULL, },
+ { 0x5a4c8855f350a5f0ULL, 0x6a36586fc42edea0ULL, },
+ { 0x5e6b001b04d82c70ULL, 0xe819332c365e3f20ULL, },
+ { 0x6ec35a7a1dc0c270ULL, 0x3008290cc7451b50ULL, },
+ { 0x37152f411fd35230ULL, 0xc7e3b2957c56b340ULL, },
+ { 0xcc49f1d861667630ULL, 0x1808e0646811cb90ULL, },
+ { 0xde8a7f544022c1c0ULL, 0x9886bc9978437610ULL, },
+ { 0xd5c46bb47bee61c0ULL, 0xed661d132023f920ULL, }, /* 72 */
+ { 0x6af92e4bbd8185c0ULL, 0x3d8b4ae20bdf1170ULL, },
+ { 0xe4d44869d87d45c0ULL, 0x6409d23bd9c847e0ULL, },
+ { 0x6e2e9ce94e99c4c0ULL, 0xc30837db04ed7360ULL, },
+ { 0x724d14ae60214b40ULL, 0x40eb1297771cd3e0ULL, },
+ { 0x848da22a3edd96d0ULL, 0xc168eecc874e7e60ULL, },
+ { 0x0de7f6a9b4fa15d0ULL, 0x2067546bb273a9e0ULL, },
+ { 0xc233bfd40310460cULL, 0x0d9585bacf54c5e0ULL, },
+ { 0x061015122724c70cULL, 0x0169d01f7cb17f60ULL, }, /* 80 */
+ { 0x23dacc726f603aacULL, 0xf3ea8c4eaa8b5ce0ULL, },
+ { 0xd82df953c25380acULL, 0xba87b7f0f99bbb60ULL, },
+ { 0x546cb94a0c5e7444ULL, 0x3818c320ce1bdf60ULL, },
+ { 0xa38f9428761ecf44ULL, 0x63113b9e681b66e0ULL, },
+ { 0x7dc23fbe59fe7924ULL, 0x156ddd68750e6260ULL, },
+ { 0x8a17717d36df5b24ULL, 0x36b1f5939596d2e0ULL, },
+ { 0x7e854cd9a677ce2cULL, 0xf2b6202eb36946e0ULL, },
+ { 0x246d8d067437a72cULL, 0x04c6347e9c1ff460ULL, }, /* 88 */
+ { 0xc48a013a554339ccULL, 0xcb81fd31acc4a5e0ULL, },
+ { 0xb971282c0b508fccULL, 0x20d62d6344ce5060ULL, },
+ { 0x835f812f0bc6a7a4ULL, 0x17bd6b5a08275460ULL, },
+ { 0xc0ee1b9557ab4aa4ULL, 0x170471a9d22d5fe0ULL, },
+ { 0xc6f66d89431f7984ULL, 0x5c6f5a646cad3f60ULL, },
+ { 0x5ae0b289f6ac0b84ULL, 0x6f9f6bc81fdb6be0ULL, },
+ { 0x2f584ee03fd2014cULL, 0xa7e34ccbd1bc3fe0ULL, },
+ { 0x5947927731cb724cULL, 0xf76af1f9a05f4160ULL, }, /* 96 */
+ { 0x68112ad490e3a34cULL, 0x7f944a22f5d630e0ULL, },
+ { 0x1cf6705c5faa944cULL, 0x801292d47291e660ULL, },
+ { 0x5519f2782cb0454cULL, 0x3d691c2dd53919e0ULL, },
+ { 0xe5c979861aac06ecULL, 0x585247d6e899e160ULL, },
+ { 0x2450b27896665b8cULL, 0x8276d8ad504f46e0ULL, },
+ { 0x2716d456a4a5ab2cULL, 0x46e1f3460c71c260ULL, },
+ { 0x5751460331251dccULL, 0xdc1dc7a4a693abe0ULL, },
+ { 0x3bf387b7f37473ccULL, 0x8efb4ff7cc92de60ULL, }, /* 104 */
+ { 0xc3103a3df066c9ccULL, 0x7d3b07351cd59ee0ULL, },
+ { 0x0d612554557c1fccULL, 0x5dbabfc2ac8ed560ULL, },
+ { 0x1cd018ef103475ccULL, 0xca277277956f49e0ULL, },
+ { 0x15d520225c2e79a4ULL, 0x08f2025804e95de0ULL, },
+ { 0x820f9c65be3ea1acULL, 0x37094edbda6ef1e0ULL, },
+ { 0x0f18515c62838744ULL, 0xcfbd4b5627d005e0ULL, },
+ { 0x11d549f26502488cULL, 0x8de999d53cdc99e0ULL, },
};
reset_msa_registers();
uint64_t b128_result[TEST_COUNT_TOTAL][2];
uint64_t b128_expect[TEST_COUNT_TOTAL][2] = {
- { 0x0000000000000002ULL, 0x0000000000000002ULL, }, /* 0 */
- { 0x0000000000000002ULL, 0x0000000000000002ULL, },
- { 0x00000000aaaaaaaeULL, 0x00000000aaaaaaaeULL, },
- { 0x0000000000000004ULL, 0x0000000000000004ULL, },
- { 0x000000006666666cULL, 0x000000006666666cULL, },
- { 0x0000000000000006ULL, 0x0000000000000006ULL, },
- { 0x000000008e38e395ULL, 0xffffffffe38e38ebULL, },
- { 0x0000000000000008ULL, 0x0000000000000008ULL, },
- { 0x0000000000000008ULL, 0x0000000000000008ULL, }, /* 8 */
- { 0x0000000000000008ULL, 0x0000000000000008ULL, },
- { 0x0000000000000008ULL, 0x0000000000000008ULL, },
- { 0x0000000000000008ULL, 0x0000000000000008ULL, },
- { 0x0000000000000008ULL, 0x0000000000000008ULL, },
- { 0x0000000000000008ULL, 0x0000000000000008ULL, },
- { 0x0000000000000008ULL, 0x0000000000000008ULL, },
- { 0x0000000000000008ULL, 0x0000000000000008ULL, },
- { 0x00000000aaaaaab4ULL, 0x00000000aaaaaab4ULL, }, /* 16 */
- { 0x00000000aaaaaab4ULL, 0x00000000aaaaaab4ULL, },
- { 0x38e38e3a71c71c7cULL, 0x38e38e3a71c71c7cULL, },
- { 0x0000000155555560ULL, 0x0000000155555560ULL, },
- { 0x2222222444444450ULL, 0x2222222444444450ULL, },
- { 0x000000020000000cULL, 0x000000020000000cULL, },
- { 0x2f684bdcb425ed16ULL, 0xf684bda397b425faULL, },
- { 0x00000002aaaaaab8ULL, 0x00000002aaaaaab8ULL, },
- { 0x000000020000000eULL, 0x000000020000000eULL, }, /* 24 */
- { 0x000000020000000eULL, 0x000000020000000eULL, },
- { 0xc71c71c8e38e38f2ULL, 0xc71c71c8e38e38f2ULL, },
- { 0x0000000155555564ULL, 0x0000000155555564ULL, },
- { 0xdddddddeccccccdcULL, 0xdddddddeccccccdcULL, },
- { 0x00000000aaaaaabaULL, 0x00000000aaaaaabaULL, },
- { 0xd097b42684bda13fULL, 0x097b425ef684bdb1ULL, },
- { 0x0000000000000010ULL, 0x0000000000000010ULL, },
- { 0x0000000066666678ULL, 0x0000000066666678ULL, }, /* 32 */
- { 0x0000000066666678ULL, 0x0000000066666678ULL, },
- { 0x2222222355555568ULL, 0x2222222355555568ULL, },
- { 0x00000000cccccce0ULL, 0x00000000cccccce0ULL, },
- { 0x147ae1491eb85200ULL, 0x147ae1491eb85200ULL, },
- { 0x0000000133333348ULL, 0x0000000133333348ULL, },
- { 0x1c71c71e3e93e954ULL, 0xfa4fa4fbb60b60ccULL, },
- { 0x00000001999999b0ULL, 0x00000001999999b0ULL, },
- { 0x000000013333334aULL, 0x000000013333334aULL, }, /* 40 */
- { 0x000000013333334aULL, 0x000000013333334aULL, },
- { 0xdddddddeeeeeef06ULL, 0xdddddddeeeeeef06ULL, },
- { 0x00000000cccccce4ULL, 0x00000000cccccce4ULL, },
- { 0xeb851eb8e147ae2cULL, 0xeb851eb8e147ae2cULL, },
- { 0x000000006666667eULL, 0x000000006666667eULL, },
- { 0xe38e38e3e93e9401ULL, 0x05b05b05c71c71dfULL, },
- { 0x0000000000000018ULL, 0x0000000000000018ULL, },
- { 0x000000008e38e3a7ULL, 0xffffffffe38e38fdULL, }, /* 48 */
- { 0x000000008e38e3a7ULL, 0xffffffffe38e38fdULL, },
- { 0x2f684bdb425ed0b1ULL, 0xf684bda17b425eebULL, },
- { 0x000000011c71c736ULL, 0xffffffffc71c71e2ULL, },
- { 0x1c71c71e27d27d42ULL, 0xfa4fa4fa49f49f66ULL, },
- { 0x00000001aaaaaac5ULL, 0xffffffffaaaaaac7ULL, },
- { 0x35ba781b4587e6d2ULL, 0x0fcd6e9d6b74f050ULL, },
- { 0x0000000238e38e54ULL, 0xffffffff8e38e3acULL, },
- { 0x00000001aaaaaac7ULL, 0xffffffffaaaaaac9ULL, }, /* 56 */
- { 0x00000001aaaaaac7ULL, 0xffffffffaaaaaac9ULL, },
- { 0xd097b427a12f6869ULL, 0x097b425ebda12f87ULL, },
- { 0x000000011c71c73aULL, 0xffffffffc71c71e6ULL, },
- { 0xe38e38e477777796ULL, 0x05b05b05aaaaaacaULL, },
- { 0x000000008e38e3adULL, 0xffffffffe38e3903ULL, },
- { 0xca4587e781948b2fULL, 0xf032916206522c5fULL, },
- { 0x0000000000000020ULL, 0x0000000000000020ULL, },
- { 0x3e3ad4ae1266c2b0ULL, 0x1637d725aebdb734ULL, }, /* 64 */
- { 0x4c74e0d60a3d6d94ULL, 0x1badd2dd9f4dac90ULL, },
- { 0x6874e8f94205b90cULL, 0x27eb0c41af2c3022ULL, },
- { 0x42dab657e16f25e8ULL, 0x06d6782e137656f2ULL, },
- { 0x5114c27fd945d0ccULL, 0x0c4c73e604064c4eULL, },
- { 0x68a91e898c276755ULL, 0x0f77ad378bdfb302ULL, },
- { 0x54c82cde41d1cf13ULL, 0x0b6108a5f38e1598ULL, },
- { 0x6f755d3eddd1234aULL, 0xfbbaace2f5421908ULL, },
- { 0x8b75656215996ec2ULL, 0x07f7e64705209c9aULL, }, /* 72 */
- { 0x779473b6cb43d680ULL, 0x03e141b56cceff30ULL, },
- { 0xa6279a1866fb9f64ULL, 0x2631668db9e53ac1ULL, },
- { 0x67a1f71bd99e4586ULL, 0x312ec9f6206e6e69ULL, },
- { 0x4207c47a7907b262ULL, 0x101a35e284b89539ULL, },
- { 0x5cb4f4db15070699ULL, 0x0073da1f866c98a9ULL, },
- { 0x1e2f51de87a9acbbULL, 0x0b713d87ecf5cc51ULL, },
- { 0x721d49ba5f0acfa8ULL, 0x5ba5bbe9afeae691ULL, },
- { 0x4bcd68690d995de0ULL, 0x771da6b4b6c967ebULL, }, /* 80 */
- { 0x4ea9a2cfbb5acd7bULL, 0x79dd6a73439e6387ULL, },
- { 0x47c800b999dd2371ULL, 0x766d25914ef7a7a0ULL, },
- { 0x41b0fa10eb77cf84ULL, 0x26e85189458965f8ULL, },
- { 0x1fc448ce062c2944ULL, 0x31f490a9422a80e6ULL, },
- { 0x211bdfadfd79770eULL, 0x3b25f4cac5763378ULL, },
- { 0x16fbb87edd87b6f0ULL, 0x57c0b65fabdda20eULL, },
- { 0x14621091eac4a5f6ULL, 0x4d29a25d32fa9ef6ULL, },
- { 0x07832ded1c464b02ULL, 0x6396905709e3cfa4ULL, }, /* 88 */
- { 0x0ff4a84eab8df3b9ULL, 0x6bc9a7d8c6adf2eaULL, },
- { 0x21e53326bfbd0b05ULL, 0x8f8f3b9c679dff5aULL, },
- { 0x191ed6a24e1576f9ULL, 0x9e8c2e402760373aULL, },
- { 0x19b438400fc27751ULL, 0x819c4bbfd3ee6972ULL, },
- { 0x1e0d5dc1094ae999ULL, 0x7496a289f5eff010ULL, },
- { 0x11af620b7bc03943ULL, 0x8a11f229836addc7ULL, },
- { 0x46fa45d0e84440fcULL, 0xe8d2c0211fb042bfULL, },
- { 0x22142516b5a8adbcULL, 0xe1cf1923e186aad1ULL, }, /* 96 */
- { 0x066ebbbb4ff6da44ULL, 0xd918d7e6a7e61877ULL, },
- { 0x100acc9d22839a48ULL, 0xce291932929e367fULL, },
- { 0x0dfe419d62a62f64ULL, 0xc020fe45a8cf7acfULL, },
- { 0x2ba79b6ffbf3c63bULL, 0xb428f52c49fce695ULL, },
- { 0x29b3b85200bdf100ULL, 0xb4ae7ea2f52aa5b9ULL, },
- { 0x293bb84d6360c0b6ULL, 0xae33b26e4c493c49ULL, },
- { 0x46a99fdf54f4862dULL, 0xae790dc5055f6f51ULL, },
- { 0x18480e0fd728c7c3ULL, 0xa000ad7b15f8ebe0ULL, }, /* 104 */
- { 0x1b8b97aa205e1239ULL, 0x89c78b8909c4a8e5ULL, },
- { 0x09abb26b05ef649dULL, 0x74242fa1bd49e740ULL, },
- { 0x04e233bc861d272bULL, 0x9c5343ab30f62f9fULL, },
- { 0xda2da0d0884dc3d1ULL, 0xb824f201640b4147ULL, },
- { 0x9d8b22ee1b9a2e0fULL, 0xb642ddf1edb0747fULL, },
- { 0x7c81956533686a37ULL, 0xdd5181781dc3ad37ULL, },
- { 0xc60b1905717ff25aULL, 0xe2af726e71ad7ad7ULL, },
+ { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 0 */
+ { 0xffffffffffffffffULL, 0xffffffffffffffffULL, },
+ { 0xaaa9aaa9aaa9aaa9ULL, 0xaaa9aaa9aaa9aaa9ULL, },
+ { 0xfffefffefffefffeULL, 0xfffefffefffefffeULL, },
+ { 0xcccacccacccacccaULL, 0xcccacccacccacccaULL, },
+ { 0xfffdfffdfffdfffdULL, 0xfffdfffdfffdfffdULL, },
+ { 0xe38b38e08e35e38bULL, 0x38e08e35e38b38e0ULL, },
+ { 0xfffcfffcfffcfffcULL, 0xfffcfffcfffcfffcULL, },
+ { 0xfffcfffcfffcfffcULL, 0xfffcfffcfffcfffcULL, }, /* 8 */
+ { 0xfffcfffcfffcfffcULL, 0xfffcfffcfffcfffcULL, },
+ { 0xfffcfffcfffcfffcULL, 0xfffcfffcfffcfffcULL, },
+ { 0xfffcfffcfffcfffcULL, 0xfffcfffcfffcfffcULL, },
+ { 0xfffcfffcfffcfffcULL, 0xfffcfffcfffcfffcULL, },
+ { 0xfffcfffcfffcfffcULL, 0xfffcfffcfffcfffcULL, },
+ { 0xfffcfffcfffcfffcULL, 0xfffcfffcfffcfffcULL, },
+ { 0xfffcfffcfffcfffcULL, 0xfffcfffcfffcfffcULL, },
+ { 0xaaa6aaa6aaa6aaa6ULL, 0xaaa6aaa6aaa6aaa6ULL, }, /* 16 */
+ { 0xaaa6aaa6aaa6aaa6ULL, 0xaaa6aaa6aaa6aaa6ULL, },
+ { 0x71c271c271c271c2ULL, 0x71c271c271c271c2ULL, },
+ { 0x5550555055505550ULL, 0x5550555055505550ULL, },
+ { 0xddd8ddd8ddd8ddd8ULL, 0xddd8ddd8ddd8ddd8ULL, },
+ { 0xfffafffafffafffaULL, 0xfffafffafffafffaULL, },
+ { 0x97ae7b3c5eca97aeULL, 0x7b3c5eca97ae7b3cULL, },
+ { 0xaaa4aaa4aaa4aaa4ULL, 0xaaa4aaa4aaa4aaa4ULL, },
+ { 0xfff9fff9fff9fff9ULL, 0xfff9fff9fff9fff9ULL, }, /* 24 */
+ { 0xfff9fff9fff9fff9ULL, 0xfff9fff9fff9fff9ULL, },
+ { 0xe387e387e387e387ULL, 0xe387e387e387e387ULL, },
+ { 0x554e554e554e554eULL, 0x554e554e554e554eULL, },
+ { 0x9992999299929992ULL, 0x9992999299929992ULL, },
+ { 0xaaa3aaa3aaa3aaa3ULL, 0xaaa3aaa3aaa3aaa3ULL, },
+ { 0xf67d6844da0bf67dULL, 0x6844da0bf67d6844ULL, },
+ { 0xfff8fff8fff8fff8ULL, 0xfff8fff8fff8fff8ULL, },
+ { 0xccc4ccc4ccc4ccc4ULL, 0xccc4ccc4ccc4ccc4ULL, }, /* 32 */
+ { 0xccc4ccc4ccc4ccc4ULL, 0xccc4ccc4ccc4ccc4ULL, },
+ { 0x554c554c554c554cULL, 0x554c554c554c554cULL, },
+ { 0x9990999099909990ULL, 0x9990999099909990ULL, },
+ { 0xd700d700d700d700ULL, 0xd700d700d700d700ULL, },
+ { 0x665c665c665c665cULL, 0x665c665c665c665cULL, },
+ { 0xe9342d7871bce934ULL, 0x2d7871bce9342d78ULL, },
+ { 0x3328332833283328ULL, 0x3328332833283328ULL, },
+ { 0x665b665b665b665bULL, 0x665b665b665b665bULL, }, /* 40 */
+ { 0x665b665b665b665bULL, 0x665b665b665b665bULL, },
+ { 0x887d887d887d887dULL, 0x887d887d887d887dULL, },
+ { 0x998e998e998e998eULL, 0x998e998e998e998eULL, },
+ { 0x28ea28ea28ea28eaULL, 0x28ea28ea28ea28eaULL, },
+ { 0xccc1ccc1ccc1ccc1ULL, 0xccc1ccc1ccc1ccc1ULL, },
+ { 0x2d773e884f992d77ULL, 0x3e884f992d773e88ULL, },
+ { 0xfff4fff4fff4fff4ULL, 0xfff4fff4fff4fff4ULL, },
+ { 0xe38238d78e2ce382ULL, 0x38d78e2ce38238d7ULL, }, /* 48 */
+ { 0xe38238d78e2ce382ULL, 0x38d78e2ce38238d7ULL, },
+ { 0x7b36b419ecfc7b36ULL, 0xb419ecfc7b36b419ULL, },
+ { 0xc71071ba1c64c710ULL, 0x71ba1c64c71071baULL, },
+ { 0x49e838d627c449e8ULL, 0x38d627c449e838d6ULL, },
+ { 0xaa9eaa9daa9caa9eULL, 0xaa9daa9caa9eaa9dULL, },
+ { 0x87da91547e5c87daULL, 0x91547e5c87da9154ULL, },
+ { 0x8e2ce38038d48e2cULL, 0xe38038d48e2ce380ULL, },
+ { 0xaa9daa9caa9baa9dULL, 0xaa9caa9baa9daa9cULL, }, /* 56 */
+ { 0xaa9daa9caa9baa9dULL, 0xaa9caa9baa9daa9cULL, },
+ { 0xbd93da04f675bd93ULL, 0xda04f675bd93da04ULL, },
+ { 0xc70e71b81c62c70eULL, 0x71b81c62c70e71b8ULL, },
+ { 0x11027768ddce1102ULL, 0x7768ddce11027768ULL, },
+ { 0xe37f38d48e29e37fULL, 0x38d48e29e37f38d4ULL, },
+ { 0xe9d18b0048a1e9d1ULL, 0x8b0048a1e9d18b00ULL, },
+ { 0xfff0fff0fff0fff0ULL, 0xfff0fff0fff0fff0ULL, },
+ { 0x340ccd603a6c6ff0ULL, 0x7c7fc96cb0d77f60ULL, }, /* 64 */
+ { 0x07608c7c902605f0ULL, 0x7e1ef7e0f9925b90ULL, },
+ { 0xda1ca10416e8a5f0ULL, 0x2e36f13e11e9dea0ULL, },
+ { 0x6166ada860262c70ULL, 0x773f69ee43333f20ULL, },
+ { 0x34ba6cc4b5e0c270ULL, 0x78de98628bee1b50ULL, },
+ { 0x13b6467bf3775230ULL, 0xce8d99be266db340ULL, },
+ { 0xeaeababdfe9a7630ULL, 0x2d251ed87fd8cb90ULL, },
+ { 0x1b481af62b77c1c0ULL, 0x479e70e86e9a7610ULL, },
+ { 0xee042f7eb23961c0ULL, 0xf7b66a4686f1f920ULL, }, /* 72 */
+ { 0xc538a3c0bd5c85c0ULL, 0x564eef60e05c1170ULL, },
+ { 0xb5941adce7fb45c0ULL, 0xd00e7d5f672347e0ULL, },
+ { 0x25cef5ba555cc4c0ULL, 0x55b61e37e30d7360ULL, },
+ { 0xad18025e9e9a4b40ULL, 0x9ebf96e71457d3e0ULL, },
+ { 0xdd766297cb7796d0ULL, 0xb938e8f703197e60ULL, },
+ { 0x4db03d7538d815d0ULL, 0x3ee089cf7f03a9e0ULL, },
+ { 0x154fea4c3377460cULL, 0xe1ff538f49ffc5e0ULL, },
+ { 0x4a99edbce7e9c70cULL, 0x3f66800dba7a7f60ULL, }, /* 80 */
+ { 0xea0bfe08a81e3aacULL, 0xe7fcffbbd4745ce0ULL, },
+ { 0x3e2ddcb809dc80acULL, 0xc75ca276a8f8bb60ULL, },
+ { 0x5e4aa9605ec07444ULL, 0x6dc0dee66108df60ULL, },
+ { 0x03a670e01940cf44ULL, 0x05802472d23066e0ULL, },
+ { 0x8c72ca4059807924ULL, 0xb7002ade28606260ULL, },
+ { 0x945efbc07b005b24ULL, 0x4f00c3bc4040d2e0ULL, },
+ { 0xab5cc300f000ce2cULL, 0xf000bd1c6fc046e0ULL, },
+ { 0xd7445f001000a72cULL, 0x600018d43e80f460ULL, }, /* 88 */
+ { 0x66cca200e00039ccULL, 0xc000b74c5d00a5e0ULL, },
+ { 0x33140e00c0008fccULL, 0xc0005a98be005060ULL, },
+ { 0xafe8d8000000a7a4ULL, 0x00002a58c2005460ULL, },
+ { 0x99d8b80000004aa4ULL, 0x0000d6088c005fe0ULL, },
+ { 0xa388900000007984ULL, 0x0000413818003f60ULL, },
+ { 0xc5b8f00000000b84ULL, 0x0000fa7010006be0ULL, },
+ { 0x41f0c0000000014cULL, 0x00002bf0f0003fe0ULL, },
+ { 0x7490c0000000724cULL, 0x0000b9d0a0004160ULL, }, /* 96 */
+ { 0xb0f0c0000000a34cULL, 0x00008f70c00030e0ULL, },
+ { 0xed90c0000000944cULL, 0x000014508000e660ULL, },
+ { 0x0ff0c0000000454cULL, 0x00002ef0000019e0ULL, },
+ { 0xebd08000000006ecULL, 0x00001a900000e160ULL, },
+ { 0xf770000000005b8cULL, 0x000037f0000046e0ULL, },
+ { 0x825000000000ab2cULL, 0x000039900000c260ULL, },
+ { 0x5af0000000001dccULL, 0x000030f00000abe0ULL, },
+ { 0x22900000000073ccULL, 0x0000d1e00000de60ULL, }, /* 104 */
+ { 0x3bf000000000c9ccULL, 0x000083c000009ee0ULL, },
+ { 0xe990000000001fccULL, 0x0000c7800000d560ULL, },
+ { 0x0cf00000000075ccULL, 0x00000f00000049e0ULL, },
+ { 0x0ee00000000079a4ULL, 0x0000670000005de0ULL, },
+ { 0x77c000000000a1acULL, 0x00007f000000f1e0ULL, },
+ { 0x8380000000008744ULL, 0x00005700000005e0ULL, },
+ { 0xef0000000000488cULL, 0x0000ef00000099e0ULL, },
};
reset_msa_registers();
uint64_t b128_result[TEST_COUNT_TOTAL][2];
uint64_t b128_expect[TEST_COUNT_TOTAL][2] = {
- { 0x0000000000000002ULL, 0x0000000000000002ULL, }, /* 0 */
- { 0x0000000000000002ULL, 0x0000000000000002ULL, },
- { 0x00000000aaaaaaaeULL, 0x00000000aaaaaaaeULL, },
- { 0x0000000000000004ULL, 0x0000000000000004ULL, },
- { 0x000000006666666cULL, 0x000000006666666cULL, },
- { 0x0000000000000006ULL, 0x0000000000000006ULL, },
- { 0x000000008e38e395ULL, 0xffffffffe38e38ebULL, },
- { 0x0000000000000008ULL, 0x0000000000000008ULL, },
- { 0x0000000000000008ULL, 0x0000000000000008ULL, }, /* 8 */
- { 0x0000000000000008ULL, 0x0000000000000008ULL, },
- { 0x0000000000000008ULL, 0x0000000000000008ULL, },
- { 0x0000000000000008ULL, 0x0000000000000008ULL, },
- { 0x0000000000000008ULL, 0x0000000000000008ULL, },
- { 0x0000000000000008ULL, 0x0000000000000008ULL, },
- { 0x0000000000000008ULL, 0x0000000000000008ULL, },
- { 0x0000000000000008ULL, 0x0000000000000008ULL, },
- { 0x00000000aaaaaab4ULL, 0x00000000aaaaaab4ULL, }, /* 16 */
- { 0x00000000aaaaaab4ULL, 0x00000000aaaaaab4ULL, },
- { 0x38e38e3a71c71c7cULL, 0x38e38e3a71c71c7cULL, },
- { 0x0000000155555560ULL, 0x0000000155555560ULL, },
- { 0x2222222444444450ULL, 0x2222222444444450ULL, },
- { 0x000000020000000cULL, 0x000000020000000cULL, },
- { 0x2f684bdcb425ed16ULL, 0xf684bda397b425faULL, },
- { 0x00000002aaaaaab8ULL, 0x00000002aaaaaab8ULL, },
- { 0x000000020000000eULL, 0x000000020000000eULL, }, /* 24 */
- { 0x000000020000000eULL, 0x000000020000000eULL, },
- { 0xc71c71c8e38e38f2ULL, 0xc71c71c8e38e38f2ULL, },
- { 0x0000000155555564ULL, 0x0000000155555564ULL, },
- { 0xdddddddeccccccdcULL, 0xdddddddeccccccdcULL, },
- { 0x00000000aaaaaabaULL, 0x00000000aaaaaabaULL, },
- { 0xd097b42684bda13fULL, 0x097b425ef684bdb1ULL, },
- { 0x0000000000000010ULL, 0x0000000000000010ULL, },
- { 0x0000000066666678ULL, 0x0000000066666678ULL, }, /* 32 */
- { 0x0000000066666678ULL, 0x0000000066666678ULL, },
- { 0x2222222355555568ULL, 0x2222222355555568ULL, },
- { 0x00000000cccccce0ULL, 0x00000000cccccce0ULL, },
- { 0x147ae1491eb85200ULL, 0x147ae1491eb85200ULL, },
- { 0x0000000133333348ULL, 0x0000000133333348ULL, },
- { 0x1c71c71e3e93e954ULL, 0xfa4fa4fbb60b60ccULL, },
- { 0x00000001999999b0ULL, 0x00000001999999b0ULL, },
- { 0x000000013333334aULL, 0x000000013333334aULL, }, /* 40 */
- { 0x000000013333334aULL, 0x000000013333334aULL, },
- { 0xdddddddeeeeeef06ULL, 0xdddddddeeeeeef06ULL, },
- { 0x00000000cccccce4ULL, 0x00000000cccccce4ULL, },
- { 0xeb851eb8e147ae2cULL, 0xeb851eb8e147ae2cULL, },
- { 0x000000006666667eULL, 0x000000006666667eULL, },
- { 0xe38e38e3e93e9401ULL, 0x05b05b05c71c71dfULL, },
- { 0x0000000000000018ULL, 0x0000000000000018ULL, },
- { 0x000000008e38e3a7ULL, 0xffffffffe38e38fdULL, }, /* 48 */
- { 0x000000008e38e3a7ULL, 0xffffffffe38e38fdULL, },
- { 0x2f684bdb425ed0b1ULL, 0xf684bda17b425eebULL, },
- { 0x000000011c71c736ULL, 0xffffffffc71c71e2ULL, },
- { 0x1c71c71e27d27d42ULL, 0xfa4fa4fa49f49f66ULL, },
- { 0x00000001aaaaaac5ULL, 0xffffffffaaaaaac7ULL, },
- { 0x35ba781b4587e6d2ULL, 0x0fcd6e9d6b74f050ULL, },
- { 0x0000000238e38e54ULL, 0xffffffff8e38e3acULL, },
- { 0x00000001aaaaaac7ULL, 0xffffffffaaaaaac9ULL, }, /* 56 */
- { 0x00000001aaaaaac7ULL, 0xffffffffaaaaaac9ULL, },
- { 0xd097b427a12f6869ULL, 0x097b425ebda12f87ULL, },
- { 0x000000011c71c73aULL, 0xffffffffc71c71e6ULL, },
- { 0xe38e38e477777796ULL, 0x05b05b05aaaaaacaULL, },
- { 0x000000008e38e3adULL, 0xffffffffe38e3903ULL, },
- { 0xca4587e781948b2fULL, 0xf032916206522c5fULL, },
- { 0x0000000000000020ULL, 0x0000000000000020ULL, },
- { 0x3e3ad4ae1266c2b0ULL, 0x1637d725aebdb734ULL, }, /* 64 */
- { 0x4c74e0d60a3d6d94ULL, 0x1badd2dd9f4dac90ULL, },
- { 0x6874e8f94205b90cULL, 0x27eb0c41af2c3022ULL, },
- { 0x42dab657e16f25e8ULL, 0x06d6782e137656f2ULL, },
- { 0x5114c27fd945d0ccULL, 0x0c4c73e604064c4eULL, },
- { 0x68a91e898c276755ULL, 0x0f77ad378bdfb302ULL, },
- { 0x54c82cde41d1cf13ULL, 0x0b6108a5f38e1598ULL, },
- { 0x6f755d3eddd1234aULL, 0xfbbaace2f5421908ULL, },
- { 0x8b75656215996ec2ULL, 0x07f7e64705209c9aULL, }, /* 72 */
- { 0x779473b6cb43d680ULL, 0x03e141b56cceff30ULL, },
- { 0xa6279a1866fb9f64ULL, 0x2631668db9e53ac1ULL, },
- { 0x67a1f71bd99e4586ULL, 0x312ec9f6206e6e69ULL, },
- { 0x4207c47a7907b262ULL, 0x101a35e284b89539ULL, },
- { 0x5cb4f4db15070699ULL, 0x0073da1f866c98a9ULL, },
- { 0x1e2f51de87a9acbbULL, 0x0b713d87ecf5cc51ULL, },
- { 0x721d49ba5f0acfa8ULL, 0x5ba5bbe9afeae691ULL, },
- { 0x4bcd68690d995de0ULL, 0x771da6b4b6c967ebULL, }, /* 80 */
- { 0x4ea9a2cfbb5acd7bULL, 0x79dd6a73439e6387ULL, },
- { 0x47c800b999dd2371ULL, 0x766d25914ef7a7a0ULL, },
- { 0x41b0fa10eb77cf84ULL, 0x26e85189458965f8ULL, },
- { 0x1fc448ce062c2944ULL, 0x31f490a9422a80e6ULL, },
- { 0x211bdfadfd79770eULL, 0x3b25f4cac5763378ULL, },
- { 0x16fbb87edd87b6f0ULL, 0x57c0b65fabdda20eULL, },
- { 0x14621091eac4a5f6ULL, 0x4d29a25d32fa9ef6ULL, },
- { 0x07832ded1c464b02ULL, 0x6396905709e3cfa4ULL, }, /* 88 */
- { 0x0ff4a84eab8df3b9ULL, 0x6bc9a7d8c6adf2eaULL, },
- { 0x21e53326bfbd0b05ULL, 0x8f8f3b9c679dff5aULL, },
- { 0x191ed6a24e1576f9ULL, 0x9e8c2e402760373aULL, },
- { 0x19b438400fc27751ULL, 0x819c4bbfd3ee6972ULL, },
- { 0x1e0d5dc1094ae999ULL, 0x7496a289f5eff010ULL, },
- { 0x11af620b7bc03943ULL, 0x8a11f229836addc7ULL, },
- { 0x46fa45d0e84440fcULL, 0xe8d2c0211fb042bfULL, },
- { 0x22142516b5a8adbcULL, 0xe1cf1923e186aad1ULL, }, /* 96 */
- { 0x066ebbbb4ff6da44ULL, 0xd918d7e6a7e61877ULL, },
- { 0x100acc9d22839a48ULL, 0xce291932929e367fULL, },
- { 0x0dfe419d62a62f64ULL, 0xc020fe45a8cf7acfULL, },
- { 0x2ba79b6ffbf3c63bULL, 0xb428f52c49fce695ULL, },
- { 0x29b3b85200bdf100ULL, 0xb4ae7ea2f52aa5b9ULL, },
- { 0x293bb84d6360c0b6ULL, 0xae33b26e4c493c49ULL, },
- { 0x46a99fdf54f4862dULL, 0xae790dc5055f6f51ULL, },
- { 0x18480e0fd728c7c3ULL, 0xa000ad7b15f8ebe0ULL, }, /* 104 */
- { 0x1b8b97aa205e1239ULL, 0x89c78b8909c4a8e5ULL, },
- { 0x09abb26b05ef649dULL, 0x74242fa1bd49e740ULL, },
- { 0x04e233bc861d272bULL, 0x9c5343ab30f62f9fULL, },
- { 0xda2da0d0884dc3d1ULL, 0xb824f201640b4147ULL, },
- { 0x9d8b22ee1b9a2e0fULL, 0xb642ddf1edb0747fULL, },
- { 0x7c81956533686a37ULL, 0xdd5181781dc3ad37ULL, },
- { 0xc60b1905717ff25aULL, 0xe2af726e71ad7ad7ULL, },
+ { 0xffffffffffffffffULL, 0xffffffffffffffffULL, }, /* 0 */
+ { 0xffffffffffffffffULL, 0xffffffffffffffffULL, },
+ { 0xaaaaaaa9aaaaaaa9ULL, 0xaaaaaaa9aaaaaaa9ULL, },
+ { 0xfffffffefffffffeULL, 0xfffffffefffffffeULL, },
+ { 0xcccccccacccccccaULL, 0xcccccccacccccccaULL, },
+ { 0xfffffffdfffffffdULL, 0xfffffffdfffffffdULL, },
+ { 0xe38e38e08e38e38bULL, 0x38e38e35e38e38e0ULL, },
+ { 0xfffffffcfffffffcULL, 0xfffffffcfffffffcULL, },
+ { 0xfffffffcfffffffcULL, 0xfffffffcfffffffcULL, }, /* 8 */
+ { 0xfffffffcfffffffcULL, 0xfffffffcfffffffcULL, },
+ { 0xfffffffcfffffffcULL, 0xfffffffcfffffffcULL, },
+ { 0xfffffffcfffffffcULL, 0xfffffffcfffffffcULL, },
+ { 0xfffffffcfffffffcULL, 0xfffffffcfffffffcULL, },
+ { 0xfffffffcfffffffcULL, 0xfffffffcfffffffcULL, },
+ { 0xfffffffcfffffffcULL, 0xfffffffcfffffffcULL, },
+ { 0xfffffffcfffffffcULL, 0xfffffffcfffffffcULL, },
+ { 0xaaaaaaa6aaaaaaa6ULL, 0xaaaaaaa6aaaaaaa6ULL, }, /* 16 */
+ { 0xaaaaaaa6aaaaaaa6ULL, 0xaaaaaaa6aaaaaaa6ULL, },
+ { 0xc71c71c2c71c71c2ULL, 0xc71c71c2c71c71c2ULL, },
+ { 0x5555555055555550ULL, 0x5555555055555550ULL, },
+ { 0xddddddd8ddddddd8ULL, 0xddddddd8ddddddd8ULL, },
+ { 0xfffffffafffffffaULL, 0xfffffffafffffffaULL, },
+ { 0xed097b3c5ed097aeULL, 0x7b425ecaed097b3cULL, },
+ { 0xaaaaaaa4aaaaaaa4ULL, 0xaaaaaaa4aaaaaaa4ULL, },
+ { 0xfffffff9fffffff9ULL, 0xfffffff9fffffff9ULL, }, /* 24 */
+ { 0xfffffff9fffffff9ULL, 0xfffffff9fffffff9ULL, },
+ { 0x8e38e3878e38e387ULL, 0x8e38e3878e38e387ULL, },
+ { 0x5555554e5555554eULL, 0x5555554e5555554eULL, },
+ { 0x9999999299999992ULL, 0x9999999299999992ULL, },
+ { 0xaaaaaaa3aaaaaaa3ULL, 0xaaaaaaa3aaaaaaa3ULL, },
+ { 0xa12f6844da12f67dULL, 0x684bda0ba12f6844ULL, },
+ { 0xfffffff8fffffff8ULL, 0xfffffff8fffffff8ULL, },
+ { 0xccccccc4ccccccc4ULL, 0xccccccc4ccccccc4ULL, }, /* 32 */
+ { 0xccccccc4ccccccc4ULL, 0xccccccc4ccccccc4ULL, },
+ { 0x5555554c5555554cULL, 0x5555554c5555554cULL, },
+ { 0x9999999099999990ULL, 0x9999999099999990ULL, },
+ { 0x70a3d70070a3d700ULL, 0x70a3d70070a3d700ULL, },
+ { 0x6666665c6666665cULL, 0x6666665c6666665cULL, },
+ { 0x82d82d783e93e934ULL, 0xc71c71bc82d82d78ULL, },
+ { 0x3333332833333328ULL, 0x3333332833333328ULL, },
+ { 0x6666665b6666665bULL, 0x6666665b6666665bULL, }, /* 40 */
+ { 0x6666665b6666665bULL, 0x6666665b6666665bULL, },
+ { 0x8888887d8888887dULL, 0x8888887d8888887dULL, },
+ { 0x9999998e9999998eULL, 0x9999998e9999998eULL, },
+ { 0x8f5c28ea8f5c28eaULL, 0x8f5c28ea8f5c28eaULL, },
+ { 0xccccccc1ccccccc1ULL, 0xccccccc1ccccccc1ULL, },
+ { 0x93e93e8882d82d77ULL, 0xa4fa4f9993e93e88ULL, },
+ { 0xfffffff4fffffff4ULL, 0xfffffff4fffffff4ULL, },
+ { 0xe38e38d78e38e382ULL, 0x38e38e2ce38e38d7ULL, }, /* 48 */
+ { 0xe38e38d78e38e382ULL, 0x38e38e2ce38e38d7ULL, },
+ { 0xd097b419ed097b36ULL, 0xb425ecfcd097b419ULL, },
+ { 0xc71c71ba1c71c710ULL, 0x71c71c64c71c71baULL, },
+ { 0xe38e38d6f49f49e8ULL, 0xd27d27c4e38e38d6ULL, },
+ { 0xaaaaaa9daaaaaa9eULL, 0xaaaaaa9caaaaaa9dULL, },
+ { 0xf0329154ca4587daULL, 0xa4587e5cf0329154ULL, },
+ { 0x8e38e38038e38e2cULL, 0xe38e38d48e38e380ULL, },
+ { 0xaaaaaa9caaaaaa9dULL, 0xaaaaaa9baaaaaa9cULL, }, /* 56 */
+ { 0xaaaaaa9caaaaaa9dULL, 0xaaaaaa9baaaaaa9cULL, },
+ { 0x684bda04f684bd93ULL, 0xda12f675684bda04ULL, },
+ { 0xc71c71b81c71c70eULL, 0x71c71c62c71c71b8ULL, },
+ { 0x7777776811111102ULL, 0xddddddce77777768ULL, },
+ { 0xe38e38d48e38e37fULL, 0x38e38e29e38e38d4ULL, },
+ { 0x81948b00fcd6e9d1ULL, 0x781948a181948b00ULL, },
+ { 0xfffffff0fffffff0ULL, 0xfffffff0fffffff0ULL, },
+ { 0x4efccd609e9c6ff0ULL, 0xc5dac96c8b677f60ULL, }, /* 64 */
+ { 0x3e3d8c7cb78505f0ULL, 0x4463f7e01c4e5b90ULL, },
+ { 0xcaa9a104f350a5f0ULL, 0x8ca4f13ec42edea0ULL, },
+ { 0x19b8ada804d82c70ULL, 0xb62b69ee365e3f20ULL, },
+ { 0x08f96cc41dc0c270ULL, 0x34b49862c7451b50ULL, },
+ { 0x5405467b1fd35230ULL, 0xf7c999be7c56b340ULL, },
+ { 0x5cc7babd61667630ULL, 0xa4601ed86811cb90ULL, },
+ { 0xe20c1af64022c1c0ULL, 0x927a70e878437610ULL, },
+ { 0x6e782f7e7bee61c0ULL, 0xdabb6a462023f920ULL, }, /* 72 */
+ { 0x773aa3c0bd8185c0ULL, 0x8751ef600bdf1170ULL, },
+ { 0xc0871adcd87d45c0ULL, 0x6c527d5fd9c847e0ULL, },
+ { 0xd7c7f5ba4e99c4c0ULL, 0xdaa41e3704ed7360ULL, },
+ { 0x26d7025e60214b40ULL, 0x042a96e7771cd3e0ULL, },
+ { 0xac1b62973edd96d0ULL, 0xf244e8f7874e7e60ULL, },
+ { 0xc35c3d75b4fa15d0ULL, 0x609689cfb273a9e0ULL, },
+ { 0x9de4ea4c0310460cULL, 0x80c0538fcf54c5e0ULL, },
+ { 0xbd81edbc2724c70cULL, 0x7301800d7cb17f60ULL, }, /* 80 */
+ { 0xaebafe086f603aacULL, 0x35c5ffbbaa8b5ce0ULL, },
+ { 0xdf14dcb8c25380acULL, 0x3ef9a276f99bbb60ULL, },
+ { 0x5e0ea9600c5e7444ULL, 0x8ef3dee6ce1bdf60ULL, },
+ { 0x1c7370e0761ecf44ULL, 0x864a2472681b66e0ULL, },
+ { 0xb58eca4059fe7924ULL, 0x8c252ade750e6260ULL, },
+ { 0xfcc4fbc036df5b24ULL, 0x36a7c3bc9596d2e0ULL, },
+ { 0x57a2c300a677ce2cULL, 0x2922bd1cb36946e0ULL, },
+ { 0x88bd5f007437a72cULL, 0x45fd18d49c1ff460ULL, }, /* 88 */
+ { 0x2581a200554339ccULL, 0x6c99b74cacc4a5e0ULL, },
+ { 0x2d500e000b508fccULL, 0x1f975a9844ce5060ULL, },
+ { 0x5907d8000bc6a7a4ULL, 0x0eaa2a5808275460ULL, },
+ { 0xeab7b80057ab4aa4ULL, 0x8af4d608d22d5fe0ULL, },
+ { 0x95ab9000431f7984ULL, 0x840741386cad3f60ULL, },
+ { 0xf5ddf000f6ac0b84ULL, 0xd51bfa701fdb6be0ULL, },
+ { 0xdf7cc0003fd2014cULL, 0xb5052bf0d1bc3fe0ULL, },
+ { 0x3393c00031cb724cULL, 0x06abb9d0a05f4160ULL, }, /* 96 */
+ { 0xdb56c00090e3a34cULL, 0x7ff18f70f5d630e0ULL, },
+ { 0xa1b5c0005faa944cULL, 0x9e0514507291e660ULL, },
+ { 0xfa60c0002cb0454cULL, 0xc4182ef0d53919e0ULL, },
+ { 0xa6f680001aac06ecULL, 0x05ca1a90e899e160ULL, },
+ { 0x15a3000096665b8cULL, 0x0cec37f0504f46e0ULL, },
+ { 0xb79a0000a4a5ab2cULL, 0x578239900c71c260ULL, },
+ { 0xb70c000031251dccULL, 0xaa4c30f0a693abe0ULL, },
+ { 0x01140000f37473ccULL, 0x400dd1e0cc92de60ULL, }, /* 104 */
+ { 0xb1cc0000f066c9ccULL, 0x8cf683c01cd59ee0ULL, },
+ { 0xf8540000557c1fccULL, 0x0f82c780ac8ed560ULL, },
+ { 0xf88c0000103475ccULL, 0xa1f10f00956f49e0ULL, },
+ { 0x2e7000005c2e79a4ULL, 0xcf94670004e95de0ULL, },
+ { 0x96c00000be3ea1acULL, 0xdca57f00da6ef1e0ULL, },
+ { 0xbf00000062838744ULL, 0x368a570027d005e0ULL, },
+ { 0x4c0000006502488cULL, 0xcc98ef003cdc99e0ULL, },
};
reset_msa_registers();
# Fixed Multiply
# --------------
#
+/opt/img/bin/mips-img-linux-gnu-gcc fixed-multiply/test_msa_madd_q_h.c \
+-EB -static -mabi=32 -march=mips32r6 -mmsa -o /tmp/test_msa_madd_q_h_32r6eb
+/opt/img/bin/mips-img-linux-gnu-gcc fixed-multiply/test_msa_madd_q_w.c \
+-EB -static -mabi=32 -march=mips32r6 -mmsa -o /tmp/test_msa_madd_q_w_32r6eb
+/opt/img/bin/mips-img-linux-gnu-gcc fixed-multiply/test_msa_maddr_q_h.c \
+-EB -static -mabi=32 -march=mips32r6 -mmsa -o /tmp/test_msa_maddr_q_h_32r6eb
+/opt/img/bin/mips-img-linux-gnu-gcc fixed-multiply/test_msa_maddr_q_w.c \
+-EB -static -mabi=32 -march=mips32r6 -mmsa -o /tmp/test_msa_maddr_q_w_32r6eb
+/opt/img/bin/mips-img-linux-gnu-gcc fixed-multiply/test_msa_msub_q_h.c \
+-EB -static -mabi=32 -march=mips32r6 -mmsa -o /tmp/test_msa_msub_q_h_32r6eb
+/opt/img/bin/mips-img-linux-gnu-gcc fixed-multiply/test_msa_msub_q_w.c \
+-EB -static -mabi=32 -march=mips32r6 -mmsa -o /tmp/test_msa_msub_q_w_32r6eb
+/opt/img/bin/mips-img-linux-gnu-gcc fixed-multiply/test_msa_msubr_q_h.c \
+-EB -static -mabi=32 -march=mips32r6 -mmsa -o /tmp/test_msa_msubr_q_h_32r6eb
+/opt/img/bin/mips-img-linux-gnu-gcc fixed-multiply/test_msa_msubr_q_w.c \
+-EB -static -mabi=32 -march=mips32r6 -mmsa -o /tmp/test_msa_msubr_q_w_32r6eb
/opt/img/bin/mips-img-linux-gnu-gcc fixed-multiply/test_msa_mul_q_h.c \
-EB -static -mabi=32 -march=mips32r6 -mmsa -o /tmp/test_msa_mul_q_h_32r6eb
/opt/img/bin/mips-img-linux-gnu-gcc fixed-multiply/test_msa_mul_q_w.c \
-EB -static -mabi=32 -march=mips32r6 -mmsa -o /tmp/test_msa_subs_u_w_32r6eb
/opt/img/bin/mips-img-linux-gnu-gcc int-subtract/test_msa_subs_u_d.c \
-EB -static -mabi=32 -march=mips32r6 -mmsa -o /tmp/test_msa_subs_u_d_32r6eb
-/opt/img/bin/mips-img-linux-gnu-gcc int-subtract/test_msa_subsuu_s_b.c \
--EB -static -mabi=32 -march=mips32r6 -mmsa -o /tmp/test_msa_subsuu_s_b_32r6eb
-/opt/img/bin/mips-img-linux-gnu-gcc int-subtract/test_msa_subsuu_s_h.c \
--EB -static -mabi=32 -march=mips32r6 -mmsa -o /tmp/test_msa_subsuu_s_h_32r6eb
-/opt/img/bin/mips-img-linux-gnu-gcc int-subtract/test_msa_subsuu_s_w.c \
--EB -static -mabi=32 -march=mips32r6 -mmsa -o /tmp/test_msa_subsuu_s_w_32r6eb
-/opt/img/bin/mips-img-linux-gnu-gcc int-subtract/test_msa_subsuu_s_d.c \
--EB -static -mabi=32 -march=mips32r6 -mmsa -o /tmp/test_msa_subsuu_s_d_32r6eb
/opt/img/bin/mips-img-linux-gnu-gcc int-subtract/test_msa_subsus_u_b.c \
-EB -static -mabi=32 -march=mips32r6 -mmsa -o /tmp/test_msa_subsus_u_b_32r6eb
/opt/img/bin/mips-img-linux-gnu-gcc int-subtract/test_msa_subsus_u_h.c \
-EB -static -mabi=32 -march=mips32r6 -mmsa -o /tmp/test_msa_subsus_u_w_32r6eb
/opt/img/bin/mips-img-linux-gnu-gcc int-subtract/test_msa_subsus_u_d.c \
-EB -static -mabi=32 -march=mips32r6 -mmsa -o /tmp/test_msa_subsus_u_d_32r6eb
+/opt/img/bin/mips-img-linux-gnu-gcc int-subtract/test_msa_subsuu_s_b.c \
+-EB -static -mabi=32 -march=mips32r6 -mmsa -o /tmp/test_msa_subsuu_s_b_32r6eb
+/opt/img/bin/mips-img-linux-gnu-gcc int-subtract/test_msa_subsuu_s_h.c \
+-EB -static -mabi=32 -march=mips32r6 -mmsa -o /tmp/test_msa_subsuu_s_h_32r6eb
+/opt/img/bin/mips-img-linux-gnu-gcc int-subtract/test_msa_subsuu_s_w.c \
+-EB -static -mabi=32 -march=mips32r6 -mmsa -o /tmp/test_msa_subsuu_s_w_32r6eb
+/opt/img/bin/mips-img-linux-gnu-gcc int-subtract/test_msa_subsuu_s_d.c \
+-EB -static -mabi=32 -march=mips32r6 -mmsa -o /tmp/test_msa_subsuu_s_d_32r6eb
/opt/img/bin/mips-img-linux-gnu-gcc int-subtract/test_msa_subv_b.c \
-EB -static -mabi=32 -march=mips32r6 -mmsa -o /tmp/test_msa_subv_b_32r6eb
/opt/img/bin/mips-img-linux-gnu-gcc int-subtract/test_msa_subv_h.c \
# Fixed Multiply
# --------------
#
+/opt/img/bin/mips-img-linux-gnu-gcc fixed-multiply/test_msa_madd_q_h.c \
+-EL -static -mabi=32 -march=mips32r6 -mmsa -o /tmp/test_msa_madd_q_h_32r6el
+/opt/img/bin/mips-img-linux-gnu-gcc fixed-multiply/test_msa_madd_q_w.c \
+-EL -static -mabi=32 -march=mips32r6 -mmsa -o /tmp/test_msa_madd_q_w_32r6el
+/opt/img/bin/mips-img-linux-gnu-gcc fixed-multiply/test_msa_maddr_q_h.c \
+-EL -static -mabi=32 -march=mips32r6 -mmsa -o /tmp/test_msa_maddr_q_h_32r6el
+/opt/img/bin/mips-img-linux-gnu-gcc fixed-multiply/test_msa_maddr_q_w.c \
+-EL -static -mabi=32 -march=mips32r6 -mmsa -o /tmp/test_msa_maddr_q_w_32r6el
+/opt/img/bin/mips-img-linux-gnu-gcc fixed-multiply/test_msa_msub_q_h.c \
+-EL -static -mabi=32 -march=mips32r6 -mmsa -o /tmp/test_msa_msub_q_h_32r6el
+/opt/img/bin/mips-img-linux-gnu-gcc fixed-multiply/test_msa_msub_q_w.c \
+-EL -static -mabi=32 -march=mips32r6 -mmsa -o /tmp/test_msa_msub_q_w_32r6el
+/opt/img/bin/mips-img-linux-gnu-gcc fixed-multiply/test_msa_msubr_q_h.c \
+-EL -static -mabi=32 -march=mips32r6 -mmsa -o /tmp/test_msa_msubr_q_h_32r6el
+/opt/img/bin/mips-img-linux-gnu-gcc fixed-multiply/test_msa_msubr_q_w.c \
+-EL -static -mabi=32 -march=mips32r6 -mmsa -o /tmp/test_msa_msubr_q_w_32r6el
/opt/img/bin/mips-img-linux-gnu-gcc fixed-multiply/test_msa_mul_q_h.c \
-EL -static -mabi=32 -march=mips32r6 -mmsa -o /tmp/test_msa_mul_q_h_32r6el
/opt/img/bin/mips-img-linux-gnu-gcc fixed-multiply/test_msa_mul_q_w.c \
-EL -static -mabi=32 -march=mips32r6 -mmsa -o /tmp/test_msa_subs_u_w_32r6el
/opt/img/bin/mips-img-linux-gnu-gcc int-subtract/test_msa_subs_u_d.c \
-EL -static -mabi=32 -march=mips32r6 -mmsa -o /tmp/test_msa_subs_u_d_32r6el
-/opt/img/bin/mips-img-linux-gnu-gcc int-subtract/test_msa_subsuu_s_b.c \
--EL -static -mabi=32 -march=mips32r6 -mmsa -o /tmp/test_msa_subsuu_s_b_32r6el
-/opt/img/bin/mips-img-linux-gnu-gcc int-subtract/test_msa_subsuu_s_h.c \
--EL -static -mabi=32 -march=mips32r6 -mmsa -o /tmp/test_msa_subsuu_s_h_32r6el
-/opt/img/bin/mips-img-linux-gnu-gcc int-subtract/test_msa_subsuu_s_w.c \
--EL -static -mabi=32 -march=mips32r6 -mmsa -o /tmp/test_msa_subsuu_s_w_32r6el
-/opt/img/bin/mips-img-linux-gnu-gcc int-subtract/test_msa_subsuu_s_d.c \
--EL -static -mabi=32 -march=mips32r6 -mmsa -o /tmp/test_msa_subsuu_s_d_32r6el
/opt/img/bin/mips-img-linux-gnu-gcc int-subtract/test_msa_subsus_u_b.c \
-EL -static -mabi=32 -march=mips32r6 -mmsa -o /tmp/test_msa_subsus_u_b_32r6el
/opt/img/bin/mips-img-linux-gnu-gcc int-subtract/test_msa_subsus_u_h.c \
-EL -static -mabi=32 -march=mips32r6 -mmsa -o /tmp/test_msa_subsus_u_w_32r6el
/opt/img/bin/mips-img-linux-gnu-gcc int-subtract/test_msa_subsus_u_d.c \
-EL -static -mabi=32 -march=mips32r6 -mmsa -o /tmp/test_msa_subsus_u_d_32r6el
+/opt/img/bin/mips-img-linux-gnu-gcc int-subtract/test_msa_subsuu_s_b.c \
+-EL -static -mabi=32 -march=mips32r6 -mmsa -o /tmp/test_msa_subsuu_s_b_32r6el
+/opt/img/bin/mips-img-linux-gnu-gcc int-subtract/test_msa_subsuu_s_h.c \
+-EL -static -mabi=32 -march=mips32r6 -mmsa -o /tmp/test_msa_subsuu_s_h_32r6el
+/opt/img/bin/mips-img-linux-gnu-gcc int-subtract/test_msa_subsuu_s_w.c \
+-EL -static -mabi=32 -march=mips32r6 -mmsa -o /tmp/test_msa_subsuu_s_w_32r6el
+/opt/img/bin/mips-img-linux-gnu-gcc int-subtract/test_msa_subsuu_s_d.c \
+-EL -static -mabi=32 -march=mips32r6 -mmsa -o /tmp/test_msa_subsuu_s_d_32r6el
/opt/img/bin/mips-img-linux-gnu-gcc int-subtract/test_msa_subv_b.c \
-EL -static -mabi=32 -march=mips32r6 -mmsa -o /tmp/test_msa_subv_b_32r6el
/opt/img/bin/mips-img-linux-gnu-gcc int-subtract/test_msa_subv_h.c \
# Fixed Multiply
# --------------
#
+/opt/img/bin/mips-img-linux-gnu-gcc fixed-multiply/test_msa_madd_q_h.c \
+-EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_madd_q_h_64r6eb
+/opt/img/bin/mips-img-linux-gnu-gcc fixed-multiply/test_msa_madd_q_w.c \
+-EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_madd_q_w_64r6eb
+/opt/img/bin/mips-img-linux-gnu-gcc fixed-multiply/test_msa_maddr_q_h.c \
+-EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_maddr_q_h_64r6eb
+/opt/img/bin/mips-img-linux-gnu-gcc fixed-multiply/test_msa_maddr_q_w.c \
+-EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_maddr_q_w_64r6eb
+/opt/img/bin/mips-img-linux-gnu-gcc fixed-multiply/test_msa_msub_q_h.c \
+-EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_msub_q_h_64r6eb
+/opt/img/bin/mips-img-linux-gnu-gcc fixed-multiply/test_msa_msub_q_w.c \
+-EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_msub_q_w_64r6eb
+/opt/img/bin/mips-img-linux-gnu-gcc fixed-multiply/test_msa_msubr_q_h.c \
+-EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_msubr_q_h_64r6eb
+/opt/img/bin/mips-img-linux-gnu-gcc fixed-multiply/test_msa_msubr_q_w.c \
+-EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_msubr_q_w_64r6eb
/opt/img/bin/mips-img-linux-gnu-gcc fixed-multiply/test_msa_mul_q_h.c \
-EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_mul_q_h_64r6eb
/opt/img/bin/mips-img-linux-gnu-gcc fixed-multiply/test_msa_mul_q_w.c \
-EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_subs_u_w_64r6eb
/opt/img/bin/mips-img-linux-gnu-gcc int-subtract/test_msa_subs_u_d.c \
-EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_subs_u_d_64r6eb
-/opt/img/bin/mips-img-linux-gnu-gcc int-subtract/test_msa_subsuu_s_b.c \
--EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_subsuu_s_b_64r6eb
-/opt/img/bin/mips-img-linux-gnu-gcc int-subtract/test_msa_subsuu_s_h.c \
--EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_subsuu_s_h_64r6eb
-/opt/img/bin/mips-img-linux-gnu-gcc int-subtract/test_msa_subsuu_s_w.c \
--EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_subsuu_s_w_64r6eb
-/opt/img/bin/mips-img-linux-gnu-gcc int-subtract/test_msa_subsuu_s_d.c \
--EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_subsuu_s_d_64r6eb
/opt/img/bin/mips-img-linux-gnu-gcc int-subtract/test_msa_subsus_u_b.c \
-EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_subsus_u_b_64r6eb
/opt/img/bin/mips-img-linux-gnu-gcc int-subtract/test_msa_subsus_u_h.c \
-EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_subsus_u_w_64r6eb
/opt/img/bin/mips-img-linux-gnu-gcc int-subtract/test_msa_subsus_u_d.c \
-EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_subsus_u_d_64r6eb
+/opt/img/bin/mips-img-linux-gnu-gcc int-subtract/test_msa_subsuu_s_b.c \
+-EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_subsuu_s_b_64r6eb
+/opt/img/bin/mips-img-linux-gnu-gcc int-subtract/test_msa_subsuu_s_h.c \
+-EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_subsuu_s_h_64r6eb
+/opt/img/bin/mips-img-linux-gnu-gcc int-subtract/test_msa_subsuu_s_w.c \
+-EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_subsuu_s_w_64r6eb
+/opt/img/bin/mips-img-linux-gnu-gcc int-subtract/test_msa_subsuu_s_d.c \
+-EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_subsuu_s_d_64r6eb
/opt/img/bin/mips-img-linux-gnu-gcc int-subtract/test_msa_subv_b.c \
-EB -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_subv_b_64r6eb
/opt/img/bin/mips-img-linux-gnu-gcc int-subtract/test_msa_subv_h.c \
# Fixed Multiply
# --------------
#
+/opt/img/bin/mips-img-linux-gnu-gcc fixed-multiply/test_msa_madd_q_h.c \
+-EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_madd_q_h_64r6el
+/opt/img/bin/mips-img-linux-gnu-gcc fixed-multiply/test_msa_madd_q_w.c \
+-EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_madd_q_w_64r6el
+/opt/img/bin/mips-img-linux-gnu-gcc fixed-multiply/test_msa_maddr_q_h.c \
+-EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_maddr_q_h_64r6el
+/opt/img/bin/mips-img-linux-gnu-gcc fixed-multiply/test_msa_maddr_q_w.c \
+-EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_maddr_q_w_64r6el
+/opt/img/bin/mips-img-linux-gnu-gcc fixed-multiply/test_msa_msub_q_h.c \
+-EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_msub_q_h_64r6el
+/opt/img/bin/mips-img-linux-gnu-gcc fixed-multiply/test_msa_msub_q_w.c \
+-EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_msub_q_w_64r6el
+/opt/img/bin/mips-img-linux-gnu-gcc fixed-multiply/test_msa_msubr_q_h.c \
+-EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_msubr_q_h_64r6el
+/opt/img/bin/mips-img-linux-gnu-gcc fixed-multiply/test_msa_msubr_q_w.c \
+-EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_msubr_q_w_64r6el
/opt/img/bin/mips-img-linux-gnu-gcc fixed-multiply/test_msa_mul_q_h.c \
-EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_mul_q_h_64r6el
/opt/img/bin/mips-img-linux-gnu-gcc fixed-multiply/test_msa_mul_q_w.c \
-EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_subs_u_w_64r6el
/opt/img/bin/mips-img-linux-gnu-gcc int-subtract/test_msa_subs_u_d.c \
-EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_subs_u_d_64r6el
-/opt/img/bin/mips-img-linux-gnu-gcc int-subtract/test_msa_subsuu_s_b.c \
--EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_subsuu_s_b_64r6el
-/opt/img/bin/mips-img-linux-gnu-gcc int-subtract/test_msa_subsuu_s_h.c \
--EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_subsuu_s_h_64r6el
-/opt/img/bin/mips-img-linux-gnu-gcc int-subtract/test_msa_subsuu_s_w.c \
--EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_subsuu_s_w_64r6el
-/opt/img/bin/mips-img-linux-gnu-gcc int-subtract/test_msa_subsuu_s_d.c \
--EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_subsuu_s_d_64r6el
/opt/img/bin/mips-img-linux-gnu-gcc int-subtract/test_msa_subsus_u_b.c \
-EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_subsus_u_b_64r6el
/opt/img/bin/mips-img-linux-gnu-gcc int-subtract/test_msa_subsus_u_h.c \
-EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_subsus_u_w_64r6el
/opt/img/bin/mips-img-linux-gnu-gcc int-subtract/test_msa_subsus_u_d.c \
-EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_subsus_u_d_64r6el
+/opt/img/bin/mips-img-linux-gnu-gcc int-subtract/test_msa_subsuu_s_b.c \
+-EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_subsuu_s_b_64r6el
+/opt/img/bin/mips-img-linux-gnu-gcc int-subtract/test_msa_subsuu_s_h.c \
+-EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_subsuu_s_h_64r6el
+/opt/img/bin/mips-img-linux-gnu-gcc int-subtract/test_msa_subsuu_s_w.c \
+-EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_subsuu_s_w_64r6el
+/opt/img/bin/mips-img-linux-gnu-gcc int-subtract/test_msa_subsuu_s_d.c \
+-EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_subsuu_s_d_64r6el
/opt/img/bin/mips-img-linux-gnu-gcc int-subtract/test_msa_subv_b.c \
-EL -static -mabi=64 -march=mips64r6 -mmsa -o /tmp/test_msa_subv_b_64r6el
/opt/img/bin/mips-img-linux-gnu-gcc int-subtract/test_msa_subv_h.c \
# Fixed Multiply
# --------------
#
+$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_madd_q_h_32r6eb
+$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_madd_q_w_32r6eb
+$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_maddr_q_h_32r6eb
+$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_maddr_q_w_32r6eb
+$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_msub_q_h_32r6eb
+$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_msub_q_w_32r6eb
+$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_msubr_q_h_32r6eb
+$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_msubr_q_w_32r6eb
$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_mul_q_h_32r6eb
$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_mul_q_w_32r6eb
$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_mulr_q_h_32r6eb
$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_subs_u_h_32r6eb
$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_subs_u_w_32r6eb
$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_subs_u_d_32r6eb
-$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_subsuu_s_b_32r6eb
-$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_subsuu_s_h_32r6eb
-$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_subsuu_s_w_32r6eb
-$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_subsuu_s_d_32r6eb
$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_subsus_u_b_32r6eb
$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_subsus_u_h_32r6eb
$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_subsus_u_w_32r6eb
$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_subsus_u_d_32r6eb
+$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_subsuu_s_b_32r6eb
+$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_subsuu_s_h_32r6eb
+$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_subsuu_s_w_32r6eb
+$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_subsuu_s_d_32r6eb
$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_subv_b_32r6eb
$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_subv_h_32r6eb
$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_subv_w_32r6eb
# Fixed Multiply
# --------------
#
+$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_madd_q_h_32r6el
+$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_madd_q_w_32r6el
+$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_maddr_q_h_32r6el
+$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_maddr_q_w_32r6el
+$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_msub_q_h_32r6el
+$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_msub_q_w_32r6el
+$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_msubr_q_h_32r6el
+$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_msubr_q_w_32r6el
$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_mul_q_h_32r6el
$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_mul_q_w_32r6el
$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_mulr_q_h_32r6el
$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_subs_u_h_32r6el
$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_subs_u_w_32r6el
$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_subs_u_d_32r6el
-$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_subsuu_s_b_32r6el
-$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_subsuu_s_h_32r6el
-$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_subsuu_s_w_32r6el
-$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_subsuu_s_d_32r6el
$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_subsus_u_b_32r6el
$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_subsus_u_h_32r6el
$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_subsus_u_w_32r6el
$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_subsus_u_d_32r6el
+$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_subsuu_s_b_32r6el
+$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_subsuu_s_h_32r6el
+$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_subsuu_s_w_32r6el
+$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_subsuu_s_d_32r6el
$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_subv_b_32r6el
$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_subv_h_32r6el
$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_subv_w_32r6el
# Fixed Multiply
# --------------
#
+$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_madd_q_h_64r6eb
+$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_madd_q_w_64r6eb
+$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_maddr_q_h_64r6eb
+$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_maddr_q_w_64r6eb
+$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_msub_q_h_64r6eb
+$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_msub_q_w_64r6eb
+$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_msubr_q_h_64r6eb
+$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_msubr_q_w_64r6eb
$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_mul_q_h_64r6eb
$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_mul_q_w_64r6eb
$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_mulr_q_h_64r6eb
$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_subs_u_h_64r6eb
$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_subs_u_w_64r6eb
$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_subs_u_d_64r6eb
-$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_subsuu_s_b_64r6eb
-$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_subsuu_s_h_64r6eb
-$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_subsuu_s_w_64r6eb
-$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_subsuu_s_d_64r6eb
$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_subsus_u_b_64r6eb
$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_subsus_u_h_64r6eb
$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_subsus_u_w_64r6eb
$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_subsus_u_d_64r6eb
+$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_subsuu_s_b_64r6eb
+$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_subsuu_s_h_64r6eb
+$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_subsuu_s_w_64r6eb
+$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_subsuu_s_d_64r6eb
$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_subv_b_64r6eb
$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_subv_h_64r6eb
$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_subv_w_64r6eb
# Fixed Multiply
# --------------
#
+$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_madd_q_h_64r6el
+$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_madd_q_w_64r6el
+$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_maddr_q_h_64r6el
+$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_maddr_q_w_64r6el
+$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_msub_q_h_64r6el
+$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_msub_q_w_64r6el
+$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_msubr_q_h_64r6el
+$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_msubr_q_w_64r6el
$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_mul_q_h_64r6el
$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_mul_q_w_64r6el
$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_mulr_q_h_64r6el
$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_subs_u_h_64r6el
$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_subs_u_w_64r6el
$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_subs_u_d_64r6el
-$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_subsuu_s_b_64r6el
-$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_subsuu_s_h_64r6el
-$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_subsuu_s_w_64r6el
-$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_subsuu_s_d_64r6el
$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_subsus_u_b_64r6el
$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_subsus_u_h_64r6el
$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_subsus_u_w_64r6el
$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_subsus_u_d_64r6el
+$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_subsuu_s_b_64r6el
+$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_subsuu_s_h_64r6el
+$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_subsuu_s_w_64r6el
+$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_subsuu_s_d_64r6el
$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_subv_b_64r6el
$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_subv_h_64r6el
$PATH_TO_QEMU -cpu I6400 /tmp/test_msa_subv_w_64r6el
int main(void)
{
- uint64_t parmlist[] = {
+ uint64_t parmlist[] __attribute__((aligned(16))) = {
0xfedcba9876543210ull,
0,
0x7777777777777777ull,
} \
} while (0)
+enum {
+ VHOST_USER_BRIDGE_MAX_QUEUES = 8,
+};
+
typedef void (*CallbackFunc)(int sock, void *ctx);
typedef struct Event {
}
DPRINT("Got connection from remote peer on sock %d\n", conn_fd);
- vu_init(&dev->vudev,
- conn_fd,
- vubr_panic,
- vubr_set_watch,
- vubr_remove_watch,
- &vuiface);
+ if (!vu_init(&dev->vudev,
+ VHOST_USER_BRIDGE_MAX_QUEUES,
+ conn_fd,
+ vubr_panic,
+ vubr_set_watch,
+ vubr_remove_watch,
+ &vuiface)) {
+ fprintf(stderr, "Failed to initialize libvhost-user\n");
+ exit(1);
+ }
dispatcher_add(&dev->dispatcher, conn_fd, ctx, vubr_receive_cb);
dispatcher_remove(&dev->dispatcher, sock);
if (connect(dev->sock, (struct sockaddr *)&un, len) == -1) {
vubr_die("connect");
}
- vu_init(&dev->vudev,
- dev->sock,
- vubr_panic,
- vubr_set_watch,
- vubr_remove_watch,
- &vuiface);
+
+ if (!vu_init(&dev->vudev,
+ VHOST_USER_BRIDGE_MAX_QUEUES,
+ dev->sock,
+ vubr_panic,
+ vubr_set_watch,
+ vubr_remove_watch,
+ &vuiface)) {
+ fprintf(stderr, "Failed to initialize libvhost-user\n");
+ exit(1);
+ }
+
cb = vubr_receive_cb;
}
int qidx;
while (true) {
- for (qidx = 0; qidx < VHOST_MAX_NR_VIRTQUEUE; qidx++) {
+ for (qidx = 0; qidx < VHOST_USER_BRIDGE_MAX_QUEUES; qidx++) {
uint16_t *n = vubr->notifier.addr + pagesize * qidx;
if (*n == qidx) {
void *addr;
int fd;
- length = getpagesize() * VHOST_MAX_NR_VIRTQUEUE;
+ length = getpagesize() * VHOST_USER_BRIDGE_MAX_QUEUES;
fd = mkstemp(template);
if (fd < 0) {
QDict *rsp;
int ret;
uint16_t *proto = (uint16_t *)&buffer[12];
+ size_t total_received = 0;
+ uint64_t start, now, last_rxt, deadline;
+ /* Send a set of packets over a few second period */
rsp = qmp("{ 'execute' : 'announce-self', "
" 'arguments': {"
- " 'initial': 50, 'max': 550,"
- " 'rounds': 10, 'step': 50 } }");
+ " 'initial': 20, 'max': 100,"
+ " 'rounds': 300, 'step': 10, 'id': 'bob' } }");
assert(!qdict_haskey(rsp, "error"));
qobject_unref(rsp);
- /* Catch the packet and make sure it's a RARP */
+ /* Catch the first packet and make sure it's a RARP */
ret = qemu_recv(sv[0], &len, sizeof(len), 0);
g_assert_cmpint(ret, ==, sizeof(len));
len = ntohl(len);
ret = qemu_recv(sv[0], buffer, len, 0);
g_assert_cmpint(*proto, ==, htons(ETH_P_RARP));
+
+ /*
+ * Stop the announcment by settings rounds to 0 on the
+ * existing timer.
+ */
+ rsp = qmp("{ 'execute' : 'announce-self', "
+ " 'arguments': {"
+ " 'initial': 20, 'max': 100,"
+ " 'rounds': 0, 'step': 10, 'id': 'bob' } }");
+ assert(!qdict_haskey(rsp, "error"));
+ qobject_unref(rsp);
+
+ /* Now make sure the packets stop */
+
+ /* Times are in us */
+ start = g_get_monotonic_time();
+ /* 30 packets, max gap 100ms, * 4 for wiggle */
+ deadline = start + 1000 * (100 * 30 * 4);
+ last_rxt = start;
+
+ while (true) {
+ int saved_err;
+ ret = qemu_recv(sv[0], buffer, 60, MSG_DONTWAIT);
+ saved_err = errno;
+ now = g_get_monotonic_time();
+ g_assert_cmpint(now, <, deadline);
+
+ if (ret >= 0) {
+ if (ret) {
+ last_rxt = now;
+ }
+ total_received += ret;
+
+ /* Check it's not spewing loads */
+ g_assert_cmpint(total_received, <, 60 * 30 * 2);
+ } else {
+ g_assert_cmpint(saved_err, ==, EAGAIN);
+
+ /* 400ms, i.e. 4 worst case gaps */
+ if ((now - last_rxt) > (1000 * 100 * 4)) {
+ /* Nothings arrived for a while - must have stopped */
+ break;
+ };
+
+ /* 100ms */
+ g_usleep(1000 * 100);
+ }
+ };
}
static void virtio_net_test_cleanup(void *sockets)
.PHONY: vm-build-all vm-clean-all
-IMAGES := ubuntu.i386 freebsd netbsd openbsd centos
+IMAGES := ubuntu.i386 freebsd netbsd openbsd centos fedora
IMAGES_DIR := $(HOME)/.cache/qemu-vm/images
IMAGE_FILES := $(patsubst %, $(IMAGES_DIR)/%.img, $(IMAGES))
.PRECIOUS: $(IMAGE_FILES)
-vm-test:
- @echo "vm-test: Test QEMU in preconfigured virtual machines"
+# 'vm-help' target was historically named 'vm-test'
+vm-help vm-test:
+ @echo "vm-help: Test QEMU in preconfigured virtual machines"
@echo
@echo " vm-build-ubuntu.i386 - Build QEMU in ubuntu i386 VM"
@echo " vm-build-freebsd - Build QEMU in FreeBSD VM"
@echo " vm-build-netbsd - Build QEMU in NetBSD VM"
@echo " vm-build-openbsd - Build QEMU in OpenBSD VM"
@echo " vm-build-centos - Build QEMU in CentOS VM, with Docker"
+ @echo " vm-build-fedora - Build QEMU in Fedora VM"
@echo ""
@echo " vm-build-all - Build QEMU in all VMs"
@echo " vm-clean-all - Clean up VM images"
@echo
+ @echo "For trouble-shooting:"
+ @echo " vm-boot-serial-<guest> - Boot guest, serial console on stdio"
+ @echo " vm-boot-ssh-<guest> - Boot guest and login via ssh"
+ @echo
@echo "Special variables:"
@echo " BUILD_TARGET=foo - Override the build target"
@echo " TARGET_LIST=a,b,c - Override target list in builds"
$(if $(V),--verbose) \
--image "$<" \
$(if $(BUILD_TARGET),--build-target $(BUILD_TARGET)) \
+ --snapshot \
--build-qemu $(SRC_PATH) -- \
$(if $(TARGET_LIST),--target-list=$(TARGET_LIST)) \
$(if $(EXTRA_CONFIGURE_OPTS),$(EXTRA_CONFIGURE_OPTS)), \
" VM-BUILD $*")
+vm-boot-serial-%: $(IMAGES_DIR)/%.img
+ qemu-system-x86_64 -enable-kvm -m 4G -smp 2 -nographic \
+ -drive if=none,id=vblk,cache=writeback,file="$<" \
+ -netdev user,id=vnet \
+ -device virtio-blk-pci,drive=vblk \
+ -device virtio-net-pci,netdev=vnet \
+ || true
+
+vm-boot-ssh-%: $(IMAGES_DIR)/%.img
+ $(call quiet-command, \
+ $(SRC_PATH)/tests/vm/$* \
+ --image "$<" \
+ --interactive \
+ false, \
+ " VM-BOOT-SSH $*") || true
#
# VM testing base class
#
-# Copyright 2017 Red Hat Inc.
+# Copyright 2017-2019 Red Hat Inc.
#
# Authors:
# Fam Zheng <famz@redhat.com>
+# Gerd Hoffmann <kraxel@redhat.com>
#
# This code is licensed under the GPL version 2 or later. See
# the COPYING file in the top-level directory.
from __future__ import print_function
import os
+import re
import sys
+import socket
import logging
import time
import datetime
sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..', 'python'))
-from qemu import QEMUMachine, kvm_available
+from qemu import kvm_available
+from qemu.machine import QEMUMachine
import subprocess
import hashlib
import optparse
GUEST_PASS = "qemupass"
ROOT_PASS = "qemupass"
+ envvars = [
+ "https_proxy",
+ "http_proxy",
+ "ftp_proxy",
+ "no_proxy",
+ ]
+
# The script to run in the guest that builds QEMU
BUILD_SCRIPT = ""
# The guest name, to be overridden by subclasses
name = "#base"
# The guest architecture, to be overridden by subclasses
arch = "#arch"
+ # command to halt the guest, can be overridden by subclasses
+ poweroff = "poweroff"
def __init__(self, debug=False, vcpus=None):
self._guest = None
self._tmpdir = os.path.realpath(tempfile.mkdtemp(prefix="vm-test-",
"-cpu", "max",
"-netdev", "user,id=vnet,hostfwd=:127.0.0.1:0-:22",
"-device", "virtio-net-pci,netdev=vnet",
- "-vnc", "127.0.0.1:0,to=20",
- "-serial", "file:%s" % os.path.join(self._tmpdir, "serial.out")]
+ "-vnc", "127.0.0.1:0,to=20"]
if vcpus and vcpus > 1:
self._args += ["-smp", "%d" % vcpus]
if kvm_available(self.arch):
os.rename(fname + ".download", fname)
return fname
- def _ssh_do(self, user, cmd, check, interactive=False):
- ssh_cmd = ["ssh", "-q",
+ def _ssh_do(self, user, cmd, check):
+ ssh_cmd = ["ssh", "-q", "-t",
"-o", "StrictHostKeyChecking=no",
"-o", "UserKnownHostsFile=" + os.devnull,
"-o", "ConnectTimeout=1",
"-p", self.ssh_port, "-i", self._ssh_key_file]
- if interactive:
- ssh_cmd += ['-t']
+ for var in self.envvars:
+ ssh_cmd += ['-o', "SendEnv=%s" % var ]
assert not isinstance(cmd, str)
ssh_cmd += ["%s@127.0.0.1" % user] + list(cmd)
logging.debug("ssh_cmd: %s", " ".join(ssh_cmd))
def ssh(self, *cmd):
return self._ssh_do(self.GUEST_USER, cmd, False)
- def ssh_interactive(self, *cmd):
- return self._ssh_do(self.GUEST_USER, cmd, False, True)
-
def ssh_root(self, *cmd):
return self._ssh_do("root", cmd, False)
logging.debug("QEMU args: %s", " ".join(args))
qemu_bin = os.environ.get("QEMU", "qemu-system-" + self.arch)
guest = QEMUMachine(binary=qemu_bin, args=args)
+ guest.set_machine('pc')
+ guest.set_console()
try:
guest.launch()
except:
raise Exception("Cannot find ssh port from 'info usernet':\n%s" % \
usernet_info)
+ def console_init(self, timeout = 120):
+ vm = self._guest
+ vm.console_socket.settimeout(timeout)
+
+ def console_log(self, text):
+ for line in re.split("[\r\n]", text):
+ # filter out terminal escape sequences
+ line = re.sub("\x1b\[[0-9;?]*[a-zA-Z]", "", line)
+ line = re.sub("\x1b\([0-9;?]*[a-zA-Z]", "", line)
+ # replace unprintable chars
+ line = re.sub("\x1b", "<esc>", line)
+ line = re.sub("[\x00-\x1f]", ".", line)
+ line = re.sub("[\x80-\xff]", ".", line)
+ if line == "":
+ continue
+ # log console line
+ sys.stderr.write("con recv: %s\n" % line)
+
+ def console_wait(self, expect, expectalt = None):
+ vm = self._guest
+ output = ""
+ while True:
+ try:
+ chars = vm.console_socket.recv(1)
+ except socket.timeout:
+ sys.stderr.write("console: *** read timeout ***\n")
+ sys.stderr.write("console: waiting for: '%s'\n" % expect)
+ if not expectalt is None:
+ sys.stderr.write("console: waiting for: '%s' (alt)\n" % expectalt)
+ sys.stderr.write("console: line buffer:\n")
+ sys.stderr.write("\n")
+ self.console_log(output.rstrip())
+ sys.stderr.write("\n")
+ raise
+ output += chars.decode("latin1")
+ if expect in output:
+ break
+ if not expectalt is None and expectalt in output:
+ break
+ if "\r" in output or "\n" in output:
+ lines = re.split("[\r\n]", output)
+ output = lines.pop()
+ if self.debug:
+ self.console_log("\n".join(lines))
+ if self.debug:
+ self.console_log(output)
+ if not expectalt is None and expectalt in output:
+ return False
+ return True
+
+ def console_send(self, command):
+ vm = self._guest
+ if self.debug:
+ logline = re.sub("\n", "<enter>", command)
+ logline = re.sub("[\x00-\x1f]", ".", logline)
+ sys.stderr.write("con send: %s\n" % logline)
+ for char in list(command):
+ vm.console_socket.send(char.encode("utf-8"))
+ time.sleep(0.01)
+
+ def console_wait_send(self, wait, command):
+ self.console_wait(wait)
+ self.console_send(command)
+
+ def console_ssh_init(self, prompt, user, pw):
+ sshkey_cmd = "echo '%s' > .ssh/authorized_keys\n" % SSH_PUB_KEY.rstrip()
+ self.console_wait_send("login:", "%s\n" % user)
+ self.console_wait_send("Password:", "%s\n" % pw)
+ self.console_wait_send(prompt, "mkdir .ssh\n")
+ self.console_wait_send(prompt, sshkey_cmd)
+ self.console_wait_send(prompt, "chmod 755 .ssh\n")
+ self.console_wait_send(prompt, "chmod 644 .ssh/authorized_keys\n")
+
+ def console_sshd_config(self, prompt):
+ self.console_wait(prompt)
+ self.console_send("echo 'PermitRootLogin yes' >> /etc/ssh/sshd_config\n")
+ for var in self.envvars:
+ self.console_wait(prompt)
+ self.console_send("echo 'AcceptEnv %s' >> /etc/ssh/sshd_config\n" % var)
+
+ def print_step(self, text):
+ sys.stderr.write("### %s ...\n" % text)
+
def wait_ssh(self, seconds=300):
starttime = datetime.datetime.now()
endtime = starttime + datetime.timedelta(seconds=seconds)
def wait(self):
self._guest.wait()
+ def graceful_shutdown(self):
+ self.ssh_root(self.poweroff)
+ self._guest.wait()
+
def qmp(self, *args, **kwargs):
return self._guest.qmp(*args, **kwargs)
traceback.print_exc()
return 2
- if args.interactive:
- if vm.ssh_interactive(*cmd) == 0:
- return 0
- vm.ssh_interactive()
- return 3
- else:
- if vm.ssh(*cmd) != 0:
- return 3
+ exitcode = 0
+ if vm.ssh(*cmd) != 0:
+ exitcode = 3
+ if exitcode != 0 and args.interactive:
+ vm.ssh()
+
+ if not args.snapshot:
+ vm.graceful_shutdown()
+
+ return exitcode
cimg = self._download_with_cache("https://cloud.centos.org/centos/7/images/CentOS-7-x86_64-GenericCloud-1802.qcow2.xz")
img_tmp = img + ".tmp"
sys.stderr.write("Extracting the image...\n")
- subprocess.check_call(["cp", "-f", cimg, img_tmp + ".xz"])
- subprocess.check_call(["xz", "-dvf", img_tmp + ".xz"])
+ subprocess.check_call(["ln", "-f", cimg, img_tmp + ".xz"])
+ subprocess.check_call(["xz", "--keep", "-dvf", img_tmp + ".xz"])
subprocess.check_call(["qemu-img", "resize", img_tmp, "50G"])
self.boot(img_tmp, extra_args = ["-cdrom", self._gen_cloud_init_iso()])
self.wait_ssh()
self.ssh_root_check("systemctl enable docker")
self.ssh_root("poweroff")
self.wait()
- if os.path.exists(img):
- os.remove(img)
os.rename(img_tmp, img)
return 0
--- /dev/null
+#!/usr/bin/env python
+#
+# Fedora VM image
+#
+# Copyright 2019 Red Hat Inc.
+#
+# Authors:
+# Gerd Hoffmann <kraxel@redhat.com>
+#
+# This code is licensed under the GPL version 2 or later. See
+# the COPYING file in the top-level directory.
+#
+
+import os
+import re
+import sys
+import time
+import socket
+import subprocess
+import basevm
+
+class FedoraVM(basevm.BaseVM):
+ name = "fedora"
+ arch = "x86_64"
+
+ base = "http://dl.fedoraproject.org/pub/fedora/linux/releases/30/"
+ link = base + "Server/x86_64/iso/Fedora-Server-netinst-x86_64-30-1.2.iso"
+ repo = base + "Server/x86_64/os/"
+ full = base + "Everything/x86_64/os/"
+ csum = "5e4eac4566d8c572bfb3bcf54b7d6c82006ec3c6c882a2c9235c6d3494d7b100"
+ size = "20G"
+ pkgs = [
+ # tools
+ 'git-core',
+ 'flex', 'bison',
+ 'gcc', 'binutils', 'make',
+
+ # perl
+ 'perl-Test-Harness',
+
+ # libs: usb
+ '"pkgconfig(libusb-1.0)"',
+ '"pkgconfig(libusbredirparser-0.5)"',
+
+ # libs: crypto
+ '"pkgconfig(gnutls)"',
+
+ # libs: ui
+ '"pkgconfig(sdl2)"',
+ '"pkgconfig(gtk+-3.0)"',
+ '"pkgconfig(ncursesw)"',
+
+ # libs: audio
+ '"pkgconfig(libpulse)"',
+ '"pkgconfig(alsa)"',
+ ]
+
+ BUILD_SCRIPT = """
+ set -e;
+ rm -rf /home/qemu/qemu-test.*
+ cd $(mktemp -d /home/qemu/qemu-test.XXXXXX);
+ mkdir src build; cd src;
+ tar -xf /dev/vdb;
+ cd ../build
+ ../src/configure --python=python3 {configure_opts};
+ gmake --output-sync -j{jobs} {target} {verbose};
+ """
+
+ def build_image(self, img):
+ self.print_step("Downloading install iso")
+ cimg = self._download_with_cache(self.link, sha256sum=self.csum)
+ img_tmp = img + ".tmp"
+ iso = img + ".install.iso"
+
+ self.print_step("Preparing iso and disk image")
+ subprocess.check_call(["cp", "-f", cimg, iso])
+ subprocess.check_call(["qemu-img", "create", "-f", "qcow2",
+ img_tmp, self.size])
+
+ self.print_step("Booting installer")
+ self.boot(img_tmp, extra_args = [
+ "-bios", "pc-bios/bios-256k.bin",
+ "-machine", "graphics=off",
+ "-cdrom", iso
+ ])
+ self.console_init(300)
+ self.console_wait("installation process.")
+ time.sleep(0.3)
+ self.console_send("\t")
+ time.sleep(0.3)
+ self.console_send(" console=ttyS0")
+ proxy = os.environ.get("http_proxy")
+ if not proxy is None:
+ self.console_send(" proxy=%s" % proxy)
+ self.console_send(" inst.proxy=%s" % proxy)
+ self.console_send(" inst.repo=%s" % self.repo)
+ self.console_send("\n")
+
+ self.console_wait_send("2) Use text mode", "2\n")
+
+ self.console_wait_send("5) [!] Installation Dest", "5\n")
+ self.console_wait_send("1) [x]", "c\n")
+ self.console_wait_send("2) [ ] Use All Space", "2\n")
+ self.console_wait_send("2) [x] Use All Space", "c\n")
+ self.console_wait_send("1) [ ] Standard Part", "1\n")
+ self.console_wait_send("1) [x] Standard Part", "c\n")
+
+ self.console_wait_send("7) [!] Root password", "7\n")
+ self.console_wait("Password:")
+ self.console_send("%s\n" % self.ROOT_PASS)
+ self.console_wait("Password (confirm):")
+ self.console_send("%s\n" % self.ROOT_PASS)
+
+ self.console_wait_send("8) [ ] User creation", "8\n")
+ self.console_wait_send("1) [ ] Create user", "1\n")
+ self.console_wait_send("3) User name", "3\n")
+ self.console_wait_send("ENTER:", "%s\n" % self.GUEST_USER)
+ self.console_wait_send("4) [ ] Use password", "4\n")
+ self.console_wait_send("5) Password", "5\n")
+ self.console_wait("Password:")
+ self.console_send("%s\n" % self.GUEST_PASS)
+ self.console_wait("Password (confirm):")
+ self.console_send("%s\n" % self.GUEST_PASS)
+ self.console_wait_send("7) Groups", "c\n")
+
+ while True:
+ good = self.console_wait("3) [x] Installation",
+ "3) [!] Installation")
+ self.console_send("r\n")
+ if good:
+ break
+ time.sleep(10)
+
+ while True:
+ good = self.console_wait("4) [x] Software",
+ "4) [!] Software")
+ self.console_send("r\n")
+ if good:
+ break
+ time.sleep(10)
+ self.console_send("r\n" % self.GUEST_PASS)
+
+ self.console_wait_send("'b' to begin install", "b\n")
+
+ self.print_step("Installation started now, this will take a while")
+
+ self.console_wait_send("Installation complete", "\n")
+ self.print_step("Installation finished, rebooting")
+
+ # setup qemu user
+ prompt = " ~]$"
+ self.console_ssh_init(prompt, self.GUEST_USER, self.GUEST_PASS)
+ self.console_wait_send(prompt, "exit\n")
+
+ # setup root user
+ prompt = " ~]#"
+ self.console_ssh_init(prompt, "root", self.ROOT_PASS)
+ self.console_sshd_config(prompt)
+
+ # setup virtio-blk #1 (tarfile)
+ self.console_wait(prompt)
+ self.console_send("echo 'KERNEL==\"vdb\" MODE=\"666\"' >> %s\n" %
+ "/etc/udev/rules.d/99-qemu.rules")
+
+ self.print_step("Configuration finished, rebooting")
+ self.console_wait_send(prompt, "reboot\n")
+ self.console_wait("login:")
+ self.wait_ssh()
+
+ self.print_step("Installing packages")
+ self.ssh_root_check("rm -vf /etc/yum.repos.d/fedora*.repo\n")
+ self.ssh_root_check("echo '[fedora]' >> /etc/yum.repos.d/qemu.repo\n")
+ self.ssh_root_check("echo 'baseurl=%s' >> /etc/yum.repos.d/qemu.repo\n" % self.full)
+ self.ssh_root_check("echo 'gpgcheck=0' >> /etc/yum.repos.d/qemu.repo\n")
+ self.ssh_root_check("dnf install -y %s\n" % " ".join(self.pkgs))
+
+ # shutdown
+ self.ssh_root(self.poweroff)
+ self.console_wait("sleep state S5")
+ self.wait()
+
+ if os.path.exists(img):
+ os.remove(img)
+ os.rename(img_tmp, img)
+ os.remove(iso)
+ self.print_step("All done")
+
+if __name__ == "__main__":
+ sys.exit(basevm.main(FedoraVM))
#
# FreeBSD VM image
#
-# Copyright 2017 Red Hat Inc.
+# Copyright 2017-2019 Red Hat Inc.
#
# Authors:
# Fam Zheng <famz@redhat.com>
+# Gerd Hoffmann <kraxel@redhat.com>
#
# This code is licensed under the GPL version 2 or later. See
# the COPYING file in the top-level directory.
#
import os
+import re
import sys
+import time
+import socket
import subprocess
import basevm
class FreeBSDVM(basevm.BaseVM):
name = "freebsd"
arch = "x86_64"
+
+ link = "https://download.freebsd.org/ftp/releases/ISO-IMAGES/12.0/FreeBSD-12.0-RELEASE-amd64-disc1.iso.xz"
+ csum = "1d40015bea89d05b8bd13e2ed80c40b522a9ec1abd8e7c8b80954fb485fb99db"
+ size = "20G"
+ pkgs = [
+ # build tools
+ "git",
+ "pkgconf",
+ "bzip2",
+
+ # gnu tools
+ "bash",
+ "gmake",
+ "gsed",
+ "flex", "bison",
+
+ # libs: crypto
+ "gnutls",
+
+ # libs: images
+ "jpeg-turbo",
+ "png",
+
+ # libs: ui
+ "sdl2",
+ "gtk3",
+ "libxkbcommon",
+
+ # libs: opengl
+ "libepoxy",
+ "mesa-libs",
+ ]
+
BUILD_SCRIPT = """
set -e;
- rm -rf /var/tmp/qemu-test.*
- cd $(mktemp -d /var/tmp/qemu-test.XXXXXX);
+ rm -rf /home/qemu/qemu-test.*
+ cd $(mktemp -d /home/qemu/qemu-test.XXXXXX);
+ mkdir src build; cd src;
tar -xf /dev/vtbd1;
- ./configure {configure_opts};
+ cd ../build
+ ../src/configure --python=python3.6 {configure_opts};
gmake --output-sync -j{jobs} {target} {verbose};
"""
+ def console_boot_serial(self):
+ self.console_wait_send("Autoboot", "3")
+ self.console_wait_send("OK", "set console=comconsole\n")
+ self.console_wait_send("OK", "boot\n")
+
def build_image(self, img):
- cimg = self._download_with_cache("http://download.patchew.org/freebsd-11.1-amd64.img.xz",
- sha256sum='adcb771549b37bc63826c501f05121a206ed3d9f55f49145908f7e1432d65891')
- img_tmp_xz = img + ".tmp.xz"
+ self.print_step("Downloading install iso")
+ cimg = self._download_with_cache(self.link, sha256sum=self.csum)
img_tmp = img + ".tmp"
- sys.stderr.write("Extracting the image...\n")
- subprocess.check_call(["cp", "-f", cimg, img_tmp_xz])
- subprocess.check_call(["xz", "-dvf", img_tmp_xz])
+ iso = img + ".install.iso"
+ iso_xz = iso + ".xz"
+
+ self.print_step("Preparing iso and disk image")
+ subprocess.check_call(["cp", "-f", cimg, iso_xz])
+ subprocess.check_call(["xz", "-dvf", iso_xz])
+ subprocess.check_call(["qemu-img", "create", "-f", "qcow2",
+ img_tmp, self.size])
+
+ self.print_step("Booting installer")
+ self.boot(img_tmp, extra_args = [
+ "-bios", "pc-bios/bios-256k.bin",
+ "-machine", "graphics=off",
+ "-cdrom", iso
+ ])
+ self.console_init()
+ self.console_boot_serial()
+ self.console_wait_send("Console type", "xterm\n")
+
+ # pre-install configuration
+ self.console_wait_send("Welcome", "\n")
+ self.console_wait_send("Keymap Selection", "\n")
+ self.console_wait_send("Set Hostname", "freebsd\n")
+ self.console_wait_send("Distribution Select", "\n")
+ self.console_wait_send("Partitioning", "\n")
+ self.console_wait_send("Partition", "\n")
+ self.console_wait_send("Scheme", "\n")
+ self.console_wait_send("Editor", "f")
+ self.console_wait_send("Confirmation", "c")
+
+ self.print_step("Installation started now, this will take a while")
+
+ # post-install configuration
+ self.console_wait("New Password:")
+ self.console_send("%s\n" % self.ROOT_PASS)
+ self.console_wait("Retype New Password:")
+ self.console_send("%s\n" % self.ROOT_PASS)
+
+ self.console_wait_send("Network Configuration", "\n")
+ self.console_wait_send("IPv4", "y")
+ self.console_wait_send("DHCP", "y")
+ self.console_wait_send("IPv6", "n")
+ self.console_wait_send("Resolver", "\n")
+
+ self.console_wait_send("Time Zone Selector", "a\n")
+ self.console_wait_send("Confirmation", "y")
+ self.console_wait_send("Time & Date", "\n")
+ self.console_wait_send("Time & Date", "\n")
+
+ self.console_wait_send("System Configuration", "\n")
+ self.console_wait_send("System Hardening", "\n")
+
+ # qemu user
+ self.console_wait_send("Add User Accounts", "y")
+ self.console_wait("Username")
+ self.console_send("%s\n" % self.GUEST_USER)
+ self.console_wait("Full name")
+ self.console_send("%s\n" % self.GUEST_USER)
+ self.console_wait_send("Uid", "\n")
+ self.console_wait_send("Login group", "\n")
+ self.console_wait_send("Login group", "\n")
+ self.console_wait_send("Login class", "\n")
+ self.console_wait_send("Shell", "\n")
+ self.console_wait_send("Home directory", "\n")
+ self.console_wait_send("Home directory perm", "\n")
+ self.console_wait_send("Use password", "\n")
+ self.console_wait_send("Use an empty password", "\n")
+ self.console_wait_send("Use a random password", "\n")
+ self.console_wait("Enter password:")
+ self.console_send("%s\n" % self.GUEST_PASS)
+ self.console_wait("Enter password again:")
+ self.console_send("%s\n" % self.GUEST_PASS)
+ self.console_wait_send("Lock out", "\n")
+ self.console_wait_send("OK", "yes\n")
+ self.console_wait_send("Add another user", "no\n")
+
+ self.console_wait_send("Final Configuration", "\n")
+ self.console_wait_send("Manual Configuration", "\n")
+ self.console_wait_send("Complete", "\n")
+
+ self.print_step("Installation finished, rebooting")
+ self.console_boot_serial()
+
+ # setup qemu user
+ prompt = "$"
+ self.console_ssh_init(prompt, self.GUEST_USER, self.GUEST_PASS)
+ self.console_wait_send(prompt, "exit\n")
+
+ # setup root user
+ prompt = "root@freebsd:~ #"
+ self.console_ssh_init(prompt, "root", self.ROOT_PASS)
+ self.console_sshd_config(prompt)
+
+ # setup serial console
+ self.console_wait(prompt)
+ self.console_send("echo 'console=comconsole' >> /boot/loader.conf\n")
+
+ # setup boot delay
+ self.console_wait(prompt)
+ self.console_send("echo 'autoboot_delay=1' >> /boot/loader.conf\n")
+
+ # setup virtio-blk #1 (tarfile)
+ self.console_wait(prompt)
+ self.console_send("echo 'chmod 666 /dev/vtbd1' >> /etc/rc.local\n")
+
+ self.print_step("Configuration finished, rebooting")
+ self.console_wait_send(prompt, "reboot\n")
+ self.console_wait("login:")
+ self.wait_ssh()
+
+ self.print_step("Installing packages")
+ self.ssh_root_check("pkg install -y %s\n" % " ".join(self.pkgs))
+
+ # shutdown
+ self.ssh_root(self.poweroff)
+ self.console_wait("Uptime:")
+ self.wait()
+
if os.path.exists(img):
os.remove(img)
os.rename(img_tmp, img)
+ os.remove(iso)
+ self.print_step("All done")
if __name__ == "__main__":
sys.exit(basevm.main(FreeBSDVM))
img_tmp_xz = img + ".tmp.xz"
img_tmp = img + ".tmp"
sys.stderr.write("Extracting the image...\n")
- subprocess.check_call(["cp", "-f", cimg, img_tmp_xz])
- subprocess.check_call(["xz", "-dvf", img_tmp_xz])
- if os.path.exists(img):
- os.remove(img)
+ subprocess.check_call(["ln", "-f", cimg, img_tmp_xz])
+ subprocess.check_call(["xz", "--keep", "-dvf", img_tmp_xz])
os.rename(img_tmp, img)
if __name__ == "__main__":
#
# OpenBSD VM image
#
-# Copyright 2017 Red Hat Inc.
+# Copyright 2017-2019 Red Hat Inc.
#
# Authors:
# Fam Zheng <famz@redhat.com>
+# Gerd Hoffmann <kraxel@redhat.com>
#
# This code is licensed under the GPL version 2 or later. See
# the COPYING file in the top-level directory.
import os
import sys
+import socket
import subprocess
import basevm
class OpenBSDVM(basevm.BaseVM):
name = "openbsd"
arch = "x86_64"
+
+ link = "https://cdn.openbsd.org/pub/OpenBSD/6.5/amd64/install65.iso"
+ csum = "38d1f8cadd502f1c27bf05c5abde6cc505dd28f3f34f8a941048ff9a54f9f608"
+ size = "20G"
+ pkgs = [
+ # tools
+ "git",
+ "pkgconf",
+ "bzip2", "xz",
+
+ # gnu tools
+ "bash",
+ "gmake",
+ "gsed",
+ "bison",
+
+ # libs: usb
+ "libusb1",
+
+ # libs: crypto
+ "gnutls",
+
+ # libs: images
+ "jpeg",
+ "png",
+
+ # libs: ui
+ "sdl2",
+ "gtk+3",
+ "libxkbcommon",
+ ]
+
BUILD_SCRIPT = """
set -e;
- rm -rf /var/tmp/qemu-test.*
- cd $(mktemp -d /var/tmp/qemu-test.XXXXXX);
+ rm -rf /home/qemu/qemu-test.*
+ cd $(mktemp -d /home/qemu/qemu-test.XXXXXX);
+ mkdir src build; cd src;
tar -xf /dev/rsd1c;
- ./configure --cc=x86_64-unknown-openbsd6.1-gcc-4.9.4 --python=python2.7 {configure_opts};
- gmake --output-sync -j{jobs} {verbose};
- # XXX: "gmake check" seems to always hang or fail
- #gmake --output-sync -j{jobs} check {verbose};
+ cd ../build
+ ../src/configure --cc=cc --python=python3 {configure_opts};
+ gmake --output-sync -j{jobs} {target} {verbose};
"""
+ poweroff = "halt -p"
def build_image(self, img):
- cimg = self._download_with_cache("http://download.patchew.org/openbsd-6.1-amd64.img.xz",
- sha256sum='8c6cedc483e602cfee5e04f0406c64eb99138495e8ca580bc0293bcf0640c1bf')
- img_tmp_xz = img + ".tmp.xz"
+ self.print_step("Downloading install iso")
+ cimg = self._download_with_cache(self.link, sha256sum=self.csum)
img_tmp = img + ".tmp"
- sys.stderr.write("Extracting the image...\n")
- subprocess.check_call(["cp", "-f", cimg, img_tmp_xz])
- subprocess.check_call(["xz", "-dvf", img_tmp_xz])
+ iso = img + ".install.iso"
+
+ self.print_step("Preparing iso and disk image")
+ subprocess.check_call(["cp", "-f", cimg, iso])
+ subprocess.check_call(["qemu-img", "create", "-f", "qcow2",
+ img_tmp, self.size])
+
+ self.print_step("Booting installer")
+ self.boot(img_tmp, extra_args = [
+ "-bios", "pc-bios/bios-256k.bin",
+ "-machine", "graphics=off",
+ "-cdrom", iso
+ ])
+ self.console_init()
+ self.console_wait_send("boot>", "set tty com0\n")
+ self.console_wait_send("boot>", "\n")
+
+ # pre-install configuration
+ self.console_wait_send("(I)nstall", "i\n")
+ self.console_wait_send("Terminal type", "xterm\n")
+ self.console_wait_send("System hostname", "openbsd\n")
+ self.console_wait_send("Which network interface", "vio0\n")
+ self.console_wait_send("IPv4 address", "dhcp\n")
+ self.console_wait_send("IPv6 address", "none\n")
+ self.console_wait_send("Which network interface", "done\n")
+ self.console_wait_send("DNS domain name", "localnet\n")
+ self.console_wait("Password for root account")
+ self.console_send("%s\n" % self.ROOT_PASS)
+ self.console_wait("Password for root account")
+ self.console_send("%s\n" % self.ROOT_PASS)
+ self.console_wait_send("Start sshd(8)", "yes\n")
+ self.console_wait_send("X Window System", "\n")
+ self.console_wait_send("xenodm", "\n")
+ self.console_wait_send("console to com0", "\n")
+ self.console_wait_send("Which speed", "\n")
+
+ self.console_wait("Setup a user")
+ self.console_send("%s\n" % self.GUEST_USER)
+ self.console_wait("Full name")
+ self.console_send("%s\n" % self.GUEST_USER)
+ self.console_wait("Password")
+ self.console_send("%s\n" % self.GUEST_PASS)
+ self.console_wait("Password")
+ self.console_send("%s\n" % self.GUEST_PASS)
+
+ self.console_wait_send("Allow root ssh login", "yes\n")
+ self.console_wait_send("timezone", "UTC\n")
+ self.console_wait_send("root disk", "\n")
+ self.console_wait_send("(W)hole disk", "\n")
+ self.console_wait_send("(A)uto layout", "\n")
+ self.console_wait_send("Location of sets", "cd0\n")
+ self.console_wait_send("Pathname to the sets", "\n")
+ self.console_wait_send("Set name(s)", "\n")
+ self.console_wait_send("without verification", "yes\n")
+
+ self.print_step("Installation started now, this will take a while")
+ self.console_wait_send("Location of sets", "done\n")
+
+ self.console_wait("successfully completed")
+ self.print_step("Installation finished, rebooting")
+ self.console_wait_send("(R)eboot", "reboot\n")
+
+ # setup qemu user
+ prompt = "$"
+ self.console_ssh_init(prompt, self.GUEST_USER, self.GUEST_PASS)
+ self.console_wait_send(prompt, "exit\n")
+
+ # setup root user
+ prompt = "openbsd#"
+ self.console_ssh_init(prompt, "root", self.ROOT_PASS)
+ self.console_sshd_config(prompt)
+
+ # setup virtio-blk #1 (tarfile)
+ self.console_wait(prompt)
+ self.console_send("echo 'chmod 666 /dev/rsd1c' >> /etc/rc.local\n")
+
+ # enable w+x for /home
+ self.console_wait(prompt)
+ self.console_send("sed -i -e '/home/s/rw,/rw,wxallowed,/' /etc/fstab\n")
+
+ # tweak datasize limit
+ self.console_wait(prompt)
+ self.console_send("sed -i -e 's/\\(datasize[^=]*\\)=[^:]*/\\1=infinity/' /etc/login.conf\n")
+
+ # use http (be proxy cache friendly)
+ self.console_wait(prompt)
+ self.console_send("sed -i -e 's/https/http/' /etc/installurl\n")
+
+ self.print_step("Configuration finished, rebooting")
+ self.console_wait_send(prompt, "reboot\n")
+ self.console_wait("login:")
+ self.wait_ssh()
+
+ self.print_step("Installing packages")
+ self.ssh_root_check("pkg_add %s\n" % " ".join(self.pkgs))
+
+ # shutdown
+ self.ssh_root(self.poweroff)
+ self.wait()
+
if os.path.exists(img):
os.remove(img)
os.rename(img_tmp, img)
+ os.remove(iso)
+ self.print_step("All done")
if __name__ == "__main__":
sys.exit(basevm.main(OpenBSDVM))
" ssh-authorized-keys:\n",
" - %s\n" % basevm.SSH_PUB_KEY,
"locale: en_US.UTF-8\n"])
+ proxy = os.environ.get("http_proxy")
+ if not proxy is None:
+ udata.writelines(["apt:\n",
+ " proxy: %s" % proxy])
udata.close()
subprocess.check_call(["genisoimage", "-output", "cloud-init.iso",
"-volid", "cidata", "-joliet", "-rock",
return os.path.join(cidir, "cloud-init.iso")
def build_image(self, img):
- cimg = self._download_with_cache("https://cloud-images.ubuntu.com/releases/16.04/release/ubuntu-16.04-server-cloudimg-i386-disk1.img")
+ cimg = self._download_with_cache(
+ "https://cloud-images.ubuntu.com/releases/16.04/release-20190605/ubuntu-16.04-server-cloudimg-i386-disk1.img",
+ sha256sum="e30091144c73483822b7c27193e9d47346dd1064229da577c3fedcf943f7cfcc")
img_tmp = img + ".tmp"
subprocess.check_call(["cp", "-f", cimg, img_tmp])
subprocess.check_call(["qemu-img", "resize", img_tmp, "50G"])
time.sleep(5)
self.wait_ssh()
# The previous update sometimes doesn't survive a reboot, so do it again
+ self.ssh_root_check("sed -ie s/^#\ deb-src/deb-src/g /etc/apt/sources.list")
self.ssh_root_check("apt-get update")
self.ssh_root_check("apt-get build-dep -y qemu")
self.ssh_root_check("apt-get install -y libfdt-dev flex bison")
self.ssh_root("poweroff")
self.wait()
- if os.path.exists(img):
- os.remove(img)
os.rename(img_tmp, img)
return 0
if (s->width < w1)
w1 = s->width;
- cells = g_new(TextCell, s->width * s->total_height);
+ cells = g_new(TextCell, s->width * s->total_height + 1);
for(y = 0; y < s->total_height; y++) {
c = &cells[y * s->width];
if (w1 > 0) {
y2 += s->total_height;
}
if (y2 < s->height) {
+ if (x >= s->width) {
+ x = s->width - 1;
+ }
c = &s->cells[y1 * s->width + x];
vga_putcharxy(s, x, y2, c->ch,
&(c->t_attrib));
static void console_clear_xy(QemuConsole *s, int x, int y)
{
int y1 = (s->y_base + y) % s->total_height;
+ if (x >= s->width) {
+ x = s->width - 1;
+ }
TextCell *c = &s->cells[y1 * s->width + x];
c->ch = ' ';
c->t_attrib = s->t_attrib_default;
break;
case 1:
/* clear from beginning of line */
- for (x = 0; x <= s->x; x++) {
+ for (x = 0; x <= s->x && x < s->width; x++) {
console_clear_xy(s, x, s->y);
}
break;
#include "qemu/error-report.h"
#include "qemu/sockets.h"
#include "hw/hw.h"
-#include "hw/boards.h"
#include "sysemu/accel.h"
#include "hw/usb.h"
#include "hw/isa/isa.h"
#include "qapi/qapi-visit-block-core.h"
#include "qapi/qapi-visit-ui.h"
#include "qapi/qapi-commands-block-core.h"
-#include "qapi/qapi-commands-misc.h"
#include "qapi/qapi-commands-run-state.h"
#include "qapi/qapi-commands-ui.h"
#include "qapi/qmp/qerror.h"
return NULL;
}
-MachineInfoList *qmp_query_machines(Error **errp)
-{
- GSList *el, *machines = object_class_get_list(TYPE_MACHINE, false);
- MachineInfoList *mach_list = NULL;
-
- for (el = machines; el; el = el->next) {
- MachineClass *mc = el->data;
- MachineInfoList *entry;
- MachineInfo *info;
-
- info = g_malloc0(sizeof(*info));
- if (mc->is_default) {
- info->has_is_default = true;
- info->is_default = true;
- }
-
- if (mc->alias) {
- info->has_alias = true;
- info->alias = g_strdup(mc->alias);
- }
-
- info->name = g_strdup(mc->name);
- info->cpu_max = !mc->max_cpus ? 1 : mc->max_cpus;
- info->hotpluggable_cpus = mc->has_hotpluggable_cpus;
-
- entry = g_malloc0(sizeof(*entry));
- entry->value = info;
- entry->next = mach_list;
- mach_list = entry;
- }
-
- g_slist_free(machines);
- return mach_list;
-}
-
static int machine_help_func(QemuOpts *opts, MachineState *machine)
{
ObjectProperty *prop;
return wakeup_suspend_enabled;
}
-CurrentMachineParams *qmp_query_current_machine(Error **errp)
-{
- CurrentMachineParams *params = g_malloc0(sizeof(*params));
- params->wakeup_suspend_support = qemu_wakeup_suspend_enabled();
-
- return params;
-}
-
void qemu_system_killed(int signal, pid_t pid)
{
shutdown_signal = signal;
+++ /dev/null
-/*
- * Windows crashdump
- *
- * Copyright (c) 2018 Virtuozzo International GmbH
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or later.
- * See the COPYING file in the top-level directory.
- *
- */
-
-#include "qemu/osdep.h"
-#include "qemu-common.h"
-#include "qemu/cutils.h"
-#include "elf.h"
-#include "cpu.h"
-#include "exec/hwaddr.h"
-#include "monitor/monitor.h"
-#include "sysemu/kvm.h"
-#include "sysemu/dump.h"
-#include "sysemu/sysemu.h"
-#include "sysemu/memory_mapping.h"
-#include "sysemu/cpus.h"
-#include "qapi/error.h"
-#include "qapi/qmp/qerror.h"
-#include "qemu/error-report.h"
-#include "hw/misc/vmcoreinfo.h"
-#include "win_dump.h"
-
-static size_t write_run(WinDumpPhyMemRun64 *run, int fd, Error **errp)
-{
- void *buf;
- uint64_t addr = run->BasePage << TARGET_PAGE_BITS;
- uint64_t size = run->PageCount << TARGET_PAGE_BITS;
- uint64_t len, l;
- size_t total = 0;
-
- while (size) {
- len = size;
-
- buf = cpu_physical_memory_map(addr, &len, false);
- if (!buf) {
- error_setg(errp, "win-dump: failed to map physical range"
- " 0x%016" PRIx64 "-0x%016" PRIx64, addr, addr + size - 1);
- return 0;
- }
-
- l = qemu_write_full(fd, buf, len);
- cpu_physical_memory_unmap(buf, addr, false, len);
- if (l != len) {
- error_setg(errp, QERR_IO_ERROR);
- return 0;
- }
-
- addr += l;
- size -= l;
- total += l;
- }
-
- return total;
-}
-
-static void write_runs(DumpState *s, WinDumpHeader64 *h, Error **errp)
-{
- WinDumpPhyMemDesc64 *desc = &h->PhysicalMemoryBlock;
- WinDumpPhyMemRun64 *run = desc->Run;
- Error *local_err = NULL;
- int i;
-
- for (i = 0; i < desc->NumberOfRuns; i++) {
- s->written_size += write_run(run + i, s->fd, &local_err);
- if (local_err) {
- error_propagate(errp, local_err);
- return;
- }
- }
-}
-
-static void patch_mm_pfn_database(WinDumpHeader64 *h, Error **errp)
-{
- if (cpu_memory_rw_debug(first_cpu,
- h->KdDebuggerDataBlock + KDBG_MM_PFN_DATABASE_OFFSET64,
- (uint8_t *)&h->PfnDatabase, sizeof(h->PfnDatabase), 0)) {
- error_setg(errp, "win-dump: failed to read MmPfnDatabase");
- return;
- }
-}
-
-static void patch_bugcheck_data(WinDumpHeader64 *h, Error **errp)
-{
- uint64_t KiBugcheckData;
-
- if (cpu_memory_rw_debug(first_cpu,
- h->KdDebuggerDataBlock + KDBG_KI_BUGCHECK_DATA_OFFSET64,
- (uint8_t *)&KiBugcheckData, sizeof(KiBugcheckData), 0)) {
- error_setg(errp, "win-dump: failed to read KiBugcheckData");
- return;
- }
-
- if (cpu_memory_rw_debug(first_cpu,
- KiBugcheckData,
- h->BugcheckData, sizeof(h->BugcheckData), 0)) {
- error_setg(errp, "win-dump: failed to read bugcheck data");
- return;
- }
-
- /*
- * If BugcheckCode wasn't saved, we consider guest OS as alive.
- */
-
- if (!h->BugcheckCode) {
- h->BugcheckCode = LIVE_SYSTEM_DUMP;
- }
-}
-
-/*
- * This routine tries to correct mistakes in crashdump header.
- */
-static void patch_header(WinDumpHeader64 *h)
-{
- Error *local_err = NULL;
-
- h->RequiredDumpSpace = sizeof(WinDumpHeader64) +
- (h->PhysicalMemoryBlock.NumberOfPages << TARGET_PAGE_BITS);
- h->PhysicalMemoryBlock.unused = 0;
- h->unused1 = 0;
-
- patch_mm_pfn_database(h, &local_err);
- if (local_err) {
- warn_report_err(local_err);
- local_err = NULL;
- }
- patch_bugcheck_data(h, &local_err);
- if (local_err) {
- warn_report_err(local_err);
- }
-}
-
-static void check_header(WinDumpHeader64 *h, Error **errp)
-{
- const char Signature[] = "PAGE";
- const char ValidDump[] = "DU64";
-
- if (memcmp(h->Signature, Signature, sizeof(h->Signature))) {
- error_setg(errp, "win-dump: invalid header, expected '%.4s',"
- " got '%.4s'", Signature, h->Signature);
- return;
- }
-
- if (memcmp(h->ValidDump, ValidDump, sizeof(h->ValidDump))) {
- error_setg(errp, "win-dump: invalid header, expected '%.4s',"
- " got '%.4s'", ValidDump, h->ValidDump);
- return;
- }
-}
-
-static void check_kdbg(WinDumpHeader64 *h, Error **errp)
-{
- const char OwnerTag[] = "KDBG";
- char read_OwnerTag[4];
- uint64_t KdDebuggerDataBlock = h->KdDebuggerDataBlock;
- bool try_fallback = true;
-
-try_again:
- if (cpu_memory_rw_debug(first_cpu,
- KdDebuggerDataBlock + KDBG_OWNER_TAG_OFFSET64,
- (uint8_t *)&read_OwnerTag, sizeof(read_OwnerTag), 0)) {
- error_setg(errp, "win-dump: failed to read OwnerTag");
- return;
- }
-
- if (memcmp(read_OwnerTag, OwnerTag, sizeof(read_OwnerTag))) {
- if (try_fallback) {
- /*
- * If attempt to use original KDBG failed
- * (most likely because of its encryption),
- * we try to use KDBG obtained by guest driver.
- */
-
- KdDebuggerDataBlock = h->BugcheckParameter1;
- try_fallback = false;
- goto try_again;
- } else {
- error_setg(errp, "win-dump: invalid KDBG OwnerTag,"
- " expected '%.4s', got '%.4s'",
- OwnerTag, read_OwnerTag);
- return;
- }
- }
-
- h->KdDebuggerDataBlock = KdDebuggerDataBlock;
-}
-
-struct saved_context {
- WinContext ctx;
- uint64_t addr;
-};
-
-static void patch_and_save_context(WinDumpHeader64 *h,
- struct saved_context *saved_ctx,
- Error **errp)
-{
- uint64_t KiProcessorBlock;
- uint16_t OffsetPrcbContext;
- CPUState *cpu;
- int i = 0;
-
- if (cpu_memory_rw_debug(first_cpu,
- h->KdDebuggerDataBlock + KDBG_KI_PROCESSOR_BLOCK_OFFSET64,
- (uint8_t *)&KiProcessorBlock, sizeof(KiProcessorBlock), 0)) {
- error_setg(errp, "win-dump: failed to read KiProcessorBlock");
- return;
- }
-
- if (cpu_memory_rw_debug(first_cpu,
- h->KdDebuggerDataBlock + KDBG_OFFSET_PRCB_CONTEXT_OFFSET64,
- (uint8_t *)&OffsetPrcbContext, sizeof(OffsetPrcbContext), 0)) {
- error_setg(errp, "win-dump: failed to read OffsetPrcbContext");
- return;
- }
-
- CPU_FOREACH(cpu) {
- X86CPU *x86_cpu = X86_CPU(cpu);
- CPUX86State *env = &x86_cpu->env;
- uint64_t Prcb;
- uint64_t Context;
- WinContext ctx;
-
- if (cpu_memory_rw_debug(first_cpu,
- KiProcessorBlock + i * sizeof(uint64_t),
- (uint8_t *)&Prcb, sizeof(Prcb), 0)) {
- error_setg(errp, "win-dump: failed to read"
- " CPU #%d PRCB location", i);
- return;
- }
-
- if (cpu_memory_rw_debug(first_cpu,
- Prcb + OffsetPrcbContext,
- (uint8_t *)&Context, sizeof(Context), 0)) {
- error_setg(errp, "win-dump: failed to read"
- " CPU #%d ContextFrame location", i);
- return;
- }
-
- saved_ctx[i].addr = Context;
-
- ctx = (WinContext){
- .ContextFlags = WIN_CTX_ALL,
- .MxCsr = env->mxcsr,
-
- .SegEs = env->segs[0].selector,
- .SegCs = env->segs[1].selector,
- .SegSs = env->segs[2].selector,
- .SegDs = env->segs[3].selector,
- .SegFs = env->segs[4].selector,
- .SegGs = env->segs[5].selector,
- .EFlags = cpu_compute_eflags(env),
-
- .Dr0 = env->dr[0],
- .Dr1 = env->dr[1],
- .Dr2 = env->dr[2],
- .Dr3 = env->dr[3],
- .Dr6 = env->dr[6],
- .Dr7 = env->dr[7],
-
- .Rax = env->regs[R_EAX],
- .Rbx = env->regs[R_EBX],
- .Rcx = env->regs[R_ECX],
- .Rdx = env->regs[R_EDX],
- .Rsp = env->regs[R_ESP],
- .Rbp = env->regs[R_EBP],
- .Rsi = env->regs[R_ESI],
- .Rdi = env->regs[R_EDI],
- .R8 = env->regs[8],
- .R9 = env->regs[9],
- .R10 = env->regs[10],
- .R11 = env->regs[11],
- .R12 = env->regs[12],
- .R13 = env->regs[13],
- .R14 = env->regs[14],
- .R15 = env->regs[15],
-
- .Rip = env->eip,
- .FltSave = {
- .MxCsr = env->mxcsr,
- },
- };
-
- if (cpu_memory_rw_debug(first_cpu, Context,
- (uint8_t *)&saved_ctx[i].ctx, sizeof(WinContext), 0)) {
- error_setg(errp, "win-dump: failed to save CPU #%d context", i);
- return;
- }
-
- if (cpu_memory_rw_debug(first_cpu, Context,
- (uint8_t *)&ctx, sizeof(WinContext), 1)) {
- error_setg(errp, "win-dump: failed to write CPU #%d context", i);
- return;
- }
-
- i++;
- }
-}
-
-static void restore_context(WinDumpHeader64 *h,
- struct saved_context *saved_ctx)
-{
- int i;
- Error *err = NULL;
-
- for (i = 0; i < h->NumberProcessors; i++) {
- if (cpu_memory_rw_debug(first_cpu, saved_ctx[i].addr,
- (uint8_t *)&saved_ctx[i].ctx, sizeof(WinContext), 1)) {
- error_setg(&err, "win-dump: failed to restore CPU #%d context", i);
- warn_report_err(err);
- }
- }
-}
-
-void create_win_dump(DumpState *s, Error **errp)
-{
- WinDumpHeader64 *h = (WinDumpHeader64 *)(s->guest_note +
- VMCOREINFO_ELF_NOTE_HDR_SIZE);
- X86CPU *first_x86_cpu = X86_CPU(first_cpu);
- uint64_t saved_cr3 = first_x86_cpu->env.cr[3];
- struct saved_context *saved_ctx = NULL;
- Error *local_err = NULL;
-
- if (s->guest_note_size != sizeof(WinDumpHeader64) +
- VMCOREINFO_ELF_NOTE_HDR_SIZE) {
- error_setg(errp, "win-dump: invalid vmcoreinfo note size");
- return;
- }
-
- check_header(h, &local_err);
- if (local_err) {
- error_propagate(errp, local_err);
- return;
- }
-
- /*
- * Further access to kernel structures by virtual addresses
- * should be made from system context.
- */
-
- first_x86_cpu->env.cr[3] = h->DirectoryTableBase;
-
- check_kdbg(h, &local_err);
- if (local_err) {
- error_propagate(errp, local_err);
- goto out_cr3;
- }
-
- patch_header(h);
-
- saved_ctx = g_new(struct saved_context, h->NumberProcessors);
-
- /*
- * Always patch context because there is no way
- * to determine if the system-saved context is valid
- */
-
- patch_and_save_context(h, saved_ctx, &local_err);
- if (local_err) {
- error_propagate(errp, local_err);
- goto out_free;
- }
-
- s->total_size = h->RequiredDumpSpace;
-
- s->written_size = qemu_write_full(s->fd, h, sizeof(*h));
- if (s->written_size != sizeof(*h)) {
- error_setg(errp, QERR_IO_ERROR);
- goto out_restore;
- }
-
- write_runs(s, h, &local_err);
- if (local_err) {
- error_propagate(errp, local_err);
- goto out_restore;
- }
-
-out_restore:
- restore_context(h, saved_ctx);
-out_free:
- g_free(saved_ctx);
-out_cr3:
- first_x86_cpu->env.cr[3] = saved_cr3;
-
- return;
-}
+++ /dev/null
-/*
- * Windows crashdump
- *
- * Copyright (c) 2018 Virtuozzo International GmbH
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or later.
- * See the COPYING file in the top-level directory.
- *
- */
-
-#ifndef WIN_DUMP_H
-#define WIN_DUMP_H
-
-#include "qemu/win_dump_defs.h"
-
-void create_win_dump(DumpState *s, Error **errp);
-
-#endif /* WIN_DUMP_H */