aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--MAINTAINERS8
-rw-r--r--Makefile14
-rw-r--r--arch_init.c2
-rw-r--r--arch_init.h1
-rw-r--r--block.h1
-rw-r--r--block/iscsi.c59
-rw-r--r--block/qcow2.c32
-rw-r--r--block/qed-check.c26
-rw-r--r--block/qed.c11
-rw-r--r--block/qed.h5
-rw-r--r--blockdev.c1
-rwxr-xr-xconfigure53
-rw-r--r--cpu-exec.c6
-rw-r--r--cpus.c3
-rw-r--r--default-configs/arm-softmmu.mak18
-rw-r--r--default-configs/pci.mak1
-rw-r--r--default-configs/unicore32-softmmu.mak4
-rw-r--r--dma-helpers.c1
-rw-r--r--exec-all.h2
-rw-r--r--exec.c2
-rw-r--r--hw/Makefile.objs29
-rw-r--r--hw/arm/Makefile.objs15
-rw-r--r--hw/armv7m.c5
-rw-r--r--hw/armv7m_nvic.c21
-rw-r--r--hw/esp-pci.c518
-rw-r--r--hw/esp.c487
-rw-r--r--hw/esp.h119
-rw-r--r--hw/ide/ahci.c44
-rw-r--r--hw/ide/internal.h1
-rw-r--r--hw/kvm/i8259.c2
-rw-r--r--hw/kvm/ioapic.c2
-rw-r--r--hw/pc.c1
-rw-r--r--hw/pci-stub.c15
-rw-r--r--hw/petalogix_ml605_mmu.c24
-rw-r--r--hw/puv3.c131
-rw-r--r--hw/puv3.h49
-rw-r--r--hw/puv3_dma.c109
-rw-r--r--hw/puv3_gpio.c141
-rw-r--r--hw/puv3_intc.c135
-rw-r--r--hw/puv3_ost.c151
-rw-r--r--hw/puv3_pm.c149
-rw-r--r--hw/scsi-bus.c1
-rw-r--r--hw/scsi-disk.c112
-rw-r--r--hw/sd.c72
-rw-r--r--hw/sd.h6
-rw-r--r--hw/ssd0323.c4
-rw-r--r--hw/stream.c23
-rw-r--r--hw/stream.h31
-rw-r--r--hw/sun4m.c18
-rw-r--r--hw/unicore32/Makefile.objs6
-rw-r--r--hw/virtio-blk.c31
-rw-r--r--hw/virtio-blk.h4
-rw-r--r--hw/virtio-pci.c4
-rw-r--r--hw/virtio-scsi.c10
-rw-r--r--hw/xilinx.h22
-rw-r--r--hw/xilinx_axidma.c74
-rw-r--r--hw/xilinx_axidma.h39
-rw-r--r--hw/xilinx_axienet.c33
-rw-r--r--hw/xtensa_lx60.c6
-rw-r--r--hw/xtensa_sim.c5
-rw-r--r--include/qemu/object.h46
-rw-r--r--kvm-all.c54
-rw-r--r--kvm-stub.c9
-rw-r--r--kvm.h60
-rw-r--r--linux-user/main.c3
-rw-r--r--linux-user/signal.c8
-rw-r--r--net/slirp.c6
-rw-r--r--qemu-common.h1
-rw-r--r--qemu-doc.texi5
-rw-r--r--qemu-img.c2
-rw-r--r--qemu-options.hx8
-rw-r--r--qemu-timer.c10
-rw-r--r--qemu-tool.c5
-rw-r--r--qom/object.c220
-rw-r--r--scripts/qapi.py16
-rw-r--r--target-arm/arm-semi.c2
-rw-r--r--target-arm/cpu.h2
-rw-r--r--target-arm/helper.c6
-rw-r--r--target-arm/neon_helper.c26
-rw-r--r--target-arm/op_helper.c2
-rw-r--r--target-arm/translate.c12
-rw-r--r--target-i386/Makefile.objs1
-rw-r--r--target-i386/cpu.c10
-rw-r--r--target-i386/cpu.h1
-rw-r--r--target-i386/helper.c16
-rw-r--r--target-i386/kvm-stub.c18
-rw-r--r--target-i386/kvm.c13
-rw-r--r--target-i386/kvm_i386.h16
-rw-r--r--target-mips/translate.c1
-rw-r--r--target-unicore32/Makefile.objs4
-rw-r--r--target-unicore32/cpu.c19
-rw-r--r--target-unicore32/cpu.h18
-rw-r--r--target-unicore32/helper.c511
-rw-r--r--target-unicore32/helper.h17
-rw-r--r--target-unicore32/machine.c23
-rw-r--r--target-unicore32/op_helper.c44
-rw-r--r--target-unicore32/softmmu.c267
-rw-r--r--target-unicore32/translate.c159
-rw-r--r--target-unicore32/ucf64_helper.c345
-rw-r--r--target-xtensa/cpu.h6
-rw-r--r--target-xtensa/helper.c8
-rwxr-xr-xtests/qemu-iotests/0391
-rw-r--r--tests/qemu-iotests/039.out6
-rw-r--r--tests/qemu-iotests/common.rc34
-rw-r--r--user-exec.c17
-rw-r--r--vl.c23
106 files changed, 3552 insertions, 1428 deletions
diff --git a/MAINTAINERS b/MAINTAINERS
index 2d219d2ea0..708ad549ab 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -405,6 +405,14 @@ M: Alexander Graf <agraf@suse.de>
S: Maintained
F: hw/s390-*.c
+UniCore32 Machines
+-------------
+PKUnity-3 SoC initramfs-with-busybox
+M: Guan Xuetao <gxt@mprc.pku.edu.cn>
+S: Maintained
+F: hw/puv3*
+F: hw/unicore32/
+
X86 Machines
------------
PC
diff --git a/Makefile b/Makefile
index 000b46c379..d736ea5311 100644
--- a/Makefile
+++ b/Makefile
@@ -181,24 +181,26 @@ ifneq ($(wildcard config-host.mak),)
include $(SRC_PATH)/tests/Makefile
endif
+qapi-py = $(SRC_PATH)/scripts/qapi.py $(SRC_PATH)/scripts/ordereddict.py
+
qga/qapi-generated/qga-qapi-types.c qga/qapi-generated/qga-qapi-types.h :\
-$(SRC_PATH)/qapi-schema-guest.json $(SRC_PATH)/scripts/qapi-types.py
+$(SRC_PATH)/qapi-schema-guest.json $(SRC_PATH)/scripts/qapi-types.py $(qapi-py)
$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-types.py $(gen-out-type) -o qga/qapi-generated -p "qga-" < $<, " GEN $@")
qga/qapi-generated/qga-qapi-visit.c qga/qapi-generated/qga-qapi-visit.h :\
-$(SRC_PATH)/qapi-schema-guest.json $(SRC_PATH)/scripts/qapi-visit.py
+$(SRC_PATH)/qapi-schema-guest.json $(SRC_PATH)/scripts/qapi-visit.py $(qapi-py)
$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-visit.py $(gen-out-type) -o qga/qapi-generated -p "qga-" < $<, " GEN $@")
qga/qapi-generated/qga-qmp-commands.h qga/qapi-generated/qga-qmp-marshal.c :\
-$(SRC_PATH)/qapi-schema-guest.json $(SRC_PATH)/scripts/qapi-commands.py
+$(SRC_PATH)/qapi-schema-guest.json $(SRC_PATH)/scripts/qapi-commands.py $(qapi-py)
$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-commands.py $(gen-out-type) -o qga/qapi-generated -p "qga-" < $<, " GEN $@")
qapi-types.c qapi-types.h :\
-$(SRC_PATH)/qapi-schema.json $(SRC_PATH)/scripts/qapi-types.py
+$(SRC_PATH)/qapi-schema.json $(SRC_PATH)/scripts/qapi-types.py $(qapi-py)
$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-types.py $(gen-out-type) -o "." < $<, " GEN $@")
qapi-visit.c qapi-visit.h :\
-$(SRC_PATH)/qapi-schema.json $(SRC_PATH)/scripts/qapi-visit.py
+$(SRC_PATH)/qapi-schema.json $(SRC_PATH)/scripts/qapi-visit.py $(qapi-py)
$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-visit.py $(gen-out-type) -o "." < $<, " GEN $@")
qmp-commands.h qmp-marshal.c :\
-$(SRC_PATH)/qapi-schema.json $(SRC_PATH)/scripts/qapi-commands.py
+$(SRC_PATH)/qapi-schema.json $(SRC_PATH)/scripts/qapi-commands.py $(qapi-py)
$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-commands.py $(gen-out-type) -m -o "." < $<, " GEN $@")
QGALIB_GEN=$(addprefix qga/qapi-generated/, qga-qapi-types.h qga-qapi-visit.h qga-qmp-commands.h)
diff --git a/arch_init.c b/arch_init.c
index a7c09870a1..9b46bfcaa5 100644
--- a/arch_init.c
+++ b/arch_init.c
@@ -92,6 +92,8 @@ int graphic_depth = 15;
#define QEMU_ARCH QEMU_ARCH_SPARC
#elif defined(TARGET_XTENSA)
#define QEMU_ARCH QEMU_ARCH_XTENSA
+#elif defined(TARGET_UNICORE32)
+#define QEMU_ARCH QEMU_ARCH_UNICORE32
#endif
const uint32_t arch_type = QEMU_ARCH;
diff --git a/arch_init.h b/arch_init.h
index 3dfea3b4f3..547f93cd1d 100644
--- a/arch_init.h
+++ b/arch_init.h
@@ -17,6 +17,7 @@ enum {
QEMU_ARCH_SPARC = 2048,
QEMU_ARCH_XTENSA = 4096,
QEMU_ARCH_OPENRISC = 8192,
+ QEMU_ARCH_UNICORE32 = 0x4000,
};
extern const uint32_t arch_type;
diff --git a/block.h b/block.h
index 650d872f46..2e2be11071 100644
--- a/block.h
+++ b/block.h
@@ -79,6 +79,7 @@ typedef struct BlockDevOps {
#define BDRV_O_NO_FLUSH 0x0200 /* disable flushing on this disk */
#define BDRV_O_COPY_ON_READ 0x0400 /* copy read backing sectors into image */
#define BDRV_O_INCOMING 0x0800 /* consistency hint for incoming migration */
+#define BDRV_O_CHECK 0x1000 /* open solely for consistency check */
#define BDRV_O_CACHE_MASK (BDRV_O_NOCACHE | BDRV_O_CACHE_WB | BDRV_O_NO_FLUSH)
diff --git a/block/iscsi.c b/block/iscsi.c
index 993a86d829..219f927823 100644
--- a/block/iscsi.c
+++ b/block/iscsi.c
@@ -896,26 +896,26 @@ static char *parse_initiator_name(const char *target)
QemuOptsList *list;
QemuOpts *opts;
const char *name = NULL;
+ const char *iscsi_name = qemu_get_vm_name();
list = qemu_find_opts("iscsi");
- if (!list) {
- return g_strdup("iqn.2008-11.org.linux-kvm");
- }
-
- opts = qemu_opts_find(list, target);
- if (opts == NULL) {
- opts = QTAILQ_FIRST(&list->head);
+ if (list) {
+ opts = qemu_opts_find(list, target);
if (!opts) {
- return g_strdup("iqn.2008-11.org.linux-kvm");
+ opts = QTAILQ_FIRST(&list->head);
+ }
+ if (opts) {
+ name = qemu_opt_get(opts, "initiator-name");
}
}
- name = qemu_opt_get(opts, "initiator-name");
- if (!name) {
- return g_strdup("iqn.2008-11.org.linux-kvm");
+ if (name) {
+ return g_strdup(name);
+ } else {
+ return g_strdup_printf("iqn.2008-11.org.linux-kvm%s%s",
+ iscsi_name ? ":" : "",
+ iscsi_name ? iscsi_name : "");
}
-
- return g_strdup(name);
}
/*
@@ -943,7 +943,7 @@ static int iscsi_open(BlockDriverState *bs, const char *filename, int flags)
error_report("Failed to parse URL : %s %s", filename,
iscsi_get_error(iscsi));
ret = -EINVAL;
- goto failed;
+ goto out;
}
memset(iscsilun, 0, sizeof(IscsiLun));
@@ -954,13 +954,13 @@ static int iscsi_open(BlockDriverState *bs, const char *filename, int flags)
if (iscsi == NULL) {
error_report("iSCSI: Failed to create iSCSI context.");
ret = -ENOMEM;
- goto failed;
+ goto out;
}
if (iscsi_set_targetname(iscsi, iscsi_url->target)) {
error_report("iSCSI: Failed to set target name.");
ret = -EINVAL;
- goto failed;
+ goto out;
}
if (iscsi_url->user != NULL) {
@@ -969,7 +969,7 @@ static int iscsi_open(BlockDriverState *bs, const char *filename, int flags)
if (ret != 0) {
error_report("Failed to set initiator username and password");
ret = -EINVAL;
- goto failed;
+ goto out;
}
}
@@ -977,13 +977,13 @@ static int iscsi_open(BlockDriverState *bs, const char *filename, int flags)
if (parse_chap(iscsi, iscsi_url->target) != 0) {
error_report("iSCSI: Failed to set CHAP user/password");
ret = -EINVAL;
- goto failed;
+ goto out;
}
if (iscsi_set_session_type(iscsi, ISCSI_SESSION_NORMAL) != 0) {
error_report("iSCSI: Failed to set session type to normal.");
ret = -EINVAL;
- goto failed;
+ goto out;
}
iscsi_set_header_digest(iscsi, ISCSI_HEADER_DIGEST_NONE_CRC32C);
@@ -1004,7 +1004,7 @@ static int iscsi_open(BlockDriverState *bs, const char *filename, int flags)
!= 0) {
error_report("iSCSI: Failed to start async connect.");
ret = -EINVAL;
- goto failed;
+ goto out;
}
while (!task.complete) {
@@ -1015,11 +1015,7 @@ static int iscsi_open(BlockDriverState *bs, const char *filename, int flags)
error_report("iSCSI: Failed to connect to LUN : %s",
iscsi_get_error(iscsi));
ret = -EINVAL;
- goto failed;
- }
-
- if (iscsi_url != NULL) {
- iscsi_destroy_url(iscsi_url);
+ goto out;
}
/* Medium changer or tape. We dont have any emulation for this so this must
@@ -1031,19 +1027,22 @@ static int iscsi_open(BlockDriverState *bs, const char *filename, int flags)
bs->sg = 1;
}
- return 0;
+ ret = 0;
-failed:
+out:
if (initiator_name != NULL) {
g_free(initiator_name);
}
if (iscsi_url != NULL) {
iscsi_destroy_url(iscsi_url);
}
- if (iscsi != NULL) {
- iscsi_destroy_context(iscsi);
+
+ if (ret) {
+ if (iscsi != NULL) {
+ iscsi_destroy_context(iscsi);
+ }
+ memset(iscsilun, 0, sizeof(IscsiLun));
}
- memset(iscsilun, 0, sizeof(IscsiLun));
return ret;
}
diff --git a/block/qcow2.c b/block/qcow2.c
index fd5e214431..8f183f1465 100644
--- a/block/qcow2.c
+++ b/block/qcow2.c
@@ -270,6 +270,20 @@ static int qcow2_mark_clean(BlockDriverState *bs)
return 0;
}
+static int qcow2_check(BlockDriverState *bs, BdrvCheckResult *result,
+ BdrvCheckMode fix)
+{
+ int ret = qcow2_check_refcounts(bs, result, fix);
+ if (ret < 0) {
+ return ret;
+ }
+
+ if (fix && result->check_errors == 0 && result->corruptions == 0) {
+ return qcow2_mark_clean(bs);
+ }
+ return ret;
+}
+
static int qcow2_open(BlockDriverState *bs, int flags)
{
BDRVQcowState *s = bs->opaque;
@@ -470,16 +484,11 @@ static int qcow2_open(BlockDriverState *bs, int flags)
qemu_co_mutex_init(&s->lock);
/* Repair image if dirty */
- if ((s->incompatible_features & QCOW2_INCOMPAT_DIRTY) &&
- !bs->read_only) {
+ if (!(flags & BDRV_O_CHECK) && !bs->read_only &&
+ (s->incompatible_features & QCOW2_INCOMPAT_DIRTY)) {
BdrvCheckResult result = {0};
- ret = qcow2_check_refcounts(bs, &result, BDRV_FIX_ERRORS);
- if (ret < 0) {
- goto fail;
- }
-
- ret = qcow2_mark_clean(bs);
+ ret = qcow2_check(bs, &result, BDRV_FIX_ERRORS);
if (ret < 0) {
goto fail;
}
@@ -1568,13 +1577,6 @@ static int qcow2_get_info(BlockDriverState *bs, BlockDriverInfo *bdi)
return 0;
}
-
-static int qcow2_check(BlockDriverState *bs, BdrvCheckResult *result,
- BdrvCheckMode fix)
-{
- return qcow2_check_refcounts(bs, result, fix);
-}
-
#if 0
static void dump_refcounts(BlockDriverState *bs)
{
diff --git a/block/qed-check.c b/block/qed-check.c
index 5edf60775b..b473dcd61f 100644
--- a/block/qed-check.c
+++ b/block/qed-check.c
@@ -194,6 +194,28 @@ static void qed_check_for_leaks(QEDCheck *check)
}
}
+/**
+ * Mark an image clean once it passes check or has been repaired
+ */
+static void qed_check_mark_clean(BDRVQEDState *s, BdrvCheckResult *result)
+{
+ /* Skip if there were unfixable corruptions or I/O errors */
+ if (result->corruptions > 0 || result->check_errors > 0) {
+ return;
+ }
+
+ /* Skip if image is already marked clean */
+ if (!(s->header.features & QED_F_NEED_CHECK)) {
+ return;
+ }
+
+ /* Ensure fixes reach storage before clearing check bit */
+ bdrv_flush(s->bs);
+
+ s->header.features &= ~QED_F_NEED_CHECK;
+ qed_write_header_sync(s);
+}
+
int qed_check(BDRVQEDState *s, BdrvCheckResult *result, bool fix)
{
QEDCheck check = {
@@ -215,6 +237,10 @@ int qed_check(BDRVQEDState *s, BdrvCheckResult *result, bool fix)
if (ret == 0) {
/* Only check for leaks if entire image was scanned successfully */
qed_check_for_leaks(&check);
+
+ if (fix) {
+ qed_check_mark_clean(s, result);
+ }
}
g_free(check.used_clusters);
diff --git a/block/qed.c b/block/qed.c
index 5f3eefa3af..a02dbfd72d 100644
--- a/block/qed.c
+++ b/block/qed.c
@@ -89,7 +89,7 @@ static void qed_header_cpu_to_le(const QEDHeader *cpu, QEDHeader *le)
le->backing_filename_size = cpu_to_le32(cpu->backing_filename_size);
}
-static int qed_write_header_sync(BDRVQEDState *s)
+int qed_write_header_sync(BDRVQEDState *s)
{
QEDHeader le;
int ret;
@@ -477,7 +477,7 @@ static int bdrv_qed_open(BlockDriverState *bs, int flags)
}
/* If image was not closed cleanly, check consistency */
- if (s->header.features & QED_F_NEED_CHECK) {
+ if (!(flags & BDRV_O_CHECK) && (s->header.features & QED_F_NEED_CHECK)) {
/* Read-only images cannot be fixed. There is no risk of corruption
* since write operations are not possible. Therefore, allow
* potentially inconsistent images to be opened read-only. This can
@@ -491,13 +491,6 @@ static int bdrv_qed_open(BlockDriverState *bs, int flags)
if (ret) {
goto out;
}
- if (!result.corruptions && !result.check_errors) {
- /* Ensure fixes reach storage before clearing check bit */
- bdrv_flush(s->bs);
-
- s->header.features &= ~QED_F_NEED_CHECK;
- qed_write_header_sync(s);
- }
}
}
diff --git a/block/qed.h b/block/qed.h
index c716772ad7..a063bf70af 100644
--- a/block/qed.h
+++ b/block/qed.h
@@ -211,6 +211,11 @@ void *gencb_alloc(size_t len, BlockDriverCompletionFunc *cb, void *opaque);
void gencb_complete(void *opaque, int ret);
/**
+ * Header functions
+ */
+int qed_write_header_sync(BDRVQEDState *s);
+
+/**
* L2 cache functions
*/
void qed_init_l2_cache(L2TableCache *l2_cache);
diff --git a/blockdev.c b/blockdev.c
index 8669142704..7c83baa353 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -377,6 +377,7 @@ DriveInfo *drive_init(QemuOpts *opts, int default_to_scsi)
}
}
+ bdrv_flags |= BDRV_O_CACHE_WB;
if ((buf = qemu_opt_get(opts, "cache")) != NULL) {
if (bdrv_parse_cache_flags(buf, &bdrv_flags) != 0) {
error_report("invalid cache option");
diff --git a/configure b/configure
index 280726c3f8..97b69a0d73 100755
--- a/configure
+++ b/configure
@@ -27,16 +27,40 @@ printf " '%s'" "$0" "$@" >> config.log
echo >> config.log
echo "#" >> config.log
+do_cc() {
+ # Run the compiler, capturing its output to the log.
+ echo $cc "$@" >> config.log
+ $cc "$@" >> config.log 2>&1 || return $?
+ # Test passed. If this is an --enable-werror build, rerun
+ # the test with -Werror and bail out if it fails. This
+ # makes warning-generating-errors in configure test code
+ # obvious to developers.
+ if test "$werror" != "yes"; then
+ return 0
+ fi
+ # Don't bother rerunning the compile if we were already using -Werror
+ case "$*" in
+ *-Werror*)
+ return 0
+ ;;
+ esac
+ echo $cc -Werror "$@" >> config.log
+ $cc -Werror "$@" >> config.log 2>&1 && return $?
+ echo "ERROR: configure test passed without -Werror but failed with -Werror."
+ echo "This is probably a bug in the configure script. The failing command"
+ echo "will be at the bottom of config.log."
+ echo "You can run configure with --disable-werror to bypass this check."
+ exit 1
+}
+
compile_object() {
- echo $cc $QEMU_CFLAGS -c -o $TMPO $TMPC >> config.log
- $cc $QEMU_CFLAGS -c -o $TMPO $TMPC >> config.log 2>&1
+ do_cc $QEMU_CFLAGS -c -o $TMPO $TMPC
}
compile_prog() {
local_cflags="$1"
local_ldflags="$2"
- echo $cc $QEMU_CFLAGS $local_cflags -o $TMPE $TMPC $LDFLAGS $local_ldflags >> config.log
- $cc $QEMU_CFLAGS $local_cflags -o $TMPE $TMPC $LDFLAGS $local_ldflags >> config.log 2>&1
+ do_cc $QEMU_CFLAGS $local_cflags -o $TMPE $TMPC $LDFLAGS $local_ldflags
}
# symbolically link $1 to $2. Portable version of "ln -sf".
@@ -935,6 +959,7 @@ sparc64-softmmu \
s390x-softmmu \
xtensa-softmmu \
xtensaeb-softmmu \
+unicore32-softmmu \
"
fi
# the following are Linux specific
@@ -2231,7 +2256,7 @@ cat > $TMPC <<EOF
#include <sys/types.h>
#include <sys/uio.h>
#include <unistd.h>
-int main(void) { return preadv == preadv; }
+int main(void) { return preadv(0, 0, 0, 0); }
EOF
preadv=no
if compile_prog "" "" ; then
@@ -2527,7 +2552,7 @@ int main(void)
* warning but not an error, and will proceed to fail the
* qemu compile where we compile with -Werror.)
*/
- return epoll_create1 == epoll_create1;
+ return (int)(uintptr_t)&epoll_create1;
}
EOF
if compile_prog "" "" ; then
@@ -2920,7 +2945,7 @@ has_environ=no
cat > $TMPC << EOF
#include <unistd.h>
int main(void) {
- environ = environ;
+ environ = 0;
return 0;
}
EOF
@@ -3538,15 +3563,23 @@ if test "$linux" = "yes" ; then
mkdir -p linux-headers
case "$cpu" in
i386|x86_64)
- symlink "$source_path/linux-headers/asm-x86" linux-headers/asm
+ linux_arch=x86
;;
ppcemb|ppc|ppc64)
- symlink "$source_path/linux-headers/asm-powerpc" linux-headers/asm
+ linux_arch=powerpc
;;
s390x)
- symlink "$source_path/linux-headers/asm-s390" linux-headers/asm
+ linux_arch=s390
+ ;;
+ *)
+ # For most CPUs the kernel architecture name and QEMU CPU name match.
+ linux_arch="$cpu"
;;
esac
+ # For non-KVM architectures we will not have asm headers
+ if [ -e "$source_path/linux-headers/asm-$linux_arch" ]; then
+ symlink "$source_path/linux-headers/asm-$linux_arch" linux-headers/asm
+ fi
fi
for target in $target_list; do
diff --git a/cpu-exec.c b/cpu-exec.c
index 543460c34c..134b3c4fcf 100644
--- a/cpu-exec.c
+++ b/cpu-exec.c
@@ -156,12 +156,9 @@ static inline TranslationBlock *tb_find_fast(CPUArchState *env)
static CPUDebugExcpHandler *debug_excp_handler;
-CPUDebugExcpHandler *cpu_set_debug_excp_handler(CPUDebugExcpHandler *handler)
+void cpu_set_debug_excp_handler(CPUDebugExcpHandler *handler)
{
- CPUDebugExcpHandler *old_handler = debug_excp_handler;
-
debug_excp_handler = handler;
- return old_handler;
}
static void cpu_handle_debug_exception(CPUArchState *env)
@@ -447,6 +444,7 @@ int cpu_exec(CPUArchState *env)
#elif defined(TARGET_UNICORE32)
if (interrupt_request & CPU_INTERRUPT_HARD
&& !(env->uncached_asr & ASR_I)) {
+ env->exception_index = UC32_EXCP_INTR;
do_interrupt(env);
next_tb = 0;
}
diff --git a/cpus.c b/cpus.c
index 3de2e27f41..e476a3cd5e 100644
--- a/cpus.c
+++ b/cpus.c
@@ -70,7 +70,8 @@ static bool cpu_thread_is_idle(CPUArchState *env)
if (env->stopped || !runstate_is_running()) {
return true;
}
- if (!env->halted || qemu_cpu_has_work(env) || kvm_irqchip_in_kernel()) {
+ if (!env->halted || qemu_cpu_has_work(env) ||
+ kvm_async_interrupts_enabled()) {
return false;
}
return true;
diff --git a/default-configs/arm-softmmu.mak b/default-configs/arm-softmmu.mak
index e542b4f8ee..f335a725f0 100644
--- a/default-configs/arm-softmmu.mak
+++ b/default-configs/arm-softmmu.mak
@@ -27,3 +27,21 @@ CONFIG_SMC91C111=y
CONFIG_DS1338=y
CONFIG_PFLASH_CFI01=y
CONFIG_PFLASH_CFI02=y
+
+CONFIG_ARM_TIMER=y
+CONFIG_PL011=y
+CONFIG_PL022=y
+CONFIG_PL031=y
+CONFIG_PL041=y
+CONFIG_PL050=y
+CONFIG_PL061=y
+CONFIG_PL080=y
+CONFIG_PL110=y
+CONFIG_PL181=y
+CONFIG_PL190=y
+CONFIG_PL310=y
+CONFIG_CADENCE=y
+CONFIG_XGMAC=y
+
+CONFIG_VERSATILE_PCI=y
+CONFIG_VERSATILE_I2C=y
diff --git a/default-configs/pci.mak b/default-configs/pci.mak
index 9febb47ae6..69e18f1428 100644
--- a/default-configs/pci.mak
+++ b/default-configs/pci.mak
@@ -18,3 +18,4 @@ CONFIG_IDE_QDEV=y
CONFIG_IDE_PCI=y
CONFIG_AHCI=y
CONFIG_ESP=y
+CONFIG_ESP_PCI=y
diff --git a/default-configs/unicore32-softmmu.mak b/default-configs/unicore32-softmmu.mak
new file mode 100644
index 0000000000..de38577a35
--- /dev/null
+++ b/default-configs/unicore32-softmmu.mak
@@ -0,0 +1,4 @@
+# Default configuration for unicore32-softmmu
+CONFIG_PUV3=y
+CONFIG_PTIMER=y
+CONFIG_PCKBD=y
diff --git a/dma-helpers.c b/dma-helpers.c
index 35cb500581..13593d1b42 100644
--- a/dma-helpers.c
+++ b/dma-helpers.c
@@ -65,6 +65,7 @@ void qemu_sglist_add(QEMUSGList *qsg, dma_addr_t base, dma_addr_t len)
void qemu_sglist_destroy(QEMUSGList *qsg)
{
g_free(qsg->sg);
+ memset(qsg, 0, sizeof(*qsg));
}
typedef struct {
diff --git a/exec-all.h b/exec-all.h
index 9bda7f7354..c5ec8e1158 100644
--- a/exec-all.h
+++ b/exec-all.h
@@ -357,7 +357,7 @@ tb_page_addr_t get_page_addr_code(CPUArchState *env1, target_ulong addr);
typedef void (CPUDebugExcpHandler)(CPUArchState *env);
-CPUDebugExcpHandler *cpu_set_debug_excp_handler(CPUDebugExcpHandler *handler);
+void cpu_set_debug_excp_handler(CPUDebugExcpHandler *handler);
/* vl.c */
extern int singlestep;
diff --git a/exec.c b/exec.c
index a42a0b5b78..929db5cf0a 100644
--- a/exec.c
+++ b/exec.c
@@ -2550,6 +2550,8 @@ ram_addr_t qemu_ram_alloc_from_ptr(ram_addr_t size, void *host,
ram_list.phys_dirty = g_realloc(ram_list.phys_dirty,
last_ram_offset() >> TARGET_PAGE_BITS);
+ memset(ram_list.phys_dirty + (new_block->offset >> TARGET_PAGE_BITS),
+ 0, size >> TARGET_PAGE_BITS);
cpu_physical_memory_set_dirty_range(new_block->offset, size, 0xff);
if (kvm_enabled())
diff --git a/hw/Makefile.objs b/hw/Makefile.objs
index 8327e55c03..7f57ed58e2 100644
--- a/hw/Makefile.objs
+++ b/hw/Makefile.objs
@@ -65,6 +65,34 @@ hw-obj-$(CONFIG_XILINX) += xilinx_timer.o
hw-obj-$(CONFIG_XILINX) += xilinx_uartlite.o
hw-obj-$(CONFIG_XILINX_AXI) += xilinx_axidma.o
hw-obj-$(CONFIG_XILINX_AXI) += xilinx_axienet.o
+hw-obj-$(CONFIG_XILINX_AXI) += stream.o
+
+# PKUnity SoC devices
+hw-obj-$(CONFIG_PUV3) += puv3_intc.o
+hw-obj-$(CONFIG_PUV3) += puv3_ost.o
+hw-obj-$(CONFIG_PUV3) += puv3_gpio.o
+hw-obj-$(CONFIG_PUV3) += puv3_pm.o
+hw-obj-$(CONFIG_PUV3) += puv3_dma.o
+
+# ARM devices
+hw-obj-$(CONFIG_ARM_TIMER) += arm_timer.o
+hw-obj-$(CONFIG_PL011) += pl011.o
+hw-obj-$(CONFIG_PL022) += pl022.o
+hw-obj-$(CONFIG_PL031) += pl031.o
+hw-obj-$(CONFIG_PL041) += pl041.o lm4549.o
+hw-obj-$(CONFIG_PL050) += pl050.o
+hw-obj-$(CONFIG_PL061) += pl061.o
+hw-obj-$(CONFIG_PL080) += pl080.o
+hw-obj-$(CONFIG_PL110) += pl110.o
+hw-obj-$(CONFIG_PL181) += pl181.o
+hw-obj-$(CONFIG_PL190) += pl190.o
+hw-obj-$(CONFIG_PL310) += arm_l2x0.o
+hw-obj-$(CONFIG_VERSATILE_PCI) += versatile_pci.o
+hw-obj-$(CONFIG_VERSATILE_I2C) += versatile_i2c.o
+hw-obj-$(CONFIG_CADENCE) += cadence_uart.o
+hw-obj-$(CONFIG_CADENCE) += cadence_ttc.o
+hw-obj-$(CONFIG_CADENCE) += cadence_gem.o
+hw-obj-$(CONFIG_XGMAC) += xgmac.o
# PCI watchdog devices
hw-obj-$(CONFIG_PCI) += wdt_i6300esb.o
@@ -88,6 +116,7 @@ hw-obj-$(CONFIG_OPENCORES_ETH) += opencores_eth.o
hw-obj-$(CONFIG_LSI_SCSI_PCI) += lsi53c895a.o
hw-obj-$(CONFIG_MEGASAS_SCSI_PCI) += megasas.o
hw-obj-$(CONFIG_ESP) += esp.o
+hw-obj-$(CONFIG_ESP_PCI) += esp-pci.o
hw-obj-y += sysbus.o isa-bus.o
hw-obj-y += qdev-addr.o
diff --git a/hw/arm/Makefile.objs b/hw/arm/Makefile.objs
index c413780784..2b39fb3c85 100644
--- a/hw/arm/Makefile.objs
+++ b/hw/arm/Makefile.objs
@@ -1,10 +1,5 @@
-obj-y = integratorcp.o versatilepb.o arm_pic.o arm_timer.o
-obj-y += arm_boot.o pl011.o pl031.o pl050.o pl080.o pl110.o pl181.o pl190.o
-obj-y += versatile_pci.o
-obj-y += versatile_i2c.o
-obj-y += cadence_uart.o
-obj-y += cadence_ttc.o
-obj-y += cadence_gem.o
+obj-y = integratorcp.o versatilepb.o arm_pic.o
+obj-y += arm_boot.o
obj-y += xilinx_zynq.o zynq_slcr.o
obj-y += arm_gic.o arm_gic_common.o
obj-y += realview_gic.o realview.o arm_sysctl.o arm11mpcore.o a9mpcore.o
@@ -12,12 +7,9 @@ obj-y += exynos4210_gic.o exynos4210_combiner.o exynos4210.o
obj-y += exynos4_boards.o exynos4210_uart.o exynos4210_pwm.o
obj-y += exynos4210_pmu.o exynos4210_mct.o exynos4210_fimd.o
obj-y += exynos4210_rtc.o exynos4210_i2c.o
-obj-y += arm_l2x0.o
obj-y += arm_mptimer.o a15mpcore.o
-obj-y += armv7m.o armv7m_nvic.o stellaris.o pl022.o stellaris_enet.o
+obj-y += armv7m.o armv7m_nvic.o stellaris.o stellaris_enet.o
obj-y += highbank.o
-obj-y += pl061.o
-obj-y += xgmac.o
obj-y += pxa2xx.o pxa2xx_pic.o pxa2xx_gpio.o pxa2xx_timer.o pxa2xx_dma.o
obj-y += pxa2xx_lcd.o pxa2xx_mmci.o pxa2xx_pcmcia.o pxa2xx_keypad.o
obj-y += gumstix.o
@@ -37,7 +29,6 @@ obj-y += strongarm.o
obj-y += collie.o
obj-y += imx_serial.o imx_ccm.o imx_timer.o imx_avic.o
obj-y += kzm.o
-obj-y += pl041.o lm4549.o
obj-$(CONFIG_FDT) += ../device_tree.o
obj-y := $(addprefix ../,$(obj-y))
diff --git a/hw/armv7m.c b/hw/armv7m.c
index 8cec78db96..9f66667c6d 100644
--- a/hw/armv7m.c
+++ b/hw/armv7m.c
@@ -227,6 +227,11 @@ qemu_irq *armv7m_init(MemoryRegion *address_space_mem,
big_endian = 0;
#endif
+ if (!kernel_filename) {
+ fprintf(stderr, "Guest image must be specified (using -kernel)\n");
+ exit(1);
+ }
+
image_size = load_elf(kernel_filename, NULL, NULL, &entry, &lowaddr,
NULL, big_endian, ELF_MACHINE, 1);
if (image_size < 0) {
diff --git a/hw/armv7m_nvic.c b/hw/armv7m_nvic.c
index 4867c1d5fa..6a0832eb3f 100644
--- a/hw/armv7m_nvic.c
+++ b/hw/armv7m_nvic.c
@@ -467,7 +467,7 @@ static int armv7m_nvic_init(SysBusDevice *dev)
s->gic.num_cpu = 1;
/* Tell the common code we're an NVIC */
s->gic.revision = 0xffffffff;
- s->gic.num_irq = s->num_irq;
+ s->num_irq = s->gic.num_irq;
nc->parent_init(dev);
gic_init_irqs_and_distributor(&s->gic, s->num_irq);
/* The NVIC and system controller register area looks like this:
@@ -498,14 +498,21 @@ static int armv7m_nvic_init(SysBusDevice *dev)
return 0;
}
-static Property armv7m_nvic_properties[] = {
+static void armv7m_nvic_instance_init(Object *obj)
+{
+ /* We have a different default value for the num-irq property
+ * than our superclass. This function runs after qdev init
+ * has set the defaults from the Property array and before
+ * any user-specified property setting, so just modify the
+ * value in the gic_state struct.
+ */
+ gic_state *s = ARM_GIC_COMMON(obj);
/* The ARM v7m may have anything from 0 to 496 external interrupt
* IRQ lines. We default to 64. Other boards may differ and should
- * set this property appropriately.
+ * set the num-irq property appropriately.
*/
- DEFINE_PROP_UINT32("num-irq", nvic_state, num_irq, 64),
- DEFINE_PROP_END_OF_LIST(),
-};
+ s->num_irq = 64;
+}
static void armv7m_nvic_class_init(ObjectClass *klass, void *data)
{
@@ -518,12 +525,12 @@ static void armv7m_nvic_class_init(ObjectClass *klass, void *data)
sdc->init = armv7m_nvic_init;
dc->vmsd = &vmstate_nvic;
dc->reset = armv7m_nvic_reset;
- dc->props = armv7m_nvic_properties;
}
static TypeInfo armv7m_nvic_info = {
.name = TYPE_NVIC,
.parent = TYPE_ARM_GIC_COMMON,
+ .instance_init = armv7m_nvic_instance_init,
.instance_size = sizeof(nvic_state),
.class_init = armv7m_nvic_class_init,
.class_size = sizeof(NVICClass),
diff --git a/hw/esp-pci.c b/hw/esp-pci.c
new file mode 100644
index 0000000000..170e007be9
--- /dev/null
+++ b/hw/esp-pci.c
@@ -0,0 +1,518 @@
+/*
+ * QEMU ESP/NCR53C9x emulation
+ *
+ * Copyright (c) 2005-2006 Fabrice Bellard
+ * Copyright (c) 2012 Herve Poussineau
+ *
+ * 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 "pci.h"
+#include "eeprom93xx.h"
+#include "esp.h"
+#include "trace.h"
+#include "qemu-log.h"
+
+#define TYPE_AM53C974_DEVICE "am53c974"
+
+#define DMA_CMD 0x0
+#define DMA_STC 0x1
+#define DMA_SPA 0x2
+#define DMA_WBC 0x3
+#define DMA_WAC 0x4
+#define DMA_STAT 0x5
+#define DMA_SMDLA 0x6
+#define DMA_WMAC 0x7
+
+#define DMA_CMD_MASK 0x03
+#define DMA_CMD_DIAG 0x04
+#define DMA_CMD_MDL 0x10
+#define DMA_CMD_INTE_P 0x20
+#define DMA_CMD_INTE_D 0x40
+#define DMA_CMD_DIR 0x80
+
+#define DMA_STAT_PWDN 0x01
+#define DMA_STAT_ERROR 0x02
+#define DMA_STAT_ABORT 0x04
+#define DMA_STAT_DONE 0x08
+#define DMA_STAT_SCSIINT 0x10
+#define DMA_STAT_BCMBLT 0x20
+
+#define SBAC_STATUS 0x1000
+
+typedef struct PCIESPState {
+ PCIDevice dev;
+ MemoryRegion io;
+ uint32_t dma_regs[8];
+ uint32_t sbac;
+ ESPState esp;
+} PCIESPState;
+
+static void esp_pci_handle_idle(PCIESPState *pci, uint32_t val)
+{
+ trace_esp_pci_dma_idle(val);
+ esp_dma_enable(&pci->esp, 0, 0);
+}
+
+static void esp_pci_handle_blast(PCIESPState *pci, uint32_t val)
+{
+ trace_esp_pci_dma_blast(val);
+ qemu_log_mask(LOG_UNIMP, "am53c974: cmd BLAST not implemented\n");
+}
+
+static void esp_pci_handle_abort(PCIESPState *pci, uint32_t val)
+{
+ trace_esp_pci_dma_abort(val);
+ if (pci->esp.current_req) {
+ scsi_req_cancel(pci->esp.current_req);
+ }
+}
+
+static void esp_pci_handle_start(PCIESPState *pci, uint32_t val)
+{
+ trace_esp_pci_dma_start(val);
+
+ pci->dma_regs[DMA_WBC] = pci->dma_regs[DMA_STC];
+ pci->dma_regs[DMA_WAC] = pci->dma_regs[DMA_SPA];
+ pci->dma_regs[DMA_WMAC] = pci->dma_regs[DMA_SMDLA];
+
+ pci->dma_regs[DMA_STAT] &= ~(DMA_STAT_BCMBLT | DMA_STAT_SCSIINT
+ | DMA_STAT_DONE | DMA_STAT_ABORT
+ | DMA_STAT_ERROR | DMA_STAT_PWDN);
+
+ esp_dma_enable(&pci->esp, 0, 1);
+}
+
+static void esp_pci_dma_write(PCIESPState *pci, uint32_t saddr, uint32_t val)
+{
+ trace_esp_pci_dma_write(saddr, pci->dma_regs[saddr], val);
+ switch (saddr) {
+ case DMA_CMD:
+ pci->dma_regs[saddr] = val;
+ switch (val & DMA_CMD_MASK) {
+ case 0x0: /* IDLE */
+ esp_pci_handle_idle(pci, val);
+ break;
+ case 0x1: /* BLAST */
+ esp_pci_handle_blast(pci, val);
+ break;
+ case 0x2: /* ABORT */
+ esp_pci_handle_abort(pci, val);
+ break;
+ case 0x3: /* START */
+ esp_pci_handle_start(pci, val);
+ break;
+ default: /* can't happen */
+ abort();
+ }
+ break;
+ case DMA_STC:
+ case DMA_SPA:
+ case DMA_SMDLA:
+ pci->dma_regs[saddr] = val;
+ break;
+ case DMA_STAT:
+ if (!(pci->sbac & SBAC_STATUS)) {
+ /* clear some bits on write */
+ uint32_t mask = DMA_STAT_ERROR | DMA_STAT_ABORT | DMA_STAT_DONE;
+ pci->dma_regs[DMA_STAT] &= ~(val & mask);
+ }
+ break;
+ default:
+ trace_esp_pci_error_invalid_write_dma(val, saddr);
+ return;
+ }
+}
+
+static uint32_t esp_pci_dma_read(PCIESPState *pci, uint32_t saddr)
+{
+ uint32_t val;
+
+ val = pci->dma_regs[saddr];
+ if (saddr == DMA_STAT) {
+ if (pci->esp.rregs[ESP_RSTAT] & STAT_INT) {
+ val |= DMA_STAT_SCSIINT;
+ }
+ if (pci->sbac & SBAC_STATUS) {
+ pci->dma_regs[DMA_STAT] &= ~(DMA_STAT_ERROR | DMA_STAT_ABORT |
+ DMA_STAT_DONE);
+ }
+ }
+
+ trace_esp_pci_dma_read(saddr, val);
+ return val;
+}
+
+static void esp_pci_io_write(void *opaque, target_phys_addr_t addr,
+ uint64_t val, unsigned int size)
+{
+ PCIESPState *pci = opaque;
+
+ if (size < 4 || addr & 3) {
+ /* need to upgrade request: we only support 4-bytes accesses */
+ uint32_t current = 0, mask;
+ int shift;
+
+ if (addr < 0x40) {
+ current = pci->esp.wregs[addr >> 2];
+ } else if (addr < 0x60) {
+ current = pci->dma_regs[(addr - 0x40) >> 2];
+ } else if (addr < 0x74) {
+ current = pci->sbac;
+ }
+
+ shift = (4 - size) * 8;
+ mask = (~(uint32_t)0 << shift) >> shift;
+
+ shift = ((4 - (addr & 3)) & 3) * 8;
+ val <<= shift;
+ val |= current & ~(mask << shift);
+ addr &= ~3;
+ size = 4;
+ }
+
+ if (addr < 0x40) {
+ /* SCSI core reg */
+ esp_reg_write(&pci->esp, addr >> 2, val);
+ } else if (addr < 0x60) {
+ /* PCI DMA CCB */
+ esp_pci_dma_write(pci, (addr - 0x40) >> 2, val);
+ } else if (addr == 0x70) {
+ /* DMA SCSI Bus and control */
+ trace_esp_pci_sbac_write(pci->sbac, val);
+ pci->sbac = val;
+ } else {
+ trace_esp_pci_error_invalid_write((int)addr);
+ }
+}
+
+static uint64_t esp_pci_io_read(void *opaque, target_phys_addr_t addr,
+ unsigned int size)
+{
+ PCIESPState *pci = opaque;
+ uint32_t ret;
+
+ if (addr < 0x40) {
+ /* SCSI core reg */
+ ret = esp_reg_read(&pci->esp, addr >> 2);
+ } else if (addr < 0x60) {
+ /* PCI DMA CCB */
+ ret = esp_pci_dma_read(pci, (addr - 0x40) >> 2);
+ } else if (addr == 0x70) {
+ /* DMA SCSI Bus and control */
+ trace_esp_pci_sbac_read(pci->sbac);
+ ret = pci->sbac;
+ } else {
+ /* Invalid region */
+ trace_esp_pci_error_invalid_read((int)addr);
+ ret = 0;
+ }
+
+ /* give only requested data */
+ ret >>= (addr & 3) * 8;
+ ret &= ~(~(uint64_t)0 << (8 * size));
+
+ return ret;
+}
+
+static void esp_pci_dma_memory_rw(PCIESPState *pci, uint8_t *buf, int len,
+ DMADirection dir)
+{
+ dma_addr_t addr;
+ DMADirection expected_dir;
+
+ if (pci->dma_regs[DMA_CMD] & DMA_CMD_DIR) {
+ expected_dir = DMA_DIRECTION_FROM_DEVICE;
+ } else {
+ expected_dir = DMA_DIRECTION_TO_DEVICE;
+ }
+
+ if (dir != expected_dir) {
+ trace_esp_pci_error_invalid_dma_direction();
+ return;
+ }
+
+ if (pci->dma_regs[DMA_STAT] & DMA_CMD_MDL) {
+ qemu_log_mask(LOG_UNIMP, "am53c974: MDL transfer not implemented\n");
+ }
+
+ addr = pci->dma_regs[DMA_SPA];
+ if (pci->dma_regs[DMA_WBC] < len) {
+ len = pci->dma_regs[DMA_WBC];
+ }
+
+ pci_dma_rw(&pci->dev, addr, buf, len, dir);
+
+ /* update status registers */
+ pci->dma_regs[DMA_WBC] -= len;
+ pci->dma_regs[DMA_WAC] += len;
+}
+
+static void esp_pci_dma_memory_read(void *opaque, uint8_t *buf, int len)
+{
+ PCIESPState *pci = opaque;
+ esp_pci_dma_memory_rw(pci, buf, len, DMA_DIRECTION_TO_DEVICE);
+}
+
+static void esp_pci_dma_memory_write(void *opaque, uint8_t *buf, int len)
+{
+ PCIESPState *pci = opaque;
+ esp_pci_dma_memory_rw(pci, buf, len, DMA_DIRECTION_FROM_DEVICE);
+}
+
+static const MemoryRegionOps esp_pci_io_ops = {
+ .read = esp_pci_io_read,
+ .write = esp_pci_io_write,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+ .impl = {
+ .min_access_size = 1,
+ .max_access_size = 4,
+ },
+};
+
+static void esp_pci_hard_reset(DeviceState *dev)
+{
+ PCIESPState *pci = DO_UPCAST(PCIESPState, dev.qdev, dev);
+ esp_hard_reset(&pci->esp);
+ pci->dma_regs[DMA_CMD] &= ~(DMA_CMD_DIR | DMA_CMD_INTE_D | DMA_CMD_INTE_P
+ | DMA_CMD_MDL | DMA_CMD_DIAG | DMA_CMD_MASK);
+ pci->dma_regs[DMA_WBC] &= ~0xffff;
+ pci->dma_regs[DMA_WAC] = 0xffffffff;
+ pci->dma_regs[DMA_STAT] &= ~(DMA_STAT_BCMBLT | DMA_STAT_SCSIINT
+ | DMA_STAT_DONE | DMA_STAT_ABORT
+ | DMA_STAT_ERROR);
+ pci->dma_regs[DMA_WMAC] = 0xfffffffd;
+}
+
+static const VMStateDescription vmstate_esp_pci_scsi = {
+ .name = "pciespscsi",
+ .version_id = 0,
+ .minimum_version_id = 0,
+ .minimum_version_id_old = 0,
+ .fields = (VMStateField[]) {
+ VMSTATE_PCI_DEVICE(dev, PCIESPState),
+ VMSTATE_BUFFER_UNSAFE(dma_regs, PCIESPState, 0, 8 * sizeof(uint32_t)),
+ VMSTATE_STRUCT(esp, PCIESPState, 0, vmstate_esp, ESPState),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static void esp_pci_command_complete(SCSIRequest *req, uint32_t status,
+ size_t resid)
+{
+ ESPState *s = req->hba_private;
+ PCIESPState *pci = container_of(s, PCIESPState, esp);
+
+ esp_command_complete(req, status, resid);
+ pci->dma_regs[DMA_WBC] = 0;
+ pci->dma_regs[DMA_STAT] |= DMA_STAT_DONE;
+}
+
+static const struct SCSIBusInfo esp_pci_scsi_info = {
+ .tcq = false,
+ .max_target = ESP_MAX_DEVS,
+ .max_lun = 7,
+
+ .transfer_data = esp_transfer_data,
+ .complete = esp_pci_command_complete,
+ .cancel = esp_request_cancelled,
+};
+
+static int esp_pci_scsi_init(PCIDevice *dev)
+{
+ PCIESPState *pci = DO_UPCAST(PCIESPState, dev, dev);
+ ESPState *s = &pci->esp;
+ uint8_t *pci_conf;
+
+ pci_conf = pci->dev.config;
+
+ /* Interrupt pin A */
+ pci_conf[PCI_INTERRUPT_PIN] = 0x01;
+
+ s->dma_memory_read = esp_pci_dma_memory_read;
+ s->dma_memory_write = esp_pci_dma_memory_write;
+ s->dma_opaque = pci;
+ s->chip_id = TCHI_AM53C974;
+ memory_region_init_io(&pci->io, &esp_pci_io_ops, pci, "esp-io", 0x80);
+
+ pci_register_bar(&pci->dev, 0, PCI_BASE_ADDRESS_SPACE_IO, &pci->io);
+ s->irq = pci->dev.irq[0];
+
+ scsi_bus_new(&s->bus, &dev->qdev, &esp_pci_scsi_info);
+ if (!dev->qdev.hotplugged) {
+ return scsi_bus_legacy_handle_cmdline(&s->bus);
+ }
+ return 0;
+}
+
+static void esp_pci_scsi_uninit(PCIDevice *d)
+{
+ PCIESPState *pci = DO_UPCAST(PCIESPState, dev, d);
+
+ memory_region_destroy(&pci->io);
+}
+
+static void esp_pci_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+ k->init = esp_pci_scsi_init;
+ k->exit = esp_pci_scsi_uninit;
+ k->vendor_id = PCI_VENDOR_ID_AMD;
+ k->device_id = PCI_DEVICE_ID_AMD_SCSI;
+ k->revision = 0x10;
+ k->class_id = PCI_CLASS_STORAGE_SCSI;
+ dc->desc = "AMD Am53c974 PCscsi-PCI SCSI adapter";
+ dc->reset = esp_pci_hard_reset;
+ dc->vmsd = &vmstate_esp_pci_scsi;
+}
+
+static const TypeInfo esp_pci_info = {
+ .name = TYPE_AM53C974_DEVICE,
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(PCIESPState),
+ .class_init = esp_pci_class_init,
+};
+
+typedef struct {
+ PCIESPState pci;
+ eeprom_t *eeprom;
+} DC390State;
+
+#define TYPE_DC390_DEVICE "dc390"
+#define DC390(obj) \
+ OBJECT_CHECK(DC390State, obj, TYPE_DC390_DEVICE)
+
+#define EE_ADAPT_SCSI_ID 64
+#define EE_MODE2 65
+#define EE_DELAY 66
+#define EE_TAG_CMD_NUM 67
+#define EE_ADAPT_OPTIONS 68
+#define EE_BOOT_SCSI_ID 69
+#define EE_BOOT_SCSI_LUN 70
+#define EE_CHKSUM1 126
+#define EE_CHKSUM2 127
+
+#define EE_ADAPT_OPTION_F6_F8_AT_BOOT 0x01
+#define EE_ADAPT_OPTION_BOOT_FROM_CDROM 0x02
+#define EE_ADAPT_OPTION_INT13 0x04
+#define EE_ADAPT_OPTION_SCAM_SUPPORT 0x08
+
+
+static uint32_t dc390_read_config(PCIDevice *dev, uint32_t addr, int l)
+{
+ DC390State *pci = DC390(dev);
+ uint32_t val;
+
+ val = pci_default_read_config(dev, addr, l);
+
+ if (addr == 0x00 && l == 1) {
+ /* First byte of address space is AND-ed with EEPROM DO line */
+ if (!eeprom93xx_read(pci->eeprom)) {
+ val &= ~0xff;
+ }
+ }
+
+ return val;
+}
+
+static void dc390_write_config(PCIDevice *dev,
+ uint32_t addr, uint32_t val, int l)
+{
+ DC390State *pci = DC390(dev);
+ if (addr == 0x80) {
+ /* EEPROM write */
+ int eesk = val & 0x80 ? 1 : 0;
+ int eedi = val & 0x40 ? 1 : 0;
+ eeprom93xx_write(pci->eeprom, 1, eesk, eedi);
+ } else if (addr == 0xc0) {
+ /* EEPROM CS low */
+ eeprom93xx_write(pci->eeprom, 0, 0, 0);
+ } else {
+ pci_default_write_config(dev, addr, val, l);
+ }
+}
+
+static int dc390_scsi_init(PCIDevice *dev)
+{
+ DC390State *pci = DC390(dev);
+ uint8_t *contents;
+ uint16_t chksum = 0;
+ int i, ret;
+
+ /* init base class */
+ ret = esp_pci_scsi_init(dev);
+ if (ret < 0) {
+ return ret;
+ }
+
+ /* EEPROM */
+ pci->eeprom = eeprom93xx_new(DEVICE(dev), 64);
+
+ /* set default eeprom values */
+ contents = (uint8_t *)eeprom93xx_data(pci->eeprom);
+
+ for (i = 0; i < 16; i++) {
+ contents[i * 2] = 0x57;
+ contents[i * 2 + 1] = 0x00;
+ }
+ contents[EE_ADAPT_SCSI_ID] = 7;
+ contents[EE_MODE2] = 0x0f;
+ contents[EE_TAG_CMD_NUM] = 0x04;
+ contents[EE_ADAPT_OPTIONS] = EE_ADAPT_OPTION_F6_F8_AT_BOOT
+ | EE_ADAPT_OPTION_BOOT_FROM_CDROM
+ | EE_ADAPT_OPTION_INT13;
+
+ /* update eeprom checksum */
+ for (i = 0; i < EE_CHKSUM1; i += 2) {
+ chksum += contents[i] + (((uint16_t)contents[i + 1]) << 8);
+ }
+ chksum = 0x1234 - chksum;
+ contents[EE_CHKSUM1] = chksum & 0xff;
+ contents[EE_CHKSUM2] = chksum >> 8;
+
+ return 0;
+}
+
+static void dc390_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+ k->init = dc390_scsi_init;
+ k->config_read = dc390_read_config;
+ k->config_write = dc390_write_config;
+ dc->desc = "Tekram DC-390 SCSI adapter";
+}
+
+static const TypeInfo dc390_info = {
+ .name = "dc390",
+ .parent = TYPE_AM53C974_DEVICE,
+ .instance_size = sizeof(DC390State),
+ .class_init = dc390_class_init,
+};
+
+static void esp_pci_register_types(void)
+{
+ type_register_static(&esp_pci_info);
+ type_register_static(&dc390_info);
+}
+
+type_init(esp_pci_register_types)
diff --git a/hw/esp.c b/hw/esp.c
index 77f57076c7..52c46e615f 100644
--- a/hw/esp.c
+++ b/hw/esp.c
@@ -24,8 +24,6 @@
*/
#include "sysbus.h"
-#include "pci.h"
-#include "scsi.h"
#include "esp.h"
#include "trace.h"
#include "qemu-log.h"
@@ -38,114 +36,6 @@
* http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR53C9X.txt
*/
-#define ESP_REGS 16
-#define TI_BUFSZ 16
-
-typedef struct ESPState ESPState;
-
-struct ESPState {
- uint8_t rregs[ESP_REGS];
- uint8_t wregs[ESP_REGS];
- qemu_irq irq;
- uint8_t chip_id;
- int32_t ti_size;
- uint32_t ti_rptr, ti_wptr;
- uint32_t status;
- uint32_t dma;
- uint8_t ti_buf[TI_BUFSZ];
- SCSIBus bus;
- SCSIDevice *current_dev;
- SCSIRequest *current_req;
- uint8_t cmdbuf[TI_BUFSZ];
- uint32_t cmdlen;
- uint32_t do_cmd;
-
- /* The amount of data left in the current DMA transfer. */
- uint32_t dma_left;
- /* The size of the current DMA transfer. Zero if no transfer is in
- progress. */
- uint32_t dma_counter;
- int dma_enabled;
-
- uint32_t async_len;
- uint8_t *async_buf;
-
- ESPDMAMemoryReadWriteFunc dma_memory_read;
- ESPDMAMemoryReadWriteFunc dma_memory_write;
- void *dma_opaque;
- void (*dma_cb)(ESPState *s);
-};
-
-#define ESP_TCLO 0x0
-#define ESP_TCMID 0x1
-#define ESP_FIFO 0x2
-#define ESP_CMD 0x3
-#define ESP_RSTAT 0x4
-#define ESP_WBUSID 0x4
-#define ESP_RINTR 0x5
-#define ESP_WSEL 0x5
-#define ESP_RSEQ 0x6
-#define ESP_WSYNTP 0x6
-#define ESP_RFLAGS 0x7
-#define ESP_WSYNO 0x7
-#define ESP_CFG1 0x8
-#define ESP_RRES1 0x9
-#define ESP_WCCF 0x9
-#define ESP_RRES2 0xa
-#define ESP_WTEST 0xa
-#define ESP_CFG2 0xb
-#define ESP_CFG3 0xc
-#define ESP_RES3 0xd
-#define ESP_TCHI 0xe
-#define ESP_RES4 0xf
-
-#define CMD_DMA 0x80
-#define CMD_CMD 0x7f
-
-#define CMD_NOP 0x00
-#define CMD_FLUSH 0x01
-#define CMD_RESET 0x02
-#define CMD_BUSRESET 0x03
-#define CMD_TI 0x10
-#define CMD_ICCS 0x11
-#define CMD_MSGACC 0x12
-#define CMD_PAD 0x18
-#define CMD_SATN 0x1a
-#define CMD_RSTATN 0x1b
-#define CMD_SEL 0x41
-#define CMD_SELATN 0x42
-#define CMD_SELATNS 0x43
-#define CMD_ENSEL 0x44
-#define CMD_DISSEL 0x45
-
-#define STAT_DO 0x00
-#define STAT_DI 0x01
-#define STAT_CD 0x02
-#define STAT_ST 0x03
-#define STAT_MO 0x06
-#define STAT_MI 0x07
-#define STAT_PIO_MASK 0x06
-
-#define STAT_TC 0x10
-#define STAT_PE 0x20
-#define STAT_GE 0x40
-#define STAT_INT 0x80
-
-#define BUSID_DID 0x07
-
-#define INTR_FC 0x08
-#define INTR_BS 0x10
-#define INTR_DC 0x20
-#define INTR_RST 0x80
-
-#define SEQ_0 0x0
-#define SEQ_CD 0x4
-
-#define CFG1_RESREPT 0x40
-
-#define TCHI_FAS100A 0x4
-#define TCHI_AM53C974 0x12
-
static void esp_raise_irq(ESPState *s)
{
if (!(s->rregs[ESP_RSTAT] & STAT_INT)) {
@@ -164,7 +54,7 @@ static void esp_lower_irq(ESPState *s)
}
}
-static void esp_dma_enable(ESPState *s, int irq, int level)
+void esp_dma_enable(ESPState *s, int irq, int level)
{
if (level) {
s->dma_enabled = 1;
@@ -179,7 +69,7 @@ static void esp_dma_enable(ESPState *s, int irq, int level)
}
}
-static void esp_request_cancelled(SCSIRequest *req)
+void esp_request_cancelled(SCSIRequest *req)
{
ESPState *s = req->hba_private;
@@ -388,7 +278,7 @@ static void esp_do_dma(ESPState *s)
esp_dma_done(s);
}
-static void esp_command_complete(SCSIRequest *req, uint32_t status,
+void esp_command_complete(SCSIRequest *req, uint32_t status,
size_t resid)
{
ESPState *s = req->hba_private;
@@ -413,7 +303,7 @@ static void esp_command_complete(SCSIRequest *req, uint32_t status,
}
}
-static void esp_transfer_data(SCSIRequest *req, uint32_t len)
+void esp_transfer_data(SCSIRequest *req, uint32_t len)
{
ESPState *s = req->hba_private;
@@ -465,7 +355,7 @@ static void handle_ti(ESPState *s)
}
}
-static void esp_hard_reset(ESPState *s)
+void esp_hard_reset(ESPState *s)
{
memset(s->rregs, 0, ESP_REGS);
memset(s->wregs, 0, ESP_REGS);
@@ -493,7 +383,7 @@ static void parent_esp_reset(ESPState *s, int irq, int level)
}
}
-static uint64_t esp_reg_read(ESPState *s, uint32_t saddr)
+uint64_t esp_reg_read(ESPState *s, uint32_t saddr)
{
uint32_t old_val;
@@ -533,7 +423,7 @@ static uint64_t esp_reg_read(ESPState *s, uint32_t saddr)
return s->rregs[saddr];
}
-static void esp_reg_write(ESPState *s, uint32_t saddr, uint64_t val)
+void esp_reg_write(ESPState *s, uint32_t saddr, uint64_t val)
{
trace_esp_mem_writeb(saddr, s->wregs[saddr], val);
switch (saddr) {
@@ -660,7 +550,7 @@ static bool esp_mem_accepts(void *opaque, target_phys_addr_t addr,
return (size == 1) || (is_write && size == 4);
}
-static const VMStateDescription vmstate_esp = {
+const VMStateDescription vmstate_esp = {
.name ="esp",
.version_id = 3,
.minimum_version_id = 3,
@@ -823,370 +713,9 @@ static const TypeInfo sysbus_esp_info = {
.class_init = sysbus_esp_class_init,
};
-#define DMA_CMD 0x0
-#define DMA_STC 0x1
-#define DMA_SPA 0x2
-#define DMA_WBC 0x3
-#define DMA_WAC 0x4
-#define DMA_STAT 0x5
-#define DMA_SMDLA 0x6
-#define DMA_WMAC 0x7
-
-#define DMA_CMD_MASK 0x03
-#define DMA_CMD_DIAG 0x04
-#define DMA_CMD_MDL 0x10
-#define DMA_CMD_INTE_P 0x20
-#define DMA_CMD_INTE_D 0x40
-#define DMA_CMD_DIR 0x80
-
-#define DMA_STAT_PWDN 0x01
-#define DMA_STAT_ERROR 0x02
-#define DMA_STAT_ABORT 0x04
-#define DMA_STAT_DONE 0x08
-#define DMA_STAT_SCSIINT 0x10
-#define DMA_STAT_BCMBLT 0x20
-
-#define SBAC_STATUS 0x1000
-
-typedef struct PCIESPState {
- PCIDevice dev;
- MemoryRegion io;
- uint32_t dma_regs[8];
- uint32_t sbac;
- ESPState esp;
-} PCIESPState;
-
-static void esp_pci_handle_idle(PCIESPState *pci, uint32_t val)
-{
- trace_esp_pci_dma_idle(val);
- esp_dma_enable(&pci->esp, 0, 0);
-}
-
-static void esp_pci_handle_blast(PCIESPState *pci, uint32_t val)
-{
- trace_esp_pci_dma_blast(val);
- qemu_log_mask(LOG_UNIMP, "am53c974: cmd BLAST not implemented\n");
-}
-
-static void esp_pci_handle_abort(PCIESPState *pci, uint32_t val)
-{
- trace_esp_pci_dma_abort(val);
- if (pci->esp.current_req) {
- scsi_req_cancel(pci->esp.current_req);
- }
-}
-
-static void esp_pci_handle_start(PCIESPState *pci, uint32_t val)
-{
- trace_esp_pci_dma_start(val);
-
- pci->dma_regs[DMA_WBC] = pci->dma_regs[DMA_STC];
- pci->dma_regs[DMA_WAC] = pci->dma_regs[DMA_SPA];
- pci->dma_regs[DMA_WMAC] = pci->dma_regs[DMA_SMDLA];
-
- pci->dma_regs[DMA_STAT] &= ~(DMA_STAT_BCMBLT | DMA_STAT_SCSIINT
- | DMA_STAT_DONE | DMA_STAT_ABORT
- | DMA_STAT_ERROR | DMA_STAT_PWDN);
-
- esp_dma_enable(&pci->esp, 0, 1);
-}
-
-static void esp_pci_dma_write(PCIESPState *pci, uint32_t saddr, uint32_t val)
-{
- trace_esp_pci_dma_write(saddr, pci->dma_regs[saddr], val);
- switch (saddr) {
- case DMA_CMD:
- pci->dma_regs[saddr] = val;
- switch (val & DMA_CMD_MASK) {
- case 0x0: /* IDLE */
- esp_pci_handle_idle(pci, val);
- break;
- case 0x1: /* BLAST */
- esp_pci_handle_blast(pci, val);
- break;
- case 0x2: /* ABORT */
- esp_pci_handle_abort(pci, val);
- break;
- case 0x3: /* START */
- esp_pci_handle_start(pci, val);
- break;
- default: /* can't happen */
- abort();
- }
- break;
- case DMA_STC:
- case DMA_SPA:
- case DMA_SMDLA:
- pci->dma_regs[saddr] = val;
- break;
- case DMA_STAT:
- if (!(pci->sbac & SBAC_STATUS)) {
- /* clear some bits on write */
- uint32_t mask = DMA_STAT_ERROR | DMA_STAT_ABORT | DMA_STAT_DONE;
- pci->dma_regs[DMA_STAT] &= ~(val & mask);
- }
- break;
- default:
- trace_esp_pci_error_invalid_write_dma(val, saddr);
- return;
- }
-}
-
-static uint32_t esp_pci_dma_read(PCIESPState *pci, uint32_t saddr)
-{
- uint32_t val;
-
- val = pci->dma_regs[saddr];
- if (saddr == DMA_STAT) {
- if (pci->esp.rregs[ESP_RSTAT] & STAT_INT) {
- val |= DMA_STAT_SCSIINT;
- }
- if (pci->sbac & SBAC_STATUS) {
- pci->dma_regs[DMA_STAT] &= ~(DMA_STAT_ERROR | DMA_STAT_ABORT |
- DMA_STAT_DONE);
- }
- }
-
- trace_esp_pci_dma_read(saddr, val);
- return val;
-}
-
-static void esp_pci_io_write(void *opaque, target_phys_addr_t addr,
- uint64_t val, unsigned int size)
-{
- PCIESPState *pci = opaque;
-
- if (size < 4 || addr & 3) {
- /* need to upgrade request: we only support 4-bytes accesses */
- uint32_t current = 0, mask;
- int shift;
-
- if (addr < 0x40) {
- current = pci->esp.wregs[addr >> 2];
- } else if (addr < 0x60) {
- current = pci->dma_regs[(addr - 0x40) >> 2];
- } else if (addr < 0x74) {
- current = pci->sbac;
- }
-
- shift = (4 - size) * 8;
- mask = (~(uint32_t)0 << shift) >> shift;
-
- shift = ((4 - (addr & 3)) & 3) * 8;
- val <<= shift;
- val |= current & ~(mask << shift);
- addr &= ~3;
- size = 4;
- }
-
- if (addr < 0x40) {
- /* SCSI core reg */
- esp_reg_write(&pci->esp, addr >> 2, val);
- } else if (addr < 0x60) {
- /* PCI DMA CCB */
- esp_pci_dma_write(pci, (addr - 0x40) >> 2, val);
- } else if (addr == 0x70) {
- /* DMA SCSI Bus and control */
- trace_esp_pci_sbac_write(pci->sbac, val);
- pci->sbac = val;
- } else {
- trace_esp_pci_error_invalid_write((int)addr);
- }
-}
-
-static uint64_t esp_pci_io_read(void *opaque, target_phys_addr_t addr,
- unsigned int size)
-{
- PCIESPState *pci = opaque;
- uint32_t ret;
-
- if (addr < 0x40) {
- /* SCSI core reg */
- ret = esp_reg_read(&pci->esp, addr >> 2);
- } else if (addr < 0x60) {
- /* PCI DMA CCB */
- ret = esp_pci_dma_read(pci, (addr - 0x40) >> 2);
- } else if (addr == 0x70) {
- /* DMA SCSI Bus and control */
- trace_esp_pci_sbac_read(pci->sbac);
- ret = pci->sbac;
- } else {
- /* Invalid region */
- trace_esp_pci_error_invalid_read((int)addr);
- ret = 0;
- }
-
- /* give only requested data */
- ret >>= (addr & 3) * 8;
- ret &= ~(~(uint64_t)0 << (8 * size));
-
- return ret;
-}
-
-static void esp_pci_dma_memory_rw(PCIESPState *pci, uint8_t *buf, int len,
- DMADirection dir)
-{
- dma_addr_t addr;
- DMADirection expected_dir;
-
- if (pci->dma_regs[DMA_CMD] & DMA_CMD_DIR) {
- expected_dir = DMA_DIRECTION_FROM_DEVICE;
- } else {
- expected_dir = DMA_DIRECTION_TO_DEVICE;
- }
-
- if (dir != expected_dir) {
- trace_esp_pci_error_invalid_dma_direction();
- return;
- }
-
- if (pci->dma_regs[DMA_STAT] & DMA_CMD_MDL) {
- qemu_log_mask(LOG_UNIMP, "am53c974: MDL transfer not implemented\n");
- }
-
- addr = pci->dma_regs[DMA_SPA];
- if (pci->dma_regs[DMA_WBC] < len) {
- len = pci->dma_regs[DMA_WBC];
- }
-
- pci_dma_rw(&pci->dev, addr, buf, len, dir);
-
- /* update status registers */
- pci->dma_regs[DMA_WBC] -= len;
- pci->dma_regs[DMA_WAC] += len;
-}
-
-static void esp_pci_dma_memory_read(void *opaque, uint8_t *buf, int len)
-{
- PCIESPState *pci = opaque;
- esp_pci_dma_memory_rw(pci, buf, len, DMA_DIRECTION_TO_DEVICE);
-}
-
-static void esp_pci_dma_memory_write(void *opaque, uint8_t *buf, int len)
-{
- PCIESPState *pci = opaque;
- esp_pci_dma_memory_rw(pci, buf, len, DMA_DIRECTION_FROM_DEVICE);
-}
-
-static const MemoryRegionOps esp_pci_io_ops = {
- .read = esp_pci_io_read,
- .write = esp_pci_io_write,
- .endianness = DEVICE_LITTLE_ENDIAN,
- .impl = {
- .min_access_size = 1,
- .max_access_size = 4,
- },
-};
-
-static void esp_pci_hard_reset(DeviceState *dev)
-{
- PCIESPState *pci = DO_UPCAST(PCIESPState, dev.qdev, dev);
- esp_hard_reset(&pci->esp);
- pci->dma_regs[DMA_CMD] &= ~(DMA_CMD_DIR | DMA_CMD_INTE_D | DMA_CMD_INTE_P
- | DMA_CMD_MDL | DMA_CMD_DIAG | DMA_CMD_MASK);
- pci->dma_regs[DMA_WBC] &= ~0xffff;
- pci->dma_regs[DMA_WAC] = 0xffffffff;
- pci->dma_regs[DMA_STAT] &= ~(DMA_STAT_BCMBLT | DMA_STAT_SCSIINT
- | DMA_STAT_DONE | DMA_STAT_ABORT
- | DMA_STAT_ERROR);
- pci->dma_regs[DMA_WMAC] = 0xfffffffd;
-}
-
-static const VMStateDescription vmstate_esp_pci_scsi = {
- .name = "pciespscsi",
- .version_id = 0,
- .minimum_version_id = 0,
- .minimum_version_id_old = 0,
- .fields = (VMStateField[]) {
- VMSTATE_PCI_DEVICE(dev, PCIESPState),
- VMSTATE_BUFFER_UNSAFE(dma_regs, PCIESPState, 0, 8 * sizeof(uint32_t)),
- VMSTATE_STRUCT(esp, PCIESPState, 0, vmstate_esp, ESPState),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static void esp_pci_command_complete(SCSIRequest *req, uint32_t status,
- size_t resid)
-{
- ESPState *s = req->hba_private;
- PCIESPState *pci = container_of(s, PCIESPState, esp);
-
- esp_command_complete(req, status, resid);
- pci->dma_regs[DMA_WBC] = 0;
- pci->dma_regs[DMA_STAT] |= DMA_STAT_DONE;
-}
-
-static const struct SCSIBusInfo esp_pci_scsi_info = {
- .tcq = false,
- .max_target = ESP_MAX_DEVS,
- .max_lun = 7,
-
- .transfer_data = esp_transfer_data,
- .complete = esp_pci_command_complete,
- .cancel = esp_request_cancelled,
-};
-
-static int esp_pci_scsi_init(PCIDevice *dev)
-{
- PCIESPState *pci = DO_UPCAST(PCIESPState, dev, dev);
- ESPState *s = &pci->esp;
- uint8_t *pci_conf;
-
- pci_conf = pci->dev.config;
-
- /* Interrupt pin A */
- pci_conf[PCI_INTERRUPT_PIN] = 0x01;
-
- s->dma_memory_read = esp_pci_dma_memory_read;
- s->dma_memory_write = esp_pci_dma_memory_write;
- s->dma_opaque = pci;
- s->chip_id = TCHI_AM53C974;
- memory_region_init_io(&pci->io, &esp_pci_io_ops, pci, "esp-io", 0x80);
-
- pci_register_bar(&pci->dev, 0, PCI_BASE_ADDRESS_SPACE_IO, &pci->io);
- s->irq = pci->dev.irq[0];
-
- scsi_bus_new(&s->bus, &dev->qdev, &esp_pci_scsi_info);
- if (!dev->qdev.hotplugged) {
- return scsi_bus_legacy_handle_cmdline(&s->bus);
- }
- return 0;
-}
-
-static void esp_pci_scsi_uninit(PCIDevice *d)
-{
- PCIESPState *pci = DO_UPCAST(PCIESPState, dev, d);
-
- memory_region_destroy(&pci->io);
-}
-
-static void esp_pci_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
-
- k->init = esp_pci_scsi_init;
- k->exit = esp_pci_scsi_uninit;
- k->vendor_id = PCI_VENDOR_ID_AMD;
- k->device_id = PCI_DEVICE_ID_AMD_SCSI;
- k->revision = 0x10;
- k->class_id = PCI_CLASS_STORAGE_SCSI;
- dc->desc = "AMD Am53c974 PCscsi-PCI SCSI adapter";
- dc->reset = esp_pci_hard_reset;
- dc->vmsd = &vmstate_esp_pci_scsi;
-}
-
-static const TypeInfo esp_pci_info = {
- .name = "am53c974",
- .parent = TYPE_PCI_DEVICE,
- .instance_size = sizeof(PCIESPState),
- .class_init = esp_pci_class_init,
-};
-
static void esp_register_types(void)
{
type_register_static(&sysbus_esp_info);
- type_register_static(&esp_pci_info);
}
type_init(esp_register_types)
diff --git a/hw/esp.h b/hw/esp.h
index 62bfd4d129..fa855e2fdf 100644
--- a/hw/esp.h
+++ b/hw/esp.h
@@ -1,6 +1,8 @@
#ifndef QEMU_HW_ESP_H
#define QEMU_HW_ESP_H
+#include "scsi.h"
+
/* esp.c */
#define ESP_MAX_DEVS 7
typedef void (*ESPDMAMemoryReadWriteFunc)(void *opaque, uint8_t *buf, int len);
@@ -10,4 +12,121 @@ void esp_init(target_phys_addr_t espaddr, int it_shift,
void *dma_opaque, qemu_irq irq, qemu_irq *reset,
qemu_irq *dma_enable);
+#define ESP_REGS 16
+#define TI_BUFSZ 16
+
+typedef struct ESPState ESPState;
+
+struct ESPState {
+ uint8_t rregs[ESP_REGS];
+ uint8_t wregs[ESP_REGS];
+ qemu_irq irq;
+ uint8_t chip_id;
+ int32_t ti_size;
+ uint32_t ti_rptr, ti_wptr;
+ uint32_t status;
+ uint32_t dma;
+ uint8_t ti_buf[TI_BUFSZ];
+ SCSIBus bus;
+ SCSIDevice *current_dev;
+ SCSIRequest *current_req;
+ uint8_t cmdbuf[TI_BUFSZ];
+ uint32_t cmdlen;
+ uint32_t do_cmd;
+
+ /* The amount of data left in the current DMA transfer. */
+ uint32_t dma_left;
+ /* The size of the current DMA transfer. Zero if no transfer is in
+ progress. */
+ uint32_t dma_counter;
+ int dma_enabled;
+
+ uint32_t async_len;
+ uint8_t *async_buf;
+
+ ESPDMAMemoryReadWriteFunc dma_memory_read;
+ ESPDMAMemoryReadWriteFunc dma_memory_write;
+ void *dma_opaque;
+ void (*dma_cb)(ESPState *s);
+};
+
+#define ESP_TCLO 0x0
+#define ESP_TCMID 0x1
+#define ESP_FIFO 0x2
+#define ESP_CMD 0x3
+#define ESP_RSTAT 0x4
+#define ESP_WBUSID 0x4
+#define ESP_RINTR 0x5
+#define ESP_WSEL 0x5
+#define ESP_RSEQ 0x6
+#define ESP_WSYNTP 0x6
+#define ESP_RFLAGS 0x7
+#define ESP_WSYNO 0x7
+#define ESP_CFG1 0x8
+#define ESP_RRES1 0x9
+#define ESP_WCCF 0x9
+#define ESP_RRES2 0xa
+#define ESP_WTEST 0xa
+#define ESP_CFG2 0xb
+#define ESP_CFG3 0xc
+#define ESP_RES3 0xd
+#define ESP_TCHI 0xe
+#define ESP_RES4 0xf
+
+#define CMD_DMA 0x80
+#define CMD_CMD 0x7f
+
+#define CMD_NOP 0x00
+#define CMD_FLUSH 0x01
+#define CMD_RESET 0x02
+#define CMD_BUSRESET 0x03
+#define CMD_TI 0x10
+#define CMD_ICCS 0x11
+#define CMD_MSGACC 0x12
+#define CMD_PAD 0x18
+#define CMD_SATN 0x1a
+#define CMD_RSTATN 0x1b
+#define CMD_SEL 0x41
+#define CMD_SELATN 0x42
+#define CMD_SELATNS 0x43
+#define CMD_ENSEL 0x44
+#define CMD_DISSEL 0x45
+
+#define STAT_DO 0x00
+#define STAT_DI 0x01
+#define STAT_CD 0x02
+#define STAT_ST 0x03
+#define STAT_MO 0x06
+#define STAT_MI 0x07
+#define STAT_PIO_MASK 0x06
+
+#define STAT_TC 0x10
+#define STAT_PE 0x20
+#define STAT_GE 0x40
+#define STAT_INT 0x80
+
+#define BUSID_DID 0x07
+
+#define INTR_FC 0x08
+#define INTR_BS 0x10
+#define INTR_DC 0x20
+#define INTR_RST 0x80
+
+#define SEQ_0 0x0
+#define SEQ_CD 0x4
+
+#define CFG1_RESREPT 0x40
+
+#define TCHI_FAS100A 0x4
+#define TCHI_AM53C974 0x12
+
+void esp_dma_enable(ESPState *s, int irq, int level);
+void esp_request_cancelled(SCSIRequest *req);
+void esp_command_complete(SCSIRequest *req, uint32_t status, size_t resid);
+void esp_transfer_data(SCSIRequest *req, uint32_t len);
+void esp_hard_reset(ESPState *s);
+uint64_t esp_reg_read(ESPState *s, uint32_t saddr);
+void esp_reg_write(ESPState *s, uint32_t saddr, uint64_t val);
+extern const VMStateDescription vmstate_esp;
+
#endif
diff --git a/hw/ide/ahci.c b/hw/ide/ahci.c
index efea93f0b4..5ea3cadb01 100644
--- a/hw/ide/ahci.c
+++ b/hw/ide/ahci.c
@@ -636,7 +636,7 @@ static void ahci_write_fis_d2h(AHCIDevice *ad, uint8_t *cmd_fis)
}
}
-static int ahci_populate_sglist(AHCIDevice *ad, QEMUSGList *sglist)
+static int ahci_populate_sglist(AHCIDevice *ad, QEMUSGList *sglist, int offset)
{
AHCICmdHdr *cmd = ad->cur_cmd;
uint32_t opts = le32_to_cpu(cmd->opts);
@@ -647,6 +647,10 @@ static int ahci_populate_sglist(AHCIDevice *ad, QEMUSGList *sglist)
uint8_t *prdt;
int i;
int r = 0;
+ int sum = 0;
+ int off_idx = -1;
+ int off_pos = -1;
+ int tbl_entry_size;
if (!sglist_alloc_hint) {
DPRINTF(ad->port_no, "no sg list given by guest: 0x%08x\n", opts);
@@ -669,10 +673,31 @@ static int ahci_populate_sglist(AHCIDevice *ad, QEMUSGList *sglist)
/* Get entries in the PRDT, init a qemu sglist accordingly */
if (sglist_alloc_hint > 0) {
AHCI_SG *tbl = (AHCI_SG *)prdt;
-
- qemu_sglist_init(sglist, sglist_alloc_hint, ad->hba->dma);
+ sum = 0;
for (i = 0; i < sglist_alloc_hint; i++) {
/* flags_size is zero-based */
+ tbl_entry_size = (le32_to_cpu(tbl[i].flags_size) + 1);
+ if (offset <= (sum + tbl_entry_size)) {
+ off_idx = i;
+ off_pos = offset - sum;
+ break;
+ }
+ sum += tbl_entry_size;
+ }
+ if ((off_idx == -1) || (off_pos < 0) || (off_pos > tbl_entry_size)) {
+ DPRINTF(ad->port_no, "%s: Incorrect offset! "
+ "off_idx: %d, off_pos: %d\n",
+ __func__, off_idx, off_pos);
+ r = -1;
+ goto out;
+ }
+
+ qemu_sglist_init(sglist, (sglist_alloc_hint - off_idx), ad->hba->dma);
+ qemu_sglist_add(sglist, le64_to_cpu(tbl[off_idx].addr + off_pos),
+ le32_to_cpu(tbl[off_idx].flags_size) + 1 - off_pos);
+
+ for (i = off_idx + 1; i < sglist_alloc_hint; i++) {
+ /* flags_size is zero-based */
qemu_sglist_add(sglist, le64_to_cpu(tbl[i].addr),
le32_to_cpu(tbl[i].flags_size) + 1);
}
@@ -745,7 +770,7 @@ static void process_ncq_command(AHCIState *s, int port, uint8_t *cmd_fis,
ncq_tfs->lba, ncq_tfs->lba + ncq_tfs->sector_count - 2,
s->dev[port].port.ifs[0].nb_sectors - 1);
- ahci_populate_sglist(&s->dev[port], &ncq_tfs->sglist);
+ ahci_populate_sglist(&s->dev[port], &ncq_tfs->sglist, 0);
ncq_tfs->tag = tag;
switch(ncq_fis->command) {
@@ -970,7 +995,7 @@ static int ahci_start_transfer(IDEDMA *dma)
goto out;
}
- if (!ahci_populate_sglist(ad, &s->sg)) {
+ if (!ahci_populate_sglist(ad, &s->sg, 0)) {
has_sglist = 1;
}
@@ -1015,6 +1040,7 @@ static void ahci_start_dma(IDEDMA *dma, IDEState *s,
DPRINTF(ad->port_no, "\n");
ad->dma_cb = dma_cb;
ad->dma_status |= BM_STATUS_DMAING;
+ s->io_buffer_offset = 0;
dma_cb(s, 0);
}
@@ -1023,7 +1049,7 @@ static int ahci_dma_prepare_buf(IDEDMA *dma, int is_write)
AHCIDevice *ad = DO_UPCAST(AHCIDevice, dma, dma);
IDEState *s = &ad->port.ifs[0];
- ahci_populate_sglist(ad, &s->sg);
+ ahci_populate_sglist(ad, &s->sg, 0);
s->io_buffer_size = s->sg.size;
DPRINTF(ad->port_no, "len=%#x\n", s->io_buffer_size);
@@ -1037,7 +1063,7 @@ static int ahci_dma_rw_buf(IDEDMA *dma, int is_write)
uint8_t *p = s->io_buffer + s->io_buffer_index;
int l = s->io_buffer_size - s->io_buffer_index;
- if (ahci_populate_sglist(ad, &s->sg)) {
+ if (ahci_populate_sglist(ad, &s->sg, s->io_buffer_offset)) {
return 0;
}
@@ -1047,9 +1073,13 @@ static int ahci_dma_rw_buf(IDEDMA *dma, int is_write)
dma_buf_write(p, l, &s->sg);
}
+ /* free sglist that was created in ahci_populate_sglist() */
+ qemu_sglist_destroy(&s->sg);
+
/* update number of transferred bytes */
ad->cur_cmd->status = cpu_to_le32(le32_to_cpu(ad->cur_cmd->status) + l);
s->io_buffer_index += l;
+ s->io_buffer_offset += l;
DPRINTF(ad->port_no, "len=%#x\n", l);
diff --git a/hw/ide/internal.h b/hw/ide/internal.h
index 7170bd9cd0..bf7d313cf4 100644
--- a/hw/ide/internal.h
+++ b/hw/ide/internal.h
@@ -393,6 +393,7 @@ struct IDEState {
struct iovec iov;
QEMUIOVector qiov;
/* ATA DMA state */
+ int io_buffer_offset;
int io_buffer_size;
QEMUSGList sg;
/* PIO transfer handling */
diff --git a/hw/kvm/i8259.c b/hw/kvm/i8259.c
index 94d1b9aa95..1e24cd4f36 100644
--- a/hw/kvm/i8259.c
+++ b/hw/kvm/i8259.c
@@ -94,7 +94,7 @@ static void kvm_pic_set_irq(void *opaque, int irq, int level)
{
int delivered;
- delivered = kvm_irqchip_set_irq(kvm_state, irq, level);
+ delivered = kvm_set_irq(kvm_state, irq, level);
apic_report_irq_delivered(delivered);
}
diff --git a/hw/kvm/ioapic.c b/hw/kvm/ioapic.c
index 3ae3175403..6c3b8fe39a 100644
--- a/hw/kvm/ioapic.c
+++ b/hw/kvm/ioapic.c
@@ -82,7 +82,7 @@ static void kvm_ioapic_set_irq(void *opaque, int irq, int level)
KVMIOAPICState *s = opaque;
int delivered;
- delivered = kvm_irqchip_set_irq(kvm_state, s->kvm_gsi_base + irq, level);
+ delivered = kvm_set_irq(kvm_state, s->kvm_gsi_base + irq, level);
apic_report_irq_delivered(delivered);
}
diff --git a/hw/pc.c b/hw/pc.c
index 81c391cd6a..e8bcfc0b4b 100644
--- a/hw/pc.c
+++ b/hw/pc.c
@@ -42,6 +42,7 @@
#include "sysbus.h"
#include "sysemu.h"
#include "kvm.h"
+#include "kvm_i386.h"
#include "xen.h"
#include "blockdev.h"
#include "hw/block-common.h"
diff --git a/hw/pci-stub.c b/hw/pci-stub.c
index e083191529..134c4484b6 100644
--- a/hw/pci-stub.c
+++ b/hw/pci-stub.c
@@ -34,21 +34,6 @@ static void pci_error_message(Monitor *mon)
monitor_printf(mon, "PCI devices not supported\n");
}
-void pci_register_bar(PCIDevice *pci_dev, int region_num,
- uint8_t type, MemoryRegion *memory)
-{
-}
-
-const VMStateDescription vmstate_pci_device = {
- .name = "PCIDeviceStub",
- .version_id = 1,
- .minimum_version_id = 1,
- .minimum_version_id_old = 1,
- .fields = (VMStateField[]) {
- VMSTATE_END_OF_LIST()
- }
-};
-
int do_pcie_aer_inject_error(Monitor *mon,
const QDict *qdict, QObject **ret_data)
{
diff --git a/hw/petalogix_ml605_mmu.c b/hw/petalogix_ml605_mmu.c
index 6a7d0c0bff..dced648f45 100644
--- a/hw/petalogix_ml605_mmu.c
+++ b/hw/petalogix_ml605_mmu.c
@@ -39,7 +39,8 @@
#include "microblaze_boot.h"
#include "microblaze_pic_cpu.h"
-#include "xilinx_axidma.h"
+
+#include "stream.h"
#define LMB_BRAM_SIZE (128 * 1024)
#define FLASH_SIZE (32 * 1024 * 1024)
@@ -76,7 +77,7 @@ petalogix_ml605_init(ram_addr_t ram_size,
const char *initrd_filename, const char *cpu_model)
{
MemoryRegion *address_space_mem = get_system_memory();
- DeviceState *dev;
+ DeviceState *dev, *dma, *eth0;
MicroBlazeCPU *cpu;
CPUMBState *env;
DriveInfo *dinfo;
@@ -125,15 +126,18 @@ petalogix_ml605_init(ram_addr_t ram_size,
/* 2 timers at irq 2 @ 100 Mhz. */
xilinx_timer_create(TIMER_BASEADDR, irq[2], 0, 100 * 1000000);
- /* axi ethernet and dma initialization. TODO: Dynamically connect them. */
- {
- static struct XilinxDMAConnection dmach;
+ /* axi ethernet and dma initialization. */
+ dma = qdev_create(NULL, "xlnx.axi-dma");
- xilinx_axiethernet_create(&dmach, &nd_table[0], 0x82780000,
- irq[3], 0x1000, 0x1000);
- xilinx_axiethernetdma_create(&dmach, 0x84600000,
- irq[1], irq[0], 100 * 1000000);
- }
+ /* FIXME: attach to the sysbus instead */
+ object_property_add_child(container_get(qdev_get_machine(), "/unattached"),
+ "xilinx-dma", OBJECT(dma), NULL);
+
+ eth0 = xilinx_axiethernet_create(&nd_table[0], STREAM_SLAVE(dma),
+ 0x82780000, irq[3], 0x1000, 0x1000);
+
+ xilinx_axiethernetdma_init(dma, STREAM_SLAVE(eth0),
+ 0x84600000, irq[1], irq[0], 100 * 1000000);
microblaze_load_kernel(cpu, ddr_base, ram_size, BINARY_DEVICE_TREE_FILE,
machine_cpu_reset);
diff --git a/hw/puv3.c b/hw/puv3.c
new file mode 100644
index 0000000000..43f7216e4e
--- /dev/null
+++ b/hw/puv3.c
@@ -0,0 +1,131 @@
+/*
+ * Generic PKUnity SoC machine and board descriptor
+ *
+ * Copyright (C) 2010-2012 Guan Xuetao
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation, or any later version.
+ * See the COPYING file in the top-level directory.
+ */
+#include "console.h"
+#include "elf.h"
+#include "exec-memory.h"
+#include "sysbus.h"
+#include "boards.h"
+#include "loader.h"
+#include "pc.h"
+
+#undef DEBUG_PUV3
+#include "puv3.h"
+
+#define KERNEL_LOAD_ADDR 0x03000000
+#define KERNEL_MAX_SIZE 0x00800000 /* Just a guess */
+
+static void puv3_intc_cpu_handler(void *opaque, int irq, int level)
+{
+ CPUUniCore32State *env = opaque;
+
+ assert(irq == 0);
+ if (level) {
+ cpu_interrupt(env, CPU_INTERRUPT_HARD);
+ } else {
+ cpu_reset_interrupt(env, CPU_INTERRUPT_HARD);
+ }
+}
+
+static void puv3_soc_init(CPUUniCore32State *env)
+{
+ qemu_irq *cpu_intc, irqs[PUV3_IRQS_NR];
+ DeviceState *dev;
+ MemoryRegion *i8042 = g_new(MemoryRegion, 1);
+ int i;
+
+ /* Initialize interrupt controller */
+ cpu_intc = qemu_allocate_irqs(puv3_intc_cpu_handler, env, 1);
+ dev = sysbus_create_simple("puv3_intc", PUV3_INTC_BASE, *cpu_intc);
+ for (i = 0; i < PUV3_IRQS_NR; i++) {
+ irqs[i] = qdev_get_gpio_in(dev, i);
+ }
+
+ /* Initialize minimal necessary devices for kernel booting */
+ sysbus_create_simple("puv3_pm", PUV3_PM_BASE, NULL);
+ sysbus_create_simple("puv3_dma", PUV3_DMA_BASE, NULL);
+ sysbus_create_simple("puv3_ost", PUV3_OST_BASE, irqs[PUV3_IRQS_OST0]);
+ sysbus_create_varargs("puv3_gpio", PUV3_GPIO_BASE,
+ irqs[PUV3_IRQS_GPIOLOW0], irqs[PUV3_IRQS_GPIOLOW1],
+ irqs[PUV3_IRQS_GPIOLOW2], irqs[PUV3_IRQS_GPIOLOW3],
+ irqs[PUV3_IRQS_GPIOLOW4], irqs[PUV3_IRQS_GPIOLOW5],
+ irqs[PUV3_IRQS_GPIOLOW6], irqs[PUV3_IRQS_GPIOLOW7],
+ irqs[PUV3_IRQS_GPIOHIGH], NULL);
+
+ /* Keyboard (i8042), mouse disabled for nographic */
+ i8042_mm_init(irqs[PUV3_IRQS_PS2_KBD], NULL, i8042, PUV3_REGS_OFFSET, 4);
+ memory_region_add_subregion(get_system_memory(), PUV3_PS2_BASE, i8042);
+}
+
+static void puv3_board_init(CPUUniCore32State *env, ram_addr_t ram_size)
+{
+ MemoryRegion *ram_memory = g_new(MemoryRegion, 1);
+
+ /* SDRAM at address zero. */
+ memory_region_init_ram(ram_memory, "puv3.ram", ram_size);
+ vmstate_register_ram_global(ram_memory);
+ memory_region_add_subregion(get_system_memory(), 0, ram_memory);
+}
+
+static void puv3_load_kernel(const char *kernel_filename)
+{
+ int size;
+
+ assert(kernel_filename != NULL);
+
+ /* only zImage format supported */
+ size = load_image_targphys(kernel_filename, KERNEL_LOAD_ADDR,
+ KERNEL_MAX_SIZE);
+ if (size < 0) {
+ hw_error("Load kernel error: '%s'\n", kernel_filename);
+ }
+
+ /* cheat curses that we have a graphic console, only under ocd console */
+ graphic_console_init(NULL, NULL, NULL, NULL, NULL);
+}
+
+static void puv3_init(ram_addr_t ram_size, const char *boot_device,
+ const char *kernel_filename, const char *kernel_cmdline,
+ const char *initrd_filename, const char *cpu_model)
+{
+ CPUUniCore32State *env;
+
+ if (initrd_filename) {
+ hw_error("Please use kernel built-in initramdisk.\n");
+ }
+
+ if (!cpu_model) {
+ cpu_model = "UniCore-II";
+ }
+
+ env = cpu_init(cpu_model);
+ if (!env) {
+ hw_error("Unable to find CPU definition\n");
+ }
+
+ puv3_soc_init(env);
+ puv3_board_init(env, ram_size);
+ puv3_load_kernel(kernel_filename);
+}
+
+static QEMUMachine puv3_machine = {
+ .name = "puv3",
+ .desc = "PKUnity Version-3 based on UniCore32",
+ .init = puv3_init,
+ .is_default = 1,
+ .use_scsi = 0,
+};
+
+static void puv3_machine_init(void)
+{
+ qemu_register_machine(&puv3_machine);
+}
+
+machine_init(puv3_machine_init)
diff --git a/hw/puv3.h b/hw/puv3.h
new file mode 100644
index 0000000000..f37adcb665
--- /dev/null
+++ b/hw/puv3.h
@@ -0,0 +1,49 @@
+/*
+ * Misc PKUnity SoC declarations
+ *
+ * Copyright (C) 2010-2012 Guan Xuetao
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation, or any later version.
+ * See the COPYING file in the top-level directory.
+ */
+#ifndef QEMU_HW_PUV3_H
+#define QEMU_HW_PUV3_H
+
+#define PUV3_REGS_OFFSET (0x1000) /* 4K is reasonable */
+
+/* PKUnity System bus (AHB): 0xc0000000 - 0xedffffff (640MB) */
+#define PUV3_DMA_BASE (0xc0200000) /* AHB-4 */
+
+/* PKUnity Peripheral bus (APB): 0xee000000 - 0xefffffff (128MB) */
+#define PUV3_GPIO_BASE (0xee500000) /* APB-5 */
+#define PUV3_INTC_BASE (0xee600000) /* APB-6 */
+#define PUV3_OST_BASE (0xee800000) /* APB-8 */
+#define PUV3_PM_BASE (0xeea00000) /* APB-10 */
+#define PUV3_PS2_BASE (0xeeb00000) /* APB-11 */
+
+/* Hardware interrupts */
+#define PUV3_IRQS_NR (32)
+
+#define PUV3_IRQS_GPIOLOW0 (0)
+#define PUV3_IRQS_GPIOLOW1 (1)
+#define PUV3_IRQS_GPIOLOW2 (2)
+#define PUV3_IRQS_GPIOLOW3 (3)
+#define PUV3_IRQS_GPIOLOW4 (4)
+#define PUV3_IRQS_GPIOLOW5 (5)
+#define PUV3_IRQS_GPIOLOW6 (6)
+#define PUV3_IRQS_GPIOLOW7 (7)
+#define PUV3_IRQS_GPIOHIGH (8)
+#define PUV3_IRQS_PS2_KBD (22)
+#define PUV3_IRQS_PS2_AUX (23)
+#define PUV3_IRQS_OST0 (26)
+
+/* All puv3_*.c use DPRINTF for debug. */
+#ifdef DEBUG_PUV3
+#define DPRINTF(fmt, ...) printf("%s: " fmt , __func__, ## __VA_ARGS__)
+#else
+#define DPRINTF(fmt, ...) do {} while (0)
+#endif
+
+#endif /* !QEMU_HW_PUV3_H */
diff --git a/hw/puv3_dma.c b/hw/puv3_dma.c
new file mode 100644
index 0000000000..85b97bfdeb
--- /dev/null
+++ b/hw/puv3_dma.c
@@ -0,0 +1,109 @@
+/*
+ * DMA device simulation in PKUnity SoC
+ *
+ * Copyright (C) 2010-2012 Guan Xuetao
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation, or any later version.
+ * See the COPYING file in the top-level directory.
+ */
+#include "hw.h"
+#include "sysbus.h"
+
+#undef DEBUG_PUV3
+#include "puv3.h"
+
+#define PUV3_DMA_CH_NR (6)
+#define PUV3_DMA_CH_MASK (0xff)
+#define PUV3_DMA_CH(offset) ((offset) >> 8)
+
+typedef struct {
+ SysBusDevice busdev;
+ MemoryRegion iomem;
+ uint32_t reg_CFG[PUV3_DMA_CH_NR];
+} PUV3DMAState;
+
+static uint64_t puv3_dma_read(void *opaque, target_phys_addr_t offset,
+ unsigned size)
+{
+ PUV3DMAState *s = opaque;
+ uint32_t ret = 0;
+
+ assert(PUV3_DMA_CH(offset) < PUV3_DMA_CH_NR);
+
+ switch (offset & PUV3_DMA_CH_MASK) {
+ case 0x10:
+ ret = s->reg_CFG[PUV3_DMA_CH(offset)];
+ break;
+ default:
+ DPRINTF("Bad offset 0x%x\n", offset);
+ }
+ DPRINTF("offset 0x%x, value 0x%x\n", offset, ret);
+
+ return ret;
+}
+
+static void puv3_dma_write(void *opaque, target_phys_addr_t offset,
+ uint64_t value, unsigned size)
+{
+ PUV3DMAState *s = opaque;
+
+ assert(PUV3_DMA_CH(offset) < PUV3_DMA_CH_NR);
+
+ switch (offset & PUV3_DMA_CH_MASK) {
+ case 0x10:
+ s->reg_CFG[PUV3_DMA_CH(offset)] = value;
+ break;
+ default:
+ DPRINTF("Bad offset 0x%x\n", offset);
+ }
+ DPRINTF("offset 0x%x, value 0x%x\n", offset, value);
+}
+
+static const MemoryRegionOps puv3_dma_ops = {
+ .read = puv3_dma_read,
+ .write = puv3_dma_write,
+ .impl = {
+ .min_access_size = 4,
+ .max_access_size = 4,
+ },
+ .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static int puv3_dma_init(SysBusDevice *dev)
+{
+ PUV3DMAState *s = FROM_SYSBUS(PUV3DMAState, dev);
+ int i;
+
+ for (i = 0; i < PUV3_DMA_CH_NR; i++) {
+ s->reg_CFG[i] = 0x0;
+ }
+
+ memory_region_init_io(&s->iomem, &puv3_dma_ops, s, "puv3_dma",
+ PUV3_REGS_OFFSET);
+ sysbus_init_mmio(dev, &s->iomem);
+
+ return 0;
+}
+
+static void puv3_dma_class_init(ObjectClass *klass, void *data)
+{
+ SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
+
+ sdc->init = puv3_dma_init;
+}
+
+static const TypeInfo puv3_dma_info = {
+ .name = "puv3_dma",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(PUV3DMAState),
+ .class_init = puv3_dma_class_init,
+};
+
+static void puv3_dma_register_type(void)
+{
+ type_register_static(&puv3_dma_info);
+}
+
+type_init(puv3_dma_register_type)
diff --git a/hw/puv3_gpio.c b/hw/puv3_gpio.c
new file mode 100644
index 0000000000..9436e6c62c
--- /dev/null
+++ b/hw/puv3_gpio.c
@@ -0,0 +1,141 @@
+/*
+ * GPIO device simulation in PKUnity SoC
+ *
+ * Copyright (C) 2010-2012 Guan Xuetao
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation, or any later version.
+ * See the COPYING file in the top-level directory.
+ */
+#include "hw.h"
+#include "sysbus.h"
+
+#undef DEBUG_PUV3
+#include "puv3.h"
+
+typedef struct {
+ SysBusDevice busdev;
+ MemoryRegion iomem;
+ qemu_irq irq[9];
+
+ uint32_t reg_GPLR;
+ uint32_t reg_GPDR;
+ uint32_t reg_GPIR;
+} PUV3GPIOState;
+
+static uint64_t puv3_gpio_read(void *opaque, target_phys_addr_t offset,
+ unsigned size)
+{
+ PUV3GPIOState *s = opaque;
+ uint32_t ret = 0;
+
+ switch (offset) {
+ case 0x00:
+ ret = s->reg_GPLR;
+ break;
+ case 0x04:
+ ret = s->reg_GPDR;
+ break;
+ case 0x20:
+ ret = s->reg_GPIR;
+ break;
+ default:
+ DPRINTF("Bad offset 0x%x\n", offset);
+ }
+ DPRINTF("offset 0x%x, value 0x%x\n", offset, ret);
+
+ return ret;
+}
+
+static void puv3_gpio_write(void *opaque, target_phys_addr_t offset,
+ uint64_t value, unsigned size)
+{
+ PUV3GPIOState *s = opaque;
+
+ DPRINTF("offset 0x%x, value 0x%x\n", offset, value);
+ switch (offset) {
+ case 0x04:
+ s->reg_GPDR = value;
+ break;
+ case 0x08:
+ if (s->reg_GPDR & value) {
+ s->reg_GPLR |= value;
+ } else {
+ DPRINTF("Write gpio input port error!");
+ }
+ break;
+ case 0x0c:
+ if (s->reg_GPDR & value) {
+ s->reg_GPLR &= ~value;
+ } else {
+ DPRINTF("Write gpio input port error!");
+ }
+ break;
+ case 0x10: /* GRER */
+ case 0x14: /* GFER */
+ case 0x18: /* GEDR */
+ break;
+ case 0x20: /* GPIR */
+ s->reg_GPIR = value;
+ break;
+ default:
+ DPRINTF("Bad offset 0x%x\n", offset);
+ }
+}
+
+static const MemoryRegionOps puv3_gpio_ops = {
+ .read = puv3_gpio_read,
+ .write = puv3_gpio_write,
+ .impl = {
+ .min_access_size = 4,
+ .max_access_size = 4,
+ },
+ .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static int puv3_gpio_init(SysBusDevice *dev)
+{
+ PUV3GPIOState *s = FROM_SYSBUS(PUV3GPIOState, dev);
+
+ s->reg_GPLR = 0;
+ s->reg_GPDR = 0;
+
+ /* FIXME: these irqs not handled yet */
+ sysbus_init_irq(dev, &s->irq[PUV3_IRQS_GPIOLOW0]);
+ sysbus_init_irq(dev, &s->irq[PUV3_IRQS_GPIOLOW1]);
+ sysbus_init_irq(dev, &s->irq[PUV3_IRQS_GPIOLOW2]);
+ sysbus_init_irq(dev, &s->irq[PUV3_IRQS_GPIOLOW3]);
+ sysbus_init_irq(dev, &s->irq[PUV3_IRQS_GPIOLOW4]);
+ sysbus_init_irq(dev, &s->irq[PUV3_IRQS_GPIOLOW5]);
+ sysbus_init_irq(dev, &s->irq[PUV3_IRQS_GPIOLOW6]);
+ sysbus_init_irq(dev, &s->irq[PUV3_IRQS_GPIOLOW7]);
+ sysbus_init_irq(dev, &s->irq[PUV3_IRQS_GPIOHIGH]);
+
+ memory_region_init_io(&s->iomem, &puv3_gpio_ops, s, "puv3_gpio",
+ PUV3_REGS_OFFSET);
+ sysbus_init_mmio(dev, &s->iomem);
+
+ return 0;
+}
+
+static void puv3_gpio_class_init(ObjectClass *klass, void *data)
+{
+ SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
+
+ sdc->init = puv3_gpio_init;
+}
+
+static const TypeInfo puv3_gpio_info = {
+ .name = "puv3_gpio",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(PUV3GPIOState),
+ .class_init = puv3_gpio_class_init,
+};
+
+static void puv3_gpio_register_type(void)
+{
+ type_register_static(&puv3_gpio_info);
+}
+
+type_init(puv3_gpio_register_type)
diff --git a/hw/puv3_intc.c b/hw/puv3_intc.c
new file mode 100644
index 0000000000..9e0b975ea2
--- /dev/null
+++ b/hw/puv3_intc.c
@@ -0,0 +1,135 @@
+/*
+ * INTC device simulation in PKUnity SoC
+ *
+ * Copyright (C) 2010-2012 Guan Xuetao
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation, or any later version.
+ * See the COPYING file in the top-level directory.
+ */
+#include "sysbus.h"
+
+#undef DEBUG_PUV3
+#include "puv3.h"
+
+typedef struct {
+ SysBusDevice busdev;
+ MemoryRegion iomem;
+ qemu_irq parent_irq;
+
+ uint32_t reg_ICMR;
+ uint32_t reg_ICPR;
+} PUV3INTCState;
+
+/* Update interrupt status after enabled or pending bits have been changed. */
+static void puv3_intc_update(PUV3INTCState *s)
+{
+ if (s->reg_ICMR & s->reg_ICPR) {
+ qemu_irq_raise(s->parent_irq);
+ } else {
+ qemu_irq_lower(s->parent_irq);
+ }
+}
+
+/* Process a change in an external INTC input. */
+static void puv3_intc_handler(void *opaque, int irq, int level)
+{
+ PUV3INTCState *s = opaque;
+
+ DPRINTF("irq 0x%x, level 0x%x\n", irq, level);
+ if (level) {
+ s->reg_ICPR |= (1 << irq);
+ } else {
+ s->reg_ICPR &= ~(1 << irq);
+ }
+ puv3_intc_update(s);
+}
+
+static uint64_t puv3_intc_read(void *opaque, target_phys_addr_t offset,
+ unsigned size)
+{
+ PUV3INTCState *s = opaque;
+ uint32_t ret = 0;
+
+ switch (offset) {
+ case 0x04: /* INTC_ICMR */
+ ret = s->reg_ICMR;
+ break;
+ case 0x0c: /* INTC_ICIP */
+ ret = s->reg_ICPR; /* the same value with ICPR */
+ break;
+ default:
+ DPRINTF("Bad offset %x\n", (int)offset);
+ }
+ DPRINTF("offset 0x%x, value 0x%x\n", offset, ret);
+ return ret;
+}
+
+static void puv3_intc_write(void *opaque, target_phys_addr_t offset,
+ uint64_t value, unsigned size)
+{
+ PUV3INTCState *s = opaque;
+
+ DPRINTF("offset 0x%x, value 0x%x\n", offset, value);
+ switch (offset) {
+ case 0x00: /* INTC_ICLR */
+ case 0x14: /* INTC_ICCR */
+ break;
+ case 0x04: /* INTC_ICMR */
+ s->reg_ICMR = value;
+ break;
+ default:
+ DPRINTF("Bad offset 0x%x\n", (int)offset);
+ return;
+ }
+ puv3_intc_update(s);
+}
+
+static const MemoryRegionOps puv3_intc_ops = {
+ .read = puv3_intc_read,
+ .write = puv3_intc_write,
+ .impl = {
+ .min_access_size = 4,
+ .max_access_size = 4,
+ },
+ .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static int puv3_intc_init(SysBusDevice *dev)
+{
+ PUV3INTCState *s = FROM_SYSBUS(PUV3INTCState, dev);
+
+ qdev_init_gpio_in(&s->busdev.qdev, puv3_intc_handler, PUV3_IRQS_NR);
+ sysbus_init_irq(&s->busdev, &s->parent_irq);
+
+ s->reg_ICMR = 0;
+ s->reg_ICPR = 0;
+
+ memory_region_init_io(&s->iomem, &puv3_intc_ops, s, "puv3_intc",
+ PUV3_REGS_OFFSET);
+ sysbus_init_mmio(dev, &s->iomem);
+
+ return 0;
+}
+
+static void puv3_intc_class_init(ObjectClass *klass, void *data)
+{
+ SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
+
+ sdc->init = puv3_intc_init;
+}
+
+static const TypeInfo puv3_intc_info = {
+ .name = "puv3_intc",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(PUV3INTCState),
+ .class_init = puv3_intc_class_init,
+};
+
+static void puv3_intc_register_type(void)
+{
+ type_register_static(&puv3_intc_info);
+}
+
+type_init(puv3_intc_register_type)
diff --git a/hw/puv3_ost.c b/hw/puv3_ost.c
new file mode 100644
index 0000000000..dd30cad0e2
--- /dev/null
+++ b/hw/puv3_ost.c
@@ -0,0 +1,151 @@
+/*
+ * OSTimer device simulation in PKUnity SoC
+ *
+ * Copyright (C) 2010-2012 Guan Xuetao
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation, or any later version.
+ * See the COPYING file in the top-level directory.
+ */
+#include "sysbus.h"
+#include "ptimer.h"
+
+#undef DEBUG_PUV3
+#include "puv3.h"
+
+/* puv3 ostimer implementation. */
+typedef struct {
+ SysBusDevice busdev;
+ MemoryRegion iomem;
+ QEMUBH *bh;
+ qemu_irq irq;
+ ptimer_state *ptimer;
+
+ uint32_t reg_OSMR0;
+ uint32_t reg_OSCR;
+ uint32_t reg_OSSR;
+ uint32_t reg_OIER;
+} PUV3OSTState;
+
+static uint64_t puv3_ost_read(void *opaque, target_phys_addr_t offset,
+ unsigned size)
+{
+ PUV3OSTState *s = opaque;
+ uint32_t ret = 0;
+
+ switch (offset) {
+ case 0x10: /* Counter Register */
+ ret = s->reg_OSMR0 - (uint32_t)ptimer_get_count(s->ptimer);
+ break;
+ case 0x14: /* Status Register */
+ ret = s->reg_OSSR;
+ break;
+ case 0x1c: /* Interrupt Enable Register */
+ ret = s->reg_OIER;
+ break;
+ default:
+ DPRINTF("Bad offset %x\n", (int)offset);
+ }
+ DPRINTF("offset 0x%x, value 0x%x\n", offset, ret);
+ return ret;
+}
+
+static void puv3_ost_write(void *opaque, target_phys_addr_t offset,
+ uint64_t value, unsigned size)
+{
+ PUV3OSTState *s = opaque;
+
+ DPRINTF("offset 0x%x, value 0x%x\n", offset, value);
+ switch (offset) {
+ case 0x00: /* Match Register 0 */
+ s->reg_OSMR0 = value;
+ if (s->reg_OSMR0 > s->reg_OSCR) {
+ ptimer_set_count(s->ptimer, s->reg_OSMR0 - s->reg_OSCR);
+ } else {
+ ptimer_set_count(s->ptimer, s->reg_OSMR0 +
+ (0xffffffff - s->reg_OSCR));
+ }
+ ptimer_run(s->ptimer, 2);
+ break;
+ case 0x14: /* Status Register */
+ assert(value == 0);
+ if (s->reg_OSSR) {
+ s->reg_OSSR = value;
+ qemu_irq_lower(s->irq);
+ }
+ break;
+ case 0x1c: /* Interrupt Enable Register */
+ s->reg_OIER = value;
+ break;
+ default:
+ DPRINTF("Bad offset %x\n", (int)offset);
+ }
+}
+
+static const MemoryRegionOps puv3_ost_ops = {
+ .read = puv3_ost_read,
+ .write = puv3_ost_write,
+ .impl = {
+ .min_access_size = 4,
+ .max_access_size = 4,
+ },
+ .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static void puv3_ost_tick(void *opaque)
+{
+ PUV3OSTState *s = opaque;
+
+ DPRINTF("ost hit when ptimer counter from 0x%x to 0x%x!\n",
+ s->reg_OSCR, s->reg_OSMR0);
+
+ s->reg_OSCR = s->reg_OSMR0;
+ if (s->reg_OIER) {
+ s->reg_OSSR = 1;
+ qemu_irq_raise(s->irq);
+ }
+}
+
+static int puv3_ost_init(SysBusDevice *dev)
+{
+ PUV3OSTState *s = FROM_SYSBUS(PUV3OSTState, dev);
+
+ s->reg_OIER = 0;
+ s->reg_OSSR = 0;
+ s->reg_OSMR0 = 0;
+ s->reg_OSCR = 0;
+
+ sysbus_init_irq(dev, &s->irq);
+
+ s->bh = qemu_bh_new(puv3_ost_tick, s);
+ s->ptimer = ptimer_init(s->bh);
+ ptimer_set_freq(s->ptimer, 50 * 1000 * 1000);
+
+ memory_region_init_io(&s->iomem, &puv3_ost_ops, s, "puv3_ost",
+ PUV3_REGS_OFFSET);
+ sysbus_init_mmio(dev, &s->iomem);
+
+ return 0;
+}
+
+static void puv3_ost_class_init(ObjectClass *klass, void *data)
+{
+ SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
+
+ sdc->init = puv3_ost_init;
+}
+
+static const TypeInfo puv3_ost_info = {
+ .name = "puv3_ost",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(PUV3OSTState),
+ .class_init = puv3_ost_class_init,
+};
+
+static void puv3_ost_register_type(void)
+{
+ type_register_static(&puv3_ost_info);
+}
+
+type_init(puv3_ost_register_type)
diff --git a/hw/puv3_pm.c b/hw/puv3_pm.c
new file mode 100644
index 0000000000..621c96875c
--- /dev/null
+++ b/hw/puv3_pm.c
@@ -0,0 +1,149 @@
+/*
+ * Power Management device simulation in PKUnity SoC
+ *
+ * Copyright (C) 2010-2012 Guan Xuetao
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation, or any later version.
+ * See the COPYING file in the top-level directory.
+ */
+#include "hw.h"
+#include "sysbus.h"
+
+#undef DEBUG_PUV3
+#include "puv3.h"
+
+typedef struct {
+ SysBusDevice busdev;
+ MemoryRegion iomem;
+
+ uint32_t reg_PMCR;
+ uint32_t reg_PCGR;
+ uint32_t reg_PLL_SYS_CFG;
+ uint32_t reg_PLL_DDR_CFG;
+ uint32_t reg_PLL_VGA_CFG;
+ uint32_t reg_DIVCFG;
+} PUV3PMState;
+
+static uint64_t puv3_pm_read(void *opaque, target_phys_addr_t offset,
+ unsigned size)
+{
+ PUV3PMState *s = opaque;
+ uint32_t ret = 0;
+
+ switch (offset) {
+ case 0x14:
+ ret = s->reg_PCGR;
+ break;
+ case 0x18:
+ ret = s->reg_PLL_SYS_CFG;
+ break;
+ case 0x1c:
+ ret = s->reg_PLL_DDR_CFG;
+ break;
+ case 0x20:
+ ret = s->reg_PLL_VGA_CFG;
+ break;
+ case 0x24:
+ ret = s->reg_DIVCFG;
+ break;
+ case 0x28: /* PLL SYS STATUS */
+ ret = 0x00002401;
+ break;
+ case 0x2c: /* PLL DDR STATUS */
+ ret = 0x00100c00;
+ break;
+ case 0x30: /* PLL VGA STATUS */
+ ret = 0x00003801;
+ break;
+ case 0x34: /* DIV STATUS */
+ ret = 0x22f52015;
+ break;
+ case 0x38: /* SW RESET */
+ ret = 0x0;
+ break;
+ case 0x44: /* PLL DFC DONE */
+ ret = 0x7;
+ break;
+ default:
+ DPRINTF("Bad offset 0x%x\n", offset);
+ }
+ DPRINTF("offset 0x%x, value 0x%x\n", offset, ret);
+
+ return ret;
+}
+
+static void puv3_pm_write(void *opaque, target_phys_addr_t offset,
+ uint64_t value, unsigned size)
+{
+ PUV3PMState *s = opaque;
+
+ switch (offset) {
+ case 0x0:
+ s->reg_PMCR = value;
+ break;
+ case 0x14:
+ s->reg_PCGR = value;
+ break;
+ case 0x18:
+ s->reg_PLL_SYS_CFG = value;
+ break;
+ case 0x1c:
+ s->reg_PLL_DDR_CFG = value;
+ break;
+ case 0x20:
+ s->reg_PLL_VGA_CFG = value;
+ break;
+ case 0x24:
+ case 0x38:
+ break;
+ default:
+ DPRINTF("Bad offset 0x%x\n", offset);
+ }
+ DPRINTF("offset 0x%x, value 0x%x\n", offset, value);
+}
+
+static const MemoryRegionOps puv3_pm_ops = {
+ .read = puv3_pm_read,
+ .write = puv3_pm_write,
+ .impl = {
+ .min_access_size = 4,
+ .max_access_size = 4,
+ },
+ .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static int puv3_pm_init(SysBusDevice *dev)
+{
+ PUV3PMState *s = FROM_SYSBUS(PUV3PMState, dev);
+
+ s->reg_PCGR = 0x0;
+
+ memory_region_init_io(&s->iomem, &puv3_pm_ops, s, "puv3_pm",
+ PUV3_REGS_OFFSET);
+ sysbus_init_mmio(dev, &s->iomem);
+
+ return 0;
+}
+
+static void puv3_pm_class_init(ObjectClass *klass, void *data)
+{
+ SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
+
+ sdc->init = puv3_pm_init;
+}
+
+static const TypeInfo puv3_pm_info = {
+ .name = "puv3_pm",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(PUV3PMState),
+ .class_init = puv3_pm_class_init,
+};
+
+static void puv3_pm_register_type(void)
+{
+ type_register_static(&puv3_pm_info);
+}
+
+type_init(puv3_pm_register_type)
diff --git a/hw/scsi-bus.c b/hw/scsi-bus.c
index 6120cc83c1..b8a857d145 100644
--- a/hw/scsi-bus.c
+++ b/hw/scsi-bus.c
@@ -1437,7 +1437,6 @@ static const char *scsi_command_name(uint8_t cmd)
[ ATA_PASSTHROUGH_12 ] = "BLANK/ATA_PASSTHROUGH_12",
[ MOVE_MEDIUM ] = "MOVE_MEDIUM",
[ EXCHANGE_MEDIUM ] = "EXCHANGE MEDIUM",
- [ LOAD_UNLOAD ] = "LOAD_UNLOAD",
[ READ_12 ] = "READ_12",
[ WRITE_12 ] = "WRITE_12",
[ ERASE_12 ] = "ERASE_12/GET_PERFORMANCE",
diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c
index c8d5edd86e..409f760ef7 100644
--- a/hw/scsi-disk.c
+++ b/hw/scsi-disk.c
@@ -175,6 +175,8 @@ static void scsi_aio_complete(void *opaque, int ret)
SCSIDiskReq *r = (SCSIDiskReq *)opaque;
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
+ assert(r->req.aiocb != NULL);
+ r->req.aiocb = NULL;
bdrv_acct_done(s->qdev.conf.bs, &r->acct);
if (ret < 0) {
@@ -238,10 +240,9 @@ static void scsi_dma_complete(void *opaque, int ret)
SCSIDiskReq *r = (SCSIDiskReq *)opaque;
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
- if (r->req.aiocb != NULL) {
- r->req.aiocb = NULL;
- bdrv_acct_done(s->qdev.conf.bs, &r->acct);
- }
+ assert(r->req.aiocb != NULL);
+ r->req.aiocb = NULL;
+ bdrv_acct_done(s->qdev.conf.bs, &r->acct);
if (ret < 0) {
if (scsi_handle_rw_error(r, -ret)) {
@@ -270,10 +271,9 @@ static void scsi_read_complete(void * opaque, int ret)
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
int n;
- if (r->req.aiocb != NULL) {
- r->req.aiocb = NULL;
- bdrv_acct_done(s->qdev.conf.bs, &r->acct);
- }
+ assert(r->req.aiocb != NULL);
+ r->req.aiocb = NULL;
+ bdrv_acct_done(s->qdev.conf.bs, &r->acct);
if (ret < 0) {
if (scsi_handle_rw_error(r, -ret)) {
@@ -637,7 +637,7 @@ static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf)
{
buflen = 8;
outbuf[4] = 0;
- outbuf[5] = 0x60; /* write_same 10/16 supported */
+ outbuf[5] = 0xe0; /* unmap & write_same 10/16 all supported */
outbuf[6] = s->qdev.conf.discard_granularity ? 2 : 1;
outbuf[7] = 0;
break;
@@ -1449,6 +1449,89 @@ invalid_field:
return;
}
+typedef struct UnmapCBData {
+ SCSIDiskReq *r;
+ uint8_t *inbuf;
+ int count;
+} UnmapCBData;
+
+static void scsi_unmap_complete(void *opaque, int ret)
+{
+ UnmapCBData *data = opaque;
+ SCSIDiskReq *r = data->r;
+ SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
+ uint64_t sector_num;
+ uint32 nb_sectors;
+
+ r->req.aiocb = NULL;
+ if (ret < 0) {
+ if (scsi_handle_rw_error(r, -ret)) {
+ goto done;
+ }
+ }
+
+ if (data->count > 0 && !r->req.io_canceled) {
+ sector_num = ldq_be_p(&data->inbuf[0]);
+ nb_sectors = ldl_be_p(&data->inbuf[8]) & 0xffffffffULL;
+ if (sector_num > sector_num + nb_sectors ||
+ sector_num + nb_sectors - 1 > s->qdev.max_lba) {
+ scsi_check_condition(r, SENSE_CODE(LBA_OUT_OF_RANGE));
+ goto done;
+ }
+
+ r->req.aiocb = bdrv_aio_discard(s->qdev.conf.bs,
+ sector_num * (s->qdev.blocksize / 512),
+ nb_sectors * (s->qdev.blocksize / 512),
+ scsi_unmap_complete, data);
+ data->count--;
+ data->inbuf += 16;
+ return;
+ }
+
+done:
+ if (data->count == 0) {
+ scsi_req_complete(&r->req, GOOD);
+ }
+ if (!r->req.io_canceled) {
+ scsi_req_unref(&r->req);
+ }
+ g_free(data);
+}
+
+static void scsi_disk_emulate_unmap(SCSIDiskReq *r, uint8_t *inbuf)
+{
+ uint8_t *p = inbuf;
+ int len = r->req.cmd.xfer;
+ UnmapCBData *data;
+
+ if (len < 8) {
+ goto invalid_param_len;
+ }
+ if (len < lduw_be_p(&p[0]) + 2) {
+ goto invalid_param_len;
+ }
+ if (len < lduw_be_p(&p[2]) + 8) {
+ goto invalid_param_len;
+ }
+ if (lduw_be_p(&p[2]) & 15) {
+ goto invalid_param_len;
+ }
+
+ data = g_new0(UnmapCBData, 1);
+ data->r = r;
+ data->inbuf = &p[8];
+ data->count = lduw_be_p(&p[2]) >> 4;
+
+ /* The matching unref is in scsi_unmap_complete, before data is freed. */
+ scsi_req_ref(&r->req);
+ scsi_unmap_complete(data, 0);
+ return;
+
+invalid_param_len:
+ scsi_check_condition(r, SENSE_CODE(INVALID_PARAM_LEN));
+ return;
+}
+
static void scsi_disk_emulate_write_data(SCSIRequest *req)
{
SCSIDiskReq *r = DO_UPCAST(SCSIDiskReq, req, req);
@@ -1468,6 +1551,10 @@ static void scsi_disk_emulate_write_data(SCSIRequest *req)
scsi_disk_emulate_mode_select(r, r->iov.iov_base);
break;
+ case UNMAP:
+ scsi_disk_emulate_unmap(r, r->iov.iov_base);
+ break;
+
default:
abort();
}
@@ -1702,6 +1789,9 @@ static int32_t scsi_disk_emulate_command(SCSIRequest *req, uint8_t *buf)
case MODE_SELECT_10:
DPRINTF("Mode Select(10) (len %lu)\n", (long)r->req.cmd.xfer);
break;
+ case UNMAP:
+ DPRINTF("Unmap (len %lu)\n", (long)r->req.cmd.xfer);
+ break;
case WRITE_SAME_10:
nb_sectors = lduw_be_p(&req->cmd.buf[7]);
goto write_same;
@@ -1712,7 +1802,8 @@ static int32_t scsi_disk_emulate_command(SCSIRequest *req, uint8_t *buf)
scsi_check_condition(r, SENSE_CODE(WRITE_PROTECTED));
return 0;
}
- if (r->req.cmd.lba > s->qdev.max_lba) {
+ if (r->req.cmd.lba > r->req.cmd.lba + nb_sectors ||
+ r->req.cmd.lba + nb_sectors - 1 > s->qdev.max_lba) {
goto illegal_lba;
}
@@ -2067,6 +2158,7 @@ static const SCSIReqOps *const scsi_disk_reqops_dispatch[256] = {
[SEEK_10] = &scsi_disk_emulate_reqops,
[MODE_SELECT] = &scsi_disk_emulate_reqops,
[MODE_SELECT_10] = &scsi_disk_emulate_reqops,
+ [UNMAP] = &scsi_disk_emulate_reqops,
[WRITE_SAME_10] = &scsi_disk_emulate_reqops,
[WRITE_SAME_16] = &scsi_disk_emulate_reqops,
diff --git a/hw/sd.c b/hw/sd.c
index 07eb263388..ec26407543 100644
--- a/hw/sd.c
+++ b/hw/sd.c
@@ -32,6 +32,7 @@
#include "hw.h"
#include "block.h"
#include "sd.h"
+#include "bitmap.h"
//#define DEBUG_SD 1
@@ -80,8 +81,8 @@ struct SDState {
uint32_t card_status;
uint8_t sd_status[64];
uint32_t vhs;
- int wp_switch;
- int *wp_groups;
+ bool wp_switch;
+ unsigned long *wp_groups;
uint64_t size;
int blk_len;
uint32_t erase_start;
@@ -90,12 +91,12 @@ struct SDState {
int pwd_len;
int function_group[6];
- int spi;
+ bool spi;
int current_cmd;
/* True if we will handle the next command as an ACMD. Note that this does
* *not* track the APP_CMD status bit!
*/
- int expecting_acmd;
+ bool expecting_acmd;
int blk_written;
uint64_t data_start;
uint32_t data_offset;
@@ -105,7 +106,7 @@ struct SDState {
BlockDriverState *bdrv;
uint8_t *buf;
- int enable;
+ bool enable;
};
static void sd_set_mode(SDState *sd)
@@ -387,6 +388,11 @@ static void sd_response_r7_make(SDState *sd, uint8_t *response)
response[3] = (sd->vhs >> 0) & 0xff;
}
+static inline uint64_t sd_addr_to_wpnum(uint64_t addr)
+{
+ return addr >> (HWBLOCK_SHIFT + SECTOR_SHIFT + WPGROUP_SHIFT);
+}
+
static void sd_reset(SDState *sd, BlockDriverState *bdrv)
{
uint64_t size;
@@ -399,7 +405,7 @@ static void sd_reset(SDState *sd, BlockDriverState *bdrv)
}
size = sect << 9;
- sect = (size >> (HWBLOCK_SHIFT + SECTOR_SHIFT + WPGROUP_SHIFT)) + 1;
+ sect = sd_addr_to_wpnum(size) + 1;
sd->state = sd_idle_state;
sd->rca = 0x0000;
@@ -414,15 +420,15 @@ static void sd_reset(SDState *sd, BlockDriverState *bdrv)
if (sd->wp_groups)
g_free(sd->wp_groups);
- sd->wp_switch = bdrv ? bdrv_is_read_only(bdrv) : 0;
- sd->wp_groups = (int *) g_malloc0(sizeof(int) * sect);
+ sd->wp_switch = bdrv ? bdrv_is_read_only(bdrv) : false;
+ sd->wp_groups = bitmap_new(sect);
memset(sd->function_group, 0, sizeof(int) * 6);
sd->erase_start = 0;
sd->erase_end = 0;
sd->size = size;
sd->blk_len = 0x200;
sd->pwd_len = 0;
- sd->expecting_acmd = 0;
+ sd->expecting_acmd = false;
}
static void sd_cardchange(void *opaque, bool load)
@@ -444,14 +450,14 @@ static const BlockDevOps sd_block_ops = {
whether card should be in SSI or MMC/SD mode. It is also up to the
board to ensure that ssi transfers only occur when the chip select
is asserted. */
-SDState *sd_init(BlockDriverState *bs, int is_spi)
+SDState *sd_init(BlockDriverState *bs, bool is_spi)
{
SDState *sd;
sd = (SDState *) g_malloc0(sizeof(SDState));
sd->buf = qemu_blockalign(bs, 512);
sd->spi = is_spi;
- sd->enable = 1;
+ sd->enable = true;
sd_reset(sd, bs);
if (sd->bdrv) {
bdrv_attach_dev_nofail(sd->bdrv, sd);
@@ -476,17 +482,17 @@ static void sd_erase(SDState *sd)
return;
}
- start = sd->erase_start >>
- (HWBLOCK_SHIFT + SECTOR_SHIFT + WPGROUP_SHIFT);
- end = sd->erase_end >>
- (HWBLOCK_SHIFT + SECTOR_SHIFT + WPGROUP_SHIFT);
+ start = sd_addr_to_wpnum(sd->erase_start);
+ end = sd_addr_to_wpnum(sd->erase_end);
sd->erase_start = 0;
sd->erase_end = 0;
sd->csd[14] |= 0x40;
- for (i = start; i <= end; i ++)
- if (sd->wp_groups[i])
+ for (i = start; i <= end; i++) {
+ if (test_bit(i, sd->wp_groups)) {
sd->card_status |= WP_ERASE_SKIP;
+ }
+ }
}
static uint32_t sd_wpbits(SDState *sd, uint64_t addr)
@@ -494,11 +500,13 @@ static uint32_t sd_wpbits(SDState *sd, uint64_t addr)
uint32_t i, wpnum;
uint32_t ret = 0;
- wpnum = addr >> (HWBLOCK_SHIFT + SECTOR_SHIFT + WPGROUP_SHIFT);
+ wpnum = sd_addr_to_wpnum(addr);
- for (i = 0; i < 32; i ++, wpnum ++, addr += WPGROUP_SIZE)
- if (addr < sd->size && sd->wp_groups[wpnum])
+ for (i = 0; i < 32; i++, wpnum++, addr += WPGROUP_SIZE) {
+ if (addr < sd->size && test_bit(wpnum, sd->wp_groups)) {
ret |= (1 << i);
+ }
+ }
return ret;
}
@@ -534,10 +542,9 @@ static void sd_function_switch(SDState *sd, uint32_t arg)
sd->data[66] = crc & 0xff;
}
-static inline int sd_wp_addr(SDState *sd, uint32_t addr)
+static inline bool sd_wp_addr(SDState *sd, uint64_t addr)
{
- return sd->wp_groups[addr >>
- (HWBLOCK_SHIFT + SECTOR_SHIFT + WPGROUP_SHIFT)];
+ return test_bit(sd_addr_to_wpnum(addr), sd->wp_groups);
}
static void sd_lock_command(SDState *sd)
@@ -560,8 +567,7 @@ static void sd_lock_command(SDState *sd)
sd->card_status |= LOCK_UNLOCK_FAILED;
return;
}
- memset(sd->wp_groups, 0, sizeof(int) * (sd->size >>
- (HWBLOCK_SHIFT + SECTOR_SHIFT + WPGROUP_SHIFT)));
+ bitmap_zero(sd->wp_groups, sd_addr_to_wpnum(sd->size) + 1);
sd->csd[14] &= ~0x10;
sd->card_status &= ~CARD_IS_LOCKED;
sd->pwd_len = 0;
@@ -1007,8 +1013,7 @@ static sd_rsp_type_t sd_normal_command(SDState *sd,
}
sd->state = sd_programming_state;
- sd->wp_groups[addr >> (HWBLOCK_SHIFT +
- SECTOR_SHIFT + WPGROUP_SHIFT)] = 1;
+ set_bit(sd_addr_to_wpnum(addr), sd->wp_groups);
/* Bzzzzzzztt .... Operation complete. */
sd->state = sd_transfer_state;
return sd_r1b;
@@ -1027,8 +1032,7 @@ static sd_rsp_type_t sd_normal_command(SDState *sd,
}
sd->state = sd_programming_state;
- sd->wp_groups[addr >> (HWBLOCK_SHIFT +
- SECTOR_SHIFT + WPGROUP_SHIFT)] = 0;
+ clear_bit(sd_addr_to_wpnum(addr), sd->wp_groups);
/* Bzzzzzzztt .... Operation complete. */
sd->state = sd_transfer_state;
return sd_r1b;
@@ -1125,7 +1129,7 @@ static sd_rsp_type_t sd_normal_command(SDState *sd,
if (sd->rca != rca)
return sd_r0;
- sd->expecting_acmd = 1;
+ sd->expecting_acmd = true;
sd->card_status |= APP_CMD;
return sd_r1;
@@ -1307,7 +1311,7 @@ int sd_do_command(SDState *sd, SDRequest *req,
if (sd->card_status & CARD_IS_LOCKED) {
if (!cmd_valid_while_locked(sd, req)) {
sd->card_status |= ILLEGAL_COMMAND;
- sd->expecting_acmd = 0;
+ sd->expecting_acmd = false;
fprintf(stderr, "SD: Card is locked\n");
rtype = sd_illegal;
goto send_response;
@@ -1318,7 +1322,7 @@ int sd_do_command(SDState *sd, SDRequest *req,
sd_set_mode(sd);
if (sd->expecting_acmd) {
- sd->expecting_acmd = 0;
+ sd->expecting_acmd = false;
rtype = sd_app_command(sd, *req);
} else {
rtype = sd_normal_command(sd, *req);
@@ -1699,12 +1703,12 @@ uint8_t sd_read_data(SDState *sd)
return ret;
}
-int sd_data_ready(SDState *sd)
+bool sd_data_ready(SDState *sd)
{
return sd->state == sd_sendingdata_state;
}
-void sd_enable(SDState *sd, int enable)
+void sd_enable(SDState *sd, bool enable)
{
sd->enable = enable;
}
diff --git a/hw/sd.h b/hw/sd.h
index ac4b7c4dfa..4eb9679acd 100644
--- a/hw/sd.h
+++ b/hw/sd.h
@@ -67,13 +67,13 @@ typedef struct {
typedef struct SDState SDState;
-SDState *sd_init(BlockDriverState *bs, int is_spi);
+SDState *sd_init(BlockDriverState *bs, bool is_spi);
int sd_do_command(SDState *sd, SDRequest *req,
uint8_t *response);
void sd_write_data(SDState *sd, uint8_t value);
uint8_t sd_read_data(SDState *sd);
void sd_set_cb(SDState *sd, qemu_irq readonly, qemu_irq insert);
-int sd_data_ready(SDState *sd);
-void sd_enable(SDState *sd, int enable);
+bool sd_data_ready(SDState *sd);
+void sd_enable(SDState *sd, bool enable);
#endif /* __hw_sd_h */
diff --git a/hw/ssd0323.c b/hw/ssd0323.c
index b0b2e94a81..b101c5112c 100644
--- a/hw/ssd0323.c
+++ b/hw/ssd0323.c
@@ -19,7 +19,9 @@
#define DPRINTF(fmt, ...) \
do { printf("ssd0323: " fmt , ## __VA_ARGS__); } while (0)
#define BADF(fmt, ...) \
-do { fprintf(stderr, "ssd0323: error: " fmt , ## __VA_ARGS__); exit(1);} while (0)
+do { \
+ fprintf(stderr, "ssd0323: error: " fmt , ## __VA_ARGS__); abort(); \
+} while (0)
#else
#define DPRINTF(fmt, ...) do {} while(0)
#define BADF(fmt, ...) \
diff --git a/hw/stream.c b/hw/stream.c
new file mode 100644
index 0000000000..be57e8b247
--- /dev/null
+++ b/hw/stream.c
@@ -0,0 +1,23 @@
+#include "stream.h"
+
+void
+stream_push(StreamSlave *sink, uint8_t *buf, size_t len, uint32_t *app)
+{
+ StreamSlaveClass *k = STREAM_SLAVE_GET_CLASS(sink);
+
+ k->push(sink, buf, len, app);
+}
+
+static TypeInfo stream_slave_info = {
+ .name = TYPE_STREAM_SLAVE,
+ .parent = TYPE_INTERFACE,
+ .class_size = sizeof(StreamSlaveClass),
+};
+
+
+static void stream_slave_register_types(void)
+{
+ type_register_static(&stream_slave_info);
+}
+
+type_init(stream_slave_register_types)
diff --git a/hw/stream.h b/hw/stream.h
new file mode 100644
index 0000000000..21123a9089
--- /dev/null
+++ b/hw/stream.h
@@ -0,0 +1,31 @@
+#ifndef STREAM_H
+#define STREAM_H 1
+
+#include "qemu-common.h"
+#include "qemu/object.h"
+
+/* stream slave. Used until qdev provides a generic way. */
+#define TYPE_STREAM_SLAVE "stream-slave"
+
+#define STREAM_SLAVE_CLASS(klass) \
+ OBJECT_CLASS_CHECK(StreamSlaveClass, (klass), TYPE_STREAM_SLAVE)
+#define STREAM_SLAVE_GET_CLASS(obj) \
+ OBJECT_GET_CLASS(StreamSlaveClass, (obj), TYPE_STREAM_SLAVE)
+#define STREAM_SLAVE(obj) \
+ INTERFACE_CHECK(StreamSlave, (obj), TYPE_STREAM_SLAVE)
+
+typedef struct StreamSlave {
+ Object Parent;
+} StreamSlave;
+
+typedef struct StreamSlaveClass {
+ InterfaceClass parent;
+
+ void (*push)(StreamSlave *obj, unsigned char *buf, size_t len,
+ uint32_t *app);
+} StreamSlaveClass;
+
+void
+stream_push(StreamSlave *sink, uint8_t *buf, size_t len, uint32_t *app);
+
+#endif /* STREAM_H */
diff --git a/hw/sun4m.c b/hw/sun4m.c
index a959261209..0f909b5f86 100644
--- a/hw/sun4m.c
+++ b/hw/sun4m.c
@@ -832,6 +832,10 @@ static void cpu_devinit(const char *cpu_model, unsigned int id,
env->prom_addr = prom_addr;
}
+static void dummy_fdc_tc(void *opaque, int irq, int level)
+{
+}
+
static void sun4m_hw_init(const struct sun4m_hwdef *hwdef, ram_addr_t RAM_size,
const char *boot_device,
const char *kernel_filename,
@@ -942,9 +946,6 @@ static void sun4m_hw_init(const struct sun4m_hwdef *hwdef, ram_addr_t RAM_size,
serial_hds[0], serial_hds[1], ESCC_CLOCK, 1);
cpu_halt = qemu_allocate_irqs(cpu_halt_signal, NULL, 1);
- slavio_misc_init(hwdef->slavio_base, hwdef->aux1_base, hwdef->aux2_base,
- slavio_irq[30], fdc_tc);
-
if (hwdef->apc_base) {
apc_init(hwdef->apc_base, cpu_halt[0]);
}
@@ -955,8 +956,13 @@ static void sun4m_hw_init(const struct sun4m_hwdef *hwdef, ram_addr_t RAM_size,
fd[0] = drive_get(IF_FLOPPY, 0, 0);
sun4m_fdctrl_init(slavio_irq[22], hwdef->fd_base, fd,
&fdc_tc);
+ } else {
+ fdc_tc = *qemu_allocate_irqs(dummy_fdc_tc, NULL, 1);
}
+ slavio_misc_init(hwdef->slavio_base, hwdef->aux1_base, hwdef->aux2_base,
+ slavio_irq[30], fdc_tc);
+
if (drive_get_max_bus(IF_SCSI) > 0) {
fprintf(stderr, "qemu: too many SCSI bus\n");
exit(1);
@@ -1772,16 +1778,18 @@ static void sun4c_hw_init(const struct sun4c_hwdef *hwdef, ram_addr_t RAM_size,
slavio_irq[1], serial_hds[0], serial_hds[1],
ESCC_CLOCK, 1);
- slavio_misc_init(0, hwdef->aux1_base, 0, slavio_irq[1], fdc_tc);
-
if (hwdef->fd_base != (target_phys_addr_t)-1) {
/* there is zero or one floppy drive */
memset(fd, 0, sizeof(fd));
fd[0] = drive_get(IF_FLOPPY, 0, 0);
sun4m_fdctrl_init(slavio_irq[1], hwdef->fd_base, fd,
&fdc_tc);
+ } else {
+ fdc_tc = *qemu_allocate_irqs(dummy_fdc_tc, NULL, 1);
}
+ slavio_misc_init(0, hwdef->aux1_base, 0, slavio_irq[1], fdc_tc);
+
if (drive_get_max_bus(IF_SCSI) > 0) {
fprintf(stderr, "qemu: too many SCSI bus\n");
exit(1);
diff --git a/hw/unicore32/Makefile.objs b/hw/unicore32/Makefile.objs
new file mode 100644
index 0000000000..0725ce3ca7
--- /dev/null
+++ b/hw/unicore32/Makefile.objs
@@ -0,0 +1,6 @@
+# For UniCore32 machines and boards
+
+# PKUnity-v3 SoC and board information
+obj-${CONFIG_PUV3} += puv3.o
+
+obj-y := $(addprefix ../,$(obj-y))
diff --git a/hw/virtio-blk.c b/hw/virtio-blk.c
index f21757ed55..fd8fa90792 100644
--- a/hw/virtio-blk.c
+++ b/hw/virtio-blk.c
@@ -254,6 +254,7 @@ static void virtio_blk_handle_scsi(VirtIOBlockReq *req)
virtio_blk_req_complete(req, status);
g_free(req);
+ return;
#else
abort();
#endif
@@ -509,9 +510,19 @@ static void virtio_blk_update_config(VirtIODevice *vdev, uint8_t *config)
blkcfg.size_max = 0;
blkcfg.physical_block_exp = get_physical_block_exp(s->conf);
blkcfg.alignment_offset = 0;
+ blkcfg.wce = bdrv_enable_write_cache(s->bs);
memcpy(config, &blkcfg, sizeof(struct virtio_blk_config));
}
+static void virtio_blk_set_config(VirtIODevice *vdev, const uint8_t *config)
+{
+ VirtIOBlock *s = to_virtio_blk(vdev);
+ struct virtio_blk_config blkcfg;
+
+ memcpy(&blkcfg, config, sizeof(blkcfg));
+ bdrv_set_enable_write_cache(s->bs, blkcfg.wce != 0);
+}
+
static uint32_t virtio_blk_get_features(VirtIODevice *vdev, uint32_t features)
{
VirtIOBlock *s = to_virtio_blk(vdev);
@@ -522,15 +533,29 @@ static uint32_t virtio_blk_get_features(VirtIODevice *vdev, uint32_t features)
features |= (1 << VIRTIO_BLK_F_BLK_SIZE);
features |= (1 << VIRTIO_BLK_F_SCSI);
+ features |= (1 << VIRTIO_BLK_F_CONFIG_WCE);
if (bdrv_enable_write_cache(s->bs))
- features |= (1 << VIRTIO_BLK_F_WCACHE);
-
+ features |= (1 << VIRTIO_BLK_F_WCE);
+
if (bdrv_is_read_only(s->bs))
features |= 1 << VIRTIO_BLK_F_RO;
return features;
}
+static void virtio_blk_set_status(VirtIODevice *vdev, uint8_t status)
+{
+ VirtIOBlock *s = to_virtio_blk(vdev);
+ uint32_t features;
+
+ if (!(status & VIRTIO_CONFIG_S_DRIVER_OK)) {
+ return;
+ }
+
+ features = vdev->guest_features;
+ bdrv_set_enable_write_cache(s->bs, !!(features & (1 << VIRTIO_BLK_F_WCE)));
+}
+
static void virtio_blk_save(QEMUFile *f, void *opaque)
{
VirtIOBlock *s = opaque;
@@ -609,7 +634,9 @@ VirtIODevice *virtio_blk_init(DeviceState *dev, VirtIOBlkConf *blk)
sizeof(VirtIOBlock));
s->vdev.get_config = virtio_blk_update_config;
+ s->vdev.set_config = virtio_blk_set_config;
s->vdev.get_features = virtio_blk_get_features;
+ s->vdev.set_status = virtio_blk_set_status;
s->vdev.reset = virtio_blk_reset;
s->bs = blk->conf.bs;
s->conf = &blk->conf;
diff --git a/hw/virtio-blk.h b/hw/virtio-blk.h
index 79ebccc95b..35834cf493 100644
--- a/hw/virtio-blk.h
+++ b/hw/virtio-blk.h
@@ -31,8 +31,9 @@
#define VIRTIO_BLK_F_BLK_SIZE 6 /* Block size of disk is available*/
#define VIRTIO_BLK_F_SCSI 7 /* Supports scsi command passthru */
/* #define VIRTIO_BLK_F_IDENTIFY 8 ATA IDENTIFY supported, DEPRECATED */
-#define VIRTIO_BLK_F_WCACHE 9 /* write cache enabled */
+#define VIRTIO_BLK_F_WCE 9 /* write cache enabled */
#define VIRTIO_BLK_F_TOPOLOGY 10 /* Topology information is available */
+#define VIRTIO_BLK_F_CONFIG_WCE 11 /* write cache configurable */
#define VIRTIO_BLK_ID_BYTES 20 /* ID string length */
@@ -49,6 +50,7 @@ struct virtio_blk_config
uint8_t alignment_offset;
uint16_t min_io_size;
uint32_t opt_io_size;
+ uint8_t wce;
} QEMU_PACKED;
/* These two define direction. */
diff --git a/hw/virtio-pci.c b/hw/virtio-pci.c
index 125eded9ca..5e6e09efb7 100644
--- a/hw/virtio-pci.c
+++ b/hw/virtio-pci.c
@@ -627,7 +627,7 @@ static int virtio_pci_set_guest_notifiers(void *opaque, bool assign)
int r, n;
/* Must unset vector notifier while guest notifier is still assigned */
- if (kvm_irqchip_in_kernel() && !assign) {
+ if (kvm_msi_via_irqfd_enabled() && !assign) {
msix_unset_vector_notifiers(&proxy->pci_dev);
g_free(proxy->vector_irqfd);
proxy->vector_irqfd = NULL;
@@ -645,7 +645,7 @@ static int virtio_pci_set_guest_notifiers(void *opaque, bool assign)
}
/* Must set vector notifier after guest notifier has been assigned */
- if (kvm_irqchip_in_kernel() && assign) {
+ if (kvm_msi_via_irqfd_enabled() && assign) {
proxy->vector_irqfd =
g_malloc0(sizeof(*proxy->vector_irqfd) *
msix_nr_vectors_allocated(&proxy->pci_dev));
diff --git a/hw/virtio-scsi.c b/hw/virtio-scsi.c
index c4a5b22f94..5f737acd97 100644
--- a/hw/virtio-scsi.c
+++ b/hw/virtio-scsi.c
@@ -305,11 +305,17 @@ static void virtio_scsi_do_tmf(VirtIOSCSI *s, VirtIOSCSIReq *req)
goto incorrect_lun;
}
QTAILQ_FOREACH_SAFE(r, &d->requests, next, next) {
- if (r->tag == req->req.tmf->tag) {
+ VirtIOSCSIReq *cmd_req = r->hba_private;
+ if (cmd_req && cmd_req->req.cmd->tag == req->req.tmf->tag) {
break;
}
}
- if (r && r->hba_private) {
+ if (r) {
+ /*
+ * Assert that the request has not been completed yet, we
+ * check for it in the loop above.
+ */
+ assert(r->hba_private);
if (req->req.tmf->subtype == VIRTIO_SCSI_T_TMF_QUERY_TASK) {
/* "If the specified command is present in the task set, then
* return a service response set to FUNCTION SUCCEEDED".
diff --git a/hw/xilinx.h b/hw/xilinx.h
index 7df21eb958..556c5aa9f1 100644
--- a/hw/xilinx.h
+++ b/hw/xilinx.h
@@ -1,3 +1,4 @@
+#include "stream.h"
#include "qemu-common.h"
#include "net.h"
@@ -49,8 +50,8 @@ xilinx_ethlite_create(NICInfo *nd, target_phys_addr_t base, qemu_irq irq,
}
static inline DeviceState *
-xilinx_axiethernet_create(void *dmach,
- NICInfo *nd, target_phys_addr_t base, qemu_irq irq,
+xilinx_axiethernet_create(NICInfo *nd, StreamSlave *peer,
+ target_phys_addr_t base, qemu_irq irq,
int txmem, int rxmem)
{
DeviceState *dev;
@@ -60,7 +61,7 @@ xilinx_axiethernet_create(void *dmach,
qdev_set_nic_properties(dev, nd);
qdev_prop_set_uint32(dev, "rxmem", rxmem);
qdev_prop_set_uint32(dev, "txmem", txmem);
- qdev_prop_set_ptr(dev, "dmach", dmach);
+ object_property_set_link(OBJECT(dev), OBJECT(peer), "tx_dev", NULL);
qdev_init_nofail(dev);
sysbus_mmio_map(sysbus_from_qdev(dev), 0, base);
sysbus_connect_irq(sysbus_from_qdev(dev), 0, irq);
@@ -68,21 +69,16 @@ xilinx_axiethernet_create(void *dmach,
return dev;
}
-static inline DeviceState *
-xilinx_axiethernetdma_create(void *dmach,
- target_phys_addr_t base, qemu_irq irq,
- qemu_irq irq2, int freqhz)
+static inline void
+xilinx_axiethernetdma_init(DeviceState *dev, StreamSlave *peer,
+ target_phys_addr_t base, qemu_irq irq,
+ qemu_irq irq2, int freqhz)
{
- DeviceState *dev = NULL;
-
- dev = qdev_create(NULL, "xlnx.axi-dma");
qdev_prop_set_uint32(dev, "freqhz", freqhz);
- qdev_prop_set_ptr(dev, "dmach", dmach);
+ object_property_set_link(OBJECT(dev), OBJECT(peer), "tx_dev", NULL);
qdev_init_nofail(dev);
sysbus_mmio_map(sysbus_from_qdev(dev), 0, base);
sysbus_connect_irq(sysbus_from_qdev(dev), 0, irq);
sysbus_connect_irq(sysbus_from_qdev(dev), 1, irq2);
-
- return dev;
}
diff --git a/hw/xilinx_axidma.c b/hw/xilinx_axidma.c
index f4bec37c7a..0e28c51738 100644
--- a/hw/xilinx_axidma.c
+++ b/hw/xilinx_axidma.c
@@ -29,7 +29,7 @@
#include "qemu-log.h"
#include "qdev-addr.h"
-#include "xilinx_axidma.h"
+#include "stream.h"
#define D(x)
@@ -77,7 +77,7 @@ enum {
SDESC_STATUS_COMPLETE = (1 << 31)
};
-struct AXIStream {
+struct Stream {
QEMUBH *bh;
ptimer_state *ptimer;
qemu_irq irq;
@@ -94,9 +94,9 @@ struct XilinxAXIDMA {
SysBusDevice busdev;
MemoryRegion iomem;
uint32_t freqhz;
- void *dmach;
+ StreamSlave *tx_dev;
- struct AXIStream streams[2];
+ struct Stream streams[2];
};
/*
@@ -113,27 +113,27 @@ static inline int stream_desc_eof(struct SDesc *d)
return d->control & SDESC_CTRL_EOF;
}
-static inline int stream_resetting(struct AXIStream *s)
+static inline int stream_resetting(struct Stream *s)
{
return !!(s->regs[R_DMACR] & DMACR_RESET);
}
-static inline int stream_running(struct AXIStream *s)
+static inline int stream_running(struct Stream *s)
{
return s->regs[R_DMACR] & DMACR_RUNSTOP;
}
-static inline int stream_halted(struct AXIStream *s)
+static inline int stream_halted(struct Stream *s)
{
return s->regs[R_DMASR] & DMASR_HALTED;
}
-static inline int stream_idle(struct AXIStream *s)
+static inline int stream_idle(struct Stream *s)
{
return !!(s->regs[R_DMASR] & DMASR_IDLE);
}
-static void stream_reset(struct AXIStream *s)
+static void stream_reset(struct Stream *s)
{
s->regs[R_DMASR] = DMASR_HALTED; /* starts up halted. */
s->regs[R_DMACR] = 1 << 16; /* Starts with one in compl threshold. */
@@ -159,7 +159,7 @@ static void stream_desc_show(struct SDesc *d)
}
#endif
-static void stream_desc_load(struct AXIStream *s, target_phys_addr_t addr)
+static void stream_desc_load(struct Stream *s, target_phys_addr_t addr)
{
struct SDesc *d = &s->desc;
int i;
@@ -176,7 +176,7 @@ static void stream_desc_load(struct AXIStream *s, target_phys_addr_t addr)
}
}
-static void stream_desc_store(struct AXIStream *s, target_phys_addr_t addr)
+static void stream_desc_store(struct Stream *s, target_phys_addr_t addr)
{
struct SDesc *d = &s->desc;
int i;
@@ -192,7 +192,7 @@ static void stream_desc_store(struct AXIStream *s, target_phys_addr_t addr)
cpu_physical_memory_write(addr, (void *) d, sizeof *d);
}
-static void stream_update_irq(struct AXIStream *s)
+static void stream_update_irq(struct Stream *s)
{
unsigned int pending, mask, irq;
@@ -204,7 +204,7 @@ static void stream_update_irq(struct AXIStream *s)
qemu_set_irq(s->irq, !!irq);
}
-static void stream_reload_complete_cnt(struct AXIStream *s)
+static void stream_reload_complete_cnt(struct Stream *s)
{
unsigned int comp_th;
comp_th = (s->regs[R_DMACR] >> 16) & 0xff;
@@ -213,14 +213,14 @@ static void stream_reload_complete_cnt(struct AXIStream *s)
static void timer_hit(void *opaque)
{
- struct AXIStream *s = opaque;
+ struct Stream *s = opaque;
stream_reload_complete_cnt(s);
s->regs[R_DMASR] |= DMASR_DLY_IRQ;
stream_update_irq(s);
}
-static void stream_complete(struct AXIStream *s)
+static void stream_complete(struct Stream *s)
{
unsigned int comp_delay;
@@ -240,8 +240,8 @@ static void stream_complete(struct AXIStream *s)
}
}
-static void stream_process_mem2s(struct AXIStream *s,
- struct XilinxDMAConnection *dmach)
+static void stream_process_mem2s(struct Stream *s,
+ StreamSlave *tx_dev)
{
uint32_t prev_d;
unsigned char txbuf[16 * 1024];
@@ -276,7 +276,7 @@ static void stream_process_mem2s(struct AXIStream *s,
s->pos += txlen;
if (stream_desc_eof(&s->desc)) {
- xlx_dma_push_to_client(dmach, txbuf, s->pos, app);
+ stream_push(tx_dev, txbuf, s->pos, app);
s->pos = 0;
stream_complete(s);
}
@@ -295,7 +295,7 @@ static void stream_process_mem2s(struct AXIStream *s,
}
}
-static void stream_process_s2mem(struct AXIStream *s,
+static void stream_process_s2mem(struct Stream *s,
unsigned char *buf, size_t len, uint32_t *app)
{
uint32_t prev_d;
@@ -351,11 +351,11 @@ static void stream_process_s2mem(struct AXIStream *s,
}
}
-static
-void axidma_push(void *opaque, unsigned char *buf, size_t len, uint32_t *app)
+static void
+axidma_push(StreamSlave *obj, unsigned char *buf, size_t len, uint32_t *app)
{
- struct XilinxAXIDMA *d = opaque;
- struct AXIStream *s = &d->streams[1];
+ struct XilinxAXIDMA *d = FROM_SYSBUS(typeof(*d), SYS_BUS_DEVICE(obj));
+ struct Stream *s = &d->streams[1];
if (!app) {
hw_error("No stream app data!\n");
@@ -368,7 +368,7 @@ static uint64_t axidma_read(void *opaque, target_phys_addr_t addr,
unsigned size)
{
struct XilinxAXIDMA *d = opaque;
- struct AXIStream *s;
+ struct Stream *s;
uint32_t r = 0;
int sid;
@@ -403,7 +403,7 @@ static void axidma_write(void *opaque, target_phys_addr_t addr,
uint64_t value, unsigned size)
{
struct XilinxAXIDMA *d = opaque;
- struct AXIStream *s;
+ struct Stream *s;
int sid;
sid = streamid_from_addr(addr);
@@ -440,7 +440,7 @@ static void axidma_write(void *opaque, target_phys_addr_t addr,
s->regs[addr] = value;
s->regs[R_DMASR] &= ~DMASR_IDLE; /* Not idle. */
if (!sid) {
- stream_process_mem2s(s, d->dmach);
+ stream_process_mem2s(s, d->tx_dev);
}
break;
default:
@@ -466,12 +466,6 @@ static int xilinx_axidma_init(SysBusDevice *dev)
sysbus_init_irq(dev, &s->streams[0].irq);
sysbus_init_irq(dev, &s->streams[1].irq);
- if (!s->dmach) {
- hw_error("Unconnected DMA channel.\n");
- }
-
- xlx_dma_connect_dma(s->dmach, s, axidma_push);
-
memory_region_init_io(&s->iomem, &axidma_ops, s,
"xlnx.axi-dma", R_MAX * 4 * 2);
sysbus_init_mmio(dev, &s->iomem);
@@ -486,9 +480,16 @@ static int xilinx_axidma_init(SysBusDevice *dev)
return 0;
}
+static void xilinx_axidma_initfn(Object *obj)
+{
+ struct XilinxAXIDMA *s = FROM_SYSBUS(typeof(*s), SYS_BUS_DEVICE(obj));
+
+ object_property_add_link(obj, "axistream-connected", TYPE_STREAM_SLAVE,
+ (Object **) &s->tx_dev, NULL);
+}
+
static Property axidma_properties[] = {
DEFINE_PROP_UINT32("freqhz", struct XilinxAXIDMA, freqhz, 50000000),
- DEFINE_PROP_PTR("dmach", struct XilinxAXIDMA, dmach),
DEFINE_PROP_END_OF_LIST(),
};
@@ -496,9 +497,11 @@ static void axidma_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+ StreamSlaveClass *ssc = STREAM_SLAVE_CLASS(klass);
k->init = xilinx_axidma_init;
dc->props = axidma_properties;
+ ssc->push = axidma_push;
}
static TypeInfo axidma_info = {
@@ -506,6 +509,11 @@ static TypeInfo axidma_info = {
.parent = TYPE_SYS_BUS_DEVICE,
.instance_size = sizeof(struct XilinxAXIDMA),
.class_init = axidma_class_init,
+ .instance_init = xilinx_axidma_initfn,
+ .interfaces = (InterfaceInfo[]) {
+ { TYPE_STREAM_SLAVE },
+ { }
+ }
};
static void xilinx_axidma_register_types(void)
diff --git a/hw/xilinx_axidma.h b/hw/xilinx_axidma.h
deleted file mode 100644
index 37cb6f0911..0000000000
--- a/hw/xilinx_axidma.h
+++ /dev/null
@@ -1,39 +0,0 @@
-/* AXI DMA connection. Used until qdev provides a generic way. */
-typedef void (*DMAPushFn)(void *opaque,
- unsigned char *buf, size_t len, uint32_t *app);
-
-struct XilinxDMAConnection {
- void *dma;
- void *client;
-
- DMAPushFn to_dma;
- DMAPushFn to_client;
-};
-
-static inline void xlx_dma_connect_client(struct XilinxDMAConnection *dmach,
- void *c, DMAPushFn f)
-{
- dmach->client = c;
- dmach->to_client = f;
-}
-
-static inline void xlx_dma_connect_dma(struct XilinxDMAConnection *dmach,
- void *d, DMAPushFn f)
-{
- dmach->dma = d;
- dmach->to_dma = f;
-}
-
-static inline
-void xlx_dma_push_to_dma(struct XilinxDMAConnection *dmach,
- uint8_t *buf, size_t len, uint32_t *app)
-{
- dmach->to_dma(dmach->dma, buf, len, app);
-}
-static inline
-void xlx_dma_push_to_client(struct XilinxDMAConnection *dmach,
- uint8_t *buf, size_t len, uint32_t *app)
-{
- dmach->to_client(dmach->client, buf, len, app);
-}
-
diff --git a/hw/xilinx_axienet.c b/hw/xilinx_axienet.c
index adfaf2c50e..eec155d440 100644
--- a/hw/xilinx_axienet.c
+++ b/hw/xilinx_axienet.c
@@ -28,7 +28,7 @@
#include "net.h"
#include "net/checksum.h"
-#include "xilinx_axidma.h"
+#include "stream.h"
#define DPHY(x)
@@ -310,7 +310,7 @@ struct XilinxAXIEnet {
SysBusDevice busdev;
MemoryRegion iomem;
qemu_irq irq;
- void *dmach;
+ StreamSlave *tx_dev;
NICState *nic;
NICConf conf;
@@ -648,7 +648,6 @@ static ssize_t eth_rx(NetClientState *nc, const uint8_t *buf, size_t size)
uint16_t csum16;
int i;
- s = s;
DENET(qemu_log("%s: %zd bytes\n", __func__, size));
unicast = ~buf[0] & 0x1;
@@ -773,7 +772,7 @@ static ssize_t eth_rx(NetClientState *nc, const uint8_t *buf, size_t size)
/* Good frame. */
app[2] |= 1 << 6;
- xlx_dma_push_to_dma(s->dmach, (void *)s->rxmem, size, app);
+ stream_push(s->tx_dev, (void *)s->rxmem, size, app);
s->regs[R_IS] |= IS_RX_COMPLETE;
enet_update_irq(s);
@@ -789,9 +788,9 @@ static void eth_cleanup(NetClientState *nc)
}
static void
-axienet_stream_push(void *opaque, uint8_t *buf, size_t size, uint32_t *hdr)
+axienet_stream_push(StreamSlave *obj, uint8_t *buf, size_t size, uint32_t *hdr)
{
- struct XilinxAXIEnet *s = opaque;
+ struct XilinxAXIEnet *s = FROM_SYSBUS(typeof(*s), SYS_BUS_DEVICE(obj));
/* TX enable ? */
if (!(s->tc & TC_TX)) {
@@ -845,12 +844,6 @@ static int xilinx_enet_init(SysBusDevice *dev)
sysbus_init_irq(dev, &s->irq);
- if (!s->dmach) {
- hw_error("Unconnected Xilinx Ethernet MAC.\n");
- }
-
- xlx_dma_connect_client(s->dmach, s, axienet_stream_push);
-
memory_region_init_io(&s->iomem, &enet_ops, s, "enet", 0x40000);
sysbus_init_mmio(dev, &s->iomem);
@@ -870,11 +863,18 @@ static int xilinx_enet_init(SysBusDevice *dev)
return 0;
}
+static void xilinx_enet_initfn(Object *obj)
+{
+ struct XilinxAXIEnet *s = FROM_SYSBUS(typeof(*s), SYS_BUS_DEVICE(obj));
+
+ object_property_add_link(obj, "axistream-connected", TYPE_STREAM_SLAVE,
+ (Object **) &s->tx_dev, NULL);
+}
+
static Property xilinx_enet_properties[] = {
DEFINE_PROP_UINT32("phyaddr", struct XilinxAXIEnet, c_phyaddr, 7),
DEFINE_PROP_UINT32("rxmem", struct XilinxAXIEnet, c_rxmem, 0x1000),
DEFINE_PROP_UINT32("txmem", struct XilinxAXIEnet, c_txmem, 0x1000),
- DEFINE_PROP_PTR("dmach", struct XilinxAXIEnet, dmach),
DEFINE_NIC_PROPERTIES(struct XilinxAXIEnet, conf),
DEFINE_PROP_END_OF_LIST(),
};
@@ -883,9 +883,11 @@ static void xilinx_enet_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+ StreamSlaveClass *ssc = STREAM_SLAVE_CLASS(klass);
k->init = xilinx_enet_init;
dc->props = xilinx_enet_properties;
+ ssc->push = axienet_stream_push;
}
static TypeInfo xilinx_enet_info = {
@@ -893,6 +895,11 @@ static TypeInfo xilinx_enet_info = {
.parent = TYPE_SYS_BUS_DEVICE,
.instance_size = sizeof(struct XilinxAXIEnet),
.class_init = xilinx_enet_class_init,
+ .instance_init = xilinx_enet_initfn,
+ .interfaces = (InterfaceInfo[]) {
+ { TYPE_STREAM_SLAVE },
+ { }
+ }
};
static void xilinx_enet_register_types(void)
diff --git a/hw/xtensa_lx60.c b/hw/xtensa_lx60.c
index c4f616f4fb..3653f65b1e 100644
--- a/hw/xtensa_lx60.c
+++ b/hw/xtensa_lx60.c
@@ -173,7 +173,7 @@ static void lx_init(const LxBoardDesc *board,
int n;
if (!cpu_model) {
- cpu_model = "dc232b";
+ cpu_model = XTENSA_DEFAULT_CPU_MODEL;
}
for (n = 0; n < smp_cpus; n++) {
@@ -300,14 +300,14 @@ static void xtensa_lx200_init(ram_addr_t ram_size,
static QEMUMachine xtensa_lx60_machine = {
.name = "lx60",
- .desc = "lx60 EVB (dc232b)",
+ .desc = "lx60 EVB (" XTENSA_DEFAULT_CPU_MODEL ")",
.init = xtensa_lx60_init,
.max_cpus = 4,
};
static QEMUMachine xtensa_lx200_machine = {
.name = "lx200",
- .desc = "lx200 EVB (dc232b)",
+ .desc = "lx200 EVB (" XTENSA_DEFAULT_CPU_MODEL ")",
.init = xtensa_lx200_init,
.max_cpus = 4,
};
diff --git a/hw/xtensa_sim.c b/hw/xtensa_sim.c
index 1ce07fb899..831460b7c4 100644
--- a/hw/xtensa_sim.c
+++ b/hw/xtensa_sim.c
@@ -102,7 +102,7 @@ static void xtensa_sim_init(ram_addr_t ram_size,
const char *initrd_filename, const char *cpu_model)
{
if (!cpu_model) {
- cpu_model = "dc232b";
+ cpu_model = XTENSA_DEFAULT_CPU_MODEL;
}
sim_init(ram_size, boot_device, kernel_filename, kernel_cmdline,
initrd_filename, cpu_model);
@@ -110,7 +110,8 @@ static void xtensa_sim_init(ram_addr_t ram_size,
static QEMUMachine xtensa_sim_machine = {
.name = "sim",
- .desc = "sim machine (dc232b)",
+ .desc = "sim machine (" XTENSA_DEFAULT_CPU_MODEL ")",
+ .is_default = true,
.init = xtensa_sim_init,
.max_cpus = 4,
};
diff --git a/include/qemu/object.h b/include/qemu/object.h
index 8b17776bb3..cc75feed66 100644
--- a/include/qemu/object.h
+++ b/include/qemu/object.h
@@ -239,6 +239,7 @@ struct ObjectClass
{
/*< private >*/
Type type;
+ GSList *interfaces;
};
/**
@@ -260,7 +261,6 @@ struct Object
{
/*< private >*/
ObjectClass *class;
- GSList *interfaces;
QTAILQ_HEAD(, ObjectProperty) properties;
uint32_t ref;
Object *parent;
@@ -387,6 +387,16 @@ struct TypeInfo
OBJECT_CLASS_CHECK(class, object_get_class(OBJECT(obj)), name)
/**
+ * InterfaceInfo:
+ * @type: The name of the interface.
+ *
+ * The information associated with an interface.
+ */
+struct InterfaceInfo {
+ const char *type;
+};
+
+/**
* InterfaceClass:
* @parent_class: the base class
*
@@ -396,26 +406,30 @@ struct TypeInfo
struct InterfaceClass
{
ObjectClass parent_class;
+ /*< private >*/
+ ObjectClass *concrete_class;
};
+#define TYPE_INTERFACE "interface"
+
/**
- * InterfaceInfo:
- * @type: The name of the interface.
- * @interface_initfn: This method is called during class initialization and is
- * used to initialize an interface associated with a class. This function
- * should initialize any default virtual functions for a class and/or override
- * virtual functions in a parent class.
- *
- * The information associated with an interface.
+ * INTERFACE_CLASS:
+ * @klass: class to cast from
+ * Returns: An #InterfaceClass or raise an error if cast is invalid
*/
-struct InterfaceInfo
-{
- const char *type;
+#define INTERFACE_CLASS(klass) \
+ OBJECT_CLASS_CHECK(InterfaceClass, klass, TYPE_INTERFACE)
- void (*interface_initfn)(ObjectClass *class, void *data);
-};
-
-#define TYPE_INTERFACE "interface"
+/**
+ * INTERFACE_CHECK:
+ * @interface: the type to return
+ * @obj: the object to convert to an interface
+ * @name: the interface type name
+ *
+ * Returns: @obj casted to @interface if cast is valid, otherwise raise error.
+ */
+#define INTERFACE_CHECK(interface, obj, name) \
+ ((interface *)object_dynamic_cast_assert(OBJECT((obj)), (name)))
/**
* object_new:
diff --git a/kvm-all.c b/kvm-all.c
index 2148b20bdb..34b02c1fba 100644
--- a/kvm-all.c
+++ b/kvm-all.c
@@ -100,6 +100,10 @@ struct KVMState
KVMState *kvm_state;
bool kvm_kernel_irqchip;
+bool kvm_async_interrupts_allowed;
+bool kvm_irqfds_allowed;
+bool kvm_msi_via_irqfd_allowed;
+bool kvm_gsi_routing_allowed;
static const KVMCapabilityInfo kvm_required_capabilites[] = {
KVM_CAP_INFO(USER_MEMORY),
@@ -852,18 +856,18 @@ static void kvm_handle_interrupt(CPUArchState *env, int mask)
}
}
-int kvm_irqchip_set_irq(KVMState *s, int irq, int level)
+int kvm_set_irq(KVMState *s, int irq, int level)
{
struct kvm_irq_level event;
int ret;
- assert(kvm_irqchip_in_kernel());
+ assert(kvm_async_interrupts_enabled());
event.level = level;
event.irq = irq;
ret = kvm_vm_ioctl(s, s->irqchip_inject_ioctl, &event);
if (ret < 0) {
- perror("kvm_set_irqchip_line");
+ perror("kvm_set_irq");
abort();
}
@@ -1088,7 +1092,7 @@ int kvm_irqchip_send_msi(KVMState *s, MSIMessage msg)
assert(route->kroute.type == KVM_IRQ_ROUTING_MSI);
- return kvm_irqchip_set_irq(s, route->kroute.gsi, 1);
+ return kvm_set_irq(s, route->kroute.gsi, 1);
}
int kvm_irqchip_add_msi_route(KVMState *s, MSIMessage msg)
@@ -1096,7 +1100,7 @@ int kvm_irqchip_add_msi_route(KVMState *s, MSIMessage msg)
struct kvm_irq_routing_entry kroute;
int virq;
- if (!kvm_irqchip_in_kernel()) {
+ if (!kvm_gsi_routing_enabled()) {
return -ENOSYS;
}
@@ -1125,7 +1129,7 @@ static int kvm_irqchip_assign_irqfd(KVMState *s, int fd, int virq, bool assign)
.flags = assign ? 0 : KVM_IRQFD_FLAG_DEASSIGN,
};
- if (!kvm_irqchip_in_kernel()) {
+ if (!kvm_irqfds_enabled()) {
return -ENOSYS;
}
@@ -1201,12 +1205,36 @@ static int kvm_irqchip_create(KVMState *s)
s->irqchip_inject_ioctl = KVM_IRQ_LINE_STATUS;
}
kvm_kernel_irqchip = true;
+ /* If we have an in-kernel IRQ chip then we must have asynchronous
+ * interrupt delivery (though the reverse is not necessarily true)
+ */
+ kvm_async_interrupts_allowed = true;
kvm_init_irq_routing(s);
return 0;
}
+static int kvm_max_vcpus(KVMState *s)
+{
+ int ret;
+
+ /* Find number of supported CPUs using the recommended
+ * procedure from the kernel API documentation to cope with
+ * older kernels that may be missing capabilities.
+ */
+ ret = kvm_check_extension(s, KVM_CAP_MAX_VCPUS);
+ if (ret) {
+ return ret;
+ }
+ ret = kvm_check_extension(s, KVM_CAP_NR_VCPUS);
+ if (ret) {
+ return ret;
+ }
+
+ return 4;
+}
+
int kvm_init(void)
{
static const char upgrade_note[] =
@@ -1216,6 +1244,7 @@ int kvm_init(void)
const KVMCapabilityInfo *missing_cap;
int ret;
int i;
+ int max_vcpus;
s = g_malloc0(sizeof(KVMState));
@@ -1256,6 +1285,14 @@ int kvm_init(void)
goto err;
}
+ max_vcpus = kvm_max_vcpus(s);
+ if (smp_cpus > max_vcpus) {
+ ret = -EINVAL;
+ fprintf(stderr, "Number of SMP cpus requested (%d) exceeds max cpus "
+ "supported by KVM (%d)\n", smp_cpus, max_vcpus);
+ goto err;
+ }
+
s->vmfd = kvm_ioctl(s, KVM_CREATE_VM, 0);
if (s->vmfd < 0) {
#ifdef TARGET_S390X
@@ -1667,11 +1704,6 @@ int kvm_has_gsi_routing(void)
#endif
}
-int kvm_allows_irq0_override(void)
-{
- return !kvm_irqchip_in_kernel() || kvm_has_gsi_routing();
-}
-
void *kvm_vmalloc(ram_addr_t size)
{
#ifdef TARGET_S390X
diff --git a/kvm-stub.c b/kvm-stub.c
index d23b11c020..94c9ea15b0 100644
--- a/kvm-stub.c
+++ b/kvm-stub.c
@@ -19,6 +19,10 @@
KVMState *kvm_state;
bool kvm_kernel_irqchip;
+bool kvm_async_interrupts_allowed;
+bool kvm_irqfds_allowed;
+bool kvm_msi_via_irqfd_allowed;
+bool kvm_gsi_routing_allowed;
int kvm_init_vcpu(CPUArchState *env)
{
@@ -71,11 +75,6 @@ int kvm_has_many_ioeventfds(void)
return 0;
}
-int kvm_allows_irq0_override(void)
-{
- return 1;
-}
-
int kvm_has_pit_state2(void)
{
return 0;
diff --git a/kvm.h b/kvm.h
index 2617dd5acd..5b8f588813 100644
--- a/kvm.h
+++ b/kvm.h
@@ -24,13 +24,69 @@
extern int kvm_allowed;
extern bool kvm_kernel_irqchip;
+extern bool kvm_async_interrupts_allowed;
+extern bool kvm_irqfds_allowed;
+extern bool kvm_msi_via_irqfd_allowed;
+extern bool kvm_gsi_routing_allowed;
#if defined CONFIG_KVM || !defined NEED_CPU_H
#define kvm_enabled() (kvm_allowed)
+/**
+ * kvm_irqchip_in_kernel:
+ *
+ * Returns: true if the user asked us to create an in-kernel
+ * irqchip via the "kernel_irqchip=on" machine option.
+ * What this actually means is architecture and machine model
+ * specific: on PC, for instance, it means that the LAPIC,
+ * IOAPIC and PIT are all in kernel. This function should never
+ * be used from generic target-independent code: use one of the
+ * following functions or some other specific check instead.
+ */
#define kvm_irqchip_in_kernel() (kvm_kernel_irqchip)
+
+/**
+ * kvm_async_interrupts_enabled:
+ *
+ * Returns: true if we can deliver interrupts to KVM
+ * asynchronously (ie by ioctl from any thread at any time)
+ * rather than having to do interrupt delivery synchronously
+ * (where the vcpu must be stopped at a suitable point first).
+ */
+#define kvm_async_interrupts_enabled() (kvm_async_interrupts_allowed)
+
+/**
+ * kvm_irqfds_enabled:
+ *
+ * Returns: true if we can use irqfds to inject interrupts into
+ * a KVM CPU (ie the kernel supports irqfds and we are running
+ * with a configuration where it is meaningful to use them).
+ */
+#define kvm_irqfds_enabled() (kvm_irqfds_allowed)
+
+/**
+ * kvm_msi_via_irqfd_enabled:
+ *
+ * Returns: true if we can route a PCI MSI (Message Signaled Interrupt)
+ * to a KVM CPU via an irqfd. This requires that the kernel supports
+ * this and that we're running in a configuration that permits it.
+ */
+#define kvm_msi_via_irqfd_enabled() (kvm_msi_via_irqfd_allowed)
+
+/**
+ * kvm_gsi_routing_enabled:
+ *
+ * Returns: true if GSI routing is enabled (ie the kernel supports
+ * it and we're running in a configuration that permits it).
+ */
+#define kvm_gsi_routing_enabled() (kvm_gsi_routing_allowed)
+
#else
#define kvm_enabled() (0)
#define kvm_irqchip_in_kernel() (false)
+#define kvm_async_interrupts_enabled() (false)
+#define kvm_irqfds_enabled() (false)
+#define kvm_msi_via_irqfd_enabled() (false)
+#define kvm_gsi_routing_allowed() (false)
#endif
struct kvm_run;
@@ -62,8 +118,6 @@ int kvm_has_pit_state2(void);
int kvm_has_many_ioeventfds(void);
int kvm_has_gsi_routing(void);
-int kvm_allows_irq0_override(void);
-
#ifdef NEED_CPU_H
int kvm_init_vcpu(CPUArchState *env);
@@ -133,7 +187,7 @@ int kvm_arch_on_sigbus(int code, void *addr);
void kvm_arch_init_irq_routing(KVMState *s);
-int kvm_irqchip_set_irq(KVMState *s, int irq, int level);
+int kvm_set_irq(KVMState *s, int irq, int level);
int kvm_irqchip_send_msi(KVMState *s, MSIMessage msg);
void kvm_irqchip_add_irq_route(KVMState *s, int gsi, int irqchip, int pin);
diff --git a/linux-user/main.c b/linux-user/main.c
index 53714de0d4..9d921aa4f0 100644
--- a/linux-user/main.c
+++ b/linux-user/main.c
@@ -958,7 +958,8 @@ void cpu_loop(CPUUniCore32State *env)
}
}
break;
- case UC32_EXCP_TRAP:
+ case UC32_EXCP_DTRAP:
+ case UC32_EXCP_ITRAP:
info.si_signo = SIGSEGV;
info.si_errno = 0;
/* XXX: check env->error_code */
diff --git a/linux-user/signal.c b/linux-user/signal.c
index 9be5ac0788..78691473fa 100644
--- a/linux-user/signal.c
+++ b/linux-user/signal.c
@@ -1844,7 +1844,7 @@ typedef struct {
} __siginfo_t;
typedef struct {
- unsigned long si_float_regs [32];
+ abi_ulong si_float_regs[32];
unsigned long si_fsr;
unsigned long si_fpqdepth;
struct {
@@ -2056,11 +2056,9 @@ restore_fpu_state(CPUSPARCState *env, qemu_siginfo_fpu_t *fpu)
return -EFAULT;
#endif
-#if 0
/* XXX: incorrect */
- err = __copy_from_user(&env->fpr[0], &fpu->si_float_regs[0],
- (sizeof(unsigned long) * 32));
-#endif
+ err = copy_from_user(&env->fpr[0], fpu->si_float_regs[0],
+ (sizeof(abi_ulong) * 32));
err |= __get_user(env->fsr, &fpu->si_fsr);
#if 0
err |= __get_user(current->thread.fpqdepth, &fpu->si_fpqdepth);
diff --git a/net/slirp.c b/net/slirp.c
index 08adb97da5..8db66ea539 100644
--- a/net/slirp.c
+++ b/net/slirp.c
@@ -718,9 +718,9 @@ int net_init_slirp(const NetClientOptions *opts, const char *name,
net_init_slirp_configs(user->hostfwd, SLIRP_CFG_HOSTFWD);
net_init_slirp_configs(user->guestfwd, 0);
- ret = net_slirp_init(peer, "user", name, user->restrict, vnet, user->host,
- user->hostname, user->tftp, user->bootfile,
- user->dhcpstart, user->dns, user->smb,
+ ret = net_slirp_init(peer, "user", name, user->q_restrict, vnet,
+ user->host, user->hostname, user->tftp,
+ user->bootfile, user->dhcpstart, user->dns, user->smb,
user->smbserver);
while (slirp_configs) {
diff --git a/qemu-common.h b/qemu-common.h
index 9c1b95551b..095e28d89a 100644
--- a/qemu-common.h
+++ b/qemu-common.h
@@ -377,6 +377,7 @@ bool buffer_is_zero(const void *buf, size_t len);
void qemu_progress_init(int enabled, float min_skip);
void qemu_progress_end(void);
void qemu_progress_print(float delta, int max);
+const char *qemu_get_vm_name(void);
#define QEMU_FILE_TYPE_BIOS 0
#define QEMU_FILE_TYPE_KEYMAP 1
diff --git a/qemu-doc.texi b/qemu-doc.texi
index f32e9e2fb9..35cabbcb9e 100644
--- a/qemu-doc.texi
+++ b/qemu-doc.texi
@@ -734,6 +734,11 @@ Various session related parameters can be set via special options, either
in a configuration file provided via '-readconfig' or directly on the
command line.
+If the initiator-name is not specified qemu will use a default name
+of 'iqn.2008-11.org.linux-kvm[:<name>'] where <name> is the name of the
+virtual machine.
+
+
@example
Setting a specific initiator name to use when logging in to the target
-iscsi initiator-name=iqn.qemu.test:my-initiator
diff --git a/qemu-img.c b/qemu-img.c
index 94a31ad9f0..b41e670a61 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -379,7 +379,7 @@ static int img_check(int argc, char **argv)
BlockDriverState *bs;
BdrvCheckResult result;
int fix = 0;
- int flags = BDRV_O_FLAGS;
+ int flags = BDRV_O_FLAGS | BDRV_O_CHECK;
fmt = NULL;
for(;;) {
diff --git a/qemu-options.hx b/qemu-options.hx
index 5e7d0dc035..47cb5bd311 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -1897,6 +1897,11 @@ images for the guest storage. Both disk and cdrom images are supported.
Syntax for specifying iSCSI LUNs is
``iscsi://<target-ip>[:<port>]/<target-iqn>/<lun>''
+By default qemu will use the iSCSI initiator-name
+'iqn.2008-11.org.linux-kvm[:<name>]' but this can also be set from the command
+line or a configuration file.
+
+
Example (without authentication):
@example
qemu-system-i386 -iscsi initiator-name=iqn.2001-04.com.example:my-initiator \
@@ -1926,6 +1931,9 @@ DEF("iscsi", HAS_ARG, QEMU_OPTION_iscsi,
" iSCSI session parameters\n", QEMU_ARCH_ALL)
STEXI
+iSCSI parameters such as username and password can also be specified via
+a configuration file. See qemu-doc for more information and examples.
+
@item NBD
QEMU supports NBD (Network Block Devices) both using TCP protocol as well
as Unix Domain Sockets.
diff --git a/qemu-timer.c b/qemu-timer.c
index 062fdf2cb9..5aea94e8e0 100644
--- a/qemu-timer.c
+++ b/qemu-timer.c
@@ -112,14 +112,10 @@ static int64_t qemu_next_alarm_deadline(void)
static void qemu_rearm_alarm_timer(struct qemu_alarm_timer *t)
{
- int64_t nearest_delta_ns;
- if (!rt_clock->active_timers &&
- !vm_clock->active_timers &&
- !host_clock->active_timers) {
- return;
+ int64_t nearest_delta_ns = qemu_next_alarm_deadline();
+ if (nearest_delta_ns < INT64_MAX) {
+ t->rearm(t, nearest_delta_ns);
}
- nearest_delta_ns = qemu_next_alarm_deadline();
- t->rearm(t, nearest_delta_ns);
}
/* TODO: MIN_TIMER_REARM_NS should be optimized */
diff --git a/qemu-tool.c b/qemu-tool.c
index 318c5fcbca..64b5e88bc7 100644
--- a/qemu-tool.c
+++ b/qemu-tool.c
@@ -30,6 +30,11 @@ struct QEMUBH
void *opaque;
};
+const char *qemu_get_vm_name(void)
+{
+ return NULL;
+}
+
Monitor *cur_mon;
int monitor_cur_is_qmp(void)
diff --git a/qom/object.c b/qom/object.c
index 00bb3b029c..a552be258e 100644
--- a/qom/object.c
+++ b/qom/object.c
@@ -31,9 +31,7 @@ typedef struct TypeImpl TypeImpl;
struct InterfaceImpl
{
- const char *parent;
- void (*interface_initfn)(ObjectClass *class, void *data);
- TypeImpl *type;
+ const char *typename;
};
struct TypeImpl
@@ -64,14 +62,6 @@ struct TypeImpl
InterfaceImpl interfaces[MAX_INTERFACES];
};
-typedef struct Interface
-{
- Object parent;
- Object *obj;
-} Interface;
-
-#define INTERFACE(obj) OBJECT_CHECK(Interface, obj, TYPE_INTERFACE)
-
static Type type_interface;
static GHashTable *type_table_get(void)
@@ -98,6 +88,7 @@ static TypeImpl *type_table_lookup(const char *name)
static TypeImpl *type_register_internal(const TypeInfo *info)
{
TypeImpl *ti = g_malloc0(sizeof(*ti));
+ int i;
g_assert(info->name != NULL);
@@ -122,15 +113,10 @@ static TypeImpl *type_register_internal(const TypeInfo *info)
ti->abstract = info->abstract;
- if (info->interfaces) {
- int i;
-
- for (i = 0; info->interfaces[i].type; i++) {
- ti->interfaces[i].parent = info->interfaces[i].type;
- ti->interfaces[i].interface_initfn = info->interfaces[i].interface_initfn;
- ti->num_interfaces++;
- }
+ for (i = 0; info->interfaces && info->interfaces[i].type; i++) {
+ ti->interfaces[i].typename = g_strdup(info->interfaces[i].type);
}
+ ti->num_interfaces = i;
type_table_add(ti);
@@ -198,26 +184,48 @@ static size_t type_object_get_size(TypeImpl *ti)
return 0;
}
-static void type_class_interface_init(TypeImpl *ti, InterfaceImpl *iface)
+static bool type_is_ancestor(TypeImpl *type, TypeImpl *target_type)
{
- TypeInfo info = {
- .instance_size = sizeof(Interface),
- .parent = iface->parent,
- .class_size = sizeof(InterfaceClass),
- .class_init = iface->interface_initfn,
- .abstract = true,
- };
- char *name = g_strdup_printf("<%s::%s>", ti->name, iface->parent);
+ assert(target_type);
+
+ /* Check if typename is a direct ancestor of type */
+ while (type) {
+ if (type == target_type) {
+ return true;
+ }
- info.name = name;
- iface->type = type_register_internal(&info);
- g_free(name);
+ type = type_get_parent(type);
+ }
+
+ return false;
+}
+
+static void type_initialize(TypeImpl *ti);
+
+static void type_initialize_interface(TypeImpl *ti, const char *parent)
+{
+ InterfaceClass *new_iface;
+ TypeInfo info = { };
+ TypeImpl *iface_impl;
+
+ info.parent = parent;
+ info.name = g_strdup_printf("%s::%s", ti->name, info.parent);
+ info.abstract = true;
+
+ iface_impl = type_register(&info);
+ type_initialize(iface_impl);
+ g_free((char *)info.name);
+
+ new_iface = (InterfaceClass *)iface_impl->class;
+ new_iface->concrete_class = ti->class;
+
+ ti->class->interfaces = g_slist_append(ti->class->interfaces,
+ iface_impl->class);
}
static void type_initialize(TypeImpl *ti)
{
TypeImpl *parent;
- int i;
if (ti->class) {
return;
@@ -231,9 +239,33 @@ static void type_initialize(TypeImpl *ti)
parent = type_get_parent(ti);
if (parent) {
type_initialize(parent);
+ GSList *e;
+ int i;
g_assert(parent->class_size <= ti->class_size);
memcpy(ti->class, parent->class, parent->class_size);
+
+ for (e = parent->class->interfaces; e; e = e->next) {
+ ObjectClass *iface = e->data;
+ type_initialize_interface(ti, object_class_get_name(iface));
+ }
+
+ for (i = 0; i < ti->num_interfaces; i++) {
+ TypeImpl *t = type_get_by_name(ti->interfaces[i].typename);
+ for (e = ti->class->interfaces; e; e = e->next) {
+ TypeImpl *target_type = OBJECT_CLASS(e->data)->type;
+
+ if (type_is_ancestor(target_type, t)) {
+ break;
+ }
+ }
+
+ if (e) {
+ continue;
+ }
+
+ type_initialize_interface(ti, ti->interfaces[i].typename);
+ }
}
ti->class->type = ti;
@@ -245,38 +277,19 @@ static void type_initialize(TypeImpl *ti)
parent = type_get_parent(parent);
}
- for (i = 0; i < ti->num_interfaces; i++) {
- type_class_interface_init(ti, &ti->interfaces[i]);
- }
-
if (ti->class_init) {
ti->class_init(ti->class, ti->class_data);
}
-}
-static void object_interface_init(Object *obj, InterfaceImpl *iface)
-{
- TypeImpl *ti = iface->type;
- Interface *iface_obj;
-
- iface_obj = INTERFACE(object_new(ti->name));
- iface_obj->obj = obj;
- obj->interfaces = g_slist_prepend(obj->interfaces, iface_obj);
}
static void object_init_with_type(Object *obj, TypeImpl *ti)
{
- int i;
-
if (type_has_parent(ti)) {
object_init_with_type(obj, type_get_parent(ti));
}
- for (i = 0; i < ti->num_interfaces; i++) {
- object_interface_init(obj, &ti->interfaces[i]);
- }
-
if (ti->instance_init) {
ti->instance_init(obj);
}
@@ -357,12 +370,6 @@ static void object_deinit(Object *obj, TypeImpl *type)
type->instance_finalize(obj);
}
- while (obj->interfaces) {
- Interface *iface_obj = obj->interfaces->data;
- obj->interfaces = g_slist_delete_link(obj->interfaces, obj->interfaces);
- object_delete(OBJECT(iface_obj));
- }
-
if (type_has_parent(type)) {
object_deinit(obj, type_get_parent(type));
}
@@ -409,74 +416,15 @@ void object_delete(Object *obj)
g_free(obj);
}
-static bool type_is_ancestor(TypeImpl *type, TypeImpl *target_type)
-{
- assert(target_type);
-
- /* Check if typename is a direct ancestor of type */
- while (type) {
- if (type == target_type) {
- return true;
- }
-
- type = type_get_parent(type);
- }
-
- return false;
-}
-
-static bool object_is_type(Object *obj, TypeImpl *target_type)
-{
- return !target_type || type_is_ancestor(obj->class->type, target_type);
-}
-
Object *object_dynamic_cast(Object *obj, const char *typename)
{
- TypeImpl *target_type = type_get_by_name(typename);
- GSList *i;
-
- /* Check if typename is a direct ancestor. Special-case TYPE_OBJECT,
- * we want to go back from interfaces to the parent.
- */
- if (target_type && object_is_type(obj, target_type)) {
+ if (object_class_dynamic_cast(object_get_class(obj), typename)) {
return obj;
}
- /* Check if obj is an interface and its containing object is a direct
- * ancestor of typename. In principle we could do this test at the very
- * beginning of object_dynamic_cast, avoiding a second call to
- * object_is_type. However, casting between interfaces is relatively
- * rare, and object_is_type(obj, type_interface) would fail almost always.
- *
- * Perhaps we could add a magic value to the object header for increased
- * (run-time) type safety and to speed up tests like this one. If we ever
- * do that we can revisit the order here.
- */
- if (object_is_type(obj, type_interface)) {
- assert(!obj->interfaces);
- obj = INTERFACE(obj)->obj;
- if (object_is_type(obj, target_type)) {
- return obj;
- }
- }
-
- if (!target_type) {
- return obj;
- }
-
- /* Check if obj has an interface of typename */
- for (i = obj->interfaces; i; i = i->next) {
- Interface *iface = i->data;
-
- if (object_is_type(OBJECT(iface), target_type)) {
- return OBJECT(iface);
- }
- }
-
return NULL;
}
-
Object *object_dynamic_cast_assert(Object *obj, const char *typename)
{
Object *inst;
@@ -497,16 +445,30 @@ ObjectClass *object_class_dynamic_cast(ObjectClass *class,
{
TypeImpl *target_type = type_get_by_name(typename);
TypeImpl *type = class->type;
+ ObjectClass *ret = NULL;
- while (type) {
- if (type == target_type) {
- return class;
- }
+ if (type->num_interfaces && type_is_ancestor(target_type, type_interface)) {
+ int found = 0;
+ GSList *i;
- type = type_get_parent(type);
+ for (i = class->interfaces; i; i = i->next) {
+ ObjectClass *target_class = i->data;
+
+ if (type_is_ancestor(target_class->type, target_type)) {
+ ret = target_class;
+ found++;
+ }
+ }
+
+ /* The match was ambiguous, don't allow a cast */
+ if (found > 1) {
+ ret = NULL;
+ }
+ } else if (type_is_ancestor(type, target_type)) {
+ ret = class;
}
- return NULL;
+ return ret;
}
ObjectClass *object_class_dynamic_cast_assert(ObjectClass *class,
@@ -920,12 +882,6 @@ void object_property_add_child(Object *obj, const char *name,
{
gchar *type;
- /* Registering an interface object in the composition tree will mightily
- * confuse object_get_canonical_path (which, on the other hand, knows how
- * to get the canonical path of an interface object).
- */
- assert(!object_is_type(obj, type_interface));
-
type = g_strdup_printf("child<%s>", object_get_typename(OBJECT(child)));
object_property_add(obj, name, type, object_get_child_property,
@@ -1022,10 +978,6 @@ gchar *object_get_canonical_path(Object *obj)
Object *root = object_get_root();
char *newpath = NULL, *path = NULL;
- if (object_is_type(obj, type_interface)) {
- obj = INTERFACE(obj)->obj;
- }
-
while (obj != root) {
ObjectProperty *prop = NULL;
@@ -1246,7 +1198,7 @@ static void register_types(void)
{
static TypeInfo interface_info = {
.name = TYPE_INTERFACE,
- .instance_size = sizeof(Interface),
+ .class_size = sizeof(InterfaceClass),
.abstract = true,
};
diff --git a/scripts/qapi.py b/scripts/qapi.py
index d3b8b4d851..122b4cb6d1 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -142,6 +142,22 @@ def camel_case(name):
return new_name
def c_var(name):
+ # ANSI X3J11/88-090, 3.1.1
+ c89_words = set(['auto', 'break', 'case', 'char', 'const', 'continue',
+ 'default', 'do', 'double', 'else', 'enum', 'extern', 'float',
+ 'for', 'goto', 'if', 'int', 'long', 'register', 'return',
+ 'short', 'signed', 'sizeof', 'static', 'struct', 'switch',
+ 'typedef', 'union', 'unsigned', 'void', 'volatile', 'while'])
+ # ISO/IEC 9899:1999, 6.4.1
+ c99_words = set(['inline', 'restrict', '_Bool', '_Complex', '_Imaginary'])
+ # ISO/IEC 9899:2011, 6.4.1
+ c11_words = set(['_Alignas', '_Alignof', '_Atomic', '_Generic', '_Noreturn',
+ '_Static_assert', '_Thread_local'])
+ # GCC http://gcc.gnu.org/onlinedocs/gcc-4.7.1/gcc/C-Extensions.html
+ # excluding _.*
+ gcc_words = set(['asm', 'typeof'])
+ if name in c89_words | c99_words | c11_words | gcc_words:
+ return "q_" + name
return name.replace('-', '_').lstrip("*")
def c_fun(name):
diff --git a/target-arm/arm-semi.c b/target-arm/arm-semi.c
index 88ca9bb1b7..24952061cf 100644
--- a/target-arm/arm-semi.c
+++ b/target-arm/arm-semi.c
@@ -281,7 +281,7 @@ uint32_t do_arm_semihosting(CPUARMState *env)
return len - ret;
}
case TARGET_SYS_READC:
- /* XXX: Read from debug cosole. Not implemented. */
+ /* XXX: Read from debug console. Not implemented. */
return 0;
case TARGET_SYS_ISTTY:
if (use_gdb_syscalls()) {
diff --git a/target-arm/cpu.h b/target-arm/cpu.h
index 191895cca8..d7f93d98f0 100644
--- a/target-arm/cpu.h
+++ b/target-arm/cpu.h
@@ -79,7 +79,7 @@ struct arm_boot_info;
typedef struct CPUARMState {
/* Regs for current mode. */
uint32_t regs[16];
- /* Frequently accessed CPSR bits are stored separately for efficiently.
+ /* Frequently accessed CPSR bits are stored separately for efficiency.
This contains all the other bits. Use cpsr_{read,write} to access
the whole CPSR. */
uint32_t uncached_cpsr;
diff --git a/target-arm/helper.c b/target-arm/helper.c
index 5727da296c..dceaa95c80 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -988,7 +988,7 @@ static void ttbr164_reset(CPUARMState *env, const ARMCPRegInfo *ri)
}
static const ARMCPRegInfo lpae_cp_reginfo[] = {
- /* NOP AMAIR0/1: the override is because these clash with tha rather
+ /* NOP AMAIR0/1: the override is because these clash with the rather
* broadly specified TLB_LOCKDOWN entry in the generic cp_reginfo.
*/
{ .name = "AMAIR0", .cp = 15, .crn = 10, .crm = 3, .opc1 = 0, .opc2 = 0,
@@ -2899,8 +2899,8 @@ uint32_t HELPER(logicq_cc)(uint64_t val)
return (val >> 32) | (val != 0);
}
-/* VFP support. We follow the convention used for VFP instrunctions:
- Single precition routines have a "s" suffix, double precision a
+/* VFP support. We follow the convention used for VFP instructions:
+ Single precision routines have a "s" suffix, double precision a
"d" suffix. */
/* Convert host exception flags to vfp form. */
diff --git a/target-arm/neon_helper.c b/target-arm/neon_helper.c
index e0b9dbf67e..8bb5129d6a 100644
--- a/target-arm/neon_helper.c
+++ b/target-arm/neon_helper.c
@@ -530,7 +530,7 @@ NEON_VOP(rshl_s16, neon_s16, 2)
#undef NEON_FN
/* The addition of the rounding constant may overflow, so we use an
- * intermediate 64 bits accumulator. */
+ * intermediate 64 bit accumulator. */
uint32_t HELPER(neon_rshl_s32)(uint32_t valop, uint32_t shiftop)
{
int32_t dest;
@@ -547,8 +547,8 @@ uint32_t HELPER(neon_rshl_s32)(uint32_t valop, uint32_t shiftop)
return dest;
}
-/* Handling addition overflow with 64 bits inputs values is more
- * tricky than with 32 bits values. */
+/* Handling addition overflow with 64 bit input values is more
+ * tricky than with 32 bit values. */
uint64_t HELPER(neon_rshl_s64)(uint64_t valop, uint64_t shiftop)
{
int8_t shift = (int8_t)shiftop;
@@ -590,7 +590,7 @@ NEON_VOP(rshl_u16, neon_u16, 2)
#undef NEON_FN
/* The addition of the rounding constant may overflow, so we use an
- * intermediate 64 bits accumulator. */
+ * intermediate 64 bit accumulator. */
uint32_t HELPER(neon_rshl_u32)(uint32_t val, uint32_t shiftop)
{
uint32_t dest;
@@ -608,8 +608,8 @@ uint32_t HELPER(neon_rshl_u32)(uint32_t val, uint32_t shiftop)
return dest;
}
-/* Handling addition overflow with 64 bits inputs values is more
- * tricky than with 32 bits values. */
+/* Handling addition overflow with 64 bit input values is more
+ * tricky than with 32 bit values. */
uint64_t HELPER(neon_rshl_u64)(uint64_t val, uint64_t shiftop)
{
int8_t shift = (uint8_t)shiftop;
@@ -817,7 +817,7 @@ NEON_VOP_ENV(qrshl_u16, neon_u16, 2)
#undef NEON_FN
/* The addition of the rounding constant may overflow, so we use an
- * intermediate 64 bits accumulator. */
+ * intermediate 64 bit accumulator. */
uint32_t HELPER(neon_qrshl_u32)(CPUARMState *env, uint32_t val, uint32_t shiftop)
{
uint32_t dest;
@@ -846,8 +846,8 @@ uint32_t HELPER(neon_qrshl_u32)(CPUARMState *env, uint32_t val, uint32_t shiftop
return dest;
}
-/* Handling addition overflow with 64 bits inputs values is more
- * tricky than with 32 bits values. */
+/* Handling addition overflow with 64 bit input values is more
+ * tricky than with 32 bit values. */
uint64_t HELPER(neon_qrshl_u64)(CPUARMState *env, uint64_t val, uint64_t shiftop)
{
int8_t shift = (int8_t)shiftop;
@@ -914,7 +914,7 @@ NEON_VOP_ENV(qrshl_s16, neon_s16, 2)
#undef NEON_FN
/* The addition of the rounding constant may overflow, so we use an
- * intermediate 64 bits accumulator. */
+ * intermediate 64 bit accumulator. */
uint32_t HELPER(neon_qrshl_s32)(CPUARMState *env, uint32_t valop, uint32_t shiftop)
{
int32_t dest;
@@ -942,8 +942,8 @@ uint32_t HELPER(neon_qrshl_s32)(CPUARMState *env, uint32_t valop, uint32_t shift
return dest;
}
-/* Handling addition overflow with 64 bits inputs values is more
- * tricky than with 32 bits values. */
+/* Handling addition overflow with 64 bit input values is more
+ * tricky than with 32 bit values. */
uint64_t HELPER(neon_qrshl_s64)(CPUARMState *env, uint64_t valop, uint64_t shiftop)
{
int8_t shift = (uint8_t)shiftop;
@@ -1671,7 +1671,7 @@ uint64_t HELPER(neon_negl_u64)(uint64_t x)
return -x;
}
-/* Saturnating sign manuipulation. */
+/* Saturating sign manipulation. */
/* ??? Make these use NEON_VOP1 */
#define DO_QABS8(x) do { \
if (x == (int8_t)0x80) { \
diff --git a/target-arm/op_helper.c b/target-arm/op_helper.c
index 490111c22f..d77bfab771 100644
--- a/target-arm/op_helper.c
+++ b/target-arm/op_helper.c
@@ -99,7 +99,7 @@ void tlb_fill(CPUARMState *env1, target_ulong addr, int is_write, int mmu_idx,
}
#endif
-/* FIXME: Pass an axplicit pointer to QF to CPUARMState, and move saturating
+/* FIXME: Pass an explicit pointer to QF to CPUARMState, and move saturating
instructions into helper.c */
uint32_t HELPER(add_setq)(uint32_t a, uint32_t b)
{
diff --git a/target-arm/translate.c b/target-arm/translate.c
index 29008a4b34..edef79a2cf 100644
--- a/target-arm/translate.c
+++ b/target-arm/translate.c
@@ -53,7 +53,7 @@ typedef struct DisasContext {
int condjmp;
/* The label that will be jumped to when the instruction is skipped. */
int condlabel;
- /* Thumb-2 condtional execution bits. */
+ /* Thumb-2 conditional execution bits. */
int condexec_mask;
int condexec_cond;
struct TranslationBlock *tb;
@@ -77,7 +77,7 @@ static uint32_t gen_opc_condexec_bits[OPC_BUF_SIZE];
#endif
/* These instructions trap after executing, so defer them until after the
- conditional executions state has been updated. */
+ conditional execution state has been updated. */
#define DISAS_WFI 4
#define DISAS_SWI 5
@@ -155,7 +155,7 @@ static void load_reg_var(DisasContext *s, TCGv var, int reg)
{
if (reg == 15) {
uint32_t addr;
- /* normaly, since we updated PC, we need only to add one insn */
+ /* normally, since we updated PC, we need only to add one insn */
if (s->thumb)
addr = (long)s->pc + 2;
else
@@ -4897,7 +4897,7 @@ static int disas_neon_data_insn(CPUARMState * env, DisasContext *s, uint32_t ins
size--;
}
shift = (insn >> 16) & ((1 << (3 + size)) - 1);
- /* To avoid excessive dumplication of ops we implement shift
+ /* To avoid excessive duplication of ops we implement shift
by immediate using the variable shift operations. */
if (op < 8) {
/* Shift by immediate:
@@ -6402,7 +6402,7 @@ static void gen_logicq_cc(TCGv_i64 val)
/* Load/Store exclusive instructions are implemented by remembering
the value/address loaded, and seeing if these are the same
- when the store is performed. This should be is sufficient to implement
+ when the store is performed. This should be sufficient to implement
the architecturally mandated semantics, and avoids having to monitor
regular stores.
@@ -9892,7 +9892,7 @@ static inline void gen_intermediate_code_internal(CPUARMState *env,
} else {
/* While branches must always occur at the end of an IT block,
there are a few other things that can cause us to terminate
- the TB in the middel of an IT block:
+ the TB in the middle of an IT block:
- Exception generating instructions (bkpt, swi, undefined).
- Page boundaries.
- Hardware watchpoints.
diff --git a/target-i386/Makefile.objs b/target-i386/Makefile.objs
index 683fd59af9..0715f58a8e 100644
--- a/target-i386/Makefile.objs
+++ b/target-i386/Makefile.objs
@@ -3,6 +3,7 @@ obj-y += excp_helper.o fpu_helper.o cc_helper.o int_helper.o svm_helper.o
obj-y += smm_helper.o misc_helper.o mem_helper.o seg_helper.o
obj-$(CONFIG_SOFTMMU) += machine.o arch_memory_mapping.o arch_dump.o
obj-$(CONFIG_KVM) += kvm.o hyperv.o
+obj-$(CONFIG_NO_KVM) += kvm-stub.o
obj-$(CONFIG_LINUX_USER) += ioport-user.o
obj-$(CONFIG_BSD_USER) += ioport-user.o
diff --git a/target-i386/cpu.c b/target-i386/cpu.c
index 857b94ea87..880cfea3f8 100644
--- a/target-i386/cpu.c
+++ b/target-i386/cpu.c
@@ -1746,6 +1746,7 @@ static void x86_cpu_initfn(Object *obj)
{
X86CPU *cpu = X86_CPU(obj);
CPUX86State *env = &cpu->env;
+ static int inited;
cpu_exec_init(env);
@@ -1775,6 +1776,15 @@ static void x86_cpu_initfn(Object *obj)
x86_cpuid_set_tsc_freq, NULL, NULL, NULL);
env->cpuid_apic_id = env->cpu_index;
+
+ /* init various static tables used in TCG mode */
+ if (tcg_enabled() && !inited) {
+ inited = 1;
+ optimize_flags_init();
+#ifndef CONFIG_USER_ONLY
+ cpu_set_debug_excp_handler(breakpoint_handler);
+#endif
+ }
}
static void x86_cpu_common_class_init(ObjectClass *oc, void *data)
diff --git a/target-i386/cpu.h b/target-i386/cpu.h
index 2a61c810bb..60f9e972bd 100644
--- a/target-i386/cpu.h
+++ b/target-i386/cpu.h
@@ -935,6 +935,7 @@ static inline int hw_breakpoint_len(unsigned long dr7, int index)
void hw_breakpoint_insert(CPUX86State *env, int index);
void hw_breakpoint_remove(CPUX86State *env, int index);
int check_hw_breakpoints(CPUX86State *env, int force_dr6_update);
+void breakpoint_handler(CPUX86State *env);
/* will be suppressed */
void cpu_x86_update_cr0(CPUX86State *env, uint32_t new_cr0);
diff --git a/target-i386/helper.c b/target-i386/helper.c
index b748d90063..8a5da3d7c0 100644
--- a/target-i386/helper.c
+++ b/target-i386/helper.c
@@ -941,9 +941,7 @@ int check_hw_breakpoints(CPUX86State *env, int force_dr6_update)
return hit_enabled;
}
-static CPUDebugExcpHandler *prev_debug_excp_handler;
-
-static void breakpoint_handler(CPUX86State *env)
+void breakpoint_handler(CPUX86State *env)
{
CPUBreakpoint *bp;
@@ -965,8 +963,6 @@ static void breakpoint_handler(CPUX86State *env)
break;
}
}
- if (prev_debug_excp_handler)
- prev_debug_excp_handler(env);
}
typedef struct MCEInjectionParams {
@@ -1155,21 +1151,11 @@ X86CPU *cpu_x86_init(const char *cpu_model)
{
X86CPU *cpu;
CPUX86State *env;
- static int inited;
cpu = X86_CPU(object_new(TYPE_X86_CPU));
env = &cpu->env;
env->cpu_model_str = cpu_model;
- /* init various static tables used in TCG mode */
- if (tcg_enabled() && !inited) {
- inited = 1;
- optimize_flags_init();
-#ifndef CONFIG_USER_ONLY
- prev_debug_excp_handler =
- cpu_set_debug_excp_handler(breakpoint_handler);
-#endif
- }
if (cpu_x86_register(cpu, cpu_model) < 0) {
object_delete(OBJECT(cpu));
return NULL;
diff --git a/target-i386/kvm-stub.c b/target-i386/kvm-stub.c
new file mode 100644
index 0000000000..11429c461e
--- /dev/null
+++ b/target-i386/kvm-stub.c
@@ -0,0 +1,18 @@
+/*
+ * QEMU KVM x86 specific function stubs
+ *
+ * Copyright Linaro Limited 2012
+ *
+ * Author: Peter Maydell <peter.maydell@linaro.org>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+#include "qemu-common.h"
+#include "kvm_i386.h"
+
+bool kvm_allows_irq0_override(void)
+{
+ return 1;
+}
diff --git a/target-i386/kvm.c b/target-i386/kvm.c
index 4cfb3faf01..696b14a04a 100644
--- a/target-i386/kvm.c
+++ b/target-i386/kvm.c
@@ -23,6 +23,7 @@
#include "qemu-common.h"
#include "sysemu.h"
#include "kvm.h"
+#include "kvm_i386.h"
#include "cpu.h"
#include "gdbstub.h"
#include "host-utils.h"
@@ -65,6 +66,11 @@ static bool has_msr_async_pf_en;
static bool has_msr_misc_enable;
static int lm_capable_kernel;
+bool kvm_allows_irq0_override(void)
+{
+ return !kvm_irqchip_in_kernel() || kvm_has_gsi_routing();
+}
+
static struct kvm_cpuid2 *try_get_cpuid(KVMState *s, int max)
{
struct kvm_cpuid2 *cpuid;
@@ -2041,4 +2047,11 @@ void kvm_arch_init_irq_routing(KVMState *s)
*/
no_hpet = 1;
}
+ /* We know at this point that we're using the in-kernel
+ * irqchip, so we can use irqfds, and on x86 we know
+ * we can use msi via irqfd and GSI routing.
+ */
+ kvm_irqfds_allowed = true;
+ kvm_msi_via_irqfd_allowed = true;
+ kvm_gsi_routing_allowed = true;
}
diff --git a/target-i386/kvm_i386.h b/target-i386/kvm_i386.h
new file mode 100644
index 0000000000..b82bbf401e
--- /dev/null
+++ b/target-i386/kvm_i386.h
@@ -0,0 +1,16 @@
+/*
+ * QEMU KVM support -- x86 specific functions.
+ *
+ * Copyright (c) 2012 Linaro Limited
+ *
+ * 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 QEMU_KVM_I386_H
+#define QEMU_KVM_I386_H
+
+bool kvm_allows_irq0_override(void);
+
+#endif
diff --git a/target-mips/translate.c b/target-mips/translate.c
index 4e15ee36b8..47daf8574f 100644
--- a/target-mips/translate.c
+++ b/target-mips/translate.c
@@ -12763,6 +12763,7 @@ void cpu_state_reset(CPUMIPSState *env)
env->CP0_SRSConf3 = env->cpu_model->CP0_SRSConf3;
env->CP0_SRSConf4_rw_bitmask = env->cpu_model->CP0_SRSConf4_rw_bitmask;
env->CP0_SRSConf4 = env->cpu_model->CP0_SRSConf4;
+ env->active_fpu.fcr0 = env->cpu_model->CP1_fcr0;
env->insn_flags = env->cpu_model->insn_flags;
#if defined(CONFIG_USER_ONLY)
diff --git a/target-unicore32/Makefile.objs b/target-unicore32/Makefile.objs
index 2e0e093e1f..777f01fef8 100644
--- a/target-unicore32/Makefile.objs
+++ b/target-unicore32/Makefile.objs
@@ -1,4 +1,6 @@
obj-y += translate.o op_helper.o helper.o cpu.o
-obj-$(CONFIG_SOFTMMU) += machine.o
+obj-y += ucf64_helper.o
+
+obj-$(CONFIG_SOFTMMU) += machine.o softmmu.o
$(obj)/op_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS)
diff --git a/target-unicore32/cpu.c b/target-unicore32/cpu.c
index de63f58dda..3425bbeac9 100644
--- a/target-unicore32/cpu.c
+++ b/target-unicore32/cpu.c
@@ -1,7 +1,7 @@
/*
* QEMU UniCore32 CPU
*
- * Copyright (c) 2010-2011 GUAN Xue-tao
+ * Copyright (c) 2010-2012 Guan Xuetao
* Copyright (c) 2012 SUSE LINUX Products GmbH
*
* This program is free software; you can redistribute it and/or modify
@@ -32,13 +32,16 @@ static void unicore_ii_cpu_initfn(Object *obj)
UniCore32CPU *cpu = UNICORE32_CPU(obj);
CPUUniCore32State *env = &cpu->env;
- env->cp0.c0_cpuid = 0x40010863;
+ env->cp0.c0_cpuid = 0x4d000863;
+ env->cp0.c0_cachetype = 0x0d152152;
+ env->cp0.c1_sys = 0x2000;
+ env->cp0.c2_base = 0x0;
+ env->cp0.c3_faultstatus = 0x0;
+ env->cp0.c4_faultaddr = 0x0;
+ env->ucf64.xregs[UC32_UCF64_FPSCR] = 0;
set_feature(env, UC32_HWCAP_CMOV);
set_feature(env, UC32_HWCAP_UCF64);
- env->ucf64.xregs[UC32_UCF64_FPSCR] = 0;
- env->cp0.c0_cachetype = 0x1dd20d2;
- env->cp0.c1_sys = 0x00090078;
}
static void uc32_any_cpu_initfn(Object *obj)
@@ -47,6 +50,7 @@ static void uc32_any_cpu_initfn(Object *obj)
CPUUniCore32State *env = &cpu->env;
env->cp0.c0_cpuid = 0xffffffff;
+ env->ucf64.xregs[UC32_UCF64_FPSCR] = 0;
set_feature(env, UC32_HWCAP_CMOV);
set_feature(env, UC32_HWCAP_UCF64);
@@ -65,8 +69,13 @@ static void uc32_cpu_initfn(Object *obj)
cpu_exec_init(env);
env->cpu_model_str = object_get_typename(obj);
+#ifdef CONFIG_USER_ONLY
env->uncached_asr = ASR_MODE_USER;
env->regs[31] = 0;
+#else
+ env->uncached_asr = ASR_MODE_PRIV;
+ env->regs[31] = 0x03000000;
+#endif
tlb_flush(env, 1);
}
diff --git a/target-unicore32/cpu.h b/target-unicore32/cpu.h
index 81c14ffd77..06508a1278 100644
--- a/target-unicore32/cpu.h
+++ b/target-unicore32/cpu.h
@@ -1,15 +1,15 @@
/*
* UniCore32 virtual CPU header
*
- * Copyright (C) 2010-2011 GUAN Xue-tao
+ * Copyright (C) 2010-2012 Guan Xuetao
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation, or (at your option) any
* later version. See the COPYING file in the top-level directory.
*/
-#ifndef __CPU_UC32_H__
-#define __CPU_UC32_H__
+#ifndef QEMU_UNICORE32_CPU_H
+#define QEMU_UNICORE32_CPU_H
#define TARGET_LONG_BITS 32
#define TARGET_PAGE_BITS 12
@@ -89,8 +89,10 @@ typedef struct CPUUniCore32State {
#define ASR_NZCV (ASR_N | ASR_Z | ASR_C | ASR_V)
#define ASR_RESERVED (~(ASR_M | ASR_I | ASR_NZCV))
-#define UC32_EXCP_PRIV (ASR_MODE_PRIV)
-#define UC32_EXCP_TRAP (ASR_MODE_TRAP)
+#define UC32_EXCP_PRIV (1)
+#define UC32_EXCP_ITRAP (2)
+#define UC32_EXCP_DTRAP (3)
+#define UC32_EXCP_INTR (4)
/* Return the current ASR value. */
target_ulong cpu_asr_read(CPUUniCore32State *env1);
@@ -120,10 +122,6 @@ void cpu_asr_write(CPUUniCore32State *env1, target_ulong val, target_ulong mask)
#define UC32_HWCAP_CMOV 4 /* 1 << 2 */
#define UC32_HWCAP_UCF64 8 /* 1 << 3 */
-#define UC32_CPUID(env) (env->cp0.c0_cpuid)
-#define UC32_CPUID_UCV2 0x40010863
-#define UC32_CPUID_ANY 0xffffffff
-
#define cpu_init uc32_cpu_init
#define cpu_exec uc32_cpu_exec
#define cpu_signal_handler uc32_cpu_signal_handler
@@ -189,4 +187,4 @@ static inline bool cpu_has_work(CPUUniCore32State *env)
(CPU_INTERRUPT_HARD | CPU_INTERRUPT_EXITTB);
}
-#endif /* __CPU_UC32_H__ */
+#endif /* QEMU_UNICORE32_CPU_H */
diff --git a/target-unicore32/helper.c b/target-unicore32/helper.c
index 9fe4a375e4..a9e226bde4 100644
--- a/target-unicore32/helper.c
+++ b/target-unicore32/helper.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2010-2011 GUAN Xue-tao
+ * Copyright (C) 2010-2012 Guan Xuetao
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -13,6 +13,15 @@
#include "gdbstub.h"
#include "helper.h"
#include "host-utils.h"
+#include "console.h"
+
+#undef DEBUG_UC32
+
+#ifdef DEBUG_UC32
+#define DPRINTF(fmt, ...) printf("%s: " fmt , __func__, ## __VA_ARGS__)
+#else
+#define DPRINTF(fmt, ...) do {} while (0)
+#endif
CPUUniCore32State *uc32_cpu_init(const char *cpu_model)
{
@@ -45,389 +54,203 @@ uint32_t HELPER(clz)(uint32_t x)
return clz32(x);
}
-void do_interrupt(CPUUniCore32State *env)
-{
- env->exception_index = -1;
-}
-
-int uc32_cpu_handle_mmu_fault(CPUUniCore32State *env, target_ulong address, int rw,
- int mmu_idx)
-{
- env->exception_index = UC32_EXCP_TRAP;
- env->cp0.c4_faultaddr = address;
- return 1;
-}
-
-/* These should probably raise undefined insn exceptions. */
-void HELPER(set_cp)(CPUUniCore32State *env, uint32_t insn, uint32_t val)
-{
- int op1 = (insn >> 8) & 0xf;
- cpu_abort(env, "cp%i insn %08x\n", op1, insn);
- return;
-}
-
-uint32_t HELPER(get_cp)(CPUUniCore32State *env, uint32_t insn)
-{
- int op1 = (insn >> 8) & 0xf;
- cpu_abort(env, "cp%i insn %08x\n", op1, insn);
- return 0;
-}
-
-void HELPER(set_cp0)(CPUUniCore32State *env, uint32_t insn, uint32_t val)
-{
- cpu_abort(env, "cp0 insn %08x\n", insn);
-}
-
-uint32_t HELPER(get_cp0)(CPUUniCore32State *env, uint32_t insn)
-{
- cpu_abort(env, "cp0 insn %08x\n", insn);
- return 0;
-}
-
-void switch_mode(CPUUniCore32State *env, int mode)
-{
- if (mode != ASR_MODE_USER) {
- cpu_abort(env, "Tried to switch out of user mode\n");
- }
-}
-
-void HELPER(set_r29_banked)(CPUUniCore32State *env, uint32_t mode, uint32_t val)
-{
- cpu_abort(env, "banked r29 write\n");
-}
-
-uint32_t HELPER(get_r29_banked)(CPUUniCore32State *env, uint32_t mode)
-{
- cpu_abort(env, "banked r29 read\n");
- return 0;
-}
-
-/* UniCore-F64 support. We follow the convention used for F64 instrunctions:
- Single precition routines have a "s" suffix, double precision a
- "d" suffix. */
-
-/* Convert host exception flags to f64 form. */
-static inline int ucf64_exceptbits_from_host(int host_bits)
-{
- int target_bits = 0;
-
- if (host_bits & float_flag_invalid) {
- target_bits |= UCF64_FPSCR_FLAG_INVALID;
- }
- if (host_bits & float_flag_divbyzero) {
- target_bits |= UCF64_FPSCR_FLAG_DIVZERO;
- }
- if (host_bits & float_flag_overflow) {
- target_bits |= UCF64_FPSCR_FLAG_OVERFLOW;
- }
- if (host_bits & float_flag_underflow) {
- target_bits |= UCF64_FPSCR_FLAG_UNDERFLOW;
- }
- if (host_bits & float_flag_inexact) {
- target_bits |= UCF64_FPSCR_FLAG_INEXACT;
- }
- return target_bits;
-}
-
-uint32_t HELPER(ucf64_get_fpscr)(CPUUniCore32State *env)
-{
- int i;
- uint32_t fpscr;
-
- fpscr = (env->ucf64.xregs[UC32_UCF64_FPSCR] & UCF64_FPSCR_MASK);
- i = get_float_exception_flags(&env->ucf64.fp_status);
- fpscr |= ucf64_exceptbits_from_host(i);
- return fpscr;
-}
-
-/* Convert ucf64 exception flags to target form. */
-static inline int ucf64_exceptbits_to_host(int target_bits)
-{
- int host_bits = 0;
-
- if (target_bits & UCF64_FPSCR_FLAG_INVALID) {
- host_bits |= float_flag_invalid;
- }
- if (target_bits & UCF64_FPSCR_FLAG_DIVZERO) {
- host_bits |= float_flag_divbyzero;
- }
- if (target_bits & UCF64_FPSCR_FLAG_OVERFLOW) {
- host_bits |= float_flag_overflow;
- }
- if (target_bits & UCF64_FPSCR_FLAG_UNDERFLOW) {
- host_bits |= float_flag_underflow;
- }
- if (target_bits & UCF64_FPSCR_FLAG_INEXACT) {
- host_bits |= float_flag_inexact;
- }
- return host_bits;
-}
-
-void HELPER(ucf64_set_fpscr)(CPUUniCore32State *env, uint32_t val)
-{
- int i;
- uint32_t changed;
-
- changed = env->ucf64.xregs[UC32_UCF64_FPSCR];
- env->ucf64.xregs[UC32_UCF64_FPSCR] = (val & UCF64_FPSCR_MASK);
-
- changed ^= val;
- if (changed & (UCF64_FPSCR_RND_MASK)) {
- i = UCF64_FPSCR_RND(val);
- switch (i) {
- case 0:
- i = float_round_nearest_even;
- break;
- case 1:
- i = float_round_to_zero;
- break;
- case 2:
- i = float_round_up;
- break;
- case 3:
- i = float_round_down;
- break;
- default: /* 100 and 101 not implement */
- cpu_abort(env, "Unsupported UniCore-F64 round mode");
- }
- set_float_rounding_mode(i, &env->ucf64.fp_status);
- }
-
- i = ucf64_exceptbits_to_host(UCF64_FPSCR_TRAPEN(val));
- set_float_exception_flags(i, &env->ucf64.fp_status);
-}
-
-float32 HELPER(ucf64_adds)(float32 a, float32 b, CPUUniCore32State *env)
-{
- return float32_add(a, b, &env->ucf64.fp_status);
-}
-
-float64 HELPER(ucf64_addd)(float64 a, float64 b, CPUUniCore32State *env)
-{
- return float64_add(a, b, &env->ucf64.fp_status);
-}
-
-float32 HELPER(ucf64_subs)(float32 a, float32 b, CPUUniCore32State *env)
-{
- return float32_sub(a, b, &env->ucf64.fp_status);
-}
-
-float64 HELPER(ucf64_subd)(float64 a, float64 b, CPUUniCore32State *env)
-{
- return float64_sub(a, b, &env->ucf64.fp_status);
-}
-
-float32 HELPER(ucf64_muls)(float32 a, float32 b, CPUUniCore32State *env)
-{
- return float32_mul(a, b, &env->ucf64.fp_status);
-}
-
-float64 HELPER(ucf64_muld)(float64 a, float64 b, CPUUniCore32State *env)
-{
- return float64_mul(a, b, &env->ucf64.fp_status);
-}
-
-float32 HELPER(ucf64_divs)(float32 a, float32 b, CPUUniCore32State *env)
-{
- return float32_div(a, b, &env->ucf64.fp_status);
-}
-
-float64 HELPER(ucf64_divd)(float64 a, float64 b, CPUUniCore32State *env)
-{
- return float64_div(a, b, &env->ucf64.fp_status);
-}
-
-float32 HELPER(ucf64_negs)(float32 a)
-{
- return float32_chs(a);
-}
-
-float64 HELPER(ucf64_negd)(float64 a)
-{
- return float64_chs(a);
-}
-
-float32 HELPER(ucf64_abss)(float32 a)
-{
- return float32_abs(a);
-}
-
-float64 HELPER(ucf64_absd)(float64 a)
-{
- return float64_abs(a);
-}
-
-/* XXX: check quiet/signaling case */
-void HELPER(ucf64_cmps)(float32 a, float32 b, uint32_t c, CPUUniCore32State *env)
-{
- int flag;
- flag = float32_compare_quiet(a, b, &env->ucf64.fp_status);
- env->CF = 0;
- switch (c & 0x7) {
- case 0: /* F */
- break;
- case 1: /* UN */
- if (flag == 2) {
- env->CF = 1;
+#ifndef CONFIG_USER_ONLY
+void helper_cp0_set(CPUUniCore32State *env, uint32_t val, uint32_t creg,
+ uint32_t cop)
+{
+ /*
+ * movc pp.nn, rn, #imm9
+ * rn: UCOP_REG_D
+ * nn: UCOP_REG_N
+ * 1: sys control reg.
+ * 2: page table base reg.
+ * 3: data fault status reg.
+ * 4: insn fault status reg.
+ * 5: cache op. reg.
+ * 6: tlb op. reg.
+ * imm9: split UCOP_IMM10 with bit5 is 0
+ */
+ switch (creg) {
+ case 1:
+ if (cop != 0) {
+ goto unrecognized;
}
+ env->cp0.c1_sys = val;
break;
- case 2: /* EQ */
- if (flag == 0) {
- env->CF = 1;
+ case 2:
+ if (cop != 0) {
+ goto unrecognized;
}
+ env->cp0.c2_base = val;
break;
- case 3: /* UEQ */
- if ((flag == 0) || (flag == 2)) {
- env->CF = 1;
+ case 3:
+ if (cop != 0) {
+ goto unrecognized;
}
+ env->cp0.c3_faultstatus = val;
break;
- case 4: /* OLT */
- if (flag == -1) {
- env->CF = 1;
+ case 4:
+ if (cop != 0) {
+ goto unrecognized;
}
+ env->cp0.c4_faultaddr = val;
break;
- case 5: /* ULT */
- if ((flag == -1) || (flag == 2)) {
- env->CF = 1;
+ case 5:
+ switch (cop) {
+ case 28:
+ DPRINTF("Invalidate Entire I&D cache\n");
+ return;
+ case 20:
+ DPRINTF("Invalidate Entire Icache\n");
+ return;
+ case 12:
+ DPRINTF("Invalidate Entire Dcache\n");
+ return;
+ case 10:
+ DPRINTF("Clean Entire Dcache\n");
+ return;
+ case 14:
+ DPRINTF("Flush Entire Dcache\n");
+ return;
+ case 13:
+ DPRINTF("Invalidate Dcache line\n");
+ return;
+ case 11:
+ DPRINTF("Clean Dcache line\n");
+ return;
+ case 15:
+ DPRINTF("Flush Dcache line\n");
+ return;
}
break;
- case 6: /* OLE */
- if ((flag == -1) || (flag == 0)) {
- env->CF = 1;
- }
- break;
- case 7: /* ULE */
- if (flag != 1) {
- env->CF = 1;
+ case 6:
+ if ((cop <= 6) && (cop >= 2)) {
+ /* invalid all tlb */
+ tlb_flush(env, 1);
+ return;
}
break;
+ default:
+ goto unrecognized;
}
- env->ucf64.xregs[UC32_UCF64_FPSCR] = (env->CF << 29)
- | (env->ucf64.xregs[UC32_UCF64_FPSCR] & 0x0fffffff);
-}
-
-void HELPER(ucf64_cmpd)(float64 a, float64 b, uint32_t c, CPUUniCore32State *env)
-{
- int flag;
- flag = float64_compare_quiet(a, b, &env->ucf64.fp_status);
- env->CF = 0;
- switch (c & 0x7) {
- case 0: /* F */
- break;
- case 1: /* UN */
- if (flag == 2) {
- env->CF = 1;
- }
- break;
- case 2: /* EQ */
- if (flag == 0) {
- env->CF = 1;
- }
- break;
- case 3: /* UEQ */
- if ((flag == 0) || (flag == 2)) {
- env->CF = 1;
+ return;
+unrecognized:
+ DPRINTF("Wrong register (%d) or wrong operation (%d) in cp0_set!\n",
+ creg, cop);
+}
+
+uint32_t helper_cp0_get(CPUUniCore32State *env, uint32_t creg, uint32_t cop)
+{
+ /*
+ * movc rd, pp.nn, #imm9
+ * rd: UCOP_REG_D
+ * nn: UCOP_REG_N
+ * 0: cpuid and cachetype
+ * 1: sys control reg.
+ * 2: page table base reg.
+ * 3: data fault status reg.
+ * 4: insn fault status reg.
+ * imm9: split UCOP_IMM10 with bit5 is 0
+ */
+ switch (creg) {
+ case 0:
+ switch (cop) {
+ case 0:
+ return env->cp0.c0_cpuid;
+ case 1:
+ return env->cp0.c0_cachetype;
}
break;
- case 4: /* OLT */
- if (flag == -1) {
- env->CF = 1;
+ case 1:
+ if (cop == 0) {
+ return env->cp0.c1_sys;
}
break;
- case 5: /* ULT */
- if ((flag == -1) || (flag == 2)) {
- env->CF = 1;
+ case 2:
+ if (cop == 0) {
+ return env->cp0.c2_base;
}
break;
- case 6: /* OLE */
- if ((flag == -1) || (flag == 0)) {
- env->CF = 1;
+ case 3:
+ if (cop == 0) {
+ return env->cp0.c3_faultstatus;
}
break;
- case 7: /* ULE */
- if (flag != 1) {
- env->CF = 1;
+ case 4:
+ if (cop == 0) {
+ return env->cp0.c4_faultaddr;
}
break;
}
- env->ucf64.xregs[UC32_UCF64_FPSCR] = (env->CF << 29)
- | (env->ucf64.xregs[UC32_UCF64_FPSCR] & 0x0fffffff);
-}
-
-/* Helper routines to perform bitwise copies between float and int. */
-static inline float32 ucf64_itos(uint32_t i)
-{
- union {
- uint32_t i;
- float32 s;
- } v;
-
- v.i = i;
- return v.s;
-}
-
-static inline uint32_t ucf64_stoi(float32 s)
-{
- union {
- uint32_t i;
- float32 s;
- } v;
-
- v.s = s;
- return v.i;
-}
-
-static inline float64 ucf64_itod(uint64_t i)
-{
- union {
- uint64_t i;
- float64 d;
- } v;
-
- v.i = i;
- return v.d;
+ DPRINTF("Wrong register (%d) or wrong operation (%d) in cp0_set!\n",
+ creg, cop);
+ return 0;
}
-static inline uint64_t ucf64_dtoi(float64 d)
+#ifdef CONFIG_CURSES
+/*
+ * FIXME:
+ * 1. curses windows will be blank when switching back
+ * 2. backspace is not handled yet
+ */
+static void putc_on_screen(unsigned char ch)
{
- union {
- uint64_t i;
- float64 d;
- } v;
+ static WINDOW *localwin;
+ static int init;
- v.d = d;
- return v.i;
-}
+ if (!init) {
+ /* Assume 80 * 30 screen to minimize the implementation */
+ localwin = newwin(30, 80, 0, 0);
+ scrollok(localwin, TRUE);
+ init = TRUE;
+ }
-/* Integer to float conversion. */
-float32 HELPER(ucf64_si2sf)(float32 x, CPUUniCore32State *env)
-{
- return int32_to_float32(ucf64_stoi(x), &env->ucf64.fp_status);
-}
+ if (isprint(ch)) {
+ wprintw(localwin, "%c", ch);
+ } else {
+ switch (ch) {
+ case '\n':
+ wprintw(localwin, "%c", ch);
+ break;
+ case '\r':
+ /* If '\r' is put before '\n', the curses window will destroy the
+ * last print line. And meanwhile, '\n' implifies '\r' inside. */
+ break;
+ default: /* Not handled, so just print it hex code */
+ wprintw(localwin, "-- 0x%x --", ch);
+ }
+ }
-float64 HELPER(ucf64_si2df)(float32 x, CPUUniCore32State *env)
-{
- return int32_to_float64(ucf64_stoi(x), &env->ucf64.fp_status);
+ wrefresh(localwin);
}
+#else
+#define putc_on_screen(c) do { } while (0)
+#endif
-/* Float to integer conversion. */
-float32 HELPER(ucf64_sf2si)(float32 x, CPUUniCore32State *env)
+void helper_cp1_putc(target_ulong x)
{
- return ucf64_itos(float32_to_int32(x, &env->ucf64.fp_status));
+ putc_on_screen((unsigned char)x); /* Output to screen */
+ DPRINTF("%c", x); /* Output to stdout */
}
+#endif
-float32 HELPER(ucf64_df2si)(float64 x, CPUUniCore32State *env)
+#ifdef CONFIG_USER_ONLY
+void switch_mode(CPUUniCore32State *env, int mode)
{
- return ucf64_itos(float64_to_int32(x, &env->ucf64.fp_status));
+ if (mode != ASR_MODE_USER) {
+ cpu_abort(env, "Tried to switch out of user mode\n");
+ }
}
-/* floating point conversion */
-float64 HELPER(ucf64_sf2df)(float32 x, CPUUniCore32State *env)
+void do_interrupt(CPUUniCore32State *env)
{
- return float32_to_float64(x, &env->ucf64.fp_status);
+ cpu_abort(env, "NO interrupt in user mode\n");
}
-float32 HELPER(ucf64_df2sf)(float64 x, CPUUniCore32State *env)
+int uc32_cpu_handle_mmu_fault(CPUUniCore32State *env, target_ulong address,
+ int access_type, int mmu_idx)
{
- return float64_to_float32(x, &env->ucf64.fp_status);
+ cpu_abort(env, "NO mmu fault in user mode\n");
+ return 1;
}
+#endif
diff --git a/target-unicore32/helper.h b/target-unicore32/helper.h
index 5a3b8a41ea..305318ae59 100644
--- a/target-unicore32/helper.h
+++ b/target-unicore32/helper.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2010-2011 GUAN Xue-tao
+ * Copyright (C) 2010-2012 Guan Xuetao
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -8,6 +8,12 @@
*/
#include "def-helper.h"
+#ifndef CONFIG_USER_ONLY
+DEF_HELPER_4(cp0_set, void, env, i32, i32, i32)
+DEF_HELPER_3(cp0_get, i32, env, i32, i32)
+DEF_HELPER_1(cp1_putc, void, i32)
+#endif
+
DEF_HELPER_1(clz, i32, i32)
DEF_HELPER_1(clo, i32, i32)
@@ -16,12 +22,6 @@ DEF_HELPER_1(exception, void, i32)
DEF_HELPER_2(asr_write, void, i32, i32)
DEF_HELPER_0(asr_read, i32)
-DEF_HELPER_3(set_cp0, void, env, i32, i32)
-DEF_HELPER_2(get_cp0, i32, env, i32)
-
-DEF_HELPER_3(set_cp, void, env, i32, i32)
-DEF_HELPER_2(get_cp, i32, env, i32)
-
DEF_HELPER_1(get_user_reg, i32, i32)
DEF_HELPER_2(set_user_reg, void, i32, i32)
@@ -38,9 +38,6 @@ DEF_HELPER_2(shr_cc, i32, i32, i32)
DEF_HELPER_2(sar_cc, i32, i32, i32)
DEF_HELPER_2(ror_cc, i32, i32, i32)
-DEF_HELPER_2(get_r29_banked, i32, env, i32)
-DEF_HELPER_3(set_r29_banked, void, env, i32, i32)
-
DEF_HELPER_1(ucf64_get_fpscr, i32, env)
DEF_HELPER_2(ucf64_set_fpscr, void, env, i32)
diff --git a/target-unicore32/machine.c b/target-unicore32/machine.c
new file mode 100644
index 0000000000..60b2ec1771
--- /dev/null
+++ b/target-unicore32/machine.c
@@ -0,0 +1,23 @@
+/*
+ * Generic machine functions for UniCore32 ISA
+ *
+ * Copyright (C) 2010-2012 Guan Xuetao
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation, or any later version.
+ * See the COPYING file in the top-level directory.
+ */
+#include "hw/hw.h"
+
+void cpu_save(QEMUFile *f, void *opaque)
+{
+ hw_error("%s not supported yet.\n", __func__);
+}
+
+int cpu_load(QEMUFile *f, void *opaque, int version_id)
+{
+ hw_error("%s not supported yet.\n", __func__);
+
+ return 0;
+}
diff --git a/target-unicore32/op_helper.c b/target-unicore32/op_helper.c
index b954c30a84..c63789d6cb 100644
--- a/target-unicore32/op_helper.c
+++ b/target-unicore32/op_helper.c
@@ -1,7 +1,7 @@
/*
* UniCore32 helper routines
*
- * Copyright (C) 2010-2011 GUAN Xue-tao
+ * Copyright (C) 2010-2012 Guan Xuetao
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -248,3 +248,45 @@ uint32_t HELPER(ror_cc)(uint32_t x, uint32_t i)
return ((uint32_t)x >> shift) | (x << (32 - shift));
}
}
+
+#ifndef CONFIG_USER_ONLY
+#define MMUSUFFIX _mmu
+
+#define SHIFT 0
+#include "softmmu_template.h"
+
+#define SHIFT 1
+#include "softmmu_template.h"
+
+#define SHIFT 2
+#include "softmmu_template.h"
+
+#define SHIFT 3
+#include "softmmu_template.h"
+
+void tlb_fill(CPUUniCore32State *env1, target_ulong addr, int is_write,
+ int mmu_idx, uintptr_t retaddr)
+{
+ TranslationBlock *tb;
+ CPUUniCore32State *saved_env;
+ unsigned long pc;
+ int ret;
+
+ saved_env = env;
+ env = env1;
+ ret = uc32_cpu_handle_mmu_fault(env, addr, is_write, mmu_idx);
+ if (unlikely(ret)) {
+ if (retaddr) {
+ /* now we have a real cpu fault */
+ pc = (unsigned long)retaddr;
+ tb = tb_find_pc(pc);
+ if (tb) {/* the PC is inside the translated code.
+ It means that we have a virtual CPU fault */
+ cpu_restore_state(tb, env, pc);
+ }
+ }
+ cpu_loop_exit(env);
+ }
+ env = saved_env;
+}
+#endif
diff --git a/target-unicore32/softmmu.c b/target-unicore32/softmmu.c
new file mode 100644
index 0000000000..373f94b274
--- /dev/null
+++ b/target-unicore32/softmmu.c
@@ -0,0 +1,267 @@
+/*
+ * Softmmu related functions
+ *
+ * Copyright (C) 2010-2012 Guan Xuetao
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation, or any later version.
+ * See the COPYING file in the top-level directory.
+ */
+#ifdef CONFIG_USER_ONLY
+#error This file only exist under softmmu circumstance
+#endif
+
+#include <cpu.h>
+
+#undef DEBUG_UC32
+
+#ifdef DEBUG_UC32
+#define DPRINTF(fmt, ...) printf("%s: " fmt , __func__, ## __VA_ARGS__)
+#else
+#define DPRINTF(fmt, ...) do {} while (0)
+#endif
+
+#define SUPERPAGE_SIZE (1 << 22)
+#define UC32_PAGETABLE_READ (1 << 8)
+#define UC32_PAGETABLE_WRITE (1 << 7)
+#define UC32_PAGETABLE_EXEC (1 << 6)
+#define UC32_PAGETABLE_EXIST (1 << 2)
+#define PAGETABLE_TYPE(x) ((x) & 3)
+
+
+/* Map CPU modes onto saved register banks. */
+static inline int bank_number(int mode)
+{
+ switch (mode) {
+ case ASR_MODE_USER:
+ case ASR_MODE_SUSR:
+ return 0;
+ case ASR_MODE_PRIV:
+ return 1;
+ case ASR_MODE_TRAP:
+ return 2;
+ case ASR_MODE_EXTN:
+ return 3;
+ case ASR_MODE_INTR:
+ return 4;
+ }
+ cpu_abort(cpu_single_env, "Bad mode %x\n", mode);
+ return -1;
+}
+
+void switch_mode(CPUUniCore32State *env, int mode)
+{
+ int old_mode;
+ int i;
+
+ old_mode = env->uncached_asr & ASR_M;
+ if (mode == old_mode) {
+ return;
+ }
+
+ i = bank_number(old_mode);
+ env->banked_r29[i] = env->regs[29];
+ env->banked_r30[i] = env->regs[30];
+ env->banked_bsr[i] = env->bsr;
+
+ i = bank_number(mode);
+ env->regs[29] = env->banked_r29[i];
+ env->regs[30] = env->banked_r30[i];
+ env->bsr = env->banked_bsr[i];
+}
+
+/* Handle a CPU exception. */
+void do_interrupt(CPUUniCore32State *env)
+{
+ uint32_t addr;
+ int new_mode;
+
+ switch (env->exception_index) {
+ case UC32_EXCP_PRIV:
+ new_mode = ASR_MODE_PRIV;
+ addr = 0x08;
+ break;
+ case UC32_EXCP_ITRAP:
+ DPRINTF("itrap happened at %x\n", env->regs[31]);
+ new_mode = ASR_MODE_TRAP;
+ addr = 0x0c;
+ break;
+ case UC32_EXCP_DTRAP:
+ DPRINTF("dtrap happened at %x\n", env->regs[31]);
+ new_mode = ASR_MODE_TRAP;
+ addr = 0x10;
+ break;
+ case UC32_EXCP_INTR:
+ new_mode = ASR_MODE_INTR;
+ addr = 0x18;
+ break;
+ default:
+ cpu_abort(env, "Unhandled exception 0x%x\n", env->exception_index);
+ return;
+ }
+ /* High vectors. */
+ if (env->cp0.c1_sys & (1 << 13)) {
+ addr += 0xffff0000;
+ }
+
+ switch_mode(env, new_mode);
+ env->bsr = cpu_asr_read(env);
+ env->uncached_asr = (env->uncached_asr & ~ASR_M) | new_mode;
+ env->uncached_asr |= ASR_I;
+ /* The PC already points to the proper instruction. */
+ env->regs[30] = env->regs[31];
+ env->regs[31] = addr;
+ env->interrupt_request |= CPU_INTERRUPT_EXITTB;
+}
+
+static int get_phys_addr_ucv2(CPUUniCore32State *env, uint32_t address,
+ int access_type, int is_user, uint32_t *phys_ptr, int *prot,
+ target_ulong *page_size)
+{
+ int code;
+ uint32_t table;
+ uint32_t desc;
+ uint32_t phys_addr;
+
+ /* Pagetable walk. */
+ /* Lookup l1 descriptor. */
+ table = env->cp0.c2_base & 0xfffff000;
+ table |= (address >> 20) & 0xffc;
+ desc = ldl_phys(table);
+ code = 0;
+ switch (PAGETABLE_TYPE(desc)) {
+ case 3:
+ /* Superpage */
+ if (!(desc & UC32_PAGETABLE_EXIST)) {
+ code = 0x0b; /* superpage miss */
+ goto do_fault;
+ }
+ phys_addr = (desc & 0xffc00000) | (address & 0x003fffff);
+ *page_size = SUPERPAGE_SIZE;
+ break;
+ case 0:
+ /* Lookup l2 entry. */
+ if (is_user) {
+ DPRINTF("PGD address %x, desc %x\n", table, desc);
+ }
+ if (!(desc & UC32_PAGETABLE_EXIST)) {
+ code = 0x05; /* second pagetable miss */
+ goto do_fault;
+ }
+ table = (desc & 0xfffff000) | ((address >> 10) & 0xffc);
+ desc = ldl_phys(table);
+ /* 4k page. */
+ if (is_user) {
+ DPRINTF("PTE address %x, desc %x\n", table, desc);
+ }
+ if (!(desc & UC32_PAGETABLE_EXIST)) {
+ code = 0x08; /* page miss */
+ goto do_fault;
+ }
+ switch (PAGETABLE_TYPE(desc)) {
+ case 0:
+ phys_addr = (desc & 0xfffff000) | (address & 0xfff);
+ *page_size = TARGET_PAGE_SIZE;
+ break;
+ default:
+ cpu_abort(env, "wrong page type!");
+ }
+ break;
+ default:
+ cpu_abort(env, "wrong page type!");
+ }
+
+ *phys_ptr = phys_addr;
+ *prot = 0;
+ /* Check access permissions. */
+ if (desc & UC32_PAGETABLE_READ) {
+ *prot |= PAGE_READ;
+ } else {
+ if (is_user && (access_type == 0)) {
+ code = 0x11; /* access unreadable area */
+ goto do_fault;
+ }
+ }
+
+ if (desc & UC32_PAGETABLE_WRITE) {
+ *prot |= PAGE_WRITE;
+ } else {
+ if (is_user && (access_type == 1)) {
+ code = 0x12; /* access unwritable area */
+ goto do_fault;
+ }
+ }
+
+ if (desc & UC32_PAGETABLE_EXEC) {
+ *prot |= PAGE_EXEC;
+ } else {
+ if (is_user && (access_type == 2)) {
+ code = 0x13; /* access unexecutable area */
+ goto do_fault;
+ }
+ }
+
+do_fault:
+ return code;
+}
+
+int uc32_cpu_handle_mmu_fault(CPUUniCore32State *env, target_ulong address,
+ int access_type, int mmu_idx)
+{
+ uint32_t phys_addr;
+ target_ulong page_size;
+ int prot;
+ int ret, is_user;
+
+ ret = 1;
+ is_user = mmu_idx == MMU_USER_IDX;
+
+ if ((env->cp0.c1_sys & 1) == 0) {
+ /* MMU disabled. */
+ phys_addr = address;
+ prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
+ page_size = TARGET_PAGE_SIZE;
+ ret = 0;
+ } else {
+ if ((address & (1 << 31)) || (is_user)) {
+ ret = get_phys_addr_ucv2(env, address, access_type, is_user,
+ &phys_addr, &prot, &page_size);
+ if (is_user) {
+ DPRINTF("user space access: ret %x, address %x, "
+ "access_type %x, phys_addr %x, prot %x\n",
+ ret, address, access_type, phys_addr, prot);
+ }
+ } else {
+ /*IO memory */
+ phys_addr = address | (1 << 31);
+ prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
+ page_size = TARGET_PAGE_SIZE;
+ ret = 0;
+ }
+ }
+
+ if (ret == 0) {
+ /* Map a single page. */
+ phys_addr &= TARGET_PAGE_MASK;
+ address &= TARGET_PAGE_MASK;
+ tlb_set_page(env, address, phys_addr, prot, mmu_idx, page_size);
+ return 0;
+ }
+
+ env->cp0.c3_faultstatus = ret;
+ env->cp0.c4_faultaddr = address;
+ if (access_type == 2) {
+ env->exception_index = UC32_EXCP_ITRAP;
+ } else {
+ env->exception_index = UC32_EXCP_DTRAP;
+ }
+ return ret;
+}
+
+target_phys_addr_t cpu_get_phys_page_debug(CPUUniCore32State *env,
+ target_ulong addr)
+{
+ cpu_abort(env, "%s not supported yet\n", __func__);
+ return addr;
+}
diff --git a/target-unicore32/translate.c b/target-unicore32/translate.c
index 9793d14c1b..188bf8c52a 100644
--- a/target-unicore32/translate.c
+++ b/target-unicore32/translate.c
@@ -1,7 +1,7 @@
/*
* UniCore32 translation
*
- * Copyright (C) 2010-2011 GUAN Xue-tao
+ * Copyright (C) 2010-2012 Guan Xuetao
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -33,9 +33,16 @@ typedef struct DisasContext {
int condlabel;
struct TranslationBlock *tb;
int singlestep_enabled;
+#ifndef CONFIG_USER_ONLY
+ int user;
+#endif
} DisasContext;
-#define IS_USER(s) 1
+#ifndef CONFIG_USER_ONLY
+#define IS_USER(s) (s->user)
+#else
+#define IS_USER(s) 1
+#endif
/* These instructions trap after executing, so defer them until after the
conditional executions state has been updated. */
@@ -176,6 +183,73 @@ static void store_reg(DisasContext *s, int reg, TCGv var)
"Illegal UniCore32 instruction %x at line %d!", \
insn, __LINE__)
+#ifndef CONFIG_USER_ONLY
+static void disas_cp0_insn(CPUUniCore32State *env, DisasContext *s,
+ uint32_t insn)
+{
+ TCGv tmp, tmp2, tmp3;
+ if ((insn & 0xfe000000) == 0xe0000000) {
+ tmp2 = new_tmp();
+ tmp3 = new_tmp();
+ tcg_gen_movi_i32(tmp2, UCOP_REG_N);
+ tcg_gen_movi_i32(tmp3, UCOP_IMM10);
+ if (UCOP_SET_L) {
+ tmp = new_tmp();
+ gen_helper_cp0_get(tmp, cpu_env, tmp2, tmp3);
+ store_reg(s, UCOP_REG_D, tmp);
+ } else {
+ tmp = load_reg(s, UCOP_REG_D);
+ gen_helper_cp0_set(cpu_env, tmp, tmp2, tmp3);
+ dead_tmp(tmp);
+ }
+ dead_tmp(tmp2);
+ dead_tmp(tmp3);
+ return;
+ }
+ ILLEGAL;
+}
+
+static void disas_ocd_insn(CPUUniCore32State *env, DisasContext *s,
+ uint32_t insn)
+{
+ TCGv tmp;
+
+ if ((insn & 0xff003fff) == 0xe1000400) {
+ /*
+ * movc rd, pp.nn, #imm9
+ * rd: UCOP_REG_D
+ * nn: UCOP_REG_N (must be 0)
+ * imm9: 0
+ */
+ if (UCOP_REG_N == 0) {
+ tmp = new_tmp();
+ tcg_gen_movi_i32(tmp, 0);
+ store_reg(s, UCOP_REG_D, tmp);
+ return;
+ } else {
+ ILLEGAL;
+ }
+ }
+ if ((insn & 0xff003fff) == 0xe0000401) {
+ /*
+ * movc pp.nn, rn, #imm9
+ * rn: UCOP_REG_D
+ * nn: UCOP_REG_N (must be 1)
+ * imm9: 1
+ */
+ if (UCOP_REG_N == 1) {
+ tmp = load_reg(s, UCOP_REG_D);
+ gen_helper_cp1_putc(tmp);
+ dead_tmp(tmp);
+ return;
+ } else {
+ ILLEGAL;
+ }
+ }
+ ILLEGAL;
+}
+#endif
+
static inline void gen_set_asr(TCGv var, uint32_t mask)
{
TCGv tmp_mask = tcg_const_i32(mask);
@@ -1124,9 +1198,18 @@ static void gen_exception_return(DisasContext *s, TCGv pc)
s->is_jmp = DISAS_UPDATE;
}
-static void disas_coproc_insn(CPUUniCore32State *env, DisasContext *s, uint32_t insn)
+static void disas_coproc_insn(CPUUniCore32State *env, DisasContext *s,
+ uint32_t insn)
{
switch (UCOP_CPNUM) {
+#ifndef CONFIG_USER_ONLY
+ case 0:
+ disas_cp0_insn(env, s, insn);
+ break;
+ case 1:
+ disas_ocd_insn(env, s, insn);
+ break;
+#endif
case 2:
disas_ucf64_insn(env, s, insn);
break;
@@ -1478,12 +1561,12 @@ static void do_misc(CPUUniCore32State *env, DisasContext *s, uint32_t insn)
/* load/store I_offset and R_offset */
static void do_ldst_ir(CPUUniCore32State *env, DisasContext *s, uint32_t insn)
{
- unsigned int i;
+ unsigned int mmu_idx;
TCGv tmp;
TCGv tmp2;
tmp2 = load_reg(s, UCOP_REG_N);
- i = (IS_USER(s) || (!UCOP_SET_P && UCOP_SET_W));
+ mmu_idx = (IS_USER(s) || (!UCOP_SET_P && UCOP_SET_W));
/* immediate */
if (UCOP_SET_P) {
@@ -1493,17 +1576,17 @@ static void do_ldst_ir(CPUUniCore32State *env, DisasContext *s, uint32_t insn)
if (UCOP_SET_L) {
/* load */
if (UCOP_SET_B) {
- tmp = gen_ld8u(tmp2, i);
+ tmp = gen_ld8u(tmp2, mmu_idx);
} else {
- tmp = gen_ld32(tmp2, i);
+ tmp = gen_ld32(tmp2, mmu_idx);
}
} else {
/* store */
tmp = load_reg(s, UCOP_REG_D);
if (UCOP_SET_B) {
- gen_st8(tmp, tmp2, i);
+ gen_st8(tmp, tmp2, mmu_idx);
} else {
- gen_st32(tmp, tmp2, i);
+ gen_st32(tmp, tmp2, mmu_idx);
}
}
if (!UCOP_SET_P) {
@@ -1606,7 +1689,7 @@ static void do_ldst_hwsb(CPUUniCore32State *env, DisasContext *s, uint32_t insn)
/* load/store multiple words */
static void do_ldst_m(CPUUniCore32State *env, DisasContext *s, uint32_t insn)
{
- unsigned int val, i;
+ unsigned int val, i, mmu_idx;
int j, n, reg, user, loaded_base;
TCGv tmp;
TCGv tmp2;
@@ -1627,6 +1710,7 @@ static void do_ldst_m(CPUUniCore32State *env, DisasContext *s, uint32_t insn)
}
}
+ mmu_idx = (IS_USER(s) || (!UCOP_SET_P && UCOP_SET_W));
addr = load_reg(s, UCOP_REG_N);
/* compute total size */
@@ -1671,7 +1755,7 @@ static void do_ldst_m(CPUUniCore32State *env, DisasContext *s, uint32_t insn)
}
if (UCOP_SET(i)) {
if (UCOP_SET_L) { /* load */
- tmp = gen_ld32(addr, IS_USER(s));
+ tmp = gen_ld32(addr, mmu_idx);
if (reg == 31) {
gen_bx(s, tmp);
} else if (user) {
@@ -1699,7 +1783,7 @@ static void do_ldst_m(CPUUniCore32State *env, DisasContext *s, uint32_t insn)
} else {
tmp = load_reg(s, reg);
}
- gen_st32(tmp, addr, IS_USER(s));
+ gen_st32(tmp, addr, mmu_idx);
}
j++;
/* no need to add after the last transfer */
@@ -1888,6 +1972,14 @@ static inline void gen_intermediate_code_internal(CPUUniCore32State *env,
max_insns = CF_COUNT_MASK;
}
+#ifndef CONFIG_USER_ONLY
+ if ((env->uncached_asr & ASR_M) == ASR_MODE_USER) {
+ dc->user = 1;
+ } else {
+ dc->user = 0;
+ }
+#endif
+
gen_icount_start();
do {
if (unlikely(!QTAILQ_EMPTY(&env->breakpoints))) {
@@ -2046,12 +2138,12 @@ static const char *cpu_mode_names[16] = {
"UM18", "UM19", "UM1A", "EXTN", "UM1C", "UM1D", "UM1E", "SUSR"
};
-#define UCF64_DUMP_STATE
-void cpu_dump_state(CPUUniCore32State *env, FILE *f, fprintf_function cpu_fprintf,
- int flags)
+#undef UCF64_DUMP_STATE
+#ifdef UCF64_DUMP_STATE
+static void cpu_dump_state_ucf64(CPUUniCore32State *env, FILE *f,
+ fprintf_function cpu_fprintf, int flags)
{
int i;
-#ifdef UCF64_DUMP_STATE
union {
uint32_t i;
float s;
@@ -2063,7 +2155,28 @@ void cpu_dump_state(CPUUniCore32State *env, FILE *f, fprintf_function cpu_fprint
float64 f64;
double d;
} d0;
+
+ for (i = 0; i < 16; i++) {
+ d.d = env->ucf64.regs[i];
+ s0.i = d.l.lower;
+ s1.i = d.l.upper;
+ d0.f64 = d.d;
+ cpu_fprintf(f, "s%02d=%08x(%8g) s%02d=%08x(%8g)",
+ i * 2, (int)s0.i, s0.s,
+ i * 2 + 1, (int)s1.i, s1.s);
+ cpu_fprintf(f, " d%02d=%" PRIx64 "(%8g)\n",
+ i, (uint64_t)d0.f64, d0.d);
+ }
+ cpu_fprintf(f, "FPSCR: %08x\n", (int)env->ucf64.xregs[UC32_UCF64_FPSCR]);
+}
+#else
+#define cpu_dump_state_ucf64(env, file, pr, flags) do { } while (0)
#endif
+
+void cpu_dump_state(CPUUniCore32State *env, FILE *f,
+ fprintf_function cpu_fprintf, int flags)
+{
+ int i;
uint32_t psr;
for (i = 0; i < 32; i++) {
@@ -2083,19 +2196,7 @@ void cpu_dump_state(CPUUniCore32State *env, FILE *f, fprintf_function cpu_fprint
psr & (1 << 28) ? 'V' : '-',
cpu_mode_names[psr & 0xf]);
-#ifdef UCF64_DUMP_STATE
- for (i = 0; i < 16; i++) {
- d.d = env->ucf64.regs[i];
- s0.i = d.l.lower;
- s1.i = d.l.upper;
- d0.f64 = d.d;
- cpu_fprintf(f, "s%02d=%08x(%8g) s%02d=%08x(%8g) d%02d=%" PRIx64 "(%8g)\n",
- i * 2, (int)s0.i, s0.s,
- i * 2 + 1, (int)s1.i, s1.s,
- i, (uint64_t)d0.f64, d0.d);
- }
- cpu_fprintf(f, "FPSCR: %08x\n", (int)env->ucf64.xregs[UC32_UCF64_FPSCR]);
-#endif
+ cpu_dump_state_ucf64(env, f, cpu_fprintf, flags);
}
void restore_state_to_opc(CPUUniCore32State *env, TranslationBlock *tb, int pc_pos)
diff --git a/target-unicore32/ucf64_helper.c b/target-unicore32/ucf64_helper.c
new file mode 100644
index 0000000000..a516edd319
--- /dev/null
+++ b/target-unicore32/ucf64_helper.c
@@ -0,0 +1,345 @@
+/*
+ * UniCore-F64 simulation helpers for QEMU.
+ *
+ * Copyright (C) 2010-2012 Guan Xuetao
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation, or any later version.
+ * See the COPYING file in the top-level directory.
+ */
+#include "cpu.h"
+#include "helper.h"
+
+/*
+ * The convention used for UniCore-F64 instructions:
+ * Single precition routines have a "s" suffix
+ * Double precision routines have a "d" suffix.
+ */
+
+/* Convert host exception flags to f64 form. */
+static inline int ucf64_exceptbits_from_host(int host_bits)
+{
+ int target_bits = 0;
+
+ if (host_bits & float_flag_invalid) {
+ target_bits |= UCF64_FPSCR_FLAG_INVALID;
+ }
+ if (host_bits & float_flag_divbyzero) {
+ target_bits |= UCF64_FPSCR_FLAG_DIVZERO;
+ }
+ if (host_bits & float_flag_overflow) {
+ target_bits |= UCF64_FPSCR_FLAG_OVERFLOW;
+ }
+ if (host_bits & float_flag_underflow) {
+ target_bits |= UCF64_FPSCR_FLAG_UNDERFLOW;
+ }
+ if (host_bits & float_flag_inexact) {
+ target_bits |= UCF64_FPSCR_FLAG_INEXACT;
+ }
+ return target_bits;
+}
+
+uint32_t HELPER(ucf64_get_fpscr)(CPUUniCore32State *env)
+{
+ int i;
+ uint32_t fpscr;
+
+ fpscr = (env->ucf64.xregs[UC32_UCF64_FPSCR] & UCF64_FPSCR_MASK);
+ i = get_float_exception_flags(&env->ucf64.fp_status);
+ fpscr |= ucf64_exceptbits_from_host(i);
+ return fpscr;
+}
+
+/* Convert ucf64 exception flags to target form. */
+static inline int ucf64_exceptbits_to_host(int target_bits)
+{
+ int host_bits = 0;
+
+ if (target_bits & UCF64_FPSCR_FLAG_INVALID) {
+ host_bits |= float_flag_invalid;
+ }
+ if (target_bits & UCF64_FPSCR_FLAG_DIVZERO) {
+ host_bits |= float_flag_divbyzero;
+ }
+ if (target_bits & UCF64_FPSCR_FLAG_OVERFLOW) {
+ host_bits |= float_flag_overflow;
+ }
+ if (target_bits & UCF64_FPSCR_FLAG_UNDERFLOW) {
+ host_bits |= float_flag_underflow;
+ }
+ if (target_bits & UCF64_FPSCR_FLAG_INEXACT) {
+ host_bits |= float_flag_inexact;
+ }
+ return host_bits;
+}
+
+void HELPER(ucf64_set_fpscr)(CPUUniCore32State *env, uint32_t val)
+{
+ int i;
+ uint32_t changed;
+
+ changed = env->ucf64.xregs[UC32_UCF64_FPSCR];
+ env->ucf64.xregs[UC32_UCF64_FPSCR] = (val & UCF64_FPSCR_MASK);
+
+ changed ^= val;
+ if (changed & (UCF64_FPSCR_RND_MASK)) {
+ i = UCF64_FPSCR_RND(val);
+ switch (i) {
+ case 0:
+ i = float_round_nearest_even;
+ break;
+ case 1:
+ i = float_round_to_zero;
+ break;
+ case 2:
+ i = float_round_up;
+ break;
+ case 3:
+ i = float_round_down;
+ break;
+ default: /* 100 and 101 not implement */
+ cpu_abort(env, "Unsupported UniCore-F64 round mode");
+ }
+ set_float_rounding_mode(i, &env->ucf64.fp_status);
+ }
+
+ i = ucf64_exceptbits_to_host(UCF64_FPSCR_TRAPEN(val));
+ set_float_exception_flags(i, &env->ucf64.fp_status);
+}
+
+float32 HELPER(ucf64_adds)(float32 a, float32 b, CPUUniCore32State *env)
+{
+ return float32_add(a, b, &env->ucf64.fp_status);
+}
+
+float64 HELPER(ucf64_addd)(float64 a, float64 b, CPUUniCore32State *env)
+{
+ return float64_add(a, b, &env->ucf64.fp_status);
+}
+
+float32 HELPER(ucf64_subs)(float32 a, float32 b, CPUUniCore32State *env)
+{
+ return float32_sub(a, b, &env->ucf64.fp_status);
+}
+
+float64 HELPER(ucf64_subd)(float64 a, float64 b, CPUUniCore32State *env)
+{
+ return float64_sub(a, b, &env->ucf64.fp_status);
+}
+
+float32 HELPER(ucf64_muls)(float32 a, float32 b, CPUUniCore32State *env)
+{
+ return float32_mul(a, b, &env->ucf64.fp_status);
+}
+
+float64 HELPER(ucf64_muld)(float64 a, float64 b, CPUUniCore32State *env)
+{
+ return float64_mul(a, b, &env->ucf64.fp_status);
+}
+
+float32 HELPER(ucf64_divs)(float32 a, float32 b, CPUUniCore32State *env)
+{
+ return float32_div(a, b, &env->ucf64.fp_status);
+}
+
+float64 HELPER(ucf64_divd)(float64 a, float64 b, CPUUniCore32State *env)
+{
+ return float64_div(a, b, &env->ucf64.fp_status);
+}
+
+float32 HELPER(ucf64_negs)(float32 a)
+{
+ return float32_chs(a);
+}
+
+float64 HELPER(ucf64_negd)(float64 a)
+{
+ return float64_chs(a);
+}
+
+float32 HELPER(ucf64_abss)(float32 a)
+{
+ return float32_abs(a);
+}
+
+float64 HELPER(ucf64_absd)(float64 a)
+{
+ return float64_abs(a);
+}
+
+void HELPER(ucf64_cmps)(float32 a, float32 b, uint32_t c,
+ CPUUniCore32State *env)
+{
+ int flag;
+ flag = float32_compare_quiet(a, b, &env->ucf64.fp_status);
+ env->CF = 0;
+ switch (c & 0x7) {
+ case 0: /* F */
+ break;
+ case 1: /* UN */
+ if (flag == 2) {
+ env->CF = 1;
+ }
+ break;
+ case 2: /* EQ */
+ if (flag == 0) {
+ env->CF = 1;
+ }
+ break;
+ case 3: /* UEQ */
+ if ((flag == 0) || (flag == 2)) {
+ env->CF = 1;
+ }
+ break;
+ case 4: /* OLT */
+ if (flag == -1) {
+ env->CF = 1;
+ }
+ break;
+ case 5: /* ULT */
+ if ((flag == -1) || (flag == 2)) {
+ env->CF = 1;
+ }
+ break;
+ case 6: /* OLE */
+ if ((flag == -1) || (flag == 0)) {
+ env->CF = 1;
+ }
+ break;
+ case 7: /* ULE */
+ if (flag != 1) {
+ env->CF = 1;
+ }
+ break;
+ }
+ env->ucf64.xregs[UC32_UCF64_FPSCR] = (env->CF << 29)
+ | (env->ucf64.xregs[UC32_UCF64_FPSCR] & 0x0fffffff);
+}
+
+void HELPER(ucf64_cmpd)(float64 a, float64 b, uint32_t c,
+ CPUUniCore32State *env)
+{
+ int flag;
+ flag = float64_compare_quiet(a, b, &env->ucf64.fp_status);
+ env->CF = 0;
+ switch (c & 0x7) {
+ case 0: /* F */
+ break;
+ case 1: /* UN */
+ if (flag == 2) {
+ env->CF = 1;
+ }
+ break;
+ case 2: /* EQ */
+ if (flag == 0) {
+ env->CF = 1;
+ }
+ break;
+ case 3: /* UEQ */
+ if ((flag == 0) || (flag == 2)) {
+ env->CF = 1;
+ }
+ break;
+ case 4: /* OLT */
+ if (flag == -1) {
+ env->CF = 1;
+ }
+ break;
+ case 5: /* ULT */
+ if ((flag == -1) || (flag == 2)) {
+ env->CF = 1;
+ }
+ break;
+ case 6: /* OLE */
+ if ((flag == -1) || (flag == 0)) {
+ env->CF = 1;
+ }
+ break;
+ case 7: /* ULE */
+ if (flag != 1) {
+ env->CF = 1;
+ }
+ break;
+ }
+ env->ucf64.xregs[UC32_UCF64_FPSCR] = (env->CF << 29)
+ | (env->ucf64.xregs[UC32_UCF64_FPSCR] & 0x0fffffff);
+}
+
+/* Helper routines to perform bitwise copies between float and int. */
+static inline float32 ucf64_itos(uint32_t i)
+{
+ union {
+ uint32_t i;
+ float32 s;
+ } v;
+
+ v.i = i;
+ return v.s;
+}
+
+static inline uint32_t ucf64_stoi(float32 s)
+{
+ union {
+ uint32_t i;
+ float32 s;
+ } v;
+
+ v.s = s;
+ return v.i;
+}
+
+static inline float64 ucf64_itod(uint64_t i)
+{
+ union {
+ uint64_t i;
+ float64 d;
+ } v;
+
+ v.i = i;
+ return v.d;
+}
+
+static inline uint64_t ucf64_dtoi(float64 d)
+{
+ union {
+ uint64_t i;
+ float64 d;
+ } v;
+
+ v.d = d;
+ return v.i;
+}
+
+/* Integer to float conversion. */
+float32 HELPER(ucf64_si2sf)(float32 x, CPUUniCore32State *env)
+{
+ return int32_to_float32(ucf64_stoi(x), &env->ucf64.fp_status);
+}
+
+float64 HELPER(ucf64_si2df)(float32 x, CPUUniCore32State *env)
+{
+ return int32_to_float64(ucf64_stoi(x), &env->ucf64.fp_status);
+}
+
+/* Float to integer conversion. */
+float32 HELPER(ucf64_sf2si)(float32 x, CPUUniCore32State *env)
+{
+ return ucf64_itos(float32_to_int32(x, &env->ucf64.fp_status));
+}
+
+float32 HELPER(ucf64_df2si)(float64 x, CPUUniCore32State *env)
+{
+ return ucf64_itos(float64_to_int32(x, &env->ucf64.fp_status));
+}
+
+/* floating point conversion */
+float64 HELPER(ucf64_sf2df)(float32 x, CPUUniCore32State *env)
+{
+ return float32_to_float64(x, &env->ucf64.fp_status);
+}
+
+float32 HELPER(ucf64_df2sf)(float64 x, CPUUniCore32State *env)
+{
+ return float64_to_float32(x, &env->ucf64.fp_status);
+}
diff --git a/target-xtensa/cpu.h b/target-xtensa/cpu.h
index f7db116400..177094ae9a 100644
--- a/target-xtensa/cpu.h
+++ b/target-xtensa/cpu.h
@@ -351,6 +351,12 @@ typedef struct CPUXtensaState {
#define cpu_signal_handler cpu_xtensa_signal_handler
#define cpu_list xtensa_cpu_list
+#ifdef TARGET_WORDS_BIGENDIAN
+#define XTENSA_DEFAULT_CPU_MODEL "fsf"
+#else
+#define XTENSA_DEFAULT_CPU_MODEL "dc232b"
+#endif
+
XtensaCPU *cpu_xtensa_init(const char *cpu_model);
static inline CPUXtensaState *cpu_init(const char *cpu_model)
diff --git a/target-xtensa/helper.c b/target-xtensa/helper.c
index 044ce18364..d5bb171fcd 100644
--- a/target-xtensa/helper.c
+++ b/target-xtensa/helper.c
@@ -54,8 +54,6 @@ static uint32_t check_hw_breakpoints(CPUXtensaState *env)
return 0;
}
-static CPUDebugExcpHandler *prev_debug_excp_handler;
-
static void breakpoint_handler(CPUXtensaState *env)
{
if (env->watchpoint_hit) {
@@ -70,9 +68,6 @@ static void breakpoint_handler(CPUXtensaState *env)
cpu_resume_from_signal(env, NULL);
}
}
- if (prev_debug_excp_handler) {
- prev_debug_excp_handler(env);
- }
}
XtensaCPU *cpu_xtensa_init(const char *cpu_model)
@@ -105,8 +100,7 @@ XtensaCPU *cpu_xtensa_init(const char *cpu_model)
if (!debug_handler_inited && tcg_enabled()) {
debug_handler_inited = 1;
- prev_debug_excp_handler =
- cpu_set_debug_excp_handler(breakpoint_handler);
+ cpu_set_debug_excp_handler(breakpoint_handler);
}
xtensa_irq_init(env);
diff --git a/tests/qemu-iotests/039 b/tests/qemu-iotests/039
index a749fcf23b..c5ae806ecb 100755
--- a/tests/qemu-iotests/039
+++ b/tests/qemu-iotests/039
@@ -44,6 +44,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
_supported_fmt qcow2
_supported_proto generic
_supported_os Linux
+_unsupported_qemu_io_options --nocache
size=128M
diff --git a/tests/qemu-iotests/039.out b/tests/qemu-iotests/039.out
index 155a05e109..cb510d6716 100644
--- a/tests/qemu-iotests/039.out
+++ b/tests/qemu-iotests/039.out
@@ -26,6 +26,12 @@ incompatible_features 0x1
== Repairing the image file must succeed ==
ERROR OFLAG_COPIED: offset=8000000000050000 refcount=0
Repairing cluster 5 refcount=0 reference=1
+The following inconsistencies were found and repaired:
+
+ 0 leaked clusters
+ 1 corruptions
+
+Double checking the fixed image now...
No errors were found on the image.
incompatible_features 0x0
diff --git a/tests/qemu-iotests/common.rc b/tests/qemu-iotests/common.rc
index 7782808a26..d534e9466d 100644
--- a/tests/qemu-iotests/common.rc
+++ b/tests/qemu-iotests/common.rc
@@ -105,16 +105,16 @@ _make_test_img()
# XXX(hch): have global image options?
$QEMU_IMG create -f $IMGFMT $extra_img_options $TEST_IMG $image_size | \
- sed -e "s#$IMGPROTO:$TEST_DIR#TEST_DIR#g" | \
- sed -e "s#$TEST_DIR#TEST_DIR#g" | \
- sed -e "s#$IMGFMT#IMGFMT#g" | \
- sed -e "s# encryption=off##g" | \
- sed -e "s# cluster_size=[0-9]\\+##g" | \
- sed -e "s# table_size=[0-9]\\+##g" | \
- sed -e "s# compat='[^']*'##g" | \
- sed -e "s# compat6=\\(on\\|off\\)##g" | \
- sed -e "s# static=\\(on\\|off\\)##g" | \
- sed -e "s# lazy_refcounts=\\(on\\|off\\)##g"
+ sed -e "s#$IMGPROTO:$TEST_DIR#TEST_DIR#g" \
+ -e "s#$TEST_DIR#TEST_DIR#g" \
+ -e "s#$IMGFMT#IMGFMT#g" \
+ -e "s# encryption=off##g" \
+ -e "s# cluster_size=[0-9]\\+##g" \
+ -e "s# table_size=[0-9]\\+##g" \
+ -e "s# compat='[^']*'##g" \
+ -e "s# compat6=\\(on\\|off\\)##g" \
+ -e "s# static=\\(on\\|off\\)##g" \
+ -e "s# lazy_refcounts=\\(on\\|off\\)##g"
}
_cleanup_test_img()
@@ -297,6 +297,20 @@ _supported_os()
_notrun "not suitable for this OS: $HOSTOS"
}
+_unsupported_qemu_io_options()
+{
+ for bad_opt
+ do
+ for opt in $QEMU_IO_OPTIONS
+ do
+ if [ "$bad_opt" = "$opt" ]
+ then
+ _notrun "not suitable for qemu-io option: $bad_opt"
+ fi
+ done
+ done
+}
+
# this test requires that a specified command (executable) exists
#
_require_command()
diff --git a/user-exec.c b/user-exec.c
index 1a9c276eb3..b9ea9dd32f 100644
--- a/user-exec.c
+++ b/user-exec.c
@@ -18,7 +18,9 @@
*/
#include "config.h"
#include "cpu.h"
+#ifndef CONFIG_TCG_PASS_AREG0
#include "dyngen-exec.h"
+#endif
#include "disas.h"
#include "tcg.h"
@@ -58,9 +60,11 @@ void cpu_resume_from_signal(CPUArchState *env1, void *puc)
struct sigcontext *uc = puc;
#endif
+#ifndef CONFIG_TCG_PASS_AREG0
env = env1;
/* XXX: restore cpu registers saved in host registers */
+#endif
if (puc) {
/* XXX: use siglongjmp ? */
@@ -74,8 +78,8 @@ void cpu_resume_from_signal(CPUArchState *env1, void *puc)
sigprocmask(SIG_SETMASK, &uc->sc_mask, NULL);
#endif
}
- env->exception_index = -1;
- longjmp(env->jmp_env, 1);
+ env1->exception_index = -1;
+ longjmp(env1->jmp_env, 1);
}
/* 'pc' is the host PC at which the exception was raised. 'address' is
@@ -89,9 +93,11 @@ static inline int handle_cpu_signal(uintptr_t pc, unsigned long address,
TranslationBlock *tb;
int ret;
+#ifndef CONFIG_TCG_PASS_AREG0
if (cpu_single_env) {
env = cpu_single_env; /* XXX: find a correct solution for multithread */
}
+#endif
#if defined(DEBUG_SIGNAL)
qemu_printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
pc, address, is_write, *(unsigned long *)old_set);
@@ -103,7 +109,8 @@ static inline int handle_cpu_signal(uintptr_t pc, unsigned long address,
}
/* see if it is an MMU fault */
- ret = cpu_handle_mmu_fault(env, address, is_write, MMU_USER_IDX);
+ ret = cpu_handle_mmu_fault(cpu_single_env, address, is_write,
+ MMU_USER_IDX);
if (ret < 0) {
return 0; /* not an MMU fault */
}
@@ -115,13 +122,13 @@ static inline int handle_cpu_signal(uintptr_t pc, unsigned long address,
if (tb) {
/* the PC is inside the translated code. It means that we have
a virtual CPU fault */
- cpu_restore_state(tb, env, pc);
+ cpu_restore_state(tb, cpu_single_env, pc);
}
/* we restore the process signal mask as the sigreturn should
do it (XXX: use sigsetjmp) */
sigprocmask(SIG_SETMASK, old_set, NULL);
- exception_action(env);
+ exception_action(cpu_single_env);
/* never comes here */
return 1;
diff --git a/vl.c b/vl.c
index e71cb30ecf..91076f0e7c 100644
--- a/vl.c
+++ b/vl.c
@@ -293,6 +293,11 @@ static struct {
{ .driver = "qxl-vga", .flag = &default_vga },
};
+const char *qemu_get_vm_name(void)
+{
+ return qemu_name;
+}
+
static void res_free(void)
{
if (boot_splash_filedata != NULL) {
@@ -3204,6 +3209,11 @@ int main(int argc, char **argv, char **envp)
}
loc_set_none();
+ if (machine == NULL) {
+ fprintf(stderr, "No machine found.\n");
+ exit(1);
+ }
+
if (machine->hw_version) {
qemu_set_version(machine->hw_version);
}
@@ -3246,11 +3256,6 @@ int main(int argc, char **argv, char **envp)
data_dir = CONFIG_QEMU_DATADIR;
}
- if (machine == NULL) {
- fprintf(stderr, "No machine found.\n");
- exit(1);
- }
-
/*
* Default to max_cpus = smp_cpus, in case the user doesn't
* specify a max_cpus value.
@@ -3345,6 +3350,11 @@ int main(int argc, char **argv, char **envp)
ram_size = DEFAULT_RAM_SIZE * 1024 * 1024;
}
+ if (qemu_opts_foreach(qemu_find_opts("device"), device_help_func, NULL, 0)
+ != 0) {
+ exit(0);
+ }
+
configure_accelerator();
qemu_init_cpu_loop();
@@ -3500,9 +3510,6 @@ int main(int argc, char **argv, char **envp)
}
select_vgahw(vga_model);
- if (qemu_opts_foreach(qemu_find_opts("device"), device_help_func, NULL, 0) != 0)
- exit(0);
-
if (watchdog) {
i = select_watchdog(watchdog);
if (i > 0)