summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--Makefile9
-rw-r--r--Makefile.target11
-rw-r--r--audio/dsoundaudio.c1
-rw-r--r--block-qcow.c4
-rw-r--r--block-qcow2.c2
-rw-r--r--block-raw-posix.c2
-rw-r--r--block-vvfat.c9
-rw-r--r--block.c9
-rw-r--r--block_int.h5
-rwxr-xr-xconfigure57
-rw-r--r--cpu-all.h4
-rw-r--r--cpu-defs.h5
-rw-r--r--cpu-exec.c17
-rw-r--r--exec.c43
-rw-r--r--hw/ac97.c2
-rw-r--r--hw/acpi.c2
-rw-r--r--hw/apb_pci.c2
-rw-r--r--hw/cirrus_vga.c41
-rw-r--r--hw/etraxfs_dma.c6
-rw-r--r--hw/etraxfs_pic.c97
-rw-r--r--hw/etraxfs_ser.c167
-rw-r--r--hw/etraxfs_timer.c5
-rw-r--r--hw/grackle_pci.c4
-rw-r--r--hw/ide.c8
-rw-r--r--hw/mac_dbdma.c4
-rw-r--r--hw/macio.c2
-rw-r--r--hw/mc146818rtc.c62
-rw-r--r--hw/ne2000.c2
-rw-r--r--hw/openpic.c2
-rw-r--r--hw/pc.c6
-rw-r--r--hw/pci.c4
-rw-r--r--hw/pci.h4
-rw-r--r--hw/pcnet.c2
-rw-r--r--hw/piix_pci.c9
-rw-r--r--hw/prep_pci.c2
-rw-r--r--hw/rtl8139.c2
-rw-r--r--hw/sd.c14
-rw-r--r--hw/sun4u.c2
-rw-r--r--hw/tcx.c8
-rw-r--r--hw/unin_pci.c8
-rw-r--r--hw/usb-uhci.c4
-rw-r--r--hw/vga.c10
-rw-r--r--hw/virtio-blk.c123
-rw-r--r--hw/virtio-blk.h14
-rw-r--r--hw/virtio.c2
-rw-r--r--hw/vmware_vga.c4
-rw-r--r--hw/watchdog.c136
-rw-r--r--hw/watchdog.h65
-rw-r--r--hw/wdt_i6300esb.c470
-rw-r--r--hw/wdt_ib700.c112
-rw-r--r--hw/xen_blkif.h4
-rw-r--r--hw/xen_console.c2
-rw-r--r--hw/xen_disk.c22
-rw-r--r--hw/xen_domainbuild.c4
-rw-r--r--hw/xenfb.c2
-rw-r--r--kvm-all.c28
-rw-r--r--kvm.h2
-rw-r--r--linux-user/arm/nwfpe/fpa11.c5
-rw-r--r--linux-user/arm/nwfpe/fpa11.h9
-rw-r--r--linux-user/arm/nwfpe/fpa11_cpdo.c4
-rw-r--r--linux-user/arm/nwfpe/fpa11_cpdt.c80
-rw-r--r--linux-user/arm/nwfpe/fpopcode.c35
-rw-r--r--monitor.c12
-rw-r--r--net.c30
-rw-r--r--qemu-common.h13
-rw-r--r--qemu-io.c51
-rw-r--r--qemu-kvm.c19
-rw-r--r--qemu-kvm.h3
-rw-r--r--qemu-options.hx51
-rw-r--r--qemu-thread.c163
-rw-r--r--qemu-thread.h40
-rw-r--r--sysemu.h3
-rw-r--r--target-alpha/exec.h7
-rw-r--r--target-alpha/translate.c1
-rw-r--r--target-arm/exec.h9
-rw-r--r--target-arm/helper.c1
-rw-r--r--target-cris/exec.h5
-rw-r--r--target-cris/helper.c4
-rw-r--r--target-cris/mmu.c4
-rw-r--r--target-cris/mmu.h4
-rw-r--r--target-cris/translate.c1
-rw-r--r--target-i386/exec.h15
-rw-r--r--target-i386/helper.c5
-rw-r--r--target-i386/op_helper.c87
-rw-r--r--target-m68k/exec.h7
-rw-r--r--target-m68k/helper.c1
-rw-r--r--target-mips/exec.h10
-rw-r--r--target-mips/translate.c6
-rw-r--r--target-ppc/cpu.h3
-rw-r--r--target-ppc/exec.h8
-rw-r--r--target-ppc/helper.c4
-rw-r--r--target-ppc/machine.c2
-rw-r--r--target-ppc/translate_init.c45
-rw-r--r--target-sh4/exec.h7
-rw-r--r--target-sh4/translate.c1
-rw-r--r--target-sparc/exec.h9
-rw-r--r--target-sparc/helper.c14
-rw-r--r--target-sparc/op_helper.c99
-rw-r--r--target-sparc/translate.c1062
-rw-r--r--vl.c1050
-rw-r--r--vnc.c37
102 files changed, 3347 insertions, 1329 deletions
diff --git a/.gitignore b/.gitignore
index 95a2971ea..f38bb3020 100644
--- a/.gitignore
+++ b/.gitignore
@@ -16,6 +16,7 @@ qemu-img
qemu-nbd
qemu-nbd.8
qemu-nbd.pod
+qemu-options.texi
qemu-io
.gdbinit
*.a
diff --git a/Makefile b/Makefile
index 6ce206a7c..8e4906fb8 100644
--- a/Makefile
+++ b/Makefile
@@ -30,7 +30,8 @@ else
DOCS=
endif
-LIBS+=$(AIOLIBS)
+LIBS+=$(PTHREADLIBS)
+LIBS+=$(CLOCKLIBS)
ifdef CONFIG_SOLARIS
LIBS+=-lsocket -lnsl -lresolv
@@ -61,7 +62,7 @@ recurse-all: $(SUBDIR_RULES)
#######################################################################
# BLOCK_OBJS is code used by both qemu system emulation and qemu-img
-BLOCK_OBJS=cutils.o qemu-malloc.o
+BLOCK_OBJS=cutils.o cache-utils.o qemu-malloc.o
BLOCK_OBJS+=block-cow.o block-qcow.o aes.o block-vmdk.o block-cloop.o
BLOCK_OBJS+=block-dmg.o block-bochs.o block-vpc.o block-vvfat.o
BLOCK_OBJS+=block-qcow2.o block-parallels.o block-nbd.o
@@ -174,6 +175,10 @@ ifdef CONFIG_COCOA
OBJS+=cocoa.o
endif
+ifdef CONFIG_IOTHREAD
+OBJS+=qemu-thread.o
+endif
+
ifdef CONFIG_SLIRP
CPPFLAGS+=-I$(SRC_PATH)/slirp
SLIRP_OBJS=cksum.o if.o ip_icmp.o ip_input.o ip_output.o \
diff --git a/Makefile.target b/Makefile.target
index 5cb4c6426..b68a68981 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -371,7 +371,8 @@ endif
OBJS= main.o syscall.o strace.o mmap.o signal.o path.o thunk.o \
elfload.o linuxload.o uaccess.o envlist.o
-LIBS+= $(AIOLIBS)
+LIBS+= $(PTHREADLIBS)
+LIBS+= $(CLOCKLIBS)
ifdef TARGET_HAS_BFLT
OBJS+= flatload.o
endif
@@ -642,8 +643,9 @@ OBJS += pcnet.o
OBJS += rtl8139.o
OBJS += e1000.o
-# Serial mouse
-OBJS += msmouse.o
+# Generic watchdog support and some watchdog devices
+OBJS += watchdog.o
+OBJS += wdt_ib700.o wdt_i6300esb.o
ifeq ($(USE_KVM_DEVICE_ASSIGNMENT), 1)
OBJS+= device-assignment.o
@@ -778,7 +780,8 @@ ifdef CONFIG_SLIRP
CPPFLAGS+=-I$(SRC_PATH)/slirp
endif
-LIBS+=$(AIOLIBS)
+LIBS+=$(PTHREADLIBS)
+LIBS+=$(CLOCKLIBS)
# specific flags are needed for non soft mmu emulator
ifdef CONFIG_STATIC
LDFLAGS+=-static
diff --git a/audio/dsoundaudio.c b/audio/dsoundaudio.c
index df4b2f04d..a78c8567d 100644
--- a/audio/dsoundaudio.c
+++ b/audio/dsoundaudio.c
@@ -32,7 +32,6 @@
#define AUDIO_CAP "dsound"
#include "audio_int.h"
-#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <mmsystem.h>
#include <objbase.h>
diff --git a/block-qcow.c b/block-qcow.c
index b66ade35a..fc6b80971 100644
--- a/block-qcow.c
+++ b/block-qcow.c
@@ -641,7 +641,7 @@ static BlockDriverAIOCB *qcow_aio_readv(BlockDriverState *bs,
acb->sector_num = sector_num;
acb->qiov = qiov;
if (qiov->niov > 1)
- acb->buf = acb->orig_buf = qemu_memalign(512, qiov->size);
+ acb->buf = acb->orig_buf = qemu_blockalign(bs, qiov->size);
else
acb->buf = (uint8_t *)qiov->iov->iov_base;
acb->nb_sectors = nb_sectors;
@@ -736,7 +736,7 @@ static BlockDriverAIOCB *qcow_aio_writev(BlockDriverState *bs,
acb->sector_num = sector_num;
acb->qiov = qiov;
if (qiov->niov > 1) {
- acb->buf = acb->orig_buf = qemu_memalign(512, qiov->size);
+ acb->buf = acb->orig_buf = qemu_blockalign(bs, qiov->size);
qemu_iovec_to_buffer(qiov, acb->buf);
} else {
acb->buf = (uint8_t *)qiov->iov->iov_base;
diff --git a/block-qcow2.c b/block-qcow2.c
index 7840634b5..1f3312590 100644
--- a/block-qcow2.c
+++ b/block-qcow2.c
@@ -1412,7 +1412,7 @@ static QCowAIOCB *qcow_aio_setup(BlockDriverState *bs,
acb->sector_num = sector_num;
acb->qiov = qiov;
if (qiov->niov > 1) {
- acb->buf = acb->orig_buf = qemu_memalign(512, qiov->size);
+ acb->buf = acb->orig_buf = qemu_blockalign(bs, qiov->size);
if (is_write)
qemu_iovec_to_buffer(qiov, acb->buf);
} else {
diff --git a/block-raw-posix.c b/block-raw-posix.c
index f033baee5..650e2912d 100644
--- a/block-raw-posix.c
+++ b/block-raw-posix.c
@@ -166,7 +166,7 @@ static int raw_open(BlockDriverState *bs, const char *filename, int flags)
s->fd = fd;
s->aligned_buf = NULL;
if ((flags & BDRV_O_NOCACHE)) {
- s->aligned_buf = qemu_memalign(512, ALIGNED_BUFFER_SIZE);
+ s->aligned_buf = qemu_blockalign(bs, ALIGNED_BUFFER_SIZE);
if (s->aligned_buf == NULL) {
ret = -errno;
close(fd);
diff --git a/block-vvfat.c b/block-vvfat.c
index 429c37c5e..79059311c 100644
--- a/block-vvfat.c
+++ b/block-vvfat.c
@@ -509,9 +509,12 @@ static inline uint8_t fat_chksum(const direntry_t* entry)
uint8_t chksum=0;
int i;
- for(i=0;i<11;i++)
- chksum=(((chksum&0xfe)>>1)|((chksum&0x01)?0x80:0))
- +(unsigned char)entry->name[i];
+ for(i=0;i<11;i++) {
+ unsigned char c;
+
+ c = (i <= 8) ? entry->name[i] : entry->extension[i-8];
+ chksum=(((chksum&0xfe)>>1)|((chksum&0x01)?0x80:0)) + c;
+ }
return chksum;
}
diff --git a/block.c b/block.c
index 8348cf211..3d1223d5e 100644
--- a/block.c
+++ b/block.c
@@ -362,6 +362,8 @@ int bdrv_open2(BlockDriverState *bs, const char *filename, int flags,
bs->is_temporary = 0;
bs->encrypted = 0;
bs->valid_key = 0;
+ /* buffer_alignment defaulted to 512, drivers can change this value */
+ bs->buffer_alignment = 512;
if (flags & BDRV_O_SNAPSHOT) {
BlockDriverState *bs1;
@@ -1390,7 +1392,7 @@ static BlockDriverAIOCB *bdrv_aio_rw_vector(BlockDriverState *bs,
acb = qemu_aio_get(bs, cb, opaque);
acb->is_write = is_write;
acb->qiov = qiov;
- acb->bounce = qemu_memalign(512, qiov->size);
+ acb->bounce = qemu_blockalign(bs, qiov->size);
if (!acb->bh)
acb->bh = qemu_bh_new(bdrv_aio_bh_cb, acb);
@@ -1640,3 +1642,8 @@ BlockDriverAIOCB *bdrv_aio_ioctl(BlockDriverState *bs,
return drv->bdrv_aio_ioctl(bs, req, buf, cb, opaque);
return NULL;
}
+
+void *qemu_blockalign(BlockDriverState *bs, size_t size)
+{
+ return qemu_memalign((bs && bs->buffer_alignment) ? bs->buffer_alignment : 512, size);
+}
diff --git a/block_int.h b/block_int.h
index e10b9069f..9d119404c 100644
--- a/block_int.h
+++ b/block_int.h
@@ -145,6 +145,9 @@ struct BlockDriverState {
/* Whether the disk can expand beyond total_sectors */
int growable;
+ /* the memory alignment required for the buffers handled by this driver */
+ int buffer_alignment;
+
/* NOTE: the following infos are only hints for real hardware
drivers. They are not used by the block driver */
int cyls, heads, secs, translation;
@@ -173,6 +176,8 @@ void *qemu_aio_get_pool(AIOPool *pool, BlockDriverState *bs,
BlockDriverCompletionFunc *cb, void *opaque);
void qemu_aio_release(void *p);
+void *qemu_blockalign(BlockDriverState *bs, size_t size);
+
extern BlockDriverState *bdrv_first;
#endif /* BLOCK_INT_H */
diff --git a/configure b/configure
index f16daea22..28e094482 100755
--- a/configure
+++ b/configure
@@ -192,7 +192,9 @@ bsd_user="no"
build_docs="no"
uname_release=""
curses="yes"
+pthread="yes"
aio="yes"
+io_thread="no"
nptl="yes"
mixemu="no"
bluez="yes"
@@ -509,8 +511,12 @@ for opt do
;;
--enable-mixemu) mixemu="yes"
;;
+ --disable-pthread) pthread="no"
+ ;;
--disable-aio) aio="no"
;;
+ --enable-io-thread) io_thread="yes"
+ ;;
--disable-blobs) blobs="no"
;;
--kerneldir=*) kerneldir="$optarg"
@@ -645,7 +651,9 @@ echo " --oss-lib path to OSS library"
echo " --enable-uname-release=R Return R for uname -r in usermode emulation"
echo " --sparc_cpu=V Build qemu for Sparc architecture v7, v8, v8plus, v8plusa, v9"
echo " --disable-vde disable support for vde network"
+echo " --disable-pthread disable pthread support"
echo " --disable-aio disable AIO support"
+echo " --enable-io-thread enable IO thread"
echo " --disable-blobs disable installing provided firmware blobs"
echo " --kerneldir=PATH look for kernel includes in PATH"
echo " --disable-cpu-emulation disables use of qemu cpu emulation code"
@@ -918,7 +926,7 @@ cat > $TMPC <<EOF
#include <xs.h>
int main(void) { xs_daemon_open; xc_interface_open; }
EOF
- if $cc $ARCH_CFLAGS -c -o $TMPO $TMPC -lxenstore -lxenctrl 2> /dev/null ; then
+ if $cc $ARCH_CFLAGS -c -o $TMPO $TMPC -lxenstore -lxenctrl 2> /dev/null > /dev/null ; then
:
else
xen="no"
@@ -1016,7 +1024,7 @@ EOF
vnc_sasl_cflags=""
vnc_sasl_libs="-lsasl2"
if $cc $ARCH_CFLAGS -o $TMPE ${OS_CFLAGS} $vnc_sasl_cflags $TMPC \
- $vnc_sasl_libs 2> /dev/null ; then
+ $vnc_sasl_libs 2> /dev/null > /dev/null ; then
:
else
vnc_sasl="no"
@@ -1160,15 +1168,15 @@ fi # test "$curses"
##########################################
# bluez support probe
if test "$bluez" = "yes" ; then
- `pkg-config bluez` || bluez="no"
+ `pkg-config bluez 2> /dev/null` || bluez="no"
fi
if test "$bluez" = "yes" ; then
cat > $TMPC << EOF
#include <bluetooth/bluetooth.h>
int main(void) { return bt_error(0); }
EOF
- bluez_cflags=`pkg-config --cflags bluez`
- bluez_libs=`pkg-config --libs bluez`
+ bluez_cflags=`pkg-config --cflags bluez 2> /dev/null`
+ bluez_libs=`pkg-config --libs bluez 2> /dev/null`
if $cc $ARCH_CFLAGS -o $TMPE ${OS_CFLAGS} $bluez_cflags $TMPC \
$bluez_libs > /dev/null 2> /dev/null ; then
:
@@ -1214,21 +1222,26 @@ EOF
fi
##########################################
-# AIO probe
-AIOLIBS=""
+# pthread probe
+PTHREADLIBS=""
-if test "$aio" = "yes" ; then
- aio=no
- cat > $TMPC << EOF
+if test "$pthread" = yes; then
+ pthread=no
+cat > $TMPC << EOF
#include <pthread.h>
int main(void) { pthread_mutex_t lock; return 0; }
EOF
- if $cc $ARCH_CFLAGS -o $TMPE $AIOLIBS $TMPC 2> /dev/null ; then
- aio=yes
- AIOLIBS="-lpthread"
+ if $cc $ARCH_CFLAGS -o $TMPE $PTHREADLIBS $TMPC 2> /dev/null > /dev/null ; then
+ pthread=yes
+ PTHREADLIBS="-lpthread"
fi
fi
+if test "$pthread" = no; then
+ aio=no
+ io_thread=no
+fi
+
##########################################
# iovec probe
cat > $TMPC <<EOF
@@ -1262,7 +1275,7 @@ if test "$fdt" = "yes" ; then
cat > $TMPC << EOF
int main(void) { return 0; }
EOF
- if $cc $ARCH_CFLAGS -o $TMPE ${OS_CFLAGS} $TMPC -lfdt 2> /dev/null ; then
+ if $cc $ARCH_CFLAGS -o $TMPE ${OS_CFLAGS} $TMPC -lfdt 2> /dev/null > /dev/null ; then
fdt=yes
fi
fi
@@ -1287,7 +1300,7 @@ main(void)
return (unlinkat(AT_FDCWD, "nonexistent_file", 0));
}
EOF
- if $cc $ARCH_CFLAGS -o $TMPE $TMPC 2> /dev/null ; then
+ if $cc $ARCH_CFLAGS -o $TMPE $TMPC 2> /dev/null > /dev/null ; then
atfile=yes
fi
fi
@@ -1309,7 +1322,7 @@ main(void)
return inotify_init();
}
EOF
- if $cc $ARCH_CFLAGS -o $TMPE $TMPC 2> /dev/null ; then
+ if $cc $ARCH_CFLAGS -o $TMPE $TMPC 2> /dev/null > /dev/null ; then
inotify=yes
fi
fi
@@ -1349,6 +1362,7 @@ fi
##########################################
# Do we need librt
+CLOCKLIBS=""
cat > $TMPC <<EOF
#include <signal.h>
#include <time.h>
@@ -1363,8 +1377,7 @@ elif $cc $ARCH_CFLAGS -o $TMPE $TMPC -lrt > /dev/null 2> /dev/null ; then
fi
if test "$rt" = "yes" ; then
- # Hack, we should have a general purpose LIBS for this sort of thing
- AIOLIBS="$AIOLIBS -lrt"
+ CLOCKLIBS="-lrt"
fi
if test "$mingw32" = "yes" ; then
@@ -1443,6 +1456,7 @@ echo "uname -r $uname_release"
echo "NPTL support $nptl"
echo "vde support $vde"
echo "AIO support $aio"
+echo "IO thread $io_thread"
echo "Install blobs $blobs"
echo "KVM support $kvm"
echo "fdt support $fdt"
@@ -1495,7 +1509,8 @@ echo "ARCH_LDFLAGS=$ARCH_LDFLAGS" >> $config_mak
echo "CFLAGS=$CFLAGS" >> $config_mak
echo "LDFLAGS=$LDFLAGS" >> $config_mak
echo "EXESUF=$EXESUF" >> $config_mak
-echo "AIOLIBS=$AIOLIBS" >> $config_mak
+echo "PTHREADLIBS=$PTHREADLIBS" >> $config_mak
+echo "CLOCKLIBS=$CLOCKLIBS" >> $config_mak
case "$cpu" in
i386)
echo "ARCH=i386" >> $config_mak
@@ -1758,6 +1773,10 @@ if test "$aio" = "yes" ; then
echo "#define CONFIG_AIO 1" >> $config_h
echo "CONFIG_AIO=yes" >> $config_mak
fi
+if test "$io_thread" = "yes" ; then
+ echo "CONFIG_IOTHREAD=yes" >> $config_mak
+ echo "#define CONFIG_IOTHREAD 1" >> $config_h
+fi
if test "$blobs" = "yes" ; then
echo "INSTALL_BLOBS=yes" >> $config_mak
fi
diff --git a/cpu-all.h b/cpu-all.h
index e570e03b9..d39b90f84 100644
--- a/cpu-all.h
+++ b/cpu-all.h
@@ -775,6 +775,8 @@ void cpu_reset_interrupt(CPUState *env, int mask);
void cpu_exit(CPUState *s);
+int qemu_cpu_has_work(CPUState *env);
+
/* Breakpoint/watchpoint flags */
#define BP_MEM_READ 0x01
#define BP_MEM_WRITE 0x02
@@ -916,8 +918,6 @@ int cpu_register_io_memory(int io_index,
CPUWriteMemoryFunc **mem_write,
void *opaque);
void cpu_unregister_io_memory(int table_address);
-CPUWriteMemoryFunc **cpu_get_io_memory_write(int io_index);
-CPUReadMemoryFunc **cpu_get_io_memory_read(int io_index);
void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf,
int len, int is_write);
diff --git a/cpu-defs.h b/cpu-defs.h
index 8b9c26239..376861633 100644
--- a/cpu-defs.h
+++ b/cpu-defs.h
@@ -185,6 +185,8 @@ struct KVMCPUState {
target_ulong mem_io_vaddr; /* target virtual addr at which the \
memory was accessed */ \
uint32_t halted; /* Nonzero if the CPU is in suspend state */ \
+ uint32_t stop; /* Stop request */ \
+ uint32_t stopped; /* Artificially stopped */ \
uint32_t interrupt_request; \
volatile sig_atomic_t exit_request; \
/* The meaning of the MMU modes is defined in the target code. */ \
@@ -226,6 +228,9 @@ struct KVMCPUState {
/* user data */ \
void *opaque; \
\
+ uint32_t created; \
+ struct QemuThread *thread; \
+ struct QemuCond *halt_cond; \
const char *cpu_model_str; \
struct KVMState *kvm_state; \
struct kvm_run *kvm_run; \
diff --git a/cpu-exec.c b/cpu-exec.c
index f959f4edb..777fa5fef 100644
--- a/cpu-exec.c
+++ b/cpu-exec.c
@@ -54,6 +54,11 @@ int tb_invalidated_flag;
//#define DEBUG_EXEC
//#define DEBUG_SIGNAL
+int qemu_cpu_has_work(CPUState *env)
+{
+ return cpu_has_work(env);
+}
+
void cpu_loop_exit(void)
{
/* NOTE: the register at this point must be saved by hand because
@@ -1385,12 +1390,24 @@ int cpu_signal_handler(int host_signum, void *pinfo,
if ((insn >> 30) == 3) {
switch((insn >> 19) & 0x3f) {
case 0x05: // stb
+ case 0x15: // stba
case 0x06: // sth
+ case 0x16: // stha
case 0x04: // st
+ case 0x14: // sta
case 0x07: // std
+ case 0x17: // stda
+ case 0x0e: // stx
+ case 0x1e: // stxa
case 0x24: // stf
+ case 0x34: // stfa
case 0x27: // stdf
+ case 0x37: // stdfa
+ case 0x26: // stqf
+ case 0x36: // stqfa
case 0x25: // stfsr
+ case 0x3c: // casa
+ case 0x3e: // casxa
is_write = 1;
break;
}
diff --git a/exec.c b/exec.c
index a5bca49c2..29c91fb09 100644
--- a/exec.c
+++ b/exec.c
@@ -128,7 +128,7 @@ typedef struct RAMBlock {
static RAMBlock *ram_blocks;
/* TODO: When we implement (and use) ram deallocation (e.g. for hotplug)
- then we can no longet assume contiguous ram offsets, and external uses
+ then we can no longer assume contiguous ram offsets, and external uses
of this variable will break. */
ram_addr_t last_ram_offset;
#endif
@@ -406,7 +406,7 @@ static void tlb_unprotect_code_phys(CPUState *env, ram_addr_t ram_addr,
#define DEFAULT_CODE_GEN_BUFFER_SIZE (32 * 1024 * 1024)
#if defined(CONFIG_USER_ONLY)
-/* Currently it is not recommanded to allocate big chunks of data in
+/* Currently it is not recommended to allocate big chunks of data in
user mode. It will change when a dedicated libc will be used */
#define USE_STATIC_CODE_GEN_BUFFER
#endif
@@ -431,7 +431,7 @@ static void code_gen_alloc(unsigned long tb_size)
/* in user mode, phys_ram_size is not meaningful */
code_gen_buffer_size = DEFAULT_CODE_GEN_BUFFER_SIZE;
#else
- /* XXX: needs ajustments */
+ /* XXX: needs adjustments */
code_gen_buffer_size = (unsigned long)(ram_size / 4);
#endif
}
@@ -1483,7 +1483,7 @@ void cpu_single_step(CPUState *env, int enabled)
if (kvm_enabled())
kvm_update_guest_debug(env, 0);
else {
- /* must flush all the translated code to avoid inconsistancies */
+ /* must flush all the translated code to avoid inconsistencies */
/* XXX: only flush what is necessary */
tb_flush(env);
}
@@ -1560,6 +1560,17 @@ void cpu_interrupt(CPUState *env, int mask)
if (kvm_enabled() && !qemu_kvm_irqchip_in_kernel())
kvm_update_interrupt_request(env);
+#ifndef CONFIG_USER_ONLY
+ /*
+ * If called from iothread context, wake the target cpu in
+ * case its halted.
+ */
+ if (!qemu_cpu_self(env)) {
+ qemu_cpu_kick(env);
+ return;
+ }
+#endif
+
if (use_icount) {
env->icount_decr.u16.high = 0xffff;
#ifndef CONFIG_USER_ONLY
@@ -2057,7 +2068,7 @@ int tlb_set_page_exec(CPUState *env, target_ulong vaddr,
else
iotlb |= IO_MEM_ROM;
} else {
- /* IO handlers are currently passed a phsical address.
+ /* IO handlers are currently passed a physical address.
It would be nice to pass an offset from the base address
of that region. This would avoid having to special case RAM,
and avoid full address decoding in every device.
@@ -2186,7 +2197,7 @@ int page_get_flags(target_ulong address)
}
/* modify the flags of a page and invalidate the code if
- necessary. The flag PAGE_WRITE_ORG is positionned automatically
+ necessary. The flag PAGE_WRITE_ORG is positioned automatically
depending on PAGE_WRITE */
void page_set_flags(target_ulong start, target_ulong end, int flags)
{
@@ -2253,7 +2264,7 @@ int page_check_range(target_ulong start, target_ulong len, int flags)
}
/* called from signal handler: invalidate the code and unprotect the
- page. Return TRUE if the fault was succesfully handled. */
+ page. Return TRUE if the fault was successfully handled. */
int page_unprotect(target_ulong address, unsigned long pc, void *puc)
{
unsigned int page_index, prot, pindex;
@@ -2337,7 +2348,7 @@ static void *subpage_init (target_phys_addr_t base, ram_addr_t *phys,
page size. If (phys_offset & ~TARGET_PAGE_MASK) != 0, then it is an
io memory page. The address used when calling the IO function is
the offset from the start of the region, plus region_offset. Both
- start_region and regon_offset are rounded down to a page boundary
+ start_addr and region_offset are rounded down to a page boundary
before calculating this offset. This should not be a problem unless
the low bits of start_addr and region_offset differ. */
void cpu_register_physical_memory_offset(target_phys_addr_t start_addr,
@@ -2495,6 +2506,9 @@ ram_addr_t qemu_ram_alloc(ram_addr_t size)
last_ram_offset += size;
+ if (kvm_enabled())
+ kvm_setup_guest_memory(new_block->host, size);
+
return new_block->offset;
}
@@ -3027,8 +3041,7 @@ static void io_mem_init(void)
/* mem_read and mem_write are arrays of functions containing the
function to access byte (index 0), word (index 1) and dword (index
- 2). Functions can be omitted with a NULL function pointer. The
- registered functions may be modified dynamically later.
+ 2). Functions can be omitted with a NULL function pointer.
If io_index is non zero, the corresponding io zone is
modified. If it is zero, a new io zone is allocated. The return
value can be used with cpu_register_physical_memory(). (-1) is
@@ -3072,16 +3085,6 @@ void cpu_unregister_io_memory(int io_table_address)
io_mem_used[io_index] = 0;
}
-CPUWriteMemoryFunc **cpu_get_io_memory_write(int io_index)
-{
- return io_mem_write[io_index >> IO_MEM_SHIFT];
-}
-
-CPUReadMemoryFunc **cpu_get_io_memory_read(int io_index)
-{
- return io_mem_read[io_index >> IO_MEM_SHIFT];
-}
-
#endif /* !defined(CONFIG_USER_ONLY) */
/* physical memory access (slow version, mainly for debug) */
diff --git a/hw/ac97.c b/hw/ac97.c
index ade271911..d9ef14174 100644
--- a/hw/ac97.c
+++ b/hw/ac97.c
@@ -1348,7 +1348,7 @@ int ac97_init (PCIBus *bus, AudioState *audio)
c[0x08] = 0x01; /* rid revision ro */
c[0x09] = 0x00; /* pi programming interface ro */
pci_config_set_class(c, PCI_CLASS_MULTIMEDIA_AUDIO); /* ro */
- c[0x0e] = 0x00; /* headtyp header type ro */
+ c[PCI_HEADER_TYPE] = PCI_HEADER_TYPE_NORMAL; /* headtyp header type ro */
c[0x10] = 0x01; /* nabmar native audio mixer base
address rw */
diff --git a/hw/acpi.c b/hw/acpi.c
index 356a883cf..f4062ac70 100644
--- a/hw/acpi.c
+++ b/hw/acpi.c
@@ -517,7 +517,7 @@ i2c_bus *piix4_pm_init(PCIBus *bus, int devfn, uint32_t smb_io_base,
pci_conf[0x08] = 0x03; // revision number
pci_conf[0x09] = 0x00;
pci_config_set_class(pci_conf, PCI_CLASS_BRIDGE_OTHER);
- pci_conf[0x0e] = 0x00; // header_type
+ pci_conf[PCI_HEADER_TYPE] = PCI_HEADER_TYPE_NORMAL; // header_type
pci_conf[0x3d] = 0x01; // interrupt pin 1
pci_conf[0x40] = 0x01; /* PM io base read only bit */
diff --git a/hw/apb_pci.c b/hw/apb_pci.c
index a179acde7..36ecb5584 100644
--- a/hw/apb_pci.c
+++ b/hw/apb_pci.c
@@ -262,7 +262,7 @@ PCIBus *pci_apb_init(target_phys_addr_t special_base,
d->config[0x09] = 0x00; // programming i/f
pci_config_set_class(d->config, PCI_CLASS_BRIDGE_HOST);
d->config[0x0D] = 0x10; // latency_timer
- d->config[0x0E] = 0x00; // header_type
+ d->config[PCI_HEADER_TYPE] = PCI_HEADER_TYPE_NORMAL; // header_type
/* APB secondary busses */
*bus2 = pci_bridge_init(s->bus, 8, PCI_VENDOR_ID_SUN,
diff --git a/hw/cirrus_vga.c b/hw/cirrus_vga.c
index 20f17a658..ec1ff460d 100644
--- a/hw/cirrus_vga.c
+++ b/hw/cirrus_vga.c
@@ -188,7 +188,6 @@
// PCI 0x08, 0x00ff0000
#define PCI_CLASS_SUB_VGA 0x00
// PCI 0x0c, 0x00ff0000 (0x0c:cacheline,0x0d:latency,0x0e:headertype,0x0f:Built-in self test)
-#define PCI_CLASS_HEADERTYPE_00h 0x00
// 0x10-0x3f (headertype 00h)
// PCI 0x10,0x14,0x18,0x1c,0x20,0x24: base address mapping registers
// 0x10: MEMBASE, 0x14: IOBASE(hard-coded in XFree86 3.x)
@@ -280,7 +279,6 @@ typedef struct CirrusVGAState {
int last_hw_cursor_y_start;
int last_hw_cursor_y_end;
int real_vram_size; /* XXX: suppress that */
- CPUWriteMemoryFunc **cirrus_linear_write;
int device_id;
int bustype;
} CirrusVGAState;
@@ -2486,36 +2484,6 @@ static CPUWriteMemoryFunc *cirrus_linear_write[3] = {
cirrus_linear_writel,
};
-static void cirrus_linear_mem_writeb(void *opaque, target_phys_addr_t addr,
- uint32_t val)
-{
- CirrusVGAState *s = (CirrusVGAState *) opaque;
-
- addr &= s->cirrus_addr_mask;
- *(s->vram_ptr + addr) = val;
- cpu_physical_memory_set_dirty(s->vram_offset + addr);
-}
-
-static void cirrus_linear_mem_writew(void *opaque, target_phys_addr_t addr,
- uint32_t val)
-{
- CirrusVGAState *s = (CirrusVGAState *) opaque;
-
- addr &= s->cirrus_addr_mask;
- cpu_to_le16w((uint16_t *)(s->vram_ptr + addr), val);
- cpu_physical_memory_set_dirty(s->vram_offset + addr);
-}
-
-static void cirrus_linear_mem_writel(void *opaque, target_phys_addr_t addr,
- uint32_t val)
-{
- CirrusVGAState *s = (CirrusVGAState *) opaque;
-
- addr &= s->cirrus_addr_mask;
- cpu_to_le32w((uint32_t *)(s->vram_ptr + addr), val);
- cpu_physical_memory_set_dirty(s->vram_offset + addr);
-}
-
/***************************************
*
* system to screen memory access
@@ -2689,15 +2657,9 @@ static void cirrus_update_memory_access(CirrusVGAState *s)
mode = s->gr[0x05] & 0x7;
if (mode < 4 || mode > 5 || ((s->gr[0x0B] & 0x4) == 0)) {
map_linear_vram(s);
- s->cirrus_linear_write[0] = cirrus_linear_mem_writeb;
- s->cirrus_linear_write[1] = cirrus_linear_mem_writew;
- s->cirrus_linear_write[2] = cirrus_linear_mem_writel;
} else {
generic_io:
unmap_linear_vram(s);
- s->cirrus_linear_write[0] = cirrus_linear_writeb;
- s->cirrus_linear_write[1] = cirrus_linear_writew;
- s->cirrus_linear_write[2] = cirrus_linear_writel;
}
}
}
@@ -3255,7 +3217,6 @@ static void cirrus_init_common(CirrusVGAState * s, int device_id, int is_pci)
/* I/O handler for LFB */
s->cirrus_linear_io_addr =
cpu_register_io_memory(0, cirrus_linear_read, cirrus_linear_write, s);
- s->cirrus_linear_write = cpu_get_io_memory_write(s->cirrus_linear_io_addr);
/* I/O handler for LFB */
s->cirrus_linear_bitblt_io_addr =
@@ -3375,7 +3336,7 @@ void pci_cirrus_vga_init(PCIBus *bus, int vga_ram_size)
pci_config_set_device_id(pci_conf, device_id);
pci_conf[0x04] = PCI_COMMAND_IOACCESS | PCI_COMMAND_MEMACCESS;
pci_config_set_class(pci_conf, PCI_CLASS_DISPLAY_VGA);
- pci_conf[0x0e] = PCI_CLASS_HEADERTYPE_00h;
+ pci_conf[PCI_HEADER_TYPE] = PCI_HEADER_TYPE_NORMAL;
/* setup VGA */
s = &d->cirrus_vga;
diff --git a/hw/etraxfs_dma.c b/hw/etraxfs_dma.c
index 47236378e..e4bc82438 100644
--- a/hw/etraxfs_dma.c
+++ b/hw/etraxfs_dma.c
@@ -392,10 +392,8 @@ static void channel_update_irq(struct fs_dma_ctrl *ctrl, int c)
c,
ctrl->channels[c].regs[R_MASKED_INTR]));
- if (ctrl->channels[c].regs[R_MASKED_INTR])
- qemu_irq_raise(ctrl->channels[c].irq[0]);
- else
- qemu_irq_lower(ctrl->channels[c].irq[0]);
+ qemu_set_irq(ctrl->channels[c].irq[0],
+ !!ctrl->channels[c].regs[R_MASKED_INTR]);
}
static int channel_out_run(struct fs_dma_ctrl *ctrl, int c)
diff --git a/hw/etraxfs_pic.c b/hw/etraxfs_pic.c
index f32b3021c..9e5cbb329 100644
--- a/hw/etraxfs_pic.c
+++ b/hw/etraxfs_pic.c
@@ -29,33 +29,33 @@
#define D(x)
-struct fs_pic_state_t
+#define R_RW_MASK 0
+#define R_R_VECT 1
+#define R_R_MASKED_VECT 2
+#define R_R_NMI 3
+#define R_R_GURU 4
+#define R_MAX 5
+
+struct fs_pic_state
{
CPUState *env;
-
- uint32_t rw_mask;
- /* Active interrupt lines. */
- uint32_t r_vect;
- /* Active lines, gated through the mask. */
- uint32_t r_masked_vect;
- uint32_t r_nmi;
- uint32_t r_guru;
+ uint32_t regs[R_MAX];
};
-static void pic_update(struct fs_pic_state_t *fs)
+static void pic_update(struct fs_pic_state *fs)
{
CPUState *env = fs->env;
- int i;
uint32_t vector = 0;
+ int i;
- fs->r_masked_vect = fs->r_vect & fs->rw_mask;
+ fs->regs[R_R_MASKED_VECT] = fs->regs[R_R_VECT] & fs->regs[R_RW_MASK];
/* The ETRAX interrupt controller signals interrupts to teh core
through an interrupt request wire and an irq vector bus. If
multiple interrupts are simultaneously active it chooses vector
0x30 and lets the sw choose the priorities. */
- if (fs->r_masked_vect) {
- uint32_t mv = fs->r_masked_vect;
+ if (fs->regs[R_R_MASKED_VECT]) {
+ uint32_t mv = fs->regs[R_R_MASKED_VECT];
for (i = 0; i < 31; i++) {
if (mv & 1) {
vector = 0x31 + i;
@@ -80,31 +80,10 @@ static void pic_update(struct fs_pic_state_t *fs)
static uint32_t pic_readl (void *opaque, target_phys_addr_t addr)
{
- struct fs_pic_state_t *fs = opaque;
+ struct fs_pic_state *fs = opaque;
uint32_t rval;
- switch (addr)
- {
- case 0x0:
- rval = fs->rw_mask;
- break;
- case 0x4:
- rval = fs->r_vect;
- break;
- case 0x8:
- rval = fs->r_masked_vect;
- break;
- case 0xc:
- rval = fs->r_nmi;
- break;
- case 0x10:
- rval = fs->r_guru;
- break;
- default:
- cpu_abort(fs->env, "invalid PIC register.\n");
- break;
-
- }
+ rval = fs->regs[addr >> 2];
D(printf("%s %x=%x\n", __func__, addr, rval));
return rval;
}
@@ -112,17 +91,12 @@ static uint32_t pic_readl (void *opaque, target_phys_addr_t addr)
static void
pic_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
{
- struct fs_pic_state_t *fs = opaque;
+ struct fs_pic_state *fs = opaque;
D(printf("%s addr=%x val=%x\n", __func__, addr, value));
- switch (addr)
- {
- case 0x0:
- fs->rw_mask = value;
- pic_update(fs);
- break;
- default:
- cpu_abort(fs->env, "invalid PIC register.\n");
- break;
+
+ if (addr == R_RW_MASK) {
+ fs->regs[R_RW_MASK] = value;
+ pic_update(fs);
}
}
@@ -146,32 +120,27 @@ void irq_info(Monitor *mon)
static void irq_handler(void *opaque, int irq, int level)
{
- struct fs_pic_state_t *fs = (void *)opaque;
-
- D(printf("%s irq=%d level=%d mask=%x v=%x mv=%x\n",
- __func__, irq, level,
- fs->rw_mask, fs->r_vect, fs->r_masked_vect));
-
+ struct fs_pic_state *fs = (void *)opaque;
irq -= 1;
- fs->r_vect &= ~(1 << irq);
- fs->r_vect |= (!!level << irq);
+ fs->regs[R_R_VECT] &= ~(1 << irq);
+ fs->regs[R_R_VECT] |= (!!level << irq);
pic_update(fs);
}
static void nmi_handler(void *opaque, int irq, int level)
{
- struct fs_pic_state_t *fs = (void *)opaque;
+ struct fs_pic_state *fs = (void *)opaque;
CPUState *env = fs->env;
uint32_t mask;
mask = 1 << irq;
if (level)
- fs->r_nmi |= mask;
+ fs->regs[R_R_NMI] |= mask;
else
- fs->r_nmi &= ~mask;
+ fs->regs[R_R_NMI] &= ~mask;
- if (fs->r_nmi)
+ if (fs->regs[R_R_NMI])
cpu_interrupt(env, CPU_INTERRUPT_NMI);
else
cpu_reset_interrupt(env, CPU_INTERRUPT_NMI);
@@ -179,15 +148,13 @@ static void nmi_handler(void *opaque, int irq, int level)
static void guru_handler(void *opaque, int irq, int level)
{
- struct fs_pic_state_t *fs = (void *)opaque;
- CPUState *env = fs->env;
- cpu_abort(env, "%s unsupported exception\n", __func__);
-
+ struct fs_pic_state *fs = (void *)opaque;
+ cpu_abort(fs->env, "%s unsupported exception\n", __func__);
}
struct etraxfs_pic *etraxfs_pic_init(CPUState *env, target_phys_addr_t base)
{
- struct fs_pic_state_t *fs = NULL;
+ struct fs_pic_state *fs = NULL;
struct etraxfs_pic *pic = NULL;
int intr_vect_regs;
@@ -200,7 +167,7 @@ struct etraxfs_pic *etraxfs_pic_init(CPUState *env, target_phys_addr_t base)
pic->guru = qemu_allocate_irqs(guru_handler, fs, 1);
intr_vect_regs = cpu_register_io_memory(0, pic_read, pic_write, fs);
- cpu_register_physical_memory(base, 0x14, intr_vect_regs);
+ cpu_register_physical_memory(base, R_MAX * 4, intr_vect_regs);
return pic;
}
diff --git a/hw/etraxfs_ser.c b/hw/etraxfs_ser.c
index 8367386ed..80091d571 100644
--- a/hw/etraxfs_ser.c
+++ b/hw/etraxfs_ser.c
@@ -30,195 +30,132 @@
#define D(x)
-#define RW_TR_CTRL 0x00
-#define RW_TR_DMA_EN 0x04
-#define RW_REC_CTRL 0x08
-#define RW_DOUT 0x1c
-#define RS_STAT_DIN 0x20
-#define R_STAT_DIN 0x24
-#define RW_INTR_MASK 0x2c
-#define RW_ACK_INTR 0x30
-#define R_INTR 0x34
-#define R_MASKED_INTR 0x38
+#define RW_TR_CTRL (0x00 / 4)
+#define RW_TR_DMA_EN (0x04 / 4)
+#define RW_REC_CTRL (0x08 / 4)
+#define RW_DOUT (0x1c / 4)
+#define RS_STAT_DIN (0x20 / 4)
+#define R_STAT_DIN (0x24 / 4)
+#define RW_INTR_MASK (0x2c / 4)
+#define RW_ACK_INTR (0x30 / 4)
+#define R_INTR (0x34 / 4)
+#define R_MASKED_INTR (0x38 / 4)
+#define R_MAX (0x3c / 4)
#define STAT_DAV 16
#define STAT_TR_IDLE 22
#define STAT_TR_RDY 24
-struct etrax_serial_t
+struct etrax_serial
{
CPUState *env;
CharDriverState *chr;
qemu_irq *irq;
+ /* This pending thing is a hack. */
int pending_tx;
/* Control registers. */
- uint32_t rw_tr_ctrl;
- uint32_t rw_tr_dma_en;
- uint32_t rw_rec_ctrl;
- uint32_t rs_stat_din;
- uint32_t r_stat_din;
- uint32_t rw_intr_mask;
- uint32_t rw_ack_intr;
- uint32_t r_intr;
- uint32_t r_masked_intr;
+ uint32_t regs[R_MAX];
};
-static void ser_update_irq(struct etrax_serial_t *s)
+static void ser_update_irq(struct etrax_serial *s)
{
- uint32_t o_irq = s->r_masked_intr;
-
- s->r_intr &= ~(s->rw_ack_intr);
- s->r_masked_intr = s->r_intr & s->rw_intr_mask;
-
- if (o_irq != s->r_masked_intr) {
- D(printf("irq_mask=%x r_intr=%x rmi=%x airq=%x \n",
- s->rw_intr_mask, s->r_intr,
- s->r_masked_intr, s->rw_ack_intr));
- if (s->r_masked_intr)
- qemu_irq_raise(s->irq[0]);
- else
- qemu_irq_lower(s->irq[0]);
- }
- s->rw_ack_intr = 0;
-}
-
+ s->regs[R_INTR] &= ~(s->regs[RW_ACK_INTR]);
+ s->regs[R_MASKED_INTR] = s->regs[R_INTR] & s->regs[RW_INTR_MASK];
-static uint32_t ser_readb (void *opaque, target_phys_addr_t addr)
-{
- D(CPUState *env = opaque);
- D(printf ("%s %x\n", __func__, addr));
- return 0;
+ qemu_set_irq(s->irq[0], !!s->regs[R_MASKED_INTR]);
+ s->regs[RW_ACK_INTR] = 0;
}
static uint32_t ser_readl (void *opaque, target_phys_addr_t addr)
{
- struct etrax_serial_t *s = opaque;
+ struct etrax_serial *s = opaque;
D(CPUState *env = s->env);
uint32_t r = 0;
+ addr >>= 2;
switch (addr)
{
- case RW_TR_CTRL:
- r = s->rw_tr_ctrl;
- break;
- case RW_TR_DMA_EN:
- r = s->rw_tr_dma_en;
- break;
- case RS_STAT_DIN:
- r = s->rs_stat_din;
- /* clear dav. */
- s->rs_stat_din &= ~(1 << STAT_DAV);
- break;
case R_STAT_DIN:
- r = s->rs_stat_din;
- break;
- case RW_ACK_INTR:
- D(printf("load rw_ack_intr=%x\n", s->rw_ack_intr));
- r = s->rw_ack_intr;
- break;
- case RW_INTR_MASK:
- r = s->rw_intr_mask;
+ r = s->regs[RS_STAT_DIN];
break;
- case R_INTR:
- D(printf("load r_intr=%x\n", s->r_intr));
- r = s->r_intr;
- break;
- case R_MASKED_INTR:
- D(printf("load r_maked_intr=%x\n", s->r_masked_intr));
- r = s->r_masked_intr;
+ case RS_STAT_DIN:
+ r = s->regs[addr];
+ /* Read side-effect: clear dav. */
+ s->regs[addr] &= ~(1 << STAT_DAV);
break;
-
default:
- D(printf ("%s %x\n", __func__, addr));
+ r = s->regs[addr];
+ D(printf ("%s %x=%x\n", __func__, addr, r));
break;
}
return r;
}
static void
-ser_writeb (void *opaque, target_phys_addr_t addr, uint32_t value)
-{
- D(struct etrax_serial_t *s = opaque);
- D(CPUState *env = s->env);
- D(printf ("%s %x %x\n", __func__, addr, value));
-}
-static void
ser_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
{
- struct etrax_serial_t *s = opaque;
+ struct etrax_serial *s = opaque;
unsigned char ch = value;
D(CPUState *env = s->env);
+ D(printf ("%s %x %x\n", __func__, addr, value));
+ addr >>= 2;
switch (addr)
{
- case RW_TR_CTRL:
- D(printf("rw_tr_ctrl=%x\n", value));
- s->rw_tr_ctrl = value;
- break;
- case RW_TR_DMA_EN:
- D(printf("rw_tr_dma_en=%x\n", value));
- s->rw_tr_dma_en = value;
- break;
case RW_DOUT:
qemu_chr_write(s->chr, &ch, 1);
- s->r_intr |= 1;
+ s->regs[R_INTR] |= 1;
s->pending_tx = 1;
+ s->regs[addr] = value;
break;
case RW_ACK_INTR:
- D(printf("rw_ack_intr=%x\n", value));
- s->rw_ack_intr = value;
- if (s->pending_tx && (s->rw_ack_intr & 1)) {
- s->r_intr |= 1;
+ s->regs[addr] = value;
+ if (s->pending_tx && (s->regs[addr] & 1)) {
+ s->regs[R_INTR] |= 1;
s->pending_tx = 0;
- s->rw_ack_intr &= ~1;
+ s->regs[addr] &= ~1;
}
break;
- case RW_INTR_MASK:
- D(printf("r_intr_mask=%x\n", value));
- s->rw_intr_mask = value;
- break;
default:
- D(printf ("%s %x %x\n", __func__, addr, value));
+ s->regs[addr] = value;
break;
}
ser_update_irq(s);
}
static CPUReadMemoryFunc *ser_read[] = {
- &ser_readb,
- &ser_readb,
+ NULL, NULL,
&ser_readl,
};
static CPUWriteMemoryFunc *ser_write[] = {
- &ser_writeb,
- &ser_writeb,
+ NULL, NULL,
&ser_writel,
};
static void serial_receive(void *opaque, const uint8_t *buf, int size)
{
- struct etrax_serial_t *s = opaque;
+ struct etrax_serial *s = opaque;
- s->r_intr |= 8;
- s->rs_stat_din &= ~0xff;
- s->rs_stat_din |= (buf[0] & 0xff);
- s->rs_stat_din |= (1 << STAT_DAV); /* dav. */
+ s->regs[R_INTR] |= 8;
+ s->regs[RS_STAT_DIN] &= ~0xff;
+ s->regs[RS_STAT_DIN] |= (buf[0] & 0xff);
+ s->regs[RS_STAT_DIN] |= (1 << STAT_DAV); /* dav. */
ser_update_irq(s);
}
static int serial_can_receive(void *opaque)
{
- struct etrax_serial_t *s = opaque;
+ struct etrax_serial *s = opaque;
int r;
/* Is the receiver enabled? */
- r = s->rw_rec_ctrl & 1;
+ r = s->regs[RW_REC_CTRL] & 1;
/* Pending rx data? */
- r |= !(s->r_intr & 8);
+ r |= !(s->regs[R_INTR] & 8);
return r;
}
@@ -230,7 +167,7 @@ static void serial_event(void *opaque, int event)
void etraxfs_ser_init(CPUState *env, qemu_irq *irq, CharDriverState *chr,
target_phys_addr_t base)
{
- struct etrax_serial_t *s;
+ struct etrax_serial *s;
int ser_regs;
s = qemu_mallocz(sizeof *s);
@@ -240,12 +177,12 @@ void etraxfs_ser_init(CPUState *env, qemu_irq *irq, CharDriverState *chr,
s->chr = chr;
/* transmitter begins ready and idle. */
- s->rs_stat_din |= (1 << STAT_TR_RDY);
- s->rs_stat_din |= (1 << STAT_TR_IDLE);
+ s->regs[RS_STAT_DIN] |= (1 << STAT_TR_RDY);
+ s->regs[RS_STAT_DIN] |= (1 << STAT_TR_IDLE);
qemu_chr_add_handlers(chr, serial_can_receive, serial_receive,
serial_event, s);
ser_regs = cpu_register_io_memory(0, ser_read, ser_write, s);
- cpu_register_physical_memory (base, 0x3c, ser_regs);
+ cpu_register_physical_memory (base, R_MAX * 4, ser_regs);
}
diff --git a/hw/etraxfs_timer.c b/hw/etraxfs_timer.c
index 1144369b1..6b3d17e35 100644
--- a/hw/etraxfs_timer.c
+++ b/hw/etraxfs_timer.c
@@ -178,10 +178,7 @@ static void timer_update_irq(struct fs_timer_t *t)
t->r_masked_intr = t->r_intr & t->rw_intr_mask;
D(printf("%s: masked_intr=%x\n", __func__, t->r_masked_intr));
- if (t->r_masked_intr)
- qemu_irq_raise(t->irq[0]);
- else
- qemu_irq_lower(t->irq[0]);
+ qemu_set_irq(t->irq[0], !!t->r_masked_intr);
}
static void timer0_hit(void *opaque)
diff --git a/hw/grackle_pci.c b/hw/grackle_pci.c
index 516172791..61606b22f 100644
--- a/hw/grackle_pci.c
+++ b/hw/grackle_pci.c
@@ -149,7 +149,7 @@ PCIBus *pci_grackle_init(uint32_t base, qemu_irq *pic)
d->config[0x08] = 0x00; // revision
d->config[0x09] = 0x01;
pci_config_set_class(d->config, PCI_CLASS_BRIDGE_HOST);
- d->config[0x0e] = 0x00; // header_type
+ d->config[PCI_HEADER_TYPE] = PCI_HEADER_TYPE_NORMAL; // header_type
#if 0
/* PCI2PCI bridge same values as PearPC - check this */
@@ -157,7 +157,7 @@ PCIBus *pci_grackle_init(uint32_t base, qemu_irq *pic)
pci_config_set_device_id(d->config, PCI_DEVICE_ID_DEC_21154);
d->config[0x08] = 0x02; // revision
pci_config_set_class(d->config, PCI_CLASS_BRIDGE_PCI);
- d->config[0x0e] = 0x01; // header_type
+ d->config[PCI_HEADER_TYPE] = PCI_HEADER_TYPE_BRIDGE; // header_type
d->config[0x18] = 0x0; // primary_bus
d->config[0x19] = 0x1; // secondary_bus
diff --git a/hw/ide.c b/hw/ide.c
index fc70f3696..b2a1288f5 100644
--- a/hw/ide.c
+++ b/hw/ide.c
@@ -2788,11 +2788,11 @@ static void ide_init2(IDEState *ide_state,
for(i = 0; i < 2; i++) {
s = ide_state + i;
- s->io_buffer = qemu_memalign(512, IDE_DMA_BUF_SECTORS*512 + 4);
if (i == 0)
s->bs = hd0;
else
s->bs = hd1;
+ s->io_buffer = qemu_blockalign(s->bs, IDE_DMA_BUF_SECTORS*512 + 4);
if (s->bs) {
bdrv_get_geometry(s->bs, &nb_sectors);
bdrv_guess_geometry(s->bs, &cylinders, &heads, &secs);
@@ -3301,7 +3301,7 @@ void pci_cmd646_ide_init(PCIBus *bus, BlockDriverState **hd_table,
pci_conf[0x09] = 0x8f;
pci_config_set_class(pci_conf, PCI_CLASS_STORAGE_IDE);
- pci_conf[0x0e] = 0x00; // header_type
+ pci_conf[PCI_HEADER_TYPE] = PCI_HEADER_TYPE_NORMAL; // header_type
pci_conf[0x51] = 0x04; // enable IDE0
if (secondary_ide_enabled) {
@@ -3371,7 +3371,7 @@ void pci_piix3_ide_init(PCIBus *bus, BlockDriverState **hd_table, int devfn,
pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_INTEL_82371SB_1);
pci_conf[0x09] = 0x80; // legacy ATA mode
pci_config_set_class(pci_conf, PCI_CLASS_STORAGE_IDE);
- pci_conf[0x0e] = 0x00; // header_type
+ pci_conf[PCI_HEADER_TYPE] = PCI_HEADER_TYPE_NORMAL; // header_type
qemu_register_reset(piix3_reset, d);
piix3_reset(d);
@@ -3411,7 +3411,7 @@ void pci_piix4_ide_init(PCIBus *bus, BlockDriverState **hd_table, int devfn,
pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_INTEL_82371AB);
pci_conf[0x09] = 0x80; // legacy ATA mode
pci_config_set_class(pci_conf, PCI_CLASS_STORAGE_IDE);
- pci_conf[0x0e] = 0x00; // header_type
+ pci_conf[PCI_HEADER_TYPE] = PCI_HEADER_TYPE_NORMAL; // header_type
qemu_register_reset(piix3_reset, d);
piix3_reset(d);
diff --git a/hw/mac_dbdma.c b/hw/mac_dbdma.c
index b8e4b128d..e863980d9 100644
--- a/hw/mac_dbdma.c
+++ b/hw/mac_dbdma.c
@@ -651,9 +651,7 @@ void DBDMA_register_channel(void *dbdma, int nchan, qemu_irq irq,
void DBDMA_schedule(void)
{
- CPUState *env = cpu_single_env;
- if (env)
- cpu_exit(env);
+ qemu_notify_event();
}
static void
diff --git a/hw/macio.c b/hw/macio.c
index 1333aa382..28dbaa720 100644
--- a/hw/macio.c
+++ b/hw/macio.c
@@ -110,7 +110,7 @@ void macio_init (PCIBus *bus, int device_id, int is_oldworld, int pic_mem_index,
pci_config_set_vendor_id(d->config, PCI_VENDOR_ID_APPLE);
pci_config_set_device_id(d->config, device_id);
pci_config_set_class(d->config, PCI_CLASS_OTHERS << 8);
- d->config[0x0e] = 0x00; // header_type
+ d->config[PCI_HEADER_TYPE] = PCI_HEADER_TYPE_NORMAL; // header_type
d->config[0x3d] = 0x01; // interrupt on pin 1
diff --git a/hw/mc146818rtc.c b/hw/mc146818rtc.c
index 9640afe7b..888b85a9d 100644
--- a/hw/mc146818rtc.c
+++ b/hw/mc146818rtc.c
@@ -73,6 +73,7 @@ struct RTCState {
#ifdef TARGET_I386
uint32_t irq_coalesced;
uint32_t period;
+ QEMUTimer *coalesced_timer;
#endif
QEMUTimer *second_timer;
QEMUTimer *second_timer2;
@@ -93,6 +94,37 @@ static void rtc_irq_raise(qemu_irq irq) {
static void rtc_set_time(RTCState *s);
static void rtc_copy_date(RTCState *s);
+#ifdef TARGET_I386
+static void rtc_coalesced_timer_update(RTCState *s)
+{
+ if (s->irq_coalesced == 0) {
+ qemu_del_timer(s->coalesced_timer);
+ } else {
+ /* divide each RTC interval to 2 - 8 smaller intervals */
+ int c = MIN(s->irq_coalesced, 7) + 1;
+ int64_t next_clock = qemu_get_clock(vm_clock) +
+ muldiv64(s->period / c, ticks_per_sec, 32768);
+ qemu_mod_timer(s->coalesced_timer, next_clock);
+ }
+}
+
+static void rtc_coalesced_timer(void *opaque)
+{
+ RTCState *s = opaque;
+
+ if (s->irq_coalesced != 0) {
+ apic_reset_irq_delivered();
+ s->cmos_data[RTC_REG_C] |= 0xc0;
+ rtc_irq_raise(s->irq);
+ if (apic_get_irq_delivered()) {
+ s->irq_coalesced--;
+ }
+ }
+
+ rtc_coalesced_timer_update(s);
+}
+#endif
+
static void rtc_timer_update(RTCState *s, int64_t current_time)
{
int period_code, period;
@@ -138,14 +170,18 @@ static void rtc_periodic_timer(void *opaque)
RTCState *s = opaque;
rtc_timer_update(s, s->next_periodic_time);
-#ifdef TARGET_I386
- if ((s->cmos_data[RTC_REG_C] & 0xc0) && rtc_td_hack) {
- s->irq_coalesced++;
- return;
- }
-#endif
if (s->cmos_data[RTC_REG_B] & REG_B_PIE) {
s->cmos_data[RTC_REG_C] |= 0xc0;
+#ifdef TARGET_I386
+ if(rtc_td_hack) {
+ apic_reset_irq_delivered();
+ rtc_irq_raise(s->irq);
+ if (!apic_get_irq_delivered()) {
+ s->irq_coalesced++;
+ rtc_coalesced_timer_update(s);
+ }
+ } else
+#endif
rtc_irq_raise(s->irq);
}
if (s->cmos_data[RTC_REG_B] & REG_B_SQWE) {
@@ -415,15 +451,6 @@ static uint32_t cmos_ioport_read(void *opaque, uint32_t addr)
case RTC_REG_C:
ret = s->cmos_data[s->cmos_index];
qemu_irq_lower(s->irq);
-#ifdef TARGET_I386
- if(s->irq_coalesced) {
- apic_reset_irq_delivered();
- qemu_irq_raise(s->irq);
- if (apic_get_irq_delivered())
- s->irq_coalesced--;
- break;
- }
-#endif
s->cmos_data[RTC_REG_C] = 0x00;
break;
default:
@@ -536,6 +563,7 @@ static int rtc_load_td(QEMUFile *f, void *opaque, int version_id)
s->irq_coalesced = qemu_get_be32(f);
s->period = qemu_get_be32(f);
+ rtc_coalesced_timer_update(s);
return 0;
}
#endif
@@ -558,6 +586,10 @@ RTCState *rtc_init_sqw(int base, qemu_irq irq, qemu_irq sqw_irq, int base_year)
s->periodic_timer = qemu_new_timer(vm_clock,
rtc_periodic_timer, s);
+#ifdef TARGET_I386
+ if (rtc_td_hack)
+ s->coalesced_timer = qemu_new_timer(vm_clock, rtc_coalesced_timer, s);
+#endif
s->second_timer = qemu_new_timer(vm_clock,
rtc_update_second, s);
s->second_timer2 = qemu_new_timer(vm_clock,
diff --git a/hw/ne2000.c b/hw/ne2000.c
index 613ac411f..d778cb4ca 100644
--- a/hw/ne2000.c
+++ b/hw/ne2000.c
@@ -817,7 +817,7 @@ PCIDevice *pci_ne2000_init(PCIBus *bus, NICInfo *nd, int devfn)
pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_REALTEK);
pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_REALTEK_8029);
pci_config_set_class(pci_conf, PCI_CLASS_NETWORK_ETHERNET);
- pci_conf[0x0e] = 0x00; // header_type
+ pci_conf[PCI_HEADER_TYPE] = PCI_HEADER_TYPE_NORMAL; // header_type
pci_conf[0x3d] = 1; // interrupt pin 0
pci_register_io_region(&d->dev, 0, 0x100,
diff --git a/hw/openpic.c b/hw/openpic.c
index 733284ae8..53747c458 100644
--- a/hw/openpic.c
+++ b/hw/openpic.c
@@ -1208,7 +1208,7 @@ qemu_irq *openpic_init (PCIBus *bus, int *pmem_index, int nb_cpus,
pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_IBM);
pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_IBM_OPENPIC2);
pci_config_set_class(pci_conf, PCI_CLASS_SYSTEM_OTHER); // FIXME?
- pci_conf[0x0e] = 0x00; // header_type
+ pci_conf[PCI_HEADER_TYPE] = PCI_HEADER_TYPE_NORMAL; // header_type
pci_conf[0x3d] = 0x00; // no interrupt pin
/* Register I/O spaces */
diff --git a/hw/pc.c b/hw/pc.c
index 4b17b9cb2..34a4d25b6 100644
--- a/hw/pc.c
+++ b/hw/pc.c
@@ -37,6 +37,7 @@
#include "virtio-balloon.h"
#include "virtio-console.h"
#include "hpet_emul.h"
+#include "watchdog.h"
#include "smbios.h"
#include "device-assignment.h"
@@ -968,8 +969,7 @@ static void pc_init1(ram_addr_t ram_size, int vga_ram_size,
option_rom_offset = qemu_ram_alloc(0x20000);
oprom_area_size = 0;
- cpu_register_physical_memory(0xc0000, 0x20000,
- option_rom_offset | IO_MEM_ROM);
+ cpu_register_physical_memory(0xc0000, 0x20000, option_rom_offset);
if (using_vga) {
/* VGA BIOS load */
@@ -1078,6 +1078,8 @@ static void pc_init1(ram_addr_t ram_size, int vga_ram_size,
}
}
+ watchdog_pc_init(pci_bus);
+
for(i = 0; i < nb_nics; i++) {
NICInfo *nd = &nd_table[i];
diff --git a/hw/pci.c b/hw/pci.c
index 64fb82eaa..35c08e6cc 100644
--- a/hw/pci.c
+++ b/hw/pci.c
@@ -103,6 +103,7 @@ PCIBus *pci_register_bus(pci_set_irq_fn set_irq, pci_map_irq_fn map_irq,
bus->irq_opaque = pic;
bus->devfn_min = devfn_min;
bus->nirq = nirq;
+ bus->next = first_bus;
first_bus = bus;
register_savevm("PCIBUS", nbus++, 1, pcibus_save, pcibus_load, bus);
return bus;
@@ -997,7 +998,8 @@ PCIBus *pci_bridge_init(PCIBus *bus, int devfn, uint16_t vid, uint16_t did,
s->dev.config[0x09] = 0x00; // programming i/f
pci_config_set_class(s->dev.config, PCI_CLASS_BRIDGE_PCI);
s->dev.config[0x0D] = 0x10; // latency_timer
- s->dev.config[0x0E] = 0x81; // header_type
+ s->dev.config[PCI_HEADER_TYPE] =
+ PCI_HEADER_TYPE_MULTI_FUNCTION | PCI_HEADER_TYPE_BRIDGE; // header_type
s->dev.config[0x1E] = 0xa0; // secondary status
s->bus = pci_register_secondary_bus(&s->dev, map_irq);
diff --git a/hw/pci.h b/hw/pci.h
index 21e2cbfb5..8c8d8080d 100644
--- a/hw/pci.h
+++ b/hw/pci.h
@@ -111,6 +111,10 @@ typedef struct PCIIORegion {
#define PCI_REVISION_ID 0x08 /* 8 bits */
#define PCI_CLASS_DEVICE 0x0a /* Device class */
#define PCI_HEADER_TYPE 0x0e /* 8 bits */
+#define PCI_HEADER_TYPE_NORMAL 0
+#define PCI_HEADER_TYPE_BRIDGE 1
+#define PCI_HEADER_TYPE_CARDBUS 2
+#define PCI_HEADER_TYPE_MULTI_FUNCTION 0x80
#define PCI_SUBSYSTEM_VENDOR_ID 0x2c /* 16 bits */
#define PCI_SUBSYSTEM_ID 0x2e /* 16 bits */
#define PCI_CAPABILITY_LIST 0x34
diff --git a/hw/pcnet.c b/hw/pcnet.c
index 654340b68..13f14bef0 100644
--- a/hw/pcnet.c
+++ b/hw/pcnet.c
@@ -2037,7 +2037,7 @@ PCIDevice *pci_pcnet_init(PCIBus *bus, NICInfo *nd, int devfn)
pci_conf[0x08] = 0x10;
pci_conf[0x09] = 0x00;
pci_config_set_class(pci_conf, PCI_CLASS_NETWORK_ETHERNET);
- pci_conf[0x0e] = 0x00; // header_type
+ pci_conf[PCI_HEADER_TYPE] = PCI_HEADER_TYPE_NORMAL; // header_type
*(uint32_t *)&pci_conf[0x10] = cpu_to_le32(0x00000001);
*(uint32_t *)&pci_conf[0x14] = cpu_to_le32(0x00000000);
diff --git a/hw/piix_pci.c b/hw/piix_pci.c
index 8f3c96d73..427801418 100644
--- a/hw/piix_pci.c
+++ b/hw/piix_pci.c
@@ -202,7 +202,7 @@ PCIBus *i440fx_init(PCIDevice **pi440fx_state, qemu_irq *pic)
pci_config_set_device_id(d->config, PCI_DEVICE_ID_INTEL_82441);
d->config[0x08] = 0x02; // revision
pci_config_set_class(d->config, PCI_CLASS_BRIDGE_HOST);
- d->config[0x0e] = 0x00; // header_type
+ d->config[PCI_HEADER_TYPE] = PCI_HEADER_TYPE_NORMAL; // header_type
d->config[0x72] = 0x02; /* SMRAM */
@@ -350,7 +350,8 @@ int piix3_init(PCIBus *bus, int devfn)
pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_INTEL);
pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_INTEL_82371SB_0); // 82371SB PIIX3 PCI-to-ISA bridge (Step A1)
pci_config_set_class(pci_conf, PCI_CLASS_BRIDGE_ISA);
- pci_conf[0x0e] = 0x80; // header_type = PCI_multifunction, generic
+ pci_conf[PCI_HEADER_TYPE] =
+ PCI_HEADER_TYPE_NORMAL | PCI_HEADER_TYPE_MULTI_FUNCTION; // header_type = PCI_multifunction, generic
piix3_reset(d);
return d->devfn;
@@ -371,7 +372,9 @@ int piix4_init(PCIBus *bus, int devfn)
pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_INTEL);
pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_INTEL_82371AB_0); // 82371AB/EB/MB PIIX4 PCI-to-ISA bridge
pci_config_set_class(pci_conf, PCI_CLASS_BRIDGE_ISA);
- pci_conf[0x0e] = 0x80; // header_type = PCI_multifunction, generic
+ pci_conf[PCI_HEADER_TYPE] =
+ PCI_HEADER_TYPE_NORMAL | PCI_HEADER_TYPE_MULTI_FUNCTION; // header_type = PCI_multifunction, generic
+
piix4_reset(d);
return d->devfn;
diff --git a/hw/prep_pci.c b/hw/prep_pci.c
index 205500564..a97b845b4 100644
--- a/hw/prep_pci.c
+++ b/hw/prep_pci.c
@@ -161,7 +161,7 @@ PCIBus *pci_prep_init(qemu_irq *pic)
pci_config_set_class(d->config, PCI_CLASS_BRIDGE_HOST);
d->config[0x0C] = 0x08; // cache_line_size
d->config[0x0D] = 0x10; // latency_timer
- d->config[0x0E] = 0x00; // header_type
+ d->config[PCI_HEADER_TYPE] = PCI_HEADER_TYPE_NORMAL; // header_type
d->config[0x34] = 0x00; // capabilities_pointer
return s->bus;
diff --git a/hw/rtl8139.c b/hw/rtl8139.c
index 19c7623c5..c0be1de82 100644
--- a/hw/rtl8139.c
+++ b/hw/rtl8139.c
@@ -3462,7 +3462,7 @@ PCIDevice *pci_rtl8139_init(PCIBus *bus, NICInfo *nd, int devfn)
pci_conf[0x04] = 0x05; /* command = I/O space, Bus Master */
pci_conf[0x08] = RTL8139_PCI_REVID; /* PCI revision ID; >=0x20 is for 8139C+ */
pci_config_set_class(pci_conf, PCI_CLASS_NETWORK_ETHERNET);
- pci_conf[0x0e] = 0x00; /* header_type */
+ pci_conf[PCI_HEADER_TYPE] = PCI_HEADER_TYPE_NORMAL; /* header_type */
pci_conf[0x3d] = 1; /* interrupt pin 0 */
pci_conf[0x34] = 0xdc;
diff --git a/hw/sd.c b/hw/sd.c
index 4618883fa..284cd0884 100644
--- a/hw/sd.c
+++ b/hw/sd.c
@@ -365,7 +365,11 @@ static void sd_reset(SDState *sd, BlockDriverState *bdrv)
uint32_t size;
uint64_t sect;
- bdrv_get_geometry(bdrv, &sect);
+ if (bdrv) {
+ bdrv_get_geometry(bdrv, &sect);
+ } else {
+ sect = 0;
+ }
sect <<= 9;
if (sect > 0x40000000)
@@ -388,7 +392,7 @@ static void sd_reset(SDState *sd, BlockDriverState *bdrv)
if (sd->wp_groups)
qemu_free(sd->wp_groups);
- sd->wp_switch = bdrv_is_read_only(bdrv);
+ sd->wp_switch = bdrv ? bdrv_is_read_only(bdrv) : 0;
sd->wp_groups = (int *) qemu_mallocz(sizeof(int) * sect);
memset(sd->function_group, 0, sizeof(int) * 6);
sd->erase_start = 0;
@@ -421,7 +425,9 @@ SDState *sd_init(BlockDriverState *bs, int is_spi)
sd->spi = is_spi;
sd->enable = 1;
sd_reset(sd, bs);
- bdrv_set_change_cb(sd->bdrv, sd_cardchange, sd);
+ if (sd->bdrv) {
+ bdrv_set_change_cb(sd->bdrv, sd_cardchange, sd);
+ }
return sd;
}
@@ -1228,7 +1234,7 @@ int sd_do_command(SDState *sd, struct sd_request_s *req,
sd_rsp_type_t rtype;
int rsplen;
- if (!bdrv_is_inserted(sd->bdrv) || !sd->enable) {
+ if (!sd->bdrv || !bdrv_is_inserted(sd->bdrv) || !sd->enable) {
return 0;
}
diff --git a/hw/sun4u.c b/hw/sun4u.c
index de635d429..8f9e56bb7 100644
--- a/hw/sun4u.c
+++ b/hw/sun4u.c
@@ -318,7 +318,7 @@ pci_ebus_init(PCIBus *bus, int devfn)
s->config[0x09] = 0x00; // programming i/f
pci_config_set_class(s->config, PCI_CLASS_BRIDGE_OTHER);
s->config[0x0D] = 0x0a; // latency_timer
- s->config[0x0E] = 0x00; // header_type
+ s->config[PCI_HEADER_TYPE] = PCI_HEADER_TYPE_NORMAL; // header_type
pci_register_io_region(s, 0, 0x1000000, PCI_ADDRESS_SPACE_MEM,
ebus_mmio_mapfunc);
diff --git a/hw/tcx.c b/hw/tcx.c
index f0e8f2fc4..99e65a0bf 100644
--- a/hw/tcx.c
+++ b/hw/tcx.c
@@ -197,7 +197,7 @@ static void tcx_update_display(void *opaque)
return;
page = ts->vram_offset;
y_start = -1;
- page_min = 0xffffffff;
+ page_min = -1;
page_max = 0;
d = ds_get_data(ts->ds);
s = ts->vram;
@@ -257,7 +257,7 @@ static void tcx_update_display(void *opaque)
ts->width, y - y_start);
}
/* reset modified pages */
- if (page_min <= page_max) {
+ if (page_max >= page_min) {
cpu_physical_memory_reset_dirty(page_min, page_max + TARGET_PAGE_SIZE,
VGA_DIRTY_FLAG);
}
@@ -277,7 +277,7 @@ static void tcx24_update_display(void *opaque)
page24 = ts->vram24_offset;
cpage = ts->cplane_offset;
y_start = -1;
- page_min = 0xffffffff;
+ page_min = -1;
page_max = 0;
d = ds_get_data(ts->ds);
s = ts->vram;
@@ -334,7 +334,7 @@ static void tcx24_update_display(void *opaque)
ts->width, y - y_start);
}
/* reset modified pages */
- if (page_min <= page_max) {
+ if (page_max >= page_min) {
reset_dirty(ts, page_min, page_max, page24, cpage);
}
}
diff --git a/hw/unin_pci.c b/hw/unin_pci.c
index 9fc073ab5..b75191679 100644
--- a/hw/unin_pci.c
+++ b/hw/unin_pci.c
@@ -192,7 +192,7 @@ PCIBus *pci_pmac_init(qemu_irq *pic)
pci_config_set_class(d->config, PCI_CLASS_BRIDGE_HOST);
d->config[0x0C] = 0x08; // cache_line_size
d->config[0x0D] = 0x10; // latency_timer
- d->config[0x0E] = 0x00; // header_type
+ d->config[PCI_HEADER_TYPE] = PCI_HEADER_TYPE_NORMAL; // header_type
d->config[0x34] = 0x00; // capabilities_pointer
#if 0 // XXX: not activated as PPC BIOS doesn't handle multiple buses properly
@@ -205,7 +205,7 @@ PCIBus *pci_pmac_init(qemu_irq *pic)
pci_config_set_class(d->config, PCI_CLASS_BRIDGE_PCI);
d->config[0x0C] = 0x08; // cache_line_size
d->config[0x0D] = 0x20; // latency_timer
- d->config[0x0E] = 0x01; // header_type
+ d->config[PCI_HEADER_TYPE] = PCI_HEADER_TYPE_BRIDGE; // header_type
d->config[0x18] = 0x01; // primary_bus
d->config[0x19] = 0x02; // secondary_bus
@@ -240,7 +240,7 @@ PCIBus *pci_pmac_init(qemu_irq *pic)
pci_config_set_class(d->config, PCI_CLASS_BRIDGE_HOST);
d->config[0x0C] = 0x08; // cache_line_size
d->config[0x0D] = 0x10; // latency_timer
- d->config[0x0E] = 0x00; // header_type
+ d->config[PCI_HEADER_TYPE] = PCI_HEADER_TYPE_NORMAL; // header_type
// d->config[0x34] = 0x80; // capabilities_pointer
#if 0 // XXX: not needed for now
@@ -261,7 +261,7 @@ PCIBus *pci_pmac_init(qemu_irq *pic)
pci_config_set_class(d->config, PCI_CLASS_BRIDGE_HOST);
d->config[0x0C] = 0x08; // cache_line_size
d->config[0x0D] = 0x10; // latency_timer
- d->config[0x0E] = 0x00; // header_type
+ d->config[PCI_HEADER_TYPE] = PCI_HEADER_TYPE_NORMAL; // header_type
d->config[0x34] = 0x00; // capabilities_pointer
#endif
register_savevm("uninorth", 0, 1, pci_unin_save, pci_unin_load, d);
diff --git a/hw/usb-uhci.c b/hw/usb-uhci.c
index d42d39417..689d40ac6 100644
--- a/hw/usb-uhci.c
+++ b/hw/usb-uhci.c
@@ -1084,7 +1084,7 @@ void usb_uhci_piix3_init(PCIBus *bus, int devfn)
pci_conf[0x08] = 0x01; // revision number
pci_conf[0x09] = 0x00;
pci_config_set_class(pci_conf, PCI_CLASS_SERIAL_USB);
- pci_conf[0x0e] = 0x00; // header_type
+ pci_conf[PCI_HEADER_TYPE] = PCI_HEADER_TYPE_NORMAL; // header_type
pci_conf[0x3d] = 4; // interrupt pin 3
pci_conf[0x60] = 0x10; // release number
@@ -1118,7 +1118,7 @@ void usb_uhci_piix4_init(PCIBus *bus, int devfn)
pci_conf[0x08] = 0x01; // revision number
pci_conf[0x09] = 0x00;
pci_config_set_class(pci_conf, PCI_CLASS_SERIAL_USB);
- pci_conf[0x0e] = 0x00; // header_type
+ pci_conf[PCI_HEADER_TYPE] = PCI_HEADER_TYPE_NORMAL; // header_type
pci_conf[0x3d] = 4; // interrupt pin 3
pci_conf[0x60] = 0x10; // release number
diff --git a/hw/vga.c b/hw/vga.c
index 9ab6e1ae2..d851d1f7f 100644
--- a/hw/vga.c
+++ b/hw/vga.c
@@ -1590,10 +1590,10 @@ static void vga_draw_graphic(VGAState *s, int full_update)
{
int y1, y, update, linesize, y_start, double_scan, mask, depth;
int width, height, shift_control, line_offset, bwidth, bits;
+ ram_addr_t page0, page1, page_min, page_max;
int disp_width, multi_scan, multi_run;
uint8_t *d;
uint32_t v, addr1, addr;
- long page0, page1, page_min, page_max;
vga_draw_line_func *vga_draw_line;
full_update |= update_basic_params(s);
@@ -1728,8 +1728,8 @@ static void vga_draw_graphic(VGAState *s, int full_update)
addr1 = (s->start_addr * 4);
bwidth = (width * bits + 7) / 8;
y_start = -1;
- page_min = 0x7fffffff;
- page_max = -1;
+ page_min = -1;
+ page_max = 0;
d = ds_get_data(s->ds);
linesize = ds_get_linesize(s->ds);
y1 = 0;
@@ -1796,7 +1796,7 @@ static void vga_draw_graphic(VGAState *s, int full_update)
disp_width, y - y_start);
}
/* reset modified pages */
- if (page_max != -1) {
+ if (page_max >= page_min) {
cpu_physical_memory_reset_dirty(page_min, page_max + TARGET_PAGE_SIZE,
VGA_DIRTY_FLAG);
}
@@ -2550,7 +2550,7 @@ int pci_vga_init(PCIBus *bus, int vga_ram_size,
pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_QEMU);
pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_QEMU_VGA);
pci_config_set_class(pci_conf, PCI_CLASS_DISPLAY_VGA);
- pci_conf[0x0e] = 0x00; // header_type
+ pci_conf[PCI_HEADER_TYPE] = PCI_HEADER_TYPE_NORMAL; // header_type
/* XXX: vga_ram_size must be a power of two */
pci_register_io_region(&d->dev, 0, vga_ram_size,
diff --git a/hw/virtio-blk.c b/hw/virtio-blk.c
index 51a8e2282..dad4ef08c 100644
--- a/hw/virtio-blk.c
+++ b/hw/virtio-blk.c
@@ -15,6 +15,9 @@
#include <sysemu.h>
#include "virtio-blk.h"
#include "block_int.h"
+#ifdef __linux__
+# include <scsi/sg.h>
+#endif
typedef struct VirtIOBlock
{
@@ -35,6 +38,7 @@ typedef struct VirtIOBlockReq
VirtQueueElement elem;
struct virtio_blk_inhdr *in;
struct virtio_blk_outhdr *out;
+ struct virtio_scsi_inhdr *scsi;
QEMUIOVector qiov;
struct VirtIOBlockReq *next;
} VirtIOBlockReq;
@@ -103,6 +107,108 @@ static VirtIOBlockReq *virtio_blk_get_request(VirtIOBlock *s)
return req;
}
+#ifdef __linux__
+static void virtio_blk_handle_scsi(VirtIOBlockReq *req)
+{
+ struct sg_io_hdr hdr;
+ int ret, size = 0;
+ int status;
+ int i;
+
+ /*
+ * We require at least one output segment each for the virtio_blk_outhdr
+ * and the SCSI command block.
+ *
+ * We also at least require the virtio_blk_inhdr, the virtio_scsi_inhdr
+ * and the sense buffer pointer in the input segments.
+ */
+ if (req->elem.out_num < 2 || req->elem.in_num < 3) {
+ virtio_blk_req_complete(req, VIRTIO_BLK_S_IOERR);
+ return;
+ }
+
+ /*
+ * No support for bidirection commands yet.
+ */
+ if (req->elem.out_num > 2 && req->elem.in_num > 3) {
+ virtio_blk_req_complete(req, VIRTIO_BLK_S_UNSUPP);
+ return;
+ }
+
+ /*
+ * The scsi inhdr is placed in the second-to-last input segment, just
+ * before the regular inhdr.
+ */
+ req->scsi = (void *)req->elem.in_sg[req->elem.in_num - 2].iov_base;
+ size = sizeof(*req->in) + sizeof(*req->scsi);
+
+ memset(&hdr, 0, sizeof(struct sg_io_hdr));
+ hdr.interface_id = 'S';
+ hdr.cmd_len = req->elem.out_sg[1].iov_len;
+ hdr.cmdp = req->elem.out_sg[1].iov_base;
+ hdr.dxfer_len = 0;
+
+ if (req->elem.out_num > 2) {
+ /*
+ * If there are more than the minimally required 2 output segments
+ * there is write payload starting from the third iovec.
+ */
+ hdr.dxfer_direction = SG_DXFER_TO_DEV;
+ hdr.iovec_count = req->elem.out_num - 2;
+
+ for (i = 0; i < hdr.iovec_count; i++)
+ hdr.dxfer_len += req->elem.out_sg[i + 2].iov_len;
+
+ hdr.dxferp = req->elem.out_sg + 2;
+
+ } else if (req->elem.in_num > 3) {
+ /*
+ * If we have more than 3 input segments the guest wants to actually
+ * read data.
+ */
+ hdr.dxfer_direction = SG_DXFER_FROM_DEV;
+ hdr.iovec_count = req->elem.in_num - 3;
+ for (i = 0; i < hdr.iovec_count; i++)
+ hdr.dxfer_len += req->elem.in_sg[i].iov_len;
+
+ hdr.dxferp = req->elem.in_sg;
+ size += hdr.dxfer_len;
+ } else {
+ /*
+ * Some SCSI commands don't actually transfer any data.
+ */
+ hdr.dxfer_direction = SG_DXFER_NONE;
+ }
+
+ hdr.sbp = req->elem.in_sg[req->elem.in_num - 3].iov_base;
+ hdr.mx_sb_len = req->elem.in_sg[req->elem.in_num - 3].iov_len;
+ size += hdr.mx_sb_len;
+
+ ret = bdrv_ioctl(req->dev->bs, SG_IO, &hdr);
+ if (ret) {
+ status = VIRTIO_BLK_S_UNSUPP;
+ hdr.status = ret;
+ hdr.resid = hdr.dxfer_len;
+ } else if (hdr.status) {
+ status = VIRTIO_BLK_S_IOERR;
+ } else {
+ status = VIRTIO_BLK_S_OK;
+ }
+
+ req->scsi->errors = hdr.status;
+ req->scsi->residual = hdr.resid;
+ req->scsi->sense_len = hdr.sb_len_wr;
+ req->scsi->data_len = hdr.dxfer_len;
+
+ virtio_blk_req_complete(req, status);
+}
+#else
+static void virtio_blk_handle_scsi(VirtIOBlockReq *req)
+{
+ virtio_blk_req_complete(req, VIRTIO_BLK_S_UNSUPP);
+}
+#endif /* __linux__ */
+
static void virtio_blk_handle_write(VirtIOBlockReq *req)
{
bdrv_aio_writev(req->dev->bs, req->out->sector, &req->qiov,
@@ -136,12 +242,7 @@ static void virtio_blk_handle_output(VirtIODevice *vdev, VirtQueue *vq)
req->in = (void *)req->elem.in_sg[req->elem.in_num - 1].iov_base;
if (req->out->type & VIRTIO_BLK_T_SCSI_CMD) {
- unsigned int len = sizeof(*req->in);
-
- req->in->status = VIRTIO_BLK_S_UNSUPP;
- virtqueue_push(vq, &req->elem, len);
- virtio_notify(vdev, vq);
- qemu_free(req);
+ virtio_blk_handle_scsi(req);
} else if (req->out->type & VIRTIO_BLK_T_OUT) {
qemu_iovec_init_external(&req->qiov, &req->elem.out_sg[1],
req->elem.out_num - 1);
@@ -203,7 +304,15 @@ static void virtio_blk_update_config(VirtIODevice *vdev, uint8_t *config)
static uint32_t virtio_blk_get_features(VirtIODevice *vdev)
{
- return (1 << VIRTIO_BLK_F_SEG_MAX | 1 << VIRTIO_BLK_F_GEOMETRY);
+ uint32_t features = 0;
+
+ features |= (1 << VIRTIO_BLK_F_SEG_MAX);
+ features |= (1 << VIRTIO_BLK_F_GEOMETRY);
+#ifdef __linux__
+ features |= (1 << VIRTIO_BLK_F_SCSI);
+#endif
+
+ return features;
}
static void virtio_blk_save(QEMUFile *f, void *opaque)
diff --git a/hw/virtio-blk.h b/hw/virtio-blk.h
index 8c91e1ece..5ef6c3605 100644
--- a/hw/virtio-blk.h
+++ b/hw/virtio-blk.h
@@ -28,6 +28,9 @@
#define VIRTIO_BLK_F_SIZE_MAX 1 /* Indicates maximum segment size */
#define VIRTIO_BLK_F_SEG_MAX 2 /* Indicates maximum # of segments */
#define VIRTIO_BLK_F_GEOMETRY 4 /* Indicates support of legacy geometry */
+#define VIRTIO_BLK_F_RO 5 /* Disk is read-only */
+#define VIRTIO_BLK_F_BLK_SIZE 6 /* Block size of disk is available*/
+#define VIRTIO_BLK_F_SCSI 7 /* Supports scsi command passthru */
struct virtio_blk_config
{
@@ -64,12 +67,21 @@ struct virtio_blk_outhdr
#define VIRTIO_BLK_S_IOERR 1
#define VIRTIO_BLK_S_UNSUPP 2
-/* This is the first element of the write scatter-gather list */
+/* This is the last element of the write scatter-gather list */
struct virtio_blk_inhdr
{
unsigned char status;
};
+/* SCSI pass-through header */
+struct virtio_scsi_inhdr
+{
+ uint32_t errors;
+ uint32_t data_len;
+ uint32_t sense_len;
+ uint32_t residual;
+};
+
void *virtio_blk_init(PCIBus *bus, BlockDriverState *bs);
#endif
diff --git a/hw/virtio.c b/hw/virtio.c
index 4aa5f20a7..78c763765 100644
--- a/hw/virtio.c
+++ b/hw/virtio.c
@@ -788,7 +788,7 @@ VirtIODevice *virtio_init_pci(PCIBus *bus, const char *name,
config[0x09] = pif;
pci_config_set_class(config, class_code);
- config[0x0e] = 0x00;
+ config[PCI_HEADER_TYPE] = PCI_HEADER_TYPE_NORMAL;
config[0x2c] = subvendor & 0xFF;
config[0x2d] = (subvendor >> 8) & 0xFF;
diff --git a/hw/vmware_vga.c b/hw/vmware_vga.c
index 2299aff21..26cf78981 100644
--- a/hw/vmware_vga.c
+++ b/hw/vmware_vga.c
@@ -1210,8 +1210,6 @@ static void pci_vmsvga_map_mem(PCIDevice *pci_dev, int region_num,
iomemtype);
}
-#define PCI_CLASS_HEADERTYPE_00h 0x00
-
void pci_vmsvga_init(PCIBus *bus, int vga_ram_size)
{
struct pci_vmsvga_state_s *s;
@@ -1226,7 +1224,7 @@ void pci_vmsvga_init(PCIBus *bus, int vga_ram_size)
pci_config_set_class(s->card.config, PCI_CLASS_DISPLAY_VGA);
s->card.config[0x0c] = 0x08; /* Cache line size */
s->card.config[0x0d] = 0x40; /* Latency timer */
- s->card.config[0x0e] = PCI_CLASS_HEADERTYPE_00h;
+ s->card.config[PCI_HEADER_TYPE] = PCI_HEADER_TYPE_NORMAL;
s->card.config[0x2c] = PCI_VENDOR_ID_VMWARE & 0xff;
s->card.config[0x2d] = PCI_VENDOR_ID_VMWARE >> 8;
s->card.config[0x2e] = SVGA_PCI_DEVICE_ID & 0xff;
diff --git a/hw/watchdog.c b/hw/watchdog.c
new file mode 100644
index 000000000..c64868d2c
--- /dev/null
+++ b/hw/watchdog.c
@@ -0,0 +1,136 @@
+/*
+ * Virtual hardware watchdog.
+ *
+ * Copyright (C) 2009 Red Hat Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ * USA.
+ *
+ * By Richard W.M. Jones (rjones@redhat.com).
+ */
+
+#include "qemu-common.h"
+#include "sys-queue.h"
+#include "sysemu.h"
+#include "hw/watchdog.h"
+
+static LIST_HEAD(watchdog_list, WatchdogTimerModel) watchdog_list;
+
+void watchdog_add_model(WatchdogTimerModel *model)
+{
+ LIST_INSERT_HEAD(&watchdog_list, model, entry);
+}
+
+/* Returns:
+ * 0 = continue
+ * 1 = exit program with error
+ * 2 = exit program without error
+ */
+int select_watchdog(const char *p)
+{
+ WatchdogTimerModel *model;
+
+ if (watchdog) {
+ fprintf(stderr,
+ "qemu: only one watchdog option may be given\n");
+ return 1;
+ }
+
+ /* -watchdog ? lists available devices and exits cleanly. */
+ if (strcmp(p, "?") == 0) {
+ LIST_FOREACH(model, &watchdog_list, entry) {
+ fprintf(stderr, "\t%s\t%s\n",
+ model->wdt_name, model->wdt_description);
+ }
+ return 2;
+ }
+
+ LIST_FOREACH(model, &watchdog_list, entry) {
+ if (strcasecmp(model->wdt_name, p) == 0) {
+ watchdog = model;
+ return 0;
+ }
+ }
+
+ fprintf(stderr, "Unknown -watchdog device. Supported devices are:\n");
+ LIST_FOREACH(model, &watchdog_list, entry) {
+ fprintf(stderr, "\t%s\t%s\n",
+ model->wdt_name, model->wdt_description);
+ }
+ return 1;
+}
+
+int select_watchdog_action(const char *p)
+{
+ if (strcasecmp(p, "reset") == 0)
+ watchdog_action = WDT_RESET;
+ else if (strcasecmp(p, "shutdown") == 0)
+ watchdog_action = WDT_SHUTDOWN;
+ else if (strcasecmp(p, "poweroff") == 0)
+ watchdog_action = WDT_POWEROFF;
+ else if (strcasecmp(p, "pause") == 0)
+ watchdog_action = WDT_PAUSE;
+ else if (strcasecmp(p, "debug") == 0)
+ watchdog_action = WDT_DEBUG;
+ else if (strcasecmp(p, "none") == 0)
+ watchdog_action = WDT_NONE;
+ else
+ return -1;
+
+ return 0;
+}
+
+/* This actually performs the "action" once a watchdog has expired,
+ * ie. reboot, shutdown, exit, etc.
+ */
+void watchdog_perform_action(void)
+{
+ switch(watchdog_action) {
+ case WDT_RESET: /* same as 'system_reset' in monitor */
+ qemu_system_reset_request();
+ break;
+
+ case WDT_SHUTDOWN: /* same as 'system_powerdown' in monitor */
+ qemu_system_powerdown_request();
+ break;
+
+ case WDT_POWEROFF: /* same as 'quit' command in monitor */
+ exit(0);
+ break;
+
+ case WDT_PAUSE: /* same as 'stop' command in monitor */
+ vm_stop(0);
+ break;
+
+ case WDT_DEBUG:
+ fprintf(stderr, "watchdog: timer fired\n");
+ break;
+
+ case WDT_NONE:
+ break;
+ }
+}
+
+void watchdog_pc_init(PCIBus *pci_bus)
+{
+ if (watchdog)
+ watchdog->wdt_pc_init(pci_bus);
+}
+
+void register_watchdogs(void)
+{
+ wdt_ib700_init();
+ wdt_i6300esb_init();
+}
diff --git a/hw/watchdog.h b/hw/watchdog.h
new file mode 100644
index 000000000..c2b2b3687
--- /dev/null
+++ b/hw/watchdog.h
@@ -0,0 +1,65 @@
+/*
+ * Virtual hardware watchdog.
+ *
+ * Copyright (C) 2009 Red Hat Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ * USA.
+ *
+ * By Richard W.M. Jones (rjones@redhat.com).
+ */
+
+#ifndef QEMU_WATCHDOG_H
+#define QEMU_WATCHDOG_H
+
+extern void wdt_i6300esb_init(void);
+extern void wdt_ib700_init(void);
+
+/* Possible values for action parameter. */
+#define WDT_RESET 1 /* Hard reset. */
+#define WDT_SHUTDOWN 2 /* Shutdown. */
+#define WDT_POWEROFF 3 /* Quit. */
+#define WDT_PAUSE 4 /* Pause. */
+#define WDT_DEBUG 5 /* Prints a message and continues running. */
+#define WDT_NONE 6 /* Do nothing. */
+
+struct WatchdogTimerModel {
+ LIST_ENTRY(WatchdogTimerModel) entry;
+
+ /* Short name of the device - used to select it on the command line. */
+ const char *wdt_name;
+ /* Longer description (eg. manufacturer and full model number). */
+ const char *wdt_description;
+
+ /* This callback should create/register the device. It is called
+ * indirectly from hw/pc.c when the virtual PC is being set up.
+ */
+ void (*wdt_pc_init)(PCIBus *pci_bus);
+};
+typedef struct WatchdogTimerModel WatchdogTimerModel;
+
+/* in vl.c */
+extern WatchdogTimerModel *watchdog;
+extern int watchdog_action;
+
+/* in hw/watchdog.c */
+extern int select_watchdog(const char *p);
+extern int select_watchdog_action(const char *action);
+extern void watchdog_add_model(WatchdogTimerModel *model);
+extern void watchdog_perform_action(void);
+extern void watchdog_pc_init(PCIBus *pci_bus);
+extern void register_watchdogs(void);
+
+#endif /* QEMU_WATCHDOG_H */
diff --git a/hw/wdt_i6300esb.c b/hw/wdt_i6300esb.c
new file mode 100644
index 000000000..f7ddea279
--- /dev/null
+++ b/hw/wdt_i6300esb.c
@@ -0,0 +1,470 @@
+/*
+ * Virtual hardware watchdog.
+ *
+ * Copyright (C) 2009 Red Hat Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ * USA.
+ *
+ * By Richard W.M. Jones (rjones@redhat.com).
+ */
+
+#include <inttypes.h>
+
+#include "qemu-common.h"
+#include "qemu-timer.h"
+#include "watchdog.h"
+#include "hw.h"
+#include "isa.h"
+#include "pc.h"
+#include "pci.h"
+
+/*#define I6300ESB_DEBUG 1*/
+
+#ifdef I6300ESB_DEBUG
+#define i6300esb_debug(fs,...) \
+ fprintf(stderr,"i6300esb: %s: "fs,__func__,##__VA_ARGS__)
+#else
+#define i6300esb_debug(fs,...)
+#endif
+
+#ifndef PCI_DEVICE_ID_INTEL_ESB_9
+#define PCI_DEVICE_ID_INTEL_ESB_9 0x25ab
+#endif
+
+/* PCI configuration registers */
+#define ESB_CONFIG_REG 0x60 /* Config register */
+#define ESB_LOCK_REG 0x68 /* WDT lock register */
+
+/* Memory mapped registers (offset from base address) */
+#define ESB_TIMER1_REG 0x00 /* Timer1 value after each reset */
+#define ESB_TIMER2_REG 0x04 /* Timer2 value after each reset */
+#define ESB_GINTSR_REG 0x08 /* General Interrupt Status Register */
+#define ESB_RELOAD_REG 0x0c /* Reload register */
+
+/* Lock register bits */
+#define ESB_WDT_FUNC (0x01 << 2) /* Watchdog functionality */
+#define ESB_WDT_ENABLE (0x01 << 1) /* Enable WDT */
+#define ESB_WDT_LOCK (0x01 << 0) /* Lock (nowayout) */
+
+/* Config register bits */
+#define ESB_WDT_REBOOT (0x01 << 5) /* Enable reboot on timeout */
+#define ESB_WDT_FREQ (0x01 << 2) /* Decrement frequency */
+#define ESB_WDT_INTTYPE (0x11 << 0) /* Interrupt type on timer1 timeout */
+
+/* Reload register bits */
+#define ESB_WDT_RELOAD (0x01 << 8) /* prevent timeout */
+
+/* Magic constants */
+#define ESB_UNLOCK1 0x80 /* Step 1 to unlock reset registers */
+#define ESB_UNLOCK2 0x86 /* Step 2 to unlock reset registers */
+
+/* Device state. */
+struct I6300State {
+ PCIDevice dev; /* PCI device state, must be first field. */
+
+ int reboot_enabled; /* "Reboot" on timer expiry. The real action
+ * performed depends on the -watchdog-action
+ * param passed on QEMU command line.
+ */
+ int clock_scale; /* Clock scale. */
+#define CLOCK_SCALE_1KHZ 0
+#define CLOCK_SCALE_1MHZ 1
+
+ int int_type; /* Interrupt type generated. */
+#define INT_TYPE_IRQ 0 /* APIC 1, INT 10 */
+#define INT_TYPE_SMI 2
+#define INT_TYPE_DISABLED 3
+
+ int free_run; /* If true, reload timer on expiry. */
+ int locked; /* If true, enabled field cannot be changed. */
+ int enabled; /* If true, watchdog is enabled. */
+
+ QEMUTimer *timer; /* The actual watchdog timer. */
+
+ uint32_t timer1_preload; /* Values preloaded into timer1, timer2. */
+ uint32_t timer2_preload;
+ int stage; /* Stage (1 or 2). */
+
+ int unlock_state; /* Guest writes 0x80, 0x86 to unlock the
+ * registers, and we transition through
+ * states 0 -> 1 -> 2 when this happens.
+ */
+
+ int previous_reboot_flag; /* If the watchdog caused the previous
+ * reboot, this flag will be set.
+ */
+};
+
+typedef struct I6300State I6300State;
+
+/* This function is called when the watchdog has either been enabled
+ * (hence it starts counting down) or has been keep-alived.
+ */
+static void i6300esb_restart_timer(I6300State *d, int stage)
+{
+ int64_t timeout;
+
+ if (!d->enabled)
+ return;
+
+ d->stage = stage;
+
+ if (d->stage <= 1)
+ timeout = d->timer1_preload;
+ else
+ timeout = d->timer2_preload;
+
+ if (d->clock_scale == CLOCK_SCALE_1KHZ)
+ timeout <<= 15;
+ else
+ timeout <<= 5;
+
+ /* Get the timeout in units of ticks_per_sec. */
+ timeout = ticks_per_sec * timeout / 33000000;
+
+ i6300esb_debug("stage %d, timeout %" PRIi64 "\n", d->stage, timeout);
+
+ qemu_mod_timer(d->timer, qemu_get_clock(vm_clock) + timeout);
+}
+
+/* This is called when the guest disables the watchdog. */
+static void i6300esb_disable_timer(I6300State *d)
+{
+ i6300esb_debug("timer disabled\n");
+
+ qemu_del_timer(d->timer);
+}
+
+static void i6300esb_reset(I6300State *d)
+{
+ /* XXX We should probably reset other parts of the state here,
+ * but we should also reset our state on general machine reset
+ * too. For now just disable the timer so it doesn't fire
+ * again after the reboot.
+ */
+ i6300esb_disable_timer(d);
+}
+
+/* This function is called when the watchdog expires. Note that
+ * the hardware has two timers, and so expiry happens in two stages.
+ * If d->stage == 1 then we perform the first stage action (usually,
+ * sending an interrupt) and then restart the timer again for the
+ * second stage. If the second stage expires then the watchdog
+ * really has run out.
+ */
+static void i6300esb_timer_expired(void *vp)
+{
+ I6300State *d = (I6300State *) vp;
+
+ i6300esb_debug("stage %d\n", d->stage);
+
+ if (d->stage == 1) {
+ /* What to do at the end of stage 1? */
+ switch (d->int_type) {
+ case INT_TYPE_IRQ:
+ fprintf(stderr, "i6300esb_timer_expired: I would send APIC 1 INT 10 here if I knew how (XXX)\n");
+ break;
+ case INT_TYPE_SMI:
+ fprintf(stderr, "i6300esb_timer_expired: I would send SMI here if I knew how (XXX)\n");
+ break;
+ }
+
+ /* Start the second stage. */
+ i6300esb_restart_timer(d, 2);
+ } else {
+ /* Second stage expired, reboot for real. */
+ if (d->reboot_enabled) {
+ d->previous_reboot_flag = 1;
+ watchdog_perform_action(); /* This reboots, exits, etc */
+ i6300esb_reset(d);
+ }
+
+ /* In "free running mode" we start stage 1 again. */
+ if (d->free_run)
+ i6300esb_restart_timer(d, 1);
+ }
+}
+
+static void i6300esb_config_write(PCIDevice *dev, uint32_t addr,
+ uint32_t data, int len)
+{
+ I6300State *d = (I6300State *) dev;
+ int old;
+
+ i6300esb_debug("addr = %x, data = %x, len = %d\n", addr, data, len);
+
+ if (addr == ESB_CONFIG_REG && len == 2) {
+ d->reboot_enabled = (data & ESB_WDT_REBOOT) == 0;
+ d->clock_scale =
+ (data & ESB_WDT_FREQ) != 0 ? CLOCK_SCALE_1MHZ : CLOCK_SCALE_1KHZ;
+ d->int_type = (data & ESB_WDT_INTTYPE);
+ } else if (addr == ESB_LOCK_REG && len == 1) {
+ if (!d->locked) {
+ d->locked = (data & ESB_WDT_LOCK) != 0;
+ d->free_run = (data & ESB_WDT_FUNC) != 0;
+ old = d->enabled;
+ d->enabled = (data & ESB_WDT_ENABLE) != 0;
+ if (!old && d->enabled) /* Enabled transitioned from 0 -> 1 */
+ i6300esb_restart_timer(d, 1);
+ else if (!d->enabled)
+ i6300esb_disable_timer(d);
+ }
+ } else {
+ pci_default_write_config(dev, addr, data, len);
+ }
+}
+
+static uint32_t i6300esb_config_read(PCIDevice *dev, uint32_t addr, int len)
+{
+ I6300State *d = (I6300State *) dev;
+ uint32_t data;
+
+ i6300esb_debug ("addr = %x, len = %d\n", addr, len);
+
+ if (addr == ESB_CONFIG_REG && len == 2) {
+ data =
+ (d->reboot_enabled ? 0 : ESB_WDT_REBOOT) |
+ (d->clock_scale == CLOCK_SCALE_1MHZ ? ESB_WDT_FREQ : 0) |
+ d->int_type;
+ return data;
+ } else if (addr == ESB_LOCK_REG && len == 1) {
+ data =
+ (d->free_run ? ESB_WDT_FUNC : 0) |
+ (d->locked ? ESB_WDT_LOCK : 0) |
+ (d->enabled ? ESB_WDT_ENABLE : 0);
+ return data;
+ } else {
+ return pci_default_read_config(dev, addr, len);
+ }
+}
+
+static uint32_t i6300esb_mem_readb(void *vp, target_phys_addr_t addr)
+{
+ i6300esb_debug ("addr = %x\n", (int) addr);
+
+ return 0;
+}
+
+static uint32_t i6300esb_mem_readw(void *vp, target_phys_addr_t addr)
+{
+ uint32_t data = 0;
+ I6300State *d = (I6300State *) vp;
+
+ i6300esb_debug("addr = %x\n", (int) addr);
+
+ if (addr == 0xc) {
+ /* The previous reboot flag is really bit 9, but there is
+ * a bug in the Linux driver where it thinks it's bit 12.
+ * Set both.
+ */
+ data = d->previous_reboot_flag ? 0x1200 : 0;
+ }
+
+ return data;
+}
+
+static uint32_t i6300esb_mem_readl(void *vp, target_phys_addr_t addr)
+{
+ i6300esb_debug("addr = %x\n", (int) addr);
+
+ return 0;
+}
+
+static void i6300esb_mem_writeb(void *vp, target_phys_addr_t addr, uint32_t val)
+{
+ I6300State *d = (I6300State *) vp;
+
+ i6300esb_debug("addr = %x, val = %x\n", (int) addr, val);
+
+ if (addr == 0xc && val == 0x80)
+ d->unlock_state = 1;
+ else if (addr == 0xc && val == 0x86 && d->unlock_state == 1)
+ d->unlock_state = 2;
+}
+
+static void i6300esb_mem_writew(void *vp, target_phys_addr_t addr, uint32_t val)
+{
+ I6300State *d = (I6300State *) vp;
+
+ i6300esb_debug("addr = %x, val = %x\n", (int) addr, val);
+
+ if (addr == 0xc && val == 0x80)
+ d->unlock_state = 1;
+ else if (addr == 0xc && val == 0x86 && d->unlock_state == 1)
+ d->unlock_state = 2;
+ else {
+ if (d->unlock_state == 2) {
+ if (addr == 0xc) {
+ if ((val & 0x100) != 0)
+ /* This is the "ping" from the userspace watchdog in
+ * the guest ...
+ */
+ i6300esb_restart_timer(d, 1);
+
+ /* Setting bit 9 resets the previous reboot flag.
+ * There's a bug in the Linux driver where it sets
+ * bit 12 instead.
+ */
+ if ((val & 0x200) != 0 || (val & 0x1000) != 0) {
+ d->previous_reboot_flag = 0;
+ }
+ }
+
+ d->unlock_state = 0;
+ }
+ }
+}
+
+static void i6300esb_mem_writel(void *vp, target_phys_addr_t addr, uint32_t val)
+{
+ I6300State *d = (I6300State *) vp;
+
+ i6300esb_debug ("addr = %x, val = %x\n", (int) addr, val);
+
+ if (addr == 0xc && val == 0x80)
+ d->unlock_state = 1;
+ else if (addr == 0xc && val == 0x86 && d->unlock_state == 1)
+ d->unlock_state = 2;
+ else {
+ if (d->unlock_state == 2) {
+ if (addr == 0)
+ d->timer1_preload = val & 0xfffff;
+ else if (addr == 4)
+ d->timer2_preload = val & 0xfffff;
+
+ d->unlock_state = 0;
+ }
+ }
+}
+
+static void i6300esb_map(PCIDevice *dev, int region_num,
+ uint32_t addr, uint32_t size, int type)
+{
+ static CPUReadMemoryFunc *mem_read[3] = {
+ i6300esb_mem_readb,
+ i6300esb_mem_readw,
+ i6300esb_mem_readl,
+ };
+ static CPUWriteMemoryFunc *mem_write[3] = {
+ i6300esb_mem_writeb,
+ i6300esb_mem_writew,
+ i6300esb_mem_writel,
+ };
+ I6300State *d = (I6300State *) dev;
+ int io_mem;
+
+ i6300esb_debug("addr = %x, size = %x, type = %d\n", addr, size, type);
+
+ io_mem = cpu_register_io_memory (0, mem_read, mem_write, d);
+ cpu_register_physical_memory (addr, 0x10, io_mem);
+ /* qemu_register_coalesced_mmio (addr, 0x10); ? */
+}
+
+static void i6300esb_save(QEMUFile *f, void *vp)
+{
+ I6300State *d = (I6300State *) vp;
+
+ pci_device_save(&d->dev, f);
+ qemu_put_be32(f, d->reboot_enabled);
+ qemu_put_be32(f, d->clock_scale);
+ qemu_put_be32(f, d->int_type);
+ qemu_put_be32(f, d->free_run);
+ qemu_put_be32(f, d->locked);
+ qemu_put_be32(f, d->enabled);
+ qemu_put_timer(f, d->timer);
+ qemu_put_be32(f, d->timer1_preload);
+ qemu_put_be32(f, d->timer2_preload);
+ qemu_put_be32(f, d->stage);
+ qemu_put_be32(f, d->unlock_state);
+ qemu_put_be32(f, d->previous_reboot_flag);
+}
+
+static int i6300esb_load(QEMUFile *f, void *vp, int version)
+{
+ I6300State *d = (I6300State *) vp;
+
+ if (version != sizeof (I6300State))
+ return -EINVAL;
+
+ pci_device_load(&d->dev, f);
+ d->reboot_enabled = qemu_get_be32(f);
+ d->clock_scale = qemu_get_be32(f);
+ d->int_type = qemu_get_be32(f);
+ d->free_run = qemu_get_be32(f);
+ d->locked = qemu_get_be32(f);
+ d->enabled = qemu_get_be32(f);
+ qemu_get_timer(f, d->timer);
+ d->timer1_preload = qemu_get_be32(f);
+ d->timer2_preload = qemu_get_be32(f);
+ d->stage = qemu_get_be32(f);
+ d->unlock_state = qemu_get_be32(f);
+ d->previous_reboot_flag = qemu_get_be32(f);
+
+ return 0;
+}
+
+/* Create and initialize a virtual Intel 6300ESB during PC creation. */
+static void i6300esb_pc_init(PCIBus *pci_bus)
+{
+ I6300State *d;
+ uint8_t *pci_conf;
+
+ if (!pci_bus) {
+ fprintf(stderr, "wdt_i6300esb: no PCI bus in this machine\n");
+ return;
+ }
+
+ d = (I6300State *)
+ pci_register_device (pci_bus, "i6300esb_wdt", sizeof (I6300State),
+ -1,
+ i6300esb_config_read, i6300esb_config_write);
+
+ d->reboot_enabled = 1;
+ d->clock_scale = CLOCK_SCALE_1KHZ;
+ d->int_type = INT_TYPE_IRQ;
+ d->free_run = 0;
+ d->locked = 0;
+ d->enabled = 0;
+ d->timer = qemu_new_timer(vm_clock, i6300esb_timer_expired, d);
+ d->timer1_preload = 0xfffff;
+ d->timer2_preload = 0xfffff;
+ d->stage = 1;
+ d->unlock_state = 0;
+ d->previous_reboot_flag = 0;
+
+ pci_conf = d->dev.config;
+ pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_INTEL);
+ pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_INTEL_ESB_9);
+ pci_config_set_class(pci_conf, PCI_CLASS_SYSTEM_OTHER);
+ pci_conf[0x0e] = 0x00;
+
+ pci_register_io_region(&d->dev, 0, 0x10,
+ PCI_ADDRESS_SPACE_MEM, i6300esb_map);
+
+ register_savevm("i6300esb_wdt", -1, sizeof(I6300State),
+ i6300esb_save, i6300esb_load, d);
+}
+
+static WatchdogTimerModel model = {
+ .wdt_name = "i6300esb",
+ .wdt_description = "Intel 6300ESB",
+ .wdt_pc_init = i6300esb_pc_init,
+};
+
+void wdt_i6300esb_init(void)
+{
+ watchdog_add_model(&model);
+}
diff --git a/hw/wdt_ib700.c b/hw/wdt_ib700.c
new file mode 100644
index 000000000..d32aaf13f
--- /dev/null
+++ b/hw/wdt_ib700.c
@@ -0,0 +1,112 @@
+/*
+ * Virtual hardware watchdog.
+ *
+ * Copyright (C) 2009 Red Hat Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ * USA.
+ *
+ * By Richard W.M. Jones (rjones@redhat.com).
+ */
+
+#include "qemu-common.h"
+#include "qemu-timer.h"
+#include "watchdog.h"
+#include "hw.h"
+#include "isa.h"
+#include "pc.h"
+
+/*#define IB700_DEBUG 1*/
+
+#ifdef IB700_DEBUG
+#define ib700_debug(fs,...) \
+ fprintf(stderr,"ib700: %s: "fs,__func__,##__VA_ARGS__)
+#else
+#define ib700_debug(fs,...)
+#endif
+
+/* This is the timer. We use a global here because the watchdog
+ * code ensures there is only one watchdog (it is located at a fixed,
+ * unchangable IO port, so there could only ever be one anyway).
+ */
+static QEMUTimer *timer = NULL;
+
+/* A write to this register enables the timer. */
+static void ib700_write_enable_reg(void *vp, uint32_t addr, uint32_t data)
+{
+ static int time_map[] = {
+ 30, 28, 26, 24, 22, 20, 18, 16,
+ 14, 12, 10, 8, 6, 4, 2, 0
+ };
+ int64 timeout;
+
+ ib700_debug("addr = %x, data = %x\n", addr, data);
+
+ timeout = (int64_t) time_map[data & 0xF] * ticks_per_sec;
+ qemu_mod_timer(timer, qemu_get_clock (vm_clock) + timeout);
+}
+
+/* A write (of any value) to this register disables the timer. */
+static void ib700_write_disable_reg(void *vp, uint32_t addr, uint32_t data)
+{
+ ib700_debug("addr = %x, data = %x\n", addr, data);
+
+ qemu_del_timer(timer);
+}
+
+/* This is called when the watchdog expires. */
+static void ib700_timer_expired(void *vp)
+{
+ ib700_debug("watchdog expired\n");
+
+ watchdog_perform_action();
+ qemu_del_timer(timer);
+}
+
+static void ib700_save(QEMUFile *f, void *vp)
+{
+ qemu_put_timer(f, timer);
+}
+
+static int ib700_load(QEMUFile *f, void *vp, int version)
+{
+ if (version != 0)
+ return -EINVAL;
+
+ qemu_get_timer(f, timer);
+
+ return 0;
+}
+
+/* Create and initialize a virtual IB700 during PC creation. */
+static void ib700_pc_init(PCIBus *unused)
+{
+ register_savevm("ib700_wdt", -1, 0, ib700_save, ib700_load, NULL);
+
+ register_ioport_write(0x441, 2, 1, ib700_write_disable_reg, NULL);
+ register_ioport_write(0x443, 2, 1, ib700_write_enable_reg, NULL);
+}
+
+static WatchdogTimerModel model = {
+ .wdt_name = "ib700",
+ .wdt_description = "iBASE 700",
+ .wdt_pc_init = ib700_pc_init,
+};
+
+void wdt_ib700_init(void)
+{
+ watchdog_add_model(&model);
+ timer = qemu_new_timer(vm_clock, ib700_timer_expired, NULL);
+}
diff --git a/hw/xen_blkif.h b/hw/xen_blkif.h
index 254a5fd50..738b8fe53 100644
--- a/hw/xen_blkif.h
+++ b/hw/xen_blkif.h
@@ -59,8 +59,8 @@ DEFINE_RING_TYPES(blkif_x86_64, struct blkif_x86_64_request, struct blkif_x86_64
union blkif_back_rings {
blkif_back_ring_t native;
blkif_common_back_ring_t common;
- blkif_x86_32_back_ring_t x86_32;
- blkif_x86_64_back_ring_t x86_64;
+ blkif_x86_32_back_ring_t x86_32_part;
+ blkif_x86_64_back_ring_t x86_64_part;
};
typedef union blkif_back_rings blkif_back_rings_t;
diff --git a/hw/xen_console.c b/hw/xen_console.c
index 27f809df6..27a0083d2 100644
--- a/hw/xen_console.c
+++ b/hw/xen_console.c
@@ -189,7 +189,7 @@ static int con_init(struct XenDevice *xendev)
free(dom);
type = xenstore_read_str(con->console, "type");
- if (!type || 0 != strcmp(type, "ioemu")) {
+ if (!type || strcmp(type, "ioemu") != 0) {
xen_be_printf(xendev, 1, "not for me (type=%s)\n", type);
return -1;
}
diff --git a/hw/xen_disk.c b/hw/xen_disk.c
index 527f84b3e..f95e37312 100644
--- a/hw/xen_disk.c
+++ b/hw/xen_disk.c
@@ -179,7 +179,7 @@ static int ioreq_parse(struct ioreq *ioreq)
switch (ioreq->req.operation) {
case BLKIF_OP_READ:
ioreq->prot = PROT_WRITE; /* to memory */
- if (BLKIF_OP_READ != ioreq->req.operation && blkdev->mode[0] != 'w') {
+ if (ioreq->req.operation != BLKIF_OP_READ && blkdev->mode[0] != 'w') {
xen_be_printf(&blkdev->xendev, 0, "error: write req for ro device\n");
goto err;
}
@@ -440,10 +440,12 @@ static int blk_send_response_one(struct ioreq *ioreq)
dst = RING_GET_RESPONSE(&blkdev->rings.native, blkdev->rings.native.rsp_prod_pvt);
break;
case BLKIF_PROTOCOL_X86_32:
- dst = RING_GET_RESPONSE(&blkdev->rings.x86_32, blkdev->rings.x86_32.rsp_prod_pvt);
+ dst = RING_GET_RESPONSE(&blkdev->rings.x86_32_part,
+ blkdev->rings.x86_32_part.rsp_prod_pvt);
break;
case BLKIF_PROTOCOL_X86_64:
- dst = RING_GET_RESPONSE(&blkdev->rings.x86_64, blkdev->rings.x86_64.rsp_prod_pvt);
+ dst = RING_GET_RESPONSE(&blkdev->rings.x86_64_part,
+ blkdev->rings.x86_64_part.rsp_prod_pvt);
break;
default:
dst = NULL;
@@ -491,10 +493,12 @@ static int blk_get_request(struct XenBlkDev *blkdev, struct ioreq *ioreq, RING_I
sizeof(ioreq->req));
break;
case BLKIF_PROTOCOL_X86_32:
- blkif_get_x86_32_req(&ioreq->req, RING_GET_REQUEST(&blkdev->rings.x86_32, rc));
+ blkif_get_x86_32_req(&ioreq->req,
+ RING_GET_REQUEST(&blkdev->rings.x86_32_part, rc));
break;
case BLKIF_PROTOCOL_X86_64:
- blkif_get_x86_64_req(&ioreq->req, RING_GET_REQUEST(&blkdev->rings.x86_64, rc));
+ blkif_get_x86_64_req(&ioreq->req,
+ RING_GET_REQUEST(&blkdev->rings.x86_64_part, rc));
break;
}
return 0;
@@ -513,7 +517,7 @@ static void blk_handle_requests(struct XenBlkDev *blkdev)
if (use_aio)
blk_send_response_all(blkdev);
- while ((rc != rp)) {
+ while (rc != rp) {
/* pull request from ring */
if (RING_REQUEST_CONS_OVERFLOW(&blkdev->rings.common, rc))
break;
@@ -698,13 +702,15 @@ static int blk_connect(struct XenDevice *xendev)
case BLKIF_PROTOCOL_X86_32:
{
blkif_x86_32_sring_t *sring_x86_32 = blkdev->sring;
- BACK_RING_INIT(&blkdev->rings.x86_32, sring_x86_32, XC_PAGE_SIZE);
+
+ BACK_RING_INIT(&blkdev->rings.x86_32_part, sring_x86_32, XC_PAGE_SIZE);
break;
}
case BLKIF_PROTOCOL_X86_64:
{
blkif_x86_64_sring_t *sring_x86_64 = blkdev->sring;
- BACK_RING_INIT(&blkdev->rings.x86_64, sring_x86_64, XC_PAGE_SIZE);
+
+ BACK_RING_INIT(&blkdev->rings.x86_64_part, sring_x86_64, XC_PAGE_SIZE);
break;
}
}
diff --git a/hw/xen_domainbuild.c b/hw/xen_domainbuild.c
index 21710ebf1..20d731ded 100644
--- a/hw/xen_domainbuild.c
+++ b/hw/xen_domainbuild.c
@@ -137,7 +137,7 @@ static void xen_domain_poll(void *opaque)
int rc;
rc = xc_domain_getinfo(xen_xc, xen_domid, 1, &info);
- if ((1 != rc) || (info.domid != xen_domid)) {
+ if ((rc != 1) || (info.domid != xen_domid)) {
qemu_log("xen: domain %d is gone\n", xen_domid);
goto quit;
}
@@ -186,7 +186,7 @@ static void xen_domain_watcher(void)
rc = read(fd[0], &byte, 1);
switch (rc) {
case -1:
- if (EINTR == errno)
+ if (errno == EINTR)
continue;
qemu_log("%s: Huh? read error: %s\n", __FUNCTION__, strerror(errno));
qemu_running = 0;
diff --git a/hw/xenfb.c b/hw/xenfb.c
index d93844122..ad3e8eea5 100644
--- a/hw/xenfb.c
+++ b/hw/xenfb.c
@@ -694,7 +694,6 @@ static void xenfb_send_refresh_period(struct XenFB *xenfb, int period)
static void xenfb_update(void *opaque)
{
struct XenFB *xenfb = opaque;
- struct DisplayChangeListener *l;
int i;
if (xenfb->c.xendev.be_state != XenbusStateConnected)
@@ -702,6 +701,7 @@ static void xenfb_update(void *opaque)
if (xenfb->feature_update) {
#ifdef XENFB_TYPE_REFRESH_PERIOD
+ struct DisplayChangeListener *l;
int period = 99999999;
int idle = 1;
diff --git a/kvm-all.c b/kvm-all.c
index 32cd636f8..36659a95e 100644
--- a/kvm-all.c
+++ b/kvm-all.c
@@ -583,7 +583,15 @@ void kvm_set_phys_mem(target_phys_addr_t start_addr,
int err;
if (start_addr & ~TARGET_PAGE_MASK) {
- fprintf(stderr, "Only page-aligned memory slots supported\n");
+ if (flags >= IO_MEM_UNASSIGNED) {
+ if (!kvm_lookup_overlapping_slot(s, start_addr,
+ start_addr + size)) {
+ return;
+ }
+ fprintf(stderr, "Unaligned split of a KVM memory slot\n");
+ } else {
+ fprintf(stderr, "Only page-aligned memory slots supported\n");
+ }
abort();
}
@@ -765,6 +773,24 @@ int kvm_has_sync_mmu(void)
return 0;
}
+void kvm_setup_guest_memory(void *start, size_t size)
+{
+ if (!kvm_has_sync_mmu()) {
+#ifdef MADV_DONTFORK
+ int ret = madvise(start, size, MADV_DONTFORK);
+
+ if (ret) {
+ perror("madvice");
+ exit(1);
+ }
+#else
+ fprintf(stderr,
+ "Need MADV_DONTFORK in absence of synchronous KVM MMU\n");
+ exit(1);
+#endif
+ }
+}
+
#ifdef KVM_CAP_SET_GUEST_DEBUG
struct kvm_sw_breakpoint *kvm_find_sw_breakpoint(CPUState *env,
target_ulong pc)
diff --git a/kvm.h b/kvm.h
index 5259c11ae..86d67bc94 100644
--- a/kvm.h
+++ b/kvm.h
@@ -50,6 +50,8 @@ int kvm_log_stop(target_phys_addr_t phys_addr, ram_addr_t size);
int kvm_has_sync_mmu(void);
+void kvm_setup_guest_memory(void *start, size_t size);
+
int kvm_coalesce_mmio_region(target_phys_addr_t start, ram_addr_t size);
int kvm_uncoalesce_mmio_region(target_phys_addr_t start, ram_addr_t size);
diff --git a/linux-user/arm/nwfpe/fpa11.c b/linux-user/arm/nwfpe/fpa11.c
index eb006f0df..67e65e523 100644
--- a/linux-user/arm/nwfpe/fpa11.c
+++ b/linux-user/arm/nwfpe/fpa11.c
@@ -30,11 +30,6 @@
#include <stdio.h>
-/* forward declarations */
-unsigned int EmulateCPDO(const unsigned int);
-unsigned int EmulateCPDT(const unsigned int);
-unsigned int EmulateCPRT(const unsigned int);
-
FPA11* qemufpa=0;
CPUARMState* user_registers;
diff --git a/linux-user/arm/nwfpe/fpa11.h b/linux-user/arm/nwfpe/fpa11.h
index 4fc0b3b88..032870180 100644
--- a/linux-user/arm/nwfpe/fpa11.h
+++ b/linux-user/arm/nwfpe/fpa11.h
@@ -116,6 +116,15 @@ static inline void writeConditionCodes(unsigned int x)
unsigned int EmulateAll(unsigned int opcode, FPA11* qfpa, CPUARMState* qregs);
+unsigned int EmulateCPDO(const unsigned int);
+unsigned int EmulateCPDT(const unsigned int);
+unsigned int EmulateCPRT(const unsigned int);
+
+unsigned int SingleCPDO(const unsigned int opcode);
+unsigned int DoubleCPDO(const unsigned int opcode);
+unsigned int ExtendedCPDO(const unsigned int opcode);
+
+
/* included only for get_user/put_user macros */
#include "qemu.h"
diff --git a/linux-user/arm/nwfpe/fpa11_cpdo.c b/linux-user/arm/nwfpe/fpa11_cpdo.c
index 777963728..66691122d 100644
--- a/linux-user/arm/nwfpe/fpa11_cpdo.c
+++ b/linux-user/arm/nwfpe/fpa11_cpdo.c
@@ -22,10 +22,6 @@
#include "fpa11.h"
#include "fpopcode.h"
-unsigned int SingleCPDO(const unsigned int opcode);
-unsigned int DoubleCPDO(const unsigned int opcode);
-unsigned int ExtendedCPDO(const unsigned int opcode);
-
unsigned int EmulateCPDO(const unsigned int opcode)
{
FPA11 *fpa11 = GET_FPA11();
diff --git a/linux-user/arm/nwfpe/fpa11_cpdt.c b/linux-user/arm/nwfpe/fpa11_cpdt.c
index 41877dfe8..76c6dcff3 100644
--- a/linux-user/arm/nwfpe/fpa11_cpdt.c
+++ b/linux-user/arm/nwfpe/fpa11_cpdt.c
@@ -29,9 +29,8 @@
//#include <asm/uaccess.h>
static inline
-void loadSingle(const unsigned int Fn,const unsigned int *pMem)
+void loadSingle(const unsigned int Fn, target_ulong addr)
{
- target_ulong addr = (target_ulong)(long)pMem;
FPA11 *fpa11 = GET_FPA11();
fpa11->fType[Fn] = typeSingle;
/* FIXME - handle failure of get_user() */
@@ -39,9 +38,8 @@ void loadSingle(const unsigned int Fn,const unsigned int *pMem)
}
static inline
-void loadDouble(const unsigned int Fn,const unsigned int *pMem)
+void loadDouble(const unsigned int Fn, target_ulong addr)
{
- target_ulong addr = (target_ulong)(long)pMem;
FPA11 *fpa11 = GET_FPA11();
unsigned int *p;
p = (unsigned int*)&fpa11->fpreg[Fn].fDouble;
@@ -58,9 +56,8 @@ void loadDouble(const unsigned int Fn,const unsigned int *pMem)
}
static inline
-void loadExtended(const unsigned int Fn,const unsigned int *pMem)
+void loadExtended(const unsigned int Fn, target_ulong addr)
{
- target_ulong addr = (target_ulong)(long)pMem;
FPA11 *fpa11 = GET_FPA11();
unsigned int *p;
p = (unsigned int*)&fpa11->fpreg[Fn].fExtended;
@@ -72,9 +69,8 @@ void loadExtended(const unsigned int Fn,const unsigned int *pMem)
}
static inline
-void loadMultiple(const unsigned int Fn,const unsigned int *pMem)
+void loadMultiple(const unsigned int Fn, target_ulong addr)
{
- target_ulong addr = (target_ulong)(long)pMem;
FPA11 *fpa11 = GET_FPA11();
register unsigned int *p;
unsigned long x;
@@ -108,9 +104,8 @@ void loadMultiple(const unsigned int Fn,const unsigned int *pMem)
}
static inline
-void storeSingle(const unsigned int Fn,unsigned int *pMem)
+void storeSingle(const unsigned int Fn, target_ulong addr)
{
- target_ulong addr = (target_ulong)(long)pMem;
FPA11 *fpa11 = GET_FPA11();
float32 val;
register unsigned int *p = (unsigned int*)&val;
@@ -133,9 +128,8 @@ void storeSingle(const unsigned int Fn,unsigned int *pMem)
}
static inline
-void storeDouble(const unsigned int Fn,unsigned int *pMem)
+void storeDouble(const unsigned int Fn, target_ulong addr)
{
- target_ulong addr = (target_ulong)(long)pMem;
FPA11 *fpa11 = GET_FPA11();
float64 val;
register unsigned int *p = (unsigned int*)&val;
@@ -163,9 +157,8 @@ void storeDouble(const unsigned int Fn,unsigned int *pMem)
}
static inline
-void storeExtended(const unsigned int Fn,unsigned int *pMem)
+void storeExtended(const unsigned int Fn, target_ulong addr)
{
- target_ulong addr = (target_ulong)(long)pMem;
FPA11 *fpa11 = GET_FPA11();
floatx80 val;
register unsigned int *p = (unsigned int*)&val;
@@ -190,9 +183,8 @@ void storeExtended(const unsigned int Fn,unsigned int *pMem)
}
static inline
-void storeMultiple(const unsigned int Fn,unsigned int *pMem)
+void storeMultiple(const unsigned int Fn, target_ulong addr)
{
- target_ulong addr = (target_ulong)(long)pMem;
FPA11 *fpa11 = GET_FPA11();
register unsigned int nType, *p;
@@ -220,25 +212,26 @@ void storeMultiple(const unsigned int Fn,unsigned int *pMem)
}
}
-unsigned int PerformLDF(const unsigned int opcode)
+static unsigned int PerformLDF(const unsigned int opcode)
{
- unsigned int *pBase, *pAddress, *pFinal, nRc = 1,
+ target_ulong pBase, pAddress, pFinal;
+ unsigned int nRc = 1,
write_back = WRITE_BACK(opcode);
//printk("PerformLDF(0x%08x), Fd = 0x%08x\n",opcode,getFd(opcode));
- pBase = (unsigned int*)readRegister(getRn(opcode));
+ pBase = readRegister(getRn(opcode));
if (REG_PC == getRn(opcode))
{
- pBase += 2;
+ pBase += 8;
write_back = 0;
}
pFinal = pBase;
if (BIT_UP_SET(opcode))
- pFinal += getOffset(opcode);
+ pFinal += getOffset(opcode) * 4;
else
- pFinal -= getOffset(opcode);
+ pFinal -= getOffset(opcode) * 4;
if (PREINDEXED(opcode)) pAddress = pFinal; else pAddress = pBase;
@@ -254,26 +247,27 @@ unsigned int PerformLDF(const unsigned int opcode)
return nRc;
}
-unsigned int PerformSTF(const unsigned int opcode)
+static unsigned int PerformSTF(const unsigned int opcode)
{
- unsigned int *pBase, *pAddress, *pFinal, nRc = 1,
+ target_ulong pBase, pAddress, pFinal;
+ unsigned int nRc = 1,
write_back = WRITE_BACK(opcode);
//printk("PerformSTF(0x%08x), Fd = 0x%08x\n",opcode,getFd(opcode));
SetRoundingMode(ROUND_TO_NEAREST);
- pBase = (unsigned int*)readRegister(getRn(opcode));
+ pBase = readRegister(getRn(opcode));
if (REG_PC == getRn(opcode))
{
- pBase += 2;
+ pBase += 8;
write_back = 0;
}
pFinal = pBase;
if (BIT_UP_SET(opcode))
- pFinal += getOffset(opcode);
+ pFinal += getOffset(opcode) * 4;
else
- pFinal -= getOffset(opcode);
+ pFinal -= getOffset(opcode) * 4;
if (PREINDEXED(opcode)) pAddress = pFinal; else pAddress = pBase;
@@ -289,23 +283,24 @@ unsigned int PerformSTF(const unsigned int opcode)
return nRc;
}
-unsigned int PerformLFM(const unsigned int opcode)
+static unsigned int PerformLFM(const unsigned int opcode)
{
- unsigned int i, Fd, *pBase, *pAddress, *pFinal,
+ unsigned int i, Fd,
write_back = WRITE_BACK(opcode);
+ target_ulong pBase, pAddress, pFinal;
- pBase = (unsigned int*)readRegister(getRn(opcode));
+ pBase = readRegister(getRn(opcode));
if (REG_PC == getRn(opcode))
{
- pBase += 2;
+ pBase += 8;
write_back = 0;
}
pFinal = pBase;
if (BIT_UP_SET(opcode))
- pFinal += getOffset(opcode);
+ pFinal += getOffset(opcode) * 4;
else
- pFinal -= getOffset(opcode);
+ pFinal -= getOffset(opcode) * 4;
if (PREINDEXED(opcode)) pAddress = pFinal; else pAddress = pBase;
@@ -313,7 +308,7 @@ unsigned int PerformLFM(const unsigned int opcode)
for (i=getRegisterCount(opcode);i>0;i--)
{
loadMultiple(Fd,pAddress);
- pAddress += 3; Fd++;
+ pAddress += 12; Fd++;
if (Fd == 8) Fd = 0;
}
@@ -321,23 +316,24 @@ unsigned int PerformLFM(const unsigned int opcode)
return 1;
}
-unsigned int PerformSFM(const unsigned int opcode)
+static unsigned int PerformSFM(const unsigned int opcode)
{
- unsigned int i, Fd, *pBase, *pAddress, *pFinal,
+ unsigned int i, Fd,
write_back = WRITE_BACK(opcode);
+ target_ulong pBase, pAddress, pFinal;
- pBase = (unsigned int*)readRegister(getRn(opcode));
+ pBase = readRegister(getRn(opcode));
if (REG_PC == getRn(opcode))
{
- pBase += 2;
+ pBase += 8;
write_back = 0;
}
pFinal = pBase;
if (BIT_UP_SET(opcode))
- pFinal += getOffset(opcode);
+ pFinal += getOffset(opcode) * 4;
else
- pFinal -= getOffset(opcode);
+ pFinal -= getOffset(opcode) * 4;
if (PREINDEXED(opcode)) pAddress = pFinal; else pAddress = pBase;
@@ -345,7 +341,7 @@ unsigned int PerformSFM(const unsigned int opcode)
for (i=getRegisterCount(opcode);i>0;i--)
{
storeMultiple(Fd,pAddress);
- pAddress += 3; Fd++;
+ pAddress += 12; Fd++;
if (Fd == 8) Fd = 0;
}
diff --git a/linux-user/arm/nwfpe/fpopcode.c b/linux-user/arm/nwfpe/fpopcode.c
index a733a1d1d..1e07e6048 100644
--- a/linux-user/arm/nwfpe/fpopcode.c
+++ b/linux-user/arm/nwfpe/fpopcode.c
@@ -59,21 +59,6 @@ const float32 float32Constant[] = {
0x41200000 /* single 10.0 */
};
-unsigned int getTransferLength(const unsigned int opcode)
-{
- unsigned int nRc;
-
- switch (opcode & MASK_TRANSFER_LENGTH)
- {
- case 0x00000000: nRc = 1; break; /* single precision */
- case 0x00008000: nRc = 2; break; /* double precision */
- case 0x00400000: nRc = 3; break; /* extended precision */
- default: nRc = 0;
- }
-
- return(nRc);
-}
-
unsigned int getRegisterCount(const unsigned int opcode)
{
unsigned int nRc;
@@ -90,21 +75,6 @@ unsigned int getRegisterCount(const unsigned int opcode)
return(nRc);
}
-unsigned int getRoundingPrecision(const unsigned int opcode)
-{
- unsigned int nRc;
-
- switch (opcode & MASK_ROUNDING_PRECISION)
- {
- case 0x00000000: nRc = 1; break;
- case 0x00000080: nRc = 2; break;
- case 0x00080000: nRc = 3; break;
- default: nRc = 0;
- }
-
- return(nRc);
-}
-
unsigned int getDestinationSize(const unsigned int opcode)
{
unsigned int nRc;
@@ -141,8 +111,3 @@ static const unsigned short aCC[16] = {
0xFFFF, // AL always
0 // NV
};
-
-unsigned int checkCondition(const unsigned int opcode, const unsigned int ccodes)
-{
- return (aCC[opcode>>28] >> (ccodes>>28)) & 1;
-}
diff --git a/monitor.c b/monitor.c
index 559c41c24..4a81b9dc6 100644
--- a/monitor.c
+++ b/monitor.c
@@ -27,6 +27,7 @@
#include "hw/pcmcia.h"
#include "hw/pc.h"
#include "hw/pci.h"
+#include "hw/watchdog.h"
#include "gdbstub.h"
#include "net.h"
#include "qemu-char.h"
@@ -618,6 +619,13 @@ static void do_gdbserver(Monitor *mon, const char *device)
}
#endif
+static void do_watchdog_action(Monitor *mon, const char *action)
+{
+ if (select_watchdog_action(action) == -1) {
+ monitor_printf(mon, "Unknown watchdog action '%s'\n", action);
+ }
+}
+
static void monitor_printc(Monitor *mon, int c)
{
monitor_printf(mon, "'");
@@ -1432,7 +1440,7 @@ static void do_info_kvm(Monitor *mon)
static void do_info_numa(Monitor *mon)
{
- int i, j;
+ int i;
CPUState *env;
monitor_printf(mon, "%d nodes\n", nb_numa_nodes);
@@ -1786,6 +1794,8 @@ static const mon_cmd_t mon_cmds[] = {
"target", "request VM to change it's memory allocation (in MB)" },
{ "set_link", "ss", do_set_link,
"name up|down", "change the link status of a network adapter" },
+ { "watchdog_action", "s", do_watchdog_action,
+ "[reset|shutdown|poweroff|pause|debug|none]", "change watchdog action" },
{ "acl", "sss?i?", do_acl, "<command> <aclname> [<match> [<index>]]\n",
"acl show vnc.username\n"
"acl policy vnc.username deny\n"
diff --git a/net.c b/net.c
index b5ebcead6..931def17e 100644
--- a/net.c
+++ b/net.c
@@ -630,7 +630,7 @@ void net_slirp_redir(Monitor *mon, const char *redir_str)
errmsg = "invalid redirection format\n";
fail:
if (mon) {
- monitor_printf(mon, errmsg);
+ monitor_printf(mon, "%s", errmsg);
} else {
fprintf(stderr, "qemu: %s", errmsg);
exit(1);
@@ -1289,7 +1289,7 @@ static void vde_to_qemu(void *opaque)
uint8_t buf[4096];
int size;
- size = vde_recv(s->vde, buf, sizeof(buf), 0);
+ size = vde_recv(s->vde, (char *)buf, sizeof(buf), 0);
if (size > 0) {
qemu_send_packet(s->vc, buf, size);
}
@@ -1300,7 +1300,7 @@ static void vde_from_qemu(void *opaque, const uint8_t *buf, int size)
VDEState *s = opaque;
int ret;
for(;;) {
- ret = vde_send(s->vde, buf, size, 0);
+ ret = vde_send(s->vde, (const char *)buf, size, 0);
if (ret < 0 && errno == EINTR) {
} else {
break;
@@ -1331,7 +1331,7 @@ static int net_vde_init(VLANState *vlan, const char *model,
};
s = qemu_mallocz(sizeof(VDEState));
- s->vde = vde_open(init_sock, "QEMU", &args);
+ s->vde = vde_open(init_sock, (char *)"QEMU", &args);
if (!s->vde){
free(s);
return -1;
@@ -1977,7 +1977,7 @@ int net_client_init(const char *device, const char *p)
uint8_t *macaddr;
int idx = nic_get_free_idx();
- if (check_params(buf, sizeof(buf), nic_params, p) < 0) {
+ if (check_params(nic_params, p) < 0) {
fprintf(stderr, "qemu: invalid parameter '%s' in '%s'\n",
buf, p);
return -1;
@@ -2028,7 +2028,7 @@ int net_client_init(const char *device, const char *p)
static const char * const slirp_params[] = {
"vlan", "name", "hostname", "restrict", "ip", NULL
};
- if (check_params(buf, sizeof(buf), slirp_params, p) < 0) {
+ if (check_params(slirp_params, p) < 0) {
fprintf(stderr, "qemu: invalid parameter '%s' in '%s'\n",
buf, p);
return -1;
@@ -2079,7 +2079,7 @@ int net_client_init(const char *device, const char *p)
};
char ifname[64];
- if (check_params(buf, sizeof(buf), tap_params, p) < 0) {
+ if (check_params(tap_params, p) < 0) {
fprintf(stderr, "qemu: invalid parameter '%s' in '%s'\n",
buf, p);
return -1;
@@ -2100,7 +2100,7 @@ int net_client_init(const char *device, const char *p)
int fd;
vlan->nb_host_devs++;
if (get_param_value(buf, sizeof(buf), "fd", p) > 0) {
- if (check_params(buf, sizeof(buf), fd_params, p) < 0) {
+ if (check_params(fd_params, p) < 0) {
fprintf(stderr, "qemu: invalid parameter '%s' in '%s'\n",
buf, p);
return -1;
@@ -2113,7 +2113,7 @@ int net_client_init(const char *device, const char *p)
static const char * const tap_params[] = {
"vlan", "name", "ifname", "script", "downscript", NULL
};
- if (check_params(buf, sizeof(buf), tap_params, p) < 0) {
+ if (check_params(tap_params, p) < 0) {
fprintf(stderr, "qemu: invalid parameter '%s' in '%s'\n",
buf, p);
return -1;
@@ -2134,7 +2134,7 @@ int net_client_init(const char *device, const char *p)
if (!strcmp(device, "socket")) {
if (get_param_value(buf, sizeof(buf), "fd", p) > 0) {
int fd;
- if (check_params(buf, sizeof(buf), fd_params, p) < 0) {
+ if (check_params(fd_params, p) < 0) {
fprintf(stderr, "qemu: invalid parameter '%s' in '%s'\n",
buf, p);
return -1;
@@ -2147,7 +2147,7 @@ int net_client_init(const char *device, const char *p)
static const char * const listen_params[] = {
"vlan", "name", "listen", NULL
};
- if (check_params(buf, sizeof(buf), listen_params, p) < 0) {
+ if (check_params(listen_params, p) < 0) {
fprintf(stderr, "qemu: invalid parameter '%s' in '%s'\n",
buf, p);
return -1;
@@ -2157,7 +2157,7 @@ int net_client_init(const char *device, const char *p)
static const char * const connect_params[] = {
"vlan", "name", "connect", NULL
};
- if (check_params(buf, sizeof(buf), connect_params, p) < 0) {
+ if (check_params(connect_params, p) < 0) {
fprintf(stderr, "qemu: invalid parameter '%s' in '%s'\n",
buf, p);
return -1;
@@ -2167,7 +2167,7 @@ int net_client_init(const char *device, const char *p)
static const char * const mcast_params[] = {
"vlan", "name", "mcast", NULL
};
- if (check_params(buf, sizeof(buf), mcast_params, p) < 0) {
+ if (check_params(mcast_params, p) < 0) {
fprintf(stderr, "qemu: invalid parameter '%s' in '%s'\n",
buf, p);
return -1;
@@ -2188,7 +2188,7 @@ int net_client_init(const char *device, const char *p)
char vde_sock[1024], vde_group[512];
int vde_port, vde_mode;
- if (check_params(buf, sizeof(buf), vde_params, p) < 0) {
+ if (check_params(vde_params, p) < 0) {
fprintf(stderr, "qemu: invalid parameter '%s' in '%s'\n",
buf, p);
return -1;
@@ -2271,7 +2271,7 @@ void net_host_device_add(Monitor *mon, const char *device, const char *opts)
monitor_printf(mon, "invalid host network device %s\n", device);
return;
}
- if (net_client_init(device, opts ? : "") < 0) {
+ if (net_client_init(device, opts ? opts : "") < 0) {
monitor_printf(mon, "adding host network device %s failed\n", device);
}
}
diff --git a/qemu-common.h b/qemu-common.h
index 942d3a6ec..ae334421e 100644
--- a/qemu-common.h
+++ b/qemu-common.h
@@ -194,6 +194,19 @@ struct qemu_work_item {
int done;
};
+/* Force QEMU to process pending events */
+void qemu_notify_event(void);
+
+/* Unblock cpu */
+void qemu_cpu_kick(void *env);
+int qemu_cpu_self(void *env);
+
+#ifdef CONFIG_USER_ONLY
+#define qemu_init_vcpu(env) do { } while (0)
+#else
+void qemu_init_vcpu(void *env);
+#endif
+
typedef struct QEMUIOVector {
struct iovec *iov;
int niov;
diff --git a/qemu-io.c b/qemu-io.c
index 405b6c5e0..60464e6ab 100644
--- a/qemu-io.c
+++ b/qemu-io.c
@@ -191,11 +191,13 @@ read_help(void)
"\n"
" Reads a segment of the currently open file, optionally dumping it to the\n"
" standard output stream (with -v option) for subsequent inspection.\n"
+" -C, -- report statistics in a machine parsable format\n"
+" -l, -- length for pattern verification (only with -P)\n"
" -p, -- use bdrv_pread to read the file\n"
" -P, -- use a pattern to verify read data\n"
-" -C, -- report statistics in a machine parsable format\n"
-" -v, -- dump buffer to standard output\n"
" -q, -- quite mode, do not show I/O statistics\n"
+" -s, -- start offset for pattern verification (only with -P)\n"
+" -v, -- dump buffer to standard output\n"
"\n");
}
@@ -204,18 +206,26 @@ read_f(int argc, char **argv)
{
struct timeval t1, t2;
int Cflag = 0, pflag = 0, qflag = 0, vflag = 0;
+ int Pflag = 0, sflag = 0, lflag = 0;
int c, cnt;
char *buf;
int64_t offset;
int count, total;
- int pattern = 0;
- int Pflag = 0;
+ int pattern = 0, pattern_offset = 0, pattern_count = 0;
- while ((c = getopt(argc, argv, "CpP:qv")) != EOF) {
+ while ((c = getopt(argc, argv, "Cl:pP:qs:v")) != EOF) {
switch (c) {
case 'C':
Cflag = 1;
break;
+ case 'l':
+ lflag = 1;
+ pattern_count = cvtnum(optarg);
+ if (pattern_count < 0) {
+ printf("non-numeric length argument -- %s\n", optarg);
+ return 0;
+ }
+ break;
case 'p':
pflag = 1;
break;
@@ -226,6 +236,14 @@ read_f(int argc, char **argv)
case 'q':
qflag = 1;
break;
+ case 's':
+ sflag = 1;
+ pattern_offset = cvtnum(optarg);
+ if (pattern_offset < 0) {
+ printf("non-numeric length argument -- %s\n", optarg);
+ return 0;
+ }
+ break;
case 'v':
vflag = 1;
break;
@@ -250,6 +268,19 @@ read_f(int argc, char **argv)
return 0;
}
+ if (!Pflag && (lflag || sflag)) {
+ return command_usage(&read_cmd);
+ }
+
+ if (!lflag) {
+ pattern_count = count - pattern_offset;
+ }
+
+ if ((pattern_count < 0) || (pattern_count + pattern_offset > count)) {
+ printf("pattern verfication range exceeds end of read data\n");
+ return 0;
+ }
+
if (!pflag)
if (offset & 0x1ff) {
printf("offset %lld is not sector aligned\n",
@@ -278,12 +309,12 @@ read_f(int argc, char **argv)
}
if (Pflag) {
- void* cmp_buf = malloc(count);
- memset(cmp_buf, pattern, count);
- if (memcmp(buf, cmp_buf, count)) {
+ void* cmp_buf = malloc(pattern_count);
+ memset(cmp_buf, pattern, pattern_count);
+ if (memcmp(buf + pattern_offset, cmp_buf, pattern_count)) {
printf("Pattern verification failed at offset %lld, "
"%d bytes\n",
- (long long) offset, count);
+ (long long) offset + pattern_offset, pattern_count);
}
free(cmp_buf);
}
@@ -309,7 +340,7 @@ static const cmdinfo_t read_cmd = {
.cfunc = read_f,
.argmin = 2,
.argmax = -1,
- .args = "[-aCpqv] [-P pattern ] off len",
+ .args = "[-aCpqv] [-P pattern [-s off] [-l len]] off len",
.oneline = "reads a number of bytes at a specified offset",
.help = read_help,
};
diff --git a/qemu-kvm.c b/qemu-kvm.c
index 68a921883..8c0d463c1 100644
--- a/qemu-kvm.c
+++ b/qemu-kvm.c
@@ -287,7 +287,7 @@ static int all_threads_paused(void)
return 1;
}
-void qemu_kvm_pause_all_threads(void)
+static void pause_all_threads(void)
{
CPUState *penv = first_cpu;
@@ -307,7 +307,7 @@ void qemu_kvm_pause_all_threads(void)
qemu_cond_wait(&qemu_pause_cond);
}
-void qemu_kvm_resume_all_threads(void)
+static void resume_all_threads(void)
{
CPUState *penv = first_cpu;
@@ -321,6 +321,14 @@ void qemu_kvm_resume_all_threads(void)
}
}
+static void kvm_vm_state_change_handler(void *context, int running, int reason)
+{
+ if (running)
+ resume_all_threads();
+ else
+ pause_all_threads();
+}
+
static void update_regs_for_sipi(CPUState *env)
{
kvm_arch_update_regs_for_sipi(env);
@@ -365,7 +373,7 @@ static void qemu_kvm_system_reset(void)
{
CPUState *penv = first_cpu;
- qemu_kvm_pause_all_threads();
+ pause_all_threads();
qemu_system_reset();
@@ -374,7 +382,7 @@ static void qemu_kvm_system_reset(void)
penv = (CPUState *)penv->next_cpu;
}
- qemu_kvm_resume_all_threads();
+ resume_all_threads();
}
static int kvm_main_loop_cpu(CPUState *env)
@@ -460,6 +468,7 @@ int kvm_init_ap(void)
#ifdef TARGET_I386
kvm_tpr_opt_setup();
#endif
+ qemu_add_vm_change_state_handler(kvm_vm_state_change_handler, NULL);
signal(SIG_IPI, sig_ipi_handler);
return 0;
@@ -603,7 +612,7 @@ int kvm_main_loop(void)
#endif
}
- qemu_kvm_pause_all_threads();
+ pause_all_threads();
pthread_mutex_unlock(&qemu_mutex);
return 0;
diff --git a/qemu-kvm.h b/qemu-kvm.h
index ca59af8d9..c0549dfc2 100644
--- a/qemu-kvm.h
+++ b/qemu-kvm.h
@@ -119,9 +119,6 @@ int qemu_kvm_register_coalesced_mmio(target_phys_addr_t addr,
int qemu_kvm_unregister_coalesced_mmio(target_phys_addr_t addr,
unsigned int size);
-void qemu_kvm_pause_all_threads(void);
-void qemu_kvm_resume_all_threads(void);
-
int kvm_coalesce_mmio_region(target_phys_addr_t start, ram_addr_t size);
int kvm_uncoalesce_mmio_region(target_phys_addr_t start, ram_addr_t size);
diff --git a/qemu-options.hx b/qemu-options.hx
index f7d83c97f..173f4581c 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -140,7 +140,7 @@ If your host crashes or loses power, then the guest may experience data
corruption. When using the @option{-snapshot} option, writeback caching is
used by default.
-The host page can be avoided entirely with @option{cache=none}. This will
+The host page cache can be avoided entirely with @option{cache=none}. This will
attempt to do disk IO directly to the guests memory. QEMU may still perform
an internal copy of the data.
@@ -1449,6 +1449,55 @@ order cores with complex cache hierarchies. The number of instructions
executed often has little or no correlation with actual performance.
ETEXI
+DEF("watchdog", HAS_ARG, QEMU_OPTION_watchdog, \
+ "-watchdog i6300esb|ib700\n" \
+ " enable virtual hardware watchdog [default=none]\n")
+STEXI
+@item -watchdog @var{model}
+Create a virtual hardware watchdog device. Once enabled (by a guest
+action), the watchdog must be periodically polled by an agent inside
+the guest or else the guest will be restarted.
+
+The @var{model} is the model of hardware watchdog to emulate. Choices
+for model are: @code{ib700} (iBASE 700) which is a very simple ISA
+watchdog with a single timer, or @code{i6300esb} (Intel 6300ESB I/O
+controller hub) which is a much more featureful PCI-based dual-timer
+watchdog. Choose a model for which your guest has drivers.
+
+Use @code{-watchdog ?} to list available hardware models. Only one
+watchdog can be enabled for a guest.
+ETEXI
+
+DEF("watchdog-action", HAS_ARG, QEMU_OPTION_watchdog_action, \
+ "-watchdog-action reset|shutdown|poweroff|pause|debug|none\n" \
+ " action when watchdog fires [default=reset]\n")
+STEXI
+@item -watchdog-action @var{action}
+
+The @var{action} controls what QEMU will do when the watchdog timer
+expires.
+The default is
+@code{reset} (forcefully reset the guest).
+Other possible actions are:
+@code{shutdown} (attempt to gracefully shutdown the guest),
+@code{poweroff} (forcefully poweroff the guest),
+@code{pause} (pause the guest),
+@code{debug} (print a debug message and continue), or
+@code{none} (do nothing).
+
+Note that the @code{shutdown} action requires that the guest responds
+to ACPI signals, which it may not be able to do in the sort of
+situations where the watchdog would have expired, and thus
+@code{-watchdog-action shutdown} is not recommended for production use.
+
+Examples:
+
+@table @code
+@item -watchdog i6300esb -watchdog-action pause
+@item -watchdog ib700
+@end table
+ETEXI
+
DEF("echr", HAS_ARG, QEMU_OPTION_echr, \
"-echr chr set terminal escape character instead of ctrl-a\n")
STEXI
diff --git a/qemu-thread.c b/qemu-thread.c
new file mode 100644
index 000000000..719cfcddd
--- /dev/null
+++ b/qemu-thread.c
@@ -0,0 +1,163 @@
+/*
+ * Wrappers around mutex/cond/thread functions
+ *
+ * Copyright Red Hat, Inc. 2009
+ *
+ * Author:
+ * Marcelo Tosatti <mtosatti@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <time.h>
+#include <signal.h>
+#include <stdint.h>
+#include <string.h>
+#include "qemu-thread.h"
+
+static void error_exit(int err, const char *msg)
+{
+ fprintf(stderr, "qemu: %s: %s\n", msg, strerror(err));
+ exit(1);
+}
+
+void qemu_mutex_init(QemuMutex *mutex)
+{
+ int err;
+
+ err = pthread_mutex_init(&mutex->lock, NULL);
+ if (err)
+ error_exit(err, __func__);
+}
+
+void qemu_mutex_lock(QemuMutex *mutex)
+{
+ int err;
+
+ err = pthread_mutex_lock(&mutex->lock);
+ if (err)
+ error_exit(err, __func__);
+}
+
+int qemu_mutex_trylock(QemuMutex *mutex)
+{
+ return pthread_mutex_trylock(&mutex->lock);
+}
+
+static void timespec_add_ms(struct timespec *ts, uint64_t msecs)
+{
+ ts->tv_sec = ts->tv_sec + (long)(msecs / 1000);
+ ts->tv_nsec = (ts->tv_nsec + ((long)msecs % 1000) * 1000000);
+ if (ts->tv_nsec >= 1000000000) {
+ ts->tv_nsec -= 1000000000;
+ ts->tv_sec++;
+ }
+}
+
+int qemu_mutex_timedlock(QemuMutex *mutex, uint64_t msecs)
+{
+ int err;
+ struct timespec ts;
+
+ clock_gettime(CLOCK_REALTIME, &ts);
+ timespec_add_ms(&ts, msecs);
+
+ err = pthread_mutex_timedlock(&mutex->lock, &ts);
+ if (err && err != ETIMEDOUT)
+ error_exit(err, __func__);
+ return err;
+}
+
+void qemu_mutex_unlock(QemuMutex *mutex)
+{
+ int err;
+
+ err = pthread_mutex_unlock(&mutex->lock);
+ if (err)
+ error_exit(err, __func__);
+}
+
+void qemu_cond_init(QemuCond *cond)
+{
+ int err;
+
+ err = pthread_cond_init(&cond->cond, NULL);
+ if (err)
+ error_exit(err, __func__);
+}
+
+void qemu_cond_signal(QemuCond *cond)
+{
+ int err;
+
+ err = pthread_cond_signal(&cond->cond);
+ if (err)
+ error_exit(err, __func__);
+}
+
+void qemu_cond_broadcast(QemuCond *cond)
+{
+ int err;
+
+ err = pthread_cond_broadcast(&cond->cond);
+ if (err)
+ error_exit(err, __func__);
+}
+
+void qemu_cond_wait(QemuCond *cond, QemuMutex *mutex)
+{
+ int err;
+
+ err = pthread_cond_wait(&cond->cond, &mutex->lock);
+ if (err)
+ error_exit(err, __func__);
+}
+
+int qemu_cond_timedwait(QemuCond *cond, QemuMutex *mutex, uint64_t msecs)
+{
+ struct timespec ts;
+ int err;
+
+ clock_gettime(CLOCK_REALTIME, &ts);
+ timespec_add_ms(&ts, msecs);
+
+ err = pthread_cond_timedwait(&cond->cond, &mutex->lock, &ts);
+ if (err && err != ETIMEDOUT)
+ error_exit(err, __func__);
+ return err;
+}
+
+void qemu_thread_create(QemuThread *thread,
+ void *(*start_routine)(void*),
+ void *arg)
+{
+ int err;
+
+ err = pthread_create(&thread->thread, NULL, start_routine, arg);
+ if (err)
+ error_exit(err, __func__);
+}
+
+void qemu_thread_signal(QemuThread *thread, int sig)
+{
+ int err;
+
+ err = pthread_kill(thread->thread, sig);
+ if (err)
+ error_exit(err, __func__);
+}
+
+void qemu_thread_self(QemuThread *thread)
+{
+ thread->thread = pthread_self();
+}
+
+int qemu_thread_equal(QemuThread *thread1, QemuThread *thread2)
+{
+ return (thread1->thread == thread2->thread);
+}
+
diff --git a/qemu-thread.h b/qemu-thread.h
new file mode 100644
index 000000000..5ef4a3aed
--- /dev/null
+++ b/qemu-thread.h
@@ -0,0 +1,40 @@
+#ifndef __QEMU_THREAD_H
+#define __QEMU_THREAD_H 1
+#include "semaphore.h"
+#include "pthread.h"
+
+struct QemuMutex {
+ pthread_mutex_t lock;
+};
+
+struct QemuCond {
+ pthread_cond_t cond;
+};
+
+struct QemuThread {
+ pthread_t thread;
+};
+
+typedef struct QemuMutex QemuMutex;
+typedef struct QemuCond QemuCond;
+typedef struct QemuThread QemuThread;
+
+void qemu_mutex_init(QemuMutex *mutex);
+void qemu_mutex_lock(QemuMutex *mutex);
+int qemu_mutex_trylock(QemuMutex *mutex);
+int qemu_mutex_timedlock(QemuMutex *mutex, uint64_t msecs);
+void qemu_mutex_unlock(QemuMutex *mutex);
+
+void qemu_cond_init(QemuCond *cond);
+void qemu_cond_signal(QemuCond *cond);
+void qemu_cond_broadcast(QemuCond *cond);
+void qemu_cond_wait(QemuCond *cond, QemuMutex *mutex);
+int qemu_cond_timedwait(QemuCond *cond, QemuMutex *mutex, uint64_t msecs);
+
+void qemu_thread_create(QemuThread *thread,
+ void *(*start_routine)(void*),
+ void *arg);
+void qemu_thread_signal(QemuThread *thread, int sig);
+void qemu_thread_self(QemuThread *thread);
+int qemu_thread_equal(QemuThread *thread1, QemuThread *thread2);
+#endif
diff --git a/sysemu.h b/sysemu.h
index cf6b48a7a..1f45fd667 100644
--- a/sysemu.h
+++ b/sysemu.h
@@ -260,7 +260,6 @@ const char *get_opt_name(char *buf, int buf_size, const char *p, char delim);
const char *get_opt_value(char *buf, int buf_size, const char *p);
int get_param_value(char *buf, int buf_size,
const char *tag, const char *str);
-int check_params(char *buf, int buf_size,
- const char * const *params, const char *str);
+int check_params(const char * const *params, const char *str);
#endif
diff --git a/target-alpha/exec.h b/target-alpha/exec.h
index 9ea70305e..77eaf53c1 100644
--- a/target-alpha/exec.h
+++ b/target-alpha/exec.h
@@ -48,10 +48,15 @@ static always_inline void regs_to_env(void)
{
}
+static always_inline int cpu_has_work(CPUState *env)
+{
+ return (env->interrupt_request & CPU_INTERRUPT_HARD);
+}
+
static always_inline int cpu_halted(CPUState *env) {
if (!env->halted)
return 0;
- if (env->interrupt_request & CPU_INTERRUPT_HARD) {
+ if (cpu_has_work(env)) {
env->halted = 0;
return 0;
}
diff --git a/target-alpha/translate.c b/target-alpha/translate.c
index 00751f517..4cd24d847 100644
--- a/target-alpha/translate.c
+++ b/target-alpha/translate.c
@@ -2505,6 +2505,7 @@ CPUAlphaState * cpu_alpha_init (const char *cpu_model)
env->ipr[IPR_SISR] = 0;
env->ipr[IPR_VIRBND] = -1ULL;
+ qemu_init_vcpu(env);
return env;
}
diff --git a/target-arm/exec.h b/target-arm/exec.h
index 3e4083a61..710a2f988 100644
--- a/target-arm/exec.h
+++ b/target-arm/exec.h
@@ -37,14 +37,19 @@ static inline void regs_to_env(void)
{
}
+static inline int cpu_has_work(CPUState *env)
+{
+ return (env->interrupt_request &
+ (CPU_INTERRUPT_FIQ | CPU_INTERRUPT_HARD | CPU_INTERRUPT_EXITTB));
+}
+
static inline int cpu_halted(CPUState *env) {
if (!env->halted)
return 0;
/* An interrupt wakes the CPU even if the I and F CPSR bits are
set. We use EXITTB to silently wake CPU without causing an
actual interrupt. */
- if (env->interrupt_request &
- (CPU_INTERRUPT_FIQ | CPU_INTERRUPT_HARD | CPU_INTERRUPT_EXITTB)) {
+ if (cpu_has_work(env)) {
env->halted = 0;
return 0;
}
diff --git a/target-arm/helper.c b/target-arm/helper.c
index 34641428d..701629af3 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -267,6 +267,7 @@ CPUARMState *cpu_arm_init(const char *cpu_model)
gdb_register_coprocessor(env, vfp_gdb_get_reg, vfp_gdb_set_reg,
19, "arm-vfp.xml", 0);
}
+ qemu_init_vcpu(env);
return env;
}
diff --git a/target-cris/exec.h b/target-cris/exec.h
index 77e4240e8..5f3cc0017 100644
--- a/target-cris/exec.h
+++ b/target-cris/exec.h
@@ -40,6 +40,11 @@ static inline void regs_to_env(void)
void cpu_cris_flush_flags(CPUCRISState *env, int cc_op);
void helper_movec(CPUCRISState *env, int reg, uint32_t val);
+static inline int cpu_has_work(CPUState *env)
+{
+ return (env->interrupt_request & (CPU_INTERRUPT_HARD | CPU_INTERRUPT_NMI));
+}
+
static inline int cpu_halted(CPUState *env) {
if (!env->halted)
return 0;
diff --git a/target-cris/helper.c b/target-cris/helper.c
index ae2f8dddb..405454f50 100644
--- a/target-cris/helper.c
+++ b/target-cris/helper.c
@@ -77,7 +77,7 @@ static void cris_shift_ccs(CPUState *env)
int cpu_cris_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
int mmu_idx, int is_softmmu)
{
- struct cris_mmu_result_t res;
+ struct cris_mmu_result res;
int prot, miss;
int r = -1;
target_ulong phy;
@@ -191,7 +191,7 @@ void do_interrupt(CPUState *env)
target_phys_addr_t cpu_get_phys_page_debug(CPUState * env, target_ulong addr)
{
uint32_t phy = addr;
- struct cris_mmu_result_t res;
+ struct cris_mmu_result res;
int miss;
miss = cris_mmu_translate(&res, env, addr, 0, 0);
if (!miss)
diff --git a/target-cris/mmu.c b/target-cris/mmu.c
index 9d7981663..1f3d48322 100644
--- a/target-cris/mmu.c
+++ b/target-cris/mmu.c
@@ -123,7 +123,7 @@ static void dump_tlb(CPUState *env, int mmu)
#endif
/* rw 0 = read, 1 = write, 2 = exec. */
-static int cris_mmu_translate_page(struct cris_mmu_result_t *res,
+static int cris_mmu_translate_page(struct cris_mmu_result *res,
CPUState *env, uint32_t vaddr,
int rw, int usermode)
{
@@ -324,7 +324,7 @@ void cris_mmu_flush_pid(CPUState *env, uint32_t pid)
}
}
-int cris_mmu_translate(struct cris_mmu_result_t *res,
+int cris_mmu_translate(struct cris_mmu_result *res,
CPUState *env, uint32_t vaddr,
int rw, int mmu_idx)
{
diff --git a/target-cris/mmu.h b/target-cris/mmu.h
index aca531a3e..d753b3834 100644
--- a/target-cris/mmu.h
+++ b/target-cris/mmu.h
@@ -3,7 +3,7 @@
#define CRIS_MMU_ERR_WRITE 2
#define CRIS_MMU_ERR_FLUSH 3
-struct cris_mmu_result_t
+struct cris_mmu_result
{
uint32_t phy;
int prot;
@@ -12,6 +12,6 @@ struct cris_mmu_result_t
void cris_mmu_init(CPUState *env);
void cris_mmu_flush_pid(CPUState *env, uint32_t pid);
-int cris_mmu_translate(struct cris_mmu_result_t *res,
+int cris_mmu_translate(struct cris_mmu_result *res,
CPUState *env, uint32_t vaddr,
int rw, int mmu_idx);
diff --git a/target-cris/translate.c b/target-cris/translate.c
index d9256ca42..e12be4ef1 100644
--- a/target-cris/translate.c
+++ b/target-cris/translate.c
@@ -3405,6 +3405,7 @@ CPUCRISState *cpu_cris_init (const char *cpu_model)
cpu_exec_init(env);
cpu_reset(env);
+ qemu_init_vcpu(env);
if (tcg_initialized)
return env;
diff --git a/target-i386/exec.h b/target-i386/exec.h
index b51667a1f..fbaf5bc98 100644
--- a/target-i386/exec.h
+++ b/target-i386/exec.h
@@ -338,14 +338,23 @@ static inline void regs_to_env(void)
#endif
}
+static inline int cpu_has_work(CPUState *env)
+{
+ int work;
+
+ work = (env->interrupt_request & CPU_INTERRUPT_HARD) &&
+ (env->eflags & IF_MASK);
+ work |= env->interrupt_request & CPU_INTERRUPT_NMI;
+
+ return work;
+}
+
static inline int cpu_halted(CPUState *env) {
/* handle exit of HALTED state */
if (!env->halted)
return 0;
/* disable halt condition */
- if (((env->interrupt_request & CPU_INTERRUPT_HARD) &&
- (env->eflags & IF_MASK)) ||
- (env->interrupt_request & CPU_INTERRUPT_NMI)) {
+ if (cpu_has_work(env)) {
env->halted = 0;
return 0;
}
diff --git a/target-i386/helper.c b/target-i386/helper.c
index 74409835e..719e31ec3 100644
--- a/target-i386/helper.c
+++ b/target-i386/helper.c
@@ -1695,7 +1695,8 @@ CPUX86State *cpu_x86_init(const char *cpu_model)
#ifdef CONFIG_KQEMU
kqemu_init(env);
#endif
- if (kvm_enabled())
- kvm_init_vcpu(env);
+
+ qemu_init_vcpu(env);
+
return env;
}
diff --git a/target-i386/op_helper.c b/target-i386/op_helper.c
index 1a749022b..f4cea083e 100644
--- a/target-i386/op_helper.c
+++ b/target-i386/op_helper.c
@@ -595,6 +595,21 @@ static inline unsigned int get_sp_mask(unsigned int e2)
return 0xffff;
}
+static int exeption_has_error_code(int intno)
+{
+ switch(intno) {
+ case 8:
+ case 10:
+ case 11:
+ case 12:
+ case 13:
+ case 14:
+ case 17:
+ return 1;
+ }
+ return 0;
+}
+
#ifdef TARGET_X86_64
#define SET_ESP(val, sp_mask)\
do {\
@@ -650,19 +665,8 @@ static void do_interrupt_protected(int intno, int is_int, int error_code,
uint32_t old_eip, sp_mask;
has_error_code = 0;
- if (!is_int && !is_hw) {
- switch(intno) {
- case 8:
- case 10:
- case 11:
- case 12:
- case 13:
- case 14:
- case 17:
- has_error_code = 1;
- break;
- }
- }
+ if (!is_int && !is_hw)
+ has_error_code = exeption_has_error_code(intno);
if (is_int)
old_eip = next_eip;
else
@@ -886,19 +890,8 @@ static void do_interrupt64(int intno, int is_int, int error_code,
target_ulong old_eip, esp, offset;
has_error_code = 0;
- if (!is_int && !is_hw) {
- switch(intno) {
- case 8:
- case 10:
- case 11:
- case 12:
- case 13:
- case 14:
- case 17:
- has_error_code = 1;
- break;
- }
- }
+ if (!is_int && !is_hw)
+ has_error_code = exeption_has_error_code(intno);
if (is_int)
old_eip = next_eip;
else
@@ -1198,6 +1191,27 @@ void do_interrupt_user(int intno, int is_int, int error_code,
EIP = next_eip;
}
+#if !defined(CONFIG_USER_ONLY)
+static void handle_even_inj(int intno, int is_int, int error_code,
+ int is_hw, int rm)
+{
+ uint32_t event_inj = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.event_inj));
+ if (!(event_inj & SVM_EVTINJ_VALID)) {
+ int type;
+ if (is_int)
+ type = SVM_EVTINJ_TYPE_SOFT;
+ else
+ type = SVM_EVTINJ_TYPE_EXEPT;
+ event_inj = intno | type | SVM_EVTINJ_VALID;
+ if (!rm && exeption_has_error_code(intno)) {
+ event_inj |= SVM_EVTINJ_VALID_ERR;
+ stl_phys(env->vm_vmcb + offsetof(struct vmcb, control.event_inj_err), error_code);
+ }
+ stl_phys(env->vm_vmcb + offsetof(struct vmcb, control.event_inj), event_inj);
+ }
+}
+#endif
+
/*
* Begin execution of an interruption. is_int is TRUE if coming from
* the int instruction. next_eip is the EIP value AFTER the interrupt
@@ -1238,6 +1252,10 @@ void do_interrupt(int intno, int is_int, int error_code,
}
}
if (env->cr[0] & CR0_PE_MASK) {
+#if !defined(CONFIG_USER_ONLY)
+ if (env->hflags & HF_SVMI_MASK)
+ handle_even_inj(intno, is_int, error_code, is_hw, 0);
+#endif
#ifdef TARGET_X86_64
if (env->hflags & HF_LMA_MASK) {
do_interrupt64(intno, is_int, error_code, next_eip, is_hw);
@@ -1247,8 +1265,19 @@ void do_interrupt(int intno, int is_int, int error_code,
do_interrupt_protected(intno, is_int, error_code, next_eip, is_hw);
}
} else {
+#if !defined(CONFIG_USER_ONLY)
+ if (env->hflags & HF_SVMI_MASK)
+ handle_even_inj(intno, is_int, error_code, is_hw, 1);
+#endif
do_interrupt_real(intno, is_int, error_code, next_eip);
}
+
+#if !defined(CONFIG_USER_ONLY)
+ if (env->hflags & HF_SVMI_MASK) {
+ uint32_t event_inj = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.event_inj));
+ stl_phys(env->vm_vmcb + offsetof(struct vmcb, control.event_inj), event_inj & ~SVM_EVTINJ_VALID);
+ }
+#endif
}
/* This should come from sysemu.h - if we could include it here... */
@@ -4994,7 +5023,6 @@ void helper_vmrun(int aflag, int next_eip_addend)
uint8_t vector = event_inj & SVM_EVTINJ_VEC_MASK;
uint16_t valid_err = event_inj & SVM_EVTINJ_VALID_ERR;
uint32_t event_inj_err = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.event_inj_err));
- stl_phys(env->vm_vmcb + offsetof(struct vmcb, control.event_inj), event_inj & ~SVM_EVTINJ_VALID);
qemu_log_mask(CPU_LOG_TB_IN_ASM, "Injecting(%#hx): ", valid_err);
/* FIXME: need to implement valid_err */
@@ -5332,6 +5360,11 @@ void helper_vmexit(uint32_t exit_code, uint64_t exit_info_1)
stq_phys(env->vm_vmcb + offsetof(struct vmcb, control.exit_code), exit_code);
stq_phys(env->vm_vmcb + offsetof(struct vmcb, control.exit_info_1), exit_info_1);
+ stl_phys(env->vm_vmcb + offsetof(struct vmcb, control.exit_int_info),
+ ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.event_inj)));
+ stl_phys(env->vm_vmcb + offsetof(struct vmcb, control.exit_int_info_err),
+ ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.event_inj_err)));
+
env->hflags2 &= ~HF2_GIF_MASK;
/* FIXME: Resets the current ASID register to zero (host ASID). */
diff --git a/target-m68k/exec.h b/target-m68k/exec.h
index fba371cf4..3a86b1f89 100644
--- a/target-m68k/exec.h
+++ b/target-m68k/exec.h
@@ -41,10 +41,15 @@ static inline void regs_to_env(void)
#include "softmmu_exec.h"
#endif
+static inline int cpu_has_work(CPUState *env)
+{
+ return (env->interrupt_request & (CPU_INTERRUPT_HARD));
+}
+
static inline int cpu_halted(CPUState *env) {
if (!env->halted)
return 0;
- if (env->interrupt_request & CPU_INTERRUPT_HARD) {
+ if (cpu_has_work(env)) {
env->halted = 0;
return 0;
}
diff --git a/target-m68k/helper.c b/target-m68k/helper.c
index 493498e9b..ad2832244 100644
--- a/target-m68k/helper.c
+++ b/target-m68k/helper.c
@@ -180,6 +180,7 @@ CPUM68KState *cpu_m68k_init(const char *cpu_model)
}
cpu_reset(env);
+ qemu_init_vcpu(env);
return env;
}
diff --git a/target-mips/exec.h b/target-mips/exec.h
index 18765f967..8a118bb6b 100644
--- a/target-mips/exec.h
+++ b/target-mips/exec.h
@@ -33,12 +33,18 @@ static inline void regs_to_env(void)
{
}
+static inline int cpu_has_work(CPUState *env)
+{
+ return (env->interrupt_request &
+ (CPU_INTERRUPT_HARD | CPU_INTERRUPT_TIMER));
+}
+
+
static inline int cpu_halted(CPUState *env)
{
if (!env->halted)
return 0;
- if (env->interrupt_request &
- (CPU_INTERRUPT_HARD | CPU_INTERRUPT_TIMER)) {
+ if (cpu_has_work(env)) {
env->halted = 0;
return 0;
}
diff --git a/target-mips/translate.c b/target-mips/translate.c
index e8ecb6e41..7ecc9fdaf 100644
--- a/target-mips/translate.c
+++ b/target-mips/translate.c
@@ -1590,7 +1590,7 @@ static void gen_arith (CPUState *env, DisasContext *ctx, uint32_t opc,
tcg_temp_free(t2);
tcg_gen_brcondi_tl(TCG_COND_GE, t1, 0, l1);
tcg_temp_free(t1);
- /* operands of same sign, result different sign */
+ /* operands of different sign, first operand and result different sign */
generate_exception(ctx, EXCP_OVERFLOW);
gen_set_label(l1);
gen_store_gpr(t0, rd);
@@ -1604,6 +1604,7 @@ static void gen_arith (CPUState *env, DisasContext *ctx, uint32_t opc,
tcg_gen_ext32s_tl(cpu_gpr[rd], cpu_gpr[rd]);
} else if (rs == 0 && rt != 0) {
tcg_gen_neg_tl(cpu_gpr[rd], cpu_gpr[rt]);
+ tcg_gen_ext32s_tl(cpu_gpr[rd], cpu_gpr[rd]);
} else if (rs != 0 && rt == 0) {
tcg_gen_mov_tl(cpu_gpr[rd], cpu_gpr[rs]);
} else {
@@ -1665,7 +1666,7 @@ static void gen_arith (CPUState *env, DisasContext *ctx, uint32_t opc,
tcg_temp_free(t2);
tcg_gen_brcondi_tl(TCG_COND_GE, t1, 0, l1);
tcg_temp_free(t1);
- /* operands of same sign, result different sign */
+ /* operands of different sign, first operand and result different sign */
generate_exception(ctx, EXCP_OVERFLOW);
gen_set_label(l1);
gen_store_gpr(t0, rd);
@@ -8551,6 +8552,7 @@ CPUMIPSState *cpu_mips_init (const char *cpu_model)
env->cpu_model_str = cpu_model;
mips_tcg_init();
cpu_reset(env);
+ qemu_init_vcpu(env);
return env;
}
diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h
index 82f66f8dd..eb256bc11 100644
--- a/target-ppc/cpu.h
+++ b/target-ppc/cpu.h
@@ -655,6 +655,7 @@ struct CPUPPCState {
/* Exception vectors */
target_ulong excp_vectors[POWERPC_EXCP_NB];
target_ulong excp_prefix;
+ target_ulong hreset_excp_prefix;
target_ulong ivor_mask;
target_ulong ivpr_mask;
target_ulong hreset_vector;
@@ -803,7 +804,7 @@ int ppc_dcr_write (ppc_dcr_t *dcr_env, int dcrn, target_ulong val);
#define cpu_signal_handler cpu_ppc_signal_handler
#define cpu_list ppc_cpu_list
-#define CPU_SAVE_VERSION 3
+#define CPU_SAVE_VERSION 4
/* MMU modes definitions */
#define MMU_MODE0_SUFFIX _user
diff --git a/target-ppc/exec.h b/target-ppc/exec.h
index d89698c63..f6b9ee6c8 100644
--- a/target-ppc/exec.h
+++ b/target-ppc/exec.h
@@ -44,11 +44,17 @@ static always_inline void regs_to_env (void)
{
}
+static always_inline int cpu_has_work(CPUState *env)
+{
+ return (msr_ee && (env->interrupt_request & CPU_INTERRUPT_HARD));
+}
+
+
static always_inline int cpu_halted (CPUState *env)
{
if (!env->halted)
return 0;
- if (msr_ee && (env->interrupt_request & CPU_INTERRUPT_HARD)) {
+ if (cpu_has_work(env)) {
env->halted = 0;
return 0;
}
diff --git a/target-ppc/helper.c b/target-ppc/helper.c
index a0d884ee1..db765e308 100644
--- a/target-ppc/helper.c
+++ b/target-ppc/helper.c
@@ -2796,6 +2796,7 @@ void cpu_ppc_reset (void *opaque)
msr |= (target_ulong)1 << MSR_SPE; /* Allow SPE usage */
msr |= (target_ulong)1 << MSR_PR;
#else
+ env->excp_prefix = env->hreset_excp_prefix;
env->nip = env->hreset_vector | env->excp_prefix;
if (env->mmu_model != POWERPC_MMU_REAL)
ppc_tlb_invalidate_all(env);
@@ -2831,8 +2832,7 @@ CPUPPCState *cpu_ppc_init (const char *cpu_model)
cpu_ppc_register_internal(env, def);
cpu_ppc_reset(env);
- if (kvm_enabled())
- kvm_init_vcpu(env);
+ qemu_init_vcpu(env);
return env;
}
diff --git a/target-ppc/machine.c b/target-ppc/machine.c
index 02eecb829..8b82005a1 100644
--- a/target-ppc/machine.c
+++ b/target-ppc/machine.c
@@ -87,6 +87,7 @@ void cpu_save(QEMUFile *f, void *opaque)
for (i = 0; i < POWERPC_EXCP_NB; i++)
qemu_put_betls(f, &env->excp_vectors[i]);
qemu_put_betls(f, &env->excp_prefix);
+ qemu_put_betls(f, &env->hreset_excp_prefix);
qemu_put_betls(f, &env->ivor_mask);
qemu_put_betls(f, &env->ivpr_mask);
qemu_put_betls(f, &env->hreset_vector);
@@ -173,6 +174,7 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id)
for (i = 0; i < POWERPC_EXCP_NB; i++)
qemu_get_betls(f, &env->excp_vectors[i]);
qemu_get_betls(f, &env->excp_prefix);
+ qemu_get_betls(f, &env->hreset_excp_prefix);
qemu_get_betls(f, &env->ivor_mask);
qemu_get_betls(f, &env->ivpr_mask);
qemu_get_betls(f, &env->hreset_vector);
diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c
index 56d8d93e6..f5e3b28f6 100644
--- a/target-ppc/translate_init.c
+++ b/target-ppc/translate_init.c
@@ -2609,7 +2609,7 @@ static void init_excp_4xx_real (CPUPPCState *env)
env->excp_vectors[POWERPC_EXCP_FIT] = 0x00001010;
env->excp_vectors[POWERPC_EXCP_WDT] = 0x00001020;
env->excp_vectors[POWERPC_EXCP_DEBUG] = 0x00002000;
- env->excp_prefix = 0x00000000UL;
+ env->hreset_excp_prefix = 0x00000000UL;
env->ivor_mask = 0x0000FFF0UL;
env->ivpr_mask = 0xFFFF0000UL;
/* Hardware reset vector */
@@ -2634,7 +2634,7 @@ static void init_excp_4xx_softmmu (CPUPPCState *env)
env->excp_vectors[POWERPC_EXCP_DTLB] = 0x00001100;
env->excp_vectors[POWERPC_EXCP_ITLB] = 0x00001200;
env->excp_vectors[POWERPC_EXCP_DEBUG] = 0x00002000;
- env->excp_prefix = 0x00000000UL;
+ env->hreset_excp_prefix = 0x00000000UL;
env->ivor_mask = 0x0000FFF0UL;
env->ivpr_mask = 0xFFFF0000UL;
/* Hardware reset vector */
@@ -2660,7 +2660,7 @@ static void init_excp_MPC5xx (CPUPPCState *env)
env->excp_vectors[POWERPC_EXCP_IABR] = 0x00001C00;
env->excp_vectors[POWERPC_EXCP_MEXTBR] = 0x00001E00;
env->excp_vectors[POWERPC_EXCP_NMEXTBR] = 0x00001F00;
- env->excp_prefix = 0x00000000UL;
+ env->hreset_excp_prefix = 0x00000000UL;
env->ivor_mask = 0x0000FFF0UL;
env->ivpr_mask = 0xFFFF0000UL;
/* Hardware reset vector */
@@ -2692,7 +2692,7 @@ static void init_excp_MPC8xx (CPUPPCState *env)
env->excp_vectors[POWERPC_EXCP_IABR] = 0x00001C00;
env->excp_vectors[POWERPC_EXCP_MEXTBR] = 0x00001E00;
env->excp_vectors[POWERPC_EXCP_NMEXTBR] = 0x00001F00;
- env->excp_prefix = 0x00000000UL;
+ env->hreset_excp_prefix = 0x00000000UL;
env->ivor_mask = 0x0000FFF0UL;
env->ivpr_mask = 0xFFFF0000UL;
/* Hardware reset vector */
@@ -2720,7 +2720,7 @@ static void init_excp_G2 (CPUPPCState *env)
env->excp_vectors[POWERPC_EXCP_DSTLB] = 0x00001200;
env->excp_vectors[POWERPC_EXCP_IABR] = 0x00001300;
env->excp_vectors[POWERPC_EXCP_SMI] = 0x00001400;
- env->excp_prefix = 0x00000000UL;
+ env->hreset_excp_prefix = 0x00000000UL;
/* Hardware reset vector */
env->hreset_vector = 0xFFFFFFFCUL;
#endif
@@ -2749,7 +2749,7 @@ static void init_excp_e200 (CPUPPCState *env)
env->excp_vectors[POWERPC_EXCP_SPEU] = 0x00000000;
env->excp_vectors[POWERPC_EXCP_EFPDI] = 0x00000000;
env->excp_vectors[POWERPC_EXCP_EFPRI] = 0x00000000;
- env->excp_prefix = 0x00000000UL;
+ env->hreset_excp_prefix = 0x00000000UL;
env->ivor_mask = 0x0000FFF7UL;
env->ivpr_mask = 0xFFFF0000UL;
/* Hardware reset vector */
@@ -2776,7 +2776,7 @@ static void init_excp_BookE (CPUPPCState *env)
env->excp_vectors[POWERPC_EXCP_DTLB] = 0x00000000;
env->excp_vectors[POWERPC_EXCP_ITLB] = 0x00000000;
env->excp_vectors[POWERPC_EXCP_DEBUG] = 0x00000000;
- env->excp_prefix = 0x00000000UL;
+ env->hreset_excp_prefix = 0x00000000UL;
env->ivor_mask = 0x0000FFE0UL;
env->ivpr_mask = 0xFFFF0000UL;
/* Hardware reset vector */
@@ -2799,7 +2799,7 @@ static void init_excp_601 (CPUPPCState *env)
env->excp_vectors[POWERPC_EXCP_IO] = 0x00000A00;
env->excp_vectors[POWERPC_EXCP_SYSCALL] = 0x00000C00;
env->excp_vectors[POWERPC_EXCP_RUNM] = 0x00002000;
- env->excp_prefix = 0xFFF00000UL;
+ env->hreset_excp_prefix = 0xFFF00000UL;
/* Hardware reset vector */
env->hreset_vector = 0x00000100UL;
#endif
@@ -2827,7 +2827,7 @@ static void init_excp_602 (CPUPPCState *env)
env->excp_vectors[POWERPC_EXCP_SMI] = 0x00001400;
env->excp_vectors[POWERPC_EXCP_WDT] = 0x00001500;
env->excp_vectors[POWERPC_EXCP_EMUL] = 0x00001600;
- env->excp_prefix = 0xFFF00000UL;
+ env->hreset_excp_prefix = 0xFFF00000UL;
/* Hardware reset vector */
env->hreset_vector = 0xFFFFFFFCUL;
#endif
@@ -2852,7 +2852,7 @@ static void init_excp_603 (CPUPPCState *env)
env->excp_vectors[POWERPC_EXCP_DSTLB] = 0x00001200;
env->excp_vectors[POWERPC_EXCP_IABR] = 0x00001300;
env->excp_vectors[POWERPC_EXCP_SMI] = 0x00001400;
- env->excp_prefix = 0x00000000UL;
+ env->hreset_excp_prefix = 0x00000000UL;
/* Hardware reset vector */
env->hreset_vector = 0xFFFFFFFCUL;
#endif
@@ -2875,9 +2875,9 @@ static void init_excp_604 (CPUPPCState *env)
env->excp_vectors[POWERPC_EXCP_PERFM] = 0x00000F00;
env->excp_vectors[POWERPC_EXCP_IABR] = 0x00001300;
env->excp_vectors[POWERPC_EXCP_SMI] = 0x00001400;
- env->excp_prefix = 0x00000000UL;
+ env->hreset_excp_prefix = 0xFFF00000UL;
/* Hardware reset vector */
- env->hreset_vector = 0xFFFFFFFCUL;
+ env->hreset_vector = 0x00000100UL;
#endif
}
@@ -2899,7 +2899,7 @@ static void init_excp_620 (CPUPPCState *env)
env->excp_vectors[POWERPC_EXCP_PERFM] = 0x00000F00;
env->excp_vectors[POWERPC_EXCP_IABR] = 0x00001300;
env->excp_vectors[POWERPC_EXCP_SMI] = 0x00001400;
- env->excp_prefix = 0xFFF00000UL;
+ env->hreset_excp_prefix = 0xFFF00000UL;
/* Hardware reset vector */
env->hreset_vector = 0x0000000000000100ULL;
#endif
@@ -2924,7 +2924,7 @@ static void init_excp_7x0 (CPUPPCState *env)
env->excp_vectors[POWERPC_EXCP_IABR] = 0x00001300;
env->excp_vectors[POWERPC_EXCP_SMI] = 0x00001400;
env->excp_vectors[POWERPC_EXCP_THERM] = 0x00001700;
- env->excp_prefix = 0x00000000UL;
+ env->hreset_excp_prefix = 0x00000000UL;
/* Hardware reset vector */
env->hreset_vector = 0xFFFFFFFCUL;
#endif
@@ -2947,7 +2947,7 @@ static void init_excp_750cl (CPUPPCState *env)
env->excp_vectors[POWERPC_EXCP_PERFM] = 0x00000F00;
env->excp_vectors[POWERPC_EXCP_IABR] = 0x00001300;
env->excp_vectors[POWERPC_EXCP_SMI] = 0x00001400;
- env->excp_prefix = 0x00000000UL;
+ env->hreset_excp_prefix = 0x00000000UL;
/* Hardware reset vector */
env->hreset_vector = 0xFFFFFFFCUL;
#endif
@@ -2970,7 +2970,7 @@ static void init_excp_750cx (CPUPPCState *env)
env->excp_vectors[POWERPC_EXCP_PERFM] = 0x00000F00;
env->excp_vectors[POWERPC_EXCP_IABR] = 0x00001300;
env->excp_vectors[POWERPC_EXCP_THERM] = 0x00001700;
- env->excp_prefix = 0x00000000UL;
+ env->hreset_excp_prefix = 0x00000000UL;
/* Hardware reset vector */
env->hreset_vector = 0xFFFFFFFCUL;
#endif
@@ -2998,7 +2998,7 @@ static void init_excp_7x5 (CPUPPCState *env)
env->excp_vectors[POWERPC_EXCP_IABR] = 0x00001300;
env->excp_vectors[POWERPC_EXCP_SMI] = 0x00001400;
env->excp_vectors[POWERPC_EXCP_THERM] = 0x00001700;
- env->excp_prefix = 0x00000000UL;
+ env->hreset_excp_prefix = 0x00000000UL;
/* Hardware reset vector */
env->hreset_vector = 0xFFFFFFFCUL;
#endif
@@ -3024,7 +3024,7 @@ static void init_excp_7400 (CPUPPCState *env)
env->excp_vectors[POWERPC_EXCP_SMI] = 0x00001400;
env->excp_vectors[POWERPC_EXCP_VPUA] = 0x00001600;
env->excp_vectors[POWERPC_EXCP_THERM] = 0x00001700;
- env->excp_prefix = 0x00000000UL;
+ env->hreset_excp_prefix = 0x00000000UL;
/* Hardware reset vector */
env->hreset_vector = 0xFFFFFFFCUL;
#endif
@@ -3052,7 +3052,7 @@ static void init_excp_7450 (CPUPPCState *env)
env->excp_vectors[POWERPC_EXCP_IABR] = 0x00001300;
env->excp_vectors[POWERPC_EXCP_SMI] = 0x00001400;
env->excp_vectors[POWERPC_EXCP_VPUA] = 0x00001600;
- env->excp_prefix = 0x00000000UL;
+ env->hreset_excp_prefix = 0x00000000UL;
/* Hardware reset vector */
env->hreset_vector = 0xFFFFFFFCUL;
#endif
@@ -3082,7 +3082,7 @@ static void init_excp_970 (CPUPPCState *env)
env->excp_vectors[POWERPC_EXCP_MAINT] = 0x00001600;
env->excp_vectors[POWERPC_EXCP_VPUA] = 0x00001700;
env->excp_vectors[POWERPC_EXCP_THERM] = 0x00001800;
- env->excp_prefix = 0x00000000FFF00000ULL;
+ env->hreset_excp_prefix = 0x00000000FFF00000ULL;
/* Hardware reset vector */
env->hreset_vector = 0x0000000000000100ULL;
#endif
@@ -8892,7 +8892,7 @@ static void init_ppc_proc (CPUPPCState *env, const ppc_def_t *def)
/* Set all exception vectors to an invalid address */
for (i = 0; i < POWERPC_EXCP_NB; i++)
env->excp_vectors[i] = (target_ulong)(-1ULL);
- env->excp_prefix = 0x00000000;
+ env->hreset_excp_prefix = 0x00000000;
env->ivor_mask = 0x00000000;
env->ivpr_mask = 0x00000000;
/* Default MMU definitions */
@@ -8922,6 +8922,9 @@ static void init_ppc_proc (CPUPPCState *env, const ppc_def_t *def)
}
/* PowerPC implementation specific initialisations (SPRs, timers, ...) */
(*def->init_proc)(env);
+#if !defined(CONFIG_USER_ONLY)
+ env->excp_prefix = env->hreset_excp_prefix;
+#endif
/* MSR bits & flags consistency checks */
if (env->msr_mask & (1 << 25)) {
switch (env->flags & (POWERPC_FLAG_SPE | POWERPC_FLAG_VRE)) {
diff --git a/target-sh4/exec.h b/target-sh4/exec.h
index ad26990c5..d2926750b 100644
--- a/target-sh4/exec.h
+++ b/target-sh4/exec.h
@@ -28,10 +28,15 @@ register struct CPUSH4State *env asm(AREG0);
#include "cpu.h"
#include "exec-all.h"
+static inline int cpu_has_work(CPUState *env)
+{
+ return (env->interrupt_request & CPU_INTERRUPT_HARD);
+}
+
static inline int cpu_halted(CPUState *env) {
if (!env->halted)
return 0;
- if (env->interrupt_request & CPU_INTERRUPT_HARD) {
+ if (cpu_has_work(env)) {
env->halted = 0;
env->intr_at_halt = 1;
return 0;
diff --git a/target-sh4/translate.c b/target-sh4/translate.c
index aa3b9d439..fc3633a6c 100644
--- a/target-sh4/translate.c
+++ b/target-sh4/translate.c
@@ -290,6 +290,7 @@ CPUSH4State *cpu_sh4_init(const char *cpu_model)
cpu_sh4_reset(env);
cpu_sh4_register(env, def);
tlb_flush(env, 1);
+ qemu_init_vcpu(env);
return env;
}
diff --git a/target-sparc/exec.h b/target-sparc/exec.h
index 36fd1176f..f37c8ad99 100644
--- a/target-sparc/exec.h
+++ b/target-sparc/exec.h
@@ -24,10 +24,17 @@ static inline void regs_to_env(void)
/* op_helper.c */
void do_interrupt(CPUState *env);
+static inline int cpu_has_work(CPUState *env1)
+{
+ return (env1->interrupt_request & CPU_INTERRUPT_HARD) &&
+ (env1->psret != 0);
+}
+
+
static inline int cpu_halted(CPUState *env1) {
if (!env1->halted)
return 0;
- if ((env1->interrupt_request & CPU_INTERRUPT_HARD) && (env1->psret != 0)) {
+ if (cpu_has_work(env1)) {
env1->halted = 0;
return 0;
}
diff --git a/target-sparc/helper.c b/target-sparc/helper.c
index b39b16272..2ecafd1af 100644
--- a/target-sparc/helper.c
+++ b/target-sparc/helper.c
@@ -404,7 +404,7 @@ static int get_physical_address_data(CPUState *env,
}
// ctx match, vaddr match, valid?
if (env->dmmuregs[1] == (env->dtlb_tag[i] & 0x1fff) &&
- (address & mask) == (env->dtlb_tag[i] & ~0x1fffULL) &&
+ (address & mask) == (env->dtlb_tag[i] & mask) &&
(env->dtlb_tte[i] & 0x8000000000000000ULL)) {
// access ok?
if (((env->dtlb_tte[i] & 0x4) && is_user) ||
@@ -420,8 +420,8 @@ static int get_physical_address_data(CPUState *env,
#endif
return 1;
}
- *physical = (env->dtlb_tte[i] & mask & 0x1fffffff000ULL) +
- (address & ~mask & 0x1fffffff000ULL);
+ *physical = ((env->dtlb_tte[i] & mask) | (address & ~mask)) &
+ 0x1ffffffe000ULL;
*prot = PAGE_READ;
if (env->dtlb_tte[i] & 0x2)
*prot |= PAGE_WRITE;
@@ -467,7 +467,7 @@ static int get_physical_address_code(CPUState *env,
}
// ctx match, vaddr match, valid?
if (env->dmmuregs[1] == (env->itlb_tag[i] & 0x1fff) &&
- (address & mask) == (env->itlb_tag[i] & ~0x1fffULL) &&
+ (address & mask) == (env->itlb_tag[i] & mask) &&
(env->itlb_tte[i] & 0x8000000000000000ULL)) {
// access ok?
if ((env->itlb_tte[i] & 0x4) && is_user) {
@@ -481,8 +481,8 @@ static int get_physical_address_code(CPUState *env,
#endif
return 1;
}
- *physical = (env->itlb_tte[i] & mask & 0x1fffffff000ULL) +
- (address & ~mask & 0x1fffffff000ULL);
+ *physical = ((env->itlb_tte[i] & mask) | (address & ~mask)) &
+ 0x1ffffffe000ULL;
*prot = PAGE_EXEC;
return 0;
}
@@ -490,6 +490,7 @@ static int get_physical_address_code(CPUState *env,
#ifdef DEBUG_MMU
printf("TMISS at 0x%" PRIx64 "\n", address);
#endif
+ /* Context is stored in DMMU (dmmuregs[1]) also for IMMU */
env->immuregs[6] = (address & ~0x1fffULL) | (env->dmmuregs[1] & 0x1fff);
env->exception_index = TT_TMISS;
return 1;
@@ -723,6 +724,7 @@ CPUSPARCState *cpu_sparc_init(const char *cpu_model)
return NULL;
}
cpu_reset(env);
+ qemu_init_vcpu(env);
return env;
}
diff --git a/target-sparc/op_helper.c b/target-sparc/op_helper.c
index 947a55ad1..5f86b3304 100644
--- a/target-sparc/op_helper.c
+++ b/target-sparc/op_helper.c
@@ -39,6 +39,56 @@ do { printf("ASI: " fmt , ##args); } while (0)
#endif
#endif
+#if defined(TARGET_SPARC64) && !defined(CONFIG_USER_ONLY)
+// Calculates TSB pointer value for fault page size 8k or 64k
+static uint64_t ultrasparc_tsb_pointer(uint64_t tsb_register,
+ uint64_t tag_access_register,
+ int page_size)
+{
+ uint64_t tsb_base = tsb_register & ~0x1fffULL;
+ int tsb_split = (env->dmmuregs[5] & 0x1000ULL) ? 1 : 0;
+ int tsb_size = env->dmmuregs[5] & 0xf;
+
+ // discard lower 13 bits which hold tag access context
+ uint64_t tag_access_va = tag_access_register & ~0x1fffULL;
+
+ // now reorder bits
+ uint64_t tsb_base_mask = ~0x1fffULL;
+ uint64_t va = tag_access_va;
+
+ // move va bits to correct position
+ if (page_size == 8*1024) {
+ va >>= 9;
+ } else if (page_size == 64*1024) {
+ va >>= 12;
+ }
+
+ if (tsb_size) {
+ tsb_base_mask <<= tsb_size;
+ }
+
+ // calculate tsb_base mask and adjust va if split is in use
+ if (tsb_split) {
+ if (page_size == 8*1024) {
+ va &= ~(1ULL << (13 + tsb_size));
+ } else if (page_size == 64*1024) {
+ va |= (1ULL << (13 + tsb_size));
+ }
+ tsb_base_mask <<= 1;
+ }
+
+ return ((tsb_base & tsb_base_mask) | (va & ~tsb_base_mask)) & ~0xfULL;
+}
+
+// Calculates tag target register value by reordering bits
+// in tag access register
+static uint64_t ultrasparc_tag_target(uint64_t tag_access_register)
+{
+ return ((tag_access_register & 0x1fff) << 48) | (tag_access_register >> 22);
+}
+
+#endif
+
static inline void address_mask(CPUState *env1, target_ulong *addr)
{
#ifdef TARGET_SPARC64
@@ -1652,13 +1702,31 @@ uint64_t helper_ld_asi(target_ulong addr, int asi, int size, int sign)
{
int reg = (addr >> 3) & 0xf;
- ret = env->immuregs[reg];
+ if (reg == 0) {
+ // I-TSB Tag Target register
+ ret = ultrasparc_tag_target(env->immuregs[6]);
+ } else {
+ ret = env->immuregs[reg];
+ }
+
break;
}
case 0x51: // I-MMU 8k TSB pointer
+ {
+ // env->immuregs[5] holds I-MMU TSB register value
+ // env->immuregs[6] holds I-MMU Tag Access register value
+ ret = ultrasparc_tsb_pointer(env->immuregs[5], env->immuregs[6],
+ 8*1024);
+ break;
+ }
case 0x52: // I-MMU 64k TSB pointer
- // XXX
- break;
+ {
+ // env->immuregs[5] holds I-MMU TSB register value
+ // env->immuregs[6] holds I-MMU Tag Access register value
+ ret = ultrasparc_tsb_pointer(env->immuregs[5], env->immuregs[6],
+ 64*1024);
+ break;
+ }
case 0x55: // I-MMU data access
{
int reg = (addr >> 3) & 0x3f;
@@ -1677,7 +1745,28 @@ uint64_t helper_ld_asi(target_ulong addr, int asi, int size, int sign)
{
int reg = (addr >> 3) & 0xf;
- ret = env->dmmuregs[reg];
+ if (reg == 0) {
+ // D-TSB Tag Target register
+ ret = ultrasparc_tag_target(env->dmmuregs[6]);
+ } else {
+ ret = env->dmmuregs[reg];
+ }
+ break;
+ }
+ case 0x59: // D-MMU 8k TSB pointer
+ {
+ // env->dmmuregs[5] holds D-MMU TSB register value
+ // env->dmmuregs[6] holds D-MMU Tag Access register value
+ ret = ultrasparc_tsb_pointer(env->dmmuregs[5], env->dmmuregs[6],
+ 8*1024);
+ break;
+ }
+ case 0x5a: // D-MMU 64k TSB pointer
+ {
+ // env->dmmuregs[5] holds D-MMU TSB register value
+ // env->dmmuregs[6] holds D-MMU Tag Access register value
+ ret = ultrasparc_tsb_pointer(env->dmmuregs[5], env->dmmuregs[6],
+ 64*1024);
break;
}
case 0x5d: // D-MMU data access
@@ -1707,8 +1796,6 @@ uint64_t helper_ld_asi(target_ulong addr, int asi, int size, int sign)
case 0x76: // E-cache tag
case 0x7e: // E-cache tag
break;
- case 0x59: // D-MMU 8k TSB pointer
- case 0x5a: // D-MMU 64k TSB pointer
case 0x5b: // D-MMU data pointer
case 0x48: // Interrupt dispatch, RO
case 0x49: // Interrupt data receive
diff --git a/target-sparc/translate.c b/target-sparc/translate.c
index 86319a704..ae93614cc 100644
--- a/target-sparc/translate.c
+++ b/target-sparc/translate.c
@@ -81,11 +81,11 @@ typedef struct DisasContext {
} DisasContext;
// This function uses non-native bit order
-#define GET_FIELD(X, FROM, TO) \
- ((X) >> (31 - (TO)) & ((1 << ((TO) - (FROM) + 1)) - 1))
+#define GET_FIELD(X, FROM, TO) \
+ ((X) >> (31 - (TO)) & ((1 << ((TO) - (FROM) + 1)) - 1))
// This function uses the order in the manuals, i.e. bit 0 is 2^0
-#define GET_FIELD_SP(X, FROM, TO) \
+#define GET_FIELD_SP(X, FROM, TO) \
GET_FIELD(X, 31 - (TO), 31 - (FROM))
#define GET_FIELDs(x,a,b) sign_extend (GET_FIELD(x,a,b), (b) - (a) + 1)
@@ -431,6 +431,18 @@ static inline void gen_cc_V_tag(TCGv src1, TCGv src2)
gen_set_label(l1);
}
+static inline void gen_op_logic_cc(TCGv dst)
+{
+ tcg_gen_mov_tl(cpu_cc_dst, dst);
+
+ gen_cc_clear_icc();
+ gen_cc_NZ_icc(cpu_cc_dst);
+#ifdef TARGET_SPARC64
+ gen_cc_clear_xcc();
+ gen_cc_NZ_xcc(cpu_cc_dst);
+#endif
+}
+
static inline void gen_tag_tv(TCGv src1, TCGv src2)
{
int l1;
@@ -446,17 +458,43 @@ static inline void gen_tag_tv(TCGv src1, TCGv src2)
gen_set_label(l1);
}
+static inline void gen_op_add_cc2(TCGv dst)
+{
+ gen_cc_clear_icc();
+ gen_cc_NZ_icc(cpu_cc_dst);
+ gen_cc_C_add_icc(cpu_cc_dst, cpu_cc_src);
+ gen_cc_V_add_icc(cpu_cc_dst, cpu_cc_src, cpu_cc_src2);
+#ifdef TARGET_SPARC64
+ gen_cc_clear_xcc();
+ gen_cc_NZ_xcc(cpu_cc_dst);
+ gen_cc_C_add_xcc(cpu_cc_dst, cpu_cc_src);
+ gen_cc_V_add_xcc(cpu_cc_dst, cpu_cc_src, cpu_cc_src2);
+#endif
+ tcg_gen_mov_tl(dst, cpu_cc_dst);
+}
+
+static inline void gen_op_addi_cc(TCGv dst, TCGv src1, target_long src2)
+{
+ tcg_gen_mov_tl(cpu_cc_src, src1);
+ tcg_gen_movi_tl(cpu_cc_src2, src2);
+ tcg_gen_addi_tl(cpu_cc_dst, cpu_cc_src, src2);
+ gen_op_add_cc2(dst);
+}
+
static inline void gen_op_add_cc(TCGv dst, TCGv src1, TCGv src2)
{
tcg_gen_mov_tl(cpu_cc_src, src1);
tcg_gen_mov_tl(cpu_cc_src2, src2);
tcg_gen_add_tl(cpu_cc_dst, cpu_cc_src, cpu_cc_src2);
- gen_cc_clear_icc();
+ gen_op_add_cc2(dst);
+}
+
+static inline void gen_op_addx_cc2(TCGv dst)
+{
gen_cc_NZ_icc(cpu_cc_dst);
gen_cc_C_add_icc(cpu_cc_dst, cpu_cc_src);
gen_cc_V_add_icc(cpu_cc_dst, cpu_cc_src, cpu_cc_src2);
#ifdef TARGET_SPARC64
- gen_cc_clear_xcc();
gen_cc_NZ_xcc(cpu_cc_dst);
gen_cc_C_add_xcc(cpu_cc_dst, cpu_cc_src);
gen_cc_V_add_xcc(cpu_cc_dst, cpu_cc_src, cpu_cc_src2);
@@ -464,10 +502,10 @@ static inline void gen_op_add_cc(TCGv dst, TCGv src1, TCGv src2)
tcg_gen_mov_tl(dst, cpu_cc_dst);
}
-static inline void gen_op_addx_cc(TCGv dst, TCGv src1, TCGv src2)
+static inline void gen_op_addxi_cc(TCGv dst, TCGv src1, target_long src2)
{
tcg_gen_mov_tl(cpu_cc_src, src1);
- tcg_gen_mov_tl(cpu_cc_src2, src2);
+ tcg_gen_movi_tl(cpu_cc_src2, src2);
gen_mov_reg_C(cpu_tmp0, cpu_psr);
tcg_gen_add_tl(cpu_cc_dst, cpu_cc_src, cpu_tmp0);
gen_cc_clear_icc();
@@ -476,16 +514,24 @@ static inline void gen_op_addx_cc(TCGv dst, TCGv src1, TCGv src2)
gen_cc_clear_xcc();
gen_cc_C_add_xcc(cpu_cc_dst, cpu_cc_src);
#endif
- tcg_gen_add_tl(cpu_cc_dst, cpu_cc_dst, cpu_cc_src2);
- gen_cc_NZ_icc(cpu_cc_dst);
+ tcg_gen_addi_tl(cpu_cc_dst, cpu_cc_dst, src2);
+ gen_op_addx_cc2(dst);
+}
+
+static inline void gen_op_addx_cc(TCGv dst, TCGv src1, TCGv src2)
+{
+ tcg_gen_mov_tl(cpu_cc_src, src1);
+ tcg_gen_mov_tl(cpu_cc_src2, src2);
+ gen_mov_reg_C(cpu_tmp0, cpu_psr);
+ tcg_gen_add_tl(cpu_cc_dst, cpu_cc_src, cpu_tmp0);
+ gen_cc_clear_icc();
gen_cc_C_add_icc(cpu_cc_dst, cpu_cc_src);
- gen_cc_V_add_icc(cpu_cc_dst, cpu_cc_src, cpu_cc_src2);
#ifdef TARGET_SPARC64
- gen_cc_NZ_xcc(cpu_cc_dst);
+ gen_cc_clear_xcc();
gen_cc_C_add_xcc(cpu_cc_dst, cpu_cc_src);
- gen_cc_V_add_xcc(cpu_cc_dst, cpu_cc_src, cpu_cc_src2);
#endif
- tcg_gen_mov_tl(dst, cpu_cc_dst);
+ tcg_gen_add_tl(cpu_cc_dst, cpu_cc_dst, cpu_cc_src2);
+ gen_op_addx_cc2(dst);
}
static inline void gen_op_tadd_cc(TCGv dst, TCGv src1, TCGv src2)
@@ -616,11 +662,8 @@ static inline void gen_sub_tv(TCGv dst, TCGv src1, TCGv src2)
tcg_temp_free(r_temp);
}
-static inline void gen_op_sub_cc(TCGv dst, TCGv src1, TCGv src2)
+static inline void gen_op_sub_cc2(TCGv dst)
{
- tcg_gen_mov_tl(cpu_cc_src, src1);
- tcg_gen_mov_tl(cpu_cc_src2, src2);
- tcg_gen_sub_tl(cpu_cc_dst, cpu_cc_src, cpu_cc_src2);
gen_cc_clear_icc();
gen_cc_NZ_icc(cpu_cc_dst);
gen_cc_C_sub_icc(cpu_cc_src, cpu_cc_src2);
@@ -634,10 +677,44 @@ static inline void gen_op_sub_cc(TCGv dst, TCGv src1, TCGv src2)
tcg_gen_mov_tl(dst, cpu_cc_dst);
}
-static inline void gen_op_subx_cc(TCGv dst, TCGv src1, TCGv src2)
+static inline void gen_op_subi_cc(TCGv dst, TCGv src1, target_long src2)
+{
+ tcg_gen_mov_tl(cpu_cc_src, src1);
+ tcg_gen_movi_tl(cpu_cc_src2, src2);
+ if (src2 == 0) {
+ tcg_gen_mov_tl(dst, src1);
+ gen_op_logic_cc(dst);
+ } else {
+ tcg_gen_subi_tl(cpu_cc_dst, cpu_cc_src, src2);
+ gen_op_sub_cc2(dst);
+ }
+}
+
+static inline void gen_op_sub_cc(TCGv dst, TCGv src1, TCGv src2)
{
tcg_gen_mov_tl(cpu_cc_src, src1);
tcg_gen_mov_tl(cpu_cc_src2, src2);
+ tcg_gen_sub_tl(cpu_cc_dst, cpu_cc_src, cpu_cc_src2);
+ gen_op_sub_cc2(dst);
+}
+
+static inline void gen_op_subx_cc2(TCGv dst)
+{
+ gen_cc_NZ_icc(cpu_cc_dst);
+ gen_cc_C_sub_icc(cpu_cc_dst, cpu_cc_src);
+ gen_cc_V_sub_icc(cpu_cc_dst, cpu_cc_src, cpu_cc_src2);
+#ifdef TARGET_SPARC64
+ gen_cc_NZ_xcc(cpu_cc_dst);
+ gen_cc_C_sub_xcc(cpu_cc_dst, cpu_cc_src);
+ gen_cc_V_sub_xcc(cpu_cc_dst, cpu_cc_src, cpu_cc_src2);
+#endif
+ tcg_gen_mov_tl(dst, cpu_cc_dst);
+}
+
+static inline void gen_op_subxi_cc(TCGv dst, TCGv src1, target_long src2)
+{
+ tcg_gen_mov_tl(cpu_cc_src, src1);
+ tcg_gen_movi_tl(cpu_cc_src2, src2);
gen_mov_reg_C(cpu_tmp0, cpu_psr);
tcg_gen_sub_tl(cpu_cc_dst, cpu_cc_src, cpu_tmp0);
gen_cc_clear_icc();
@@ -646,16 +723,24 @@ static inline void gen_op_subx_cc(TCGv dst, TCGv src1, TCGv src2)
gen_cc_clear_xcc();
gen_cc_C_sub_xcc(cpu_cc_dst, cpu_cc_src);
#endif
- tcg_gen_sub_tl(cpu_cc_dst, cpu_cc_dst, cpu_cc_src2);
- gen_cc_NZ_icc(cpu_cc_dst);
+ tcg_gen_subi_tl(cpu_cc_dst, cpu_cc_dst, src2);
+ gen_op_subx_cc2(dst);
+}
+
+static inline void gen_op_subx_cc(TCGv dst, TCGv src1, TCGv src2)
+{
+ tcg_gen_mov_tl(cpu_cc_src, src1);
+ tcg_gen_mov_tl(cpu_cc_src2, src2);
+ gen_mov_reg_C(cpu_tmp0, cpu_psr);
+ tcg_gen_sub_tl(cpu_cc_dst, cpu_cc_src, cpu_tmp0);
+ gen_cc_clear_icc();
gen_cc_C_sub_icc(cpu_cc_dst, cpu_cc_src);
- gen_cc_V_sub_icc(cpu_cc_dst, cpu_cc_src, cpu_cc_src2);
#ifdef TARGET_SPARC64
- gen_cc_NZ_xcc(cpu_cc_dst);
+ gen_cc_clear_xcc();
gen_cc_C_sub_xcc(cpu_cc_dst, cpu_cc_src);
- gen_cc_V_sub_xcc(cpu_cc_dst, cpu_cc_src, cpu_cc_src2);
#endif
- tcg_gen_mov_tl(dst, cpu_cc_dst);
+ tcg_gen_sub_tl(cpu_cc_dst, cpu_cc_dst, cpu_cc_src2);
+ gen_op_subx_cc2(dst);
}
static inline void gen_op_tsub_cc(TCGv dst, TCGv src1, TCGv src2)
@@ -838,18 +923,6 @@ static inline void gen_op_div_cc(TCGv dst)
gen_set_label(l1);
}
-static inline void gen_op_logic_cc(TCGv dst)
-{
- tcg_gen_mov_tl(cpu_cc_dst, dst);
-
- gen_cc_clear_icc();
- gen_cc_NZ_icc(cpu_cc_dst);
-#ifdef TARGET_SPARC64
- gen_cc_clear_xcc();
- gen_cc_NZ_xcc(cpu_cc_dst);
-#endif
-}
-
// 1
static inline void gen_op_eval_ba(TCGv dst)
{
@@ -1902,12 +1975,15 @@ static inline TCGv get_src1(unsigned int insn, TCGv def)
static inline TCGv get_src2(unsigned int insn, TCGv def)
{
TCGv r_rs2 = def;
- unsigned int rs2;
if (IS_IMM) { /* immediate */
- rs2 = GET_FIELDs(insn, 19, 31);
- r_rs2 = tcg_const_tl((int)rs2); // XXX how to free?
+ target_long simm;
+
+ simm = GET_FIELDs(insn, 19, 31);
+ r_rs2 = tcg_const_tl(simm); // XXX how to free?
} else { /* register */
+ unsigned int rs2;
+
rs2 = GET_FIELD(insn, 27, 31);
if (rs2 == 0)
r_rs2 = tcg_const_tl(0); // XXX how to free?
@@ -1930,6 +2006,7 @@ static inline TCGv get_src2(unsigned int insn, TCGv def)
static void disas_sparc_insn(DisasContext * dc)
{
unsigned int insn, opc, rs1, rs2, rd;
+ target_long simm;
if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP)))
tcg_gen_debug_insn_start(dc->pc);
@@ -2026,8 +2103,8 @@ static void disas_sparc_insn(DisasContext * dc)
break;
}
break;
- case 1:
- /*CALL*/ {
+ case 1: /*CALL*/
+ {
target_long target = GET_FIELDs(insn, 2, 31) << 2;
TCGv r_const;
@@ -2385,313 +2462,307 @@ static void disas_sparc_insn(DisasContext * dc)
rs2 = GET_FIELD(insn, 27, 31);
xop = GET_FIELD(insn, 18, 26);
switch (xop) {
- case 0x1: /* fmovs */
- tcg_gen_mov_i32(cpu_fpr[rd], cpu_fpr[rs2]);
- break;
- case 0x5: /* fnegs */
- gen_helper_fnegs(cpu_fpr[rd], cpu_fpr[rs2]);
- break;
- case 0x9: /* fabss */
- gen_helper_fabss(cpu_fpr[rd], cpu_fpr[rs2]);
- break;
- case 0x29: /* fsqrts */
- CHECK_FPU_FEATURE(dc, FSQRT);
- gen_clear_float_exceptions();
- gen_helper_fsqrts(cpu_tmp32, cpu_fpr[rs2]);
- gen_helper_check_ieee_exceptions();
- tcg_gen_mov_i32(cpu_fpr[rd], cpu_tmp32);
- break;
- case 0x2a: /* fsqrtd */
- CHECK_FPU_FEATURE(dc, FSQRT);
- gen_op_load_fpr_DT1(DFPREG(rs2));
- gen_clear_float_exceptions();
- gen_helper_fsqrtd();
- gen_helper_check_ieee_exceptions();
- gen_op_store_DT0_fpr(DFPREG(rd));
- break;
- case 0x2b: /* fsqrtq */
- CHECK_FPU_FEATURE(dc, FLOAT128);
- gen_op_load_fpr_QT1(QFPREG(rs2));
- gen_clear_float_exceptions();
- gen_helper_fsqrtq();
- gen_helper_check_ieee_exceptions();
- gen_op_store_QT0_fpr(QFPREG(rd));
- break;
- case 0x41: /* fadds */
- gen_clear_float_exceptions();
- gen_helper_fadds(cpu_tmp32,
- cpu_fpr[rs1], cpu_fpr[rs2]);
- gen_helper_check_ieee_exceptions();
- tcg_gen_mov_i32(cpu_fpr[rd], cpu_tmp32);
- break;
- case 0x42:
- gen_op_load_fpr_DT0(DFPREG(rs1));
- gen_op_load_fpr_DT1(DFPREG(rs2));
- gen_clear_float_exceptions();
- gen_helper_faddd();
- gen_helper_check_ieee_exceptions();
- gen_op_store_DT0_fpr(DFPREG(rd));
- break;
- case 0x43: /* faddq */
- CHECK_FPU_FEATURE(dc, FLOAT128);
- gen_op_load_fpr_QT0(QFPREG(rs1));
- gen_op_load_fpr_QT1(QFPREG(rs2));
- gen_clear_float_exceptions();
- gen_helper_faddq();
- gen_helper_check_ieee_exceptions();
- gen_op_store_QT0_fpr(QFPREG(rd));
- break;
- case 0x45: /* fsubs */
- gen_clear_float_exceptions();
- gen_helper_fsubs(cpu_tmp32,
- cpu_fpr[rs1], cpu_fpr[rs2]);
- gen_helper_check_ieee_exceptions();
- tcg_gen_mov_i32(cpu_fpr[rd], cpu_tmp32);
- break;
- case 0x46:
- gen_op_load_fpr_DT0(DFPREG(rs1));
- gen_op_load_fpr_DT1(DFPREG(rs2));
- gen_clear_float_exceptions();
- gen_helper_fsubd();
- gen_helper_check_ieee_exceptions();
- gen_op_store_DT0_fpr(DFPREG(rd));
- break;
- case 0x47: /* fsubq */
- CHECK_FPU_FEATURE(dc, FLOAT128);
- gen_op_load_fpr_QT0(QFPREG(rs1));
- gen_op_load_fpr_QT1(QFPREG(rs2));
- gen_clear_float_exceptions();
- gen_helper_fsubq();
- gen_helper_check_ieee_exceptions();
- gen_op_store_QT0_fpr(QFPREG(rd));
- break;
- case 0x49: /* fmuls */
- CHECK_FPU_FEATURE(dc, FMUL);
- gen_clear_float_exceptions();
- gen_helper_fmuls(cpu_tmp32,
- cpu_fpr[rs1], cpu_fpr[rs2]);
- gen_helper_check_ieee_exceptions();
- tcg_gen_mov_i32(cpu_fpr[rd], cpu_tmp32);
- break;
- case 0x4a: /* fmuld */
- CHECK_FPU_FEATURE(dc, FMUL);
- gen_op_load_fpr_DT0(DFPREG(rs1));
- gen_op_load_fpr_DT1(DFPREG(rs2));
- gen_clear_float_exceptions();
- gen_helper_fmuld();
- gen_helper_check_ieee_exceptions();
- gen_op_store_DT0_fpr(DFPREG(rd));
- break;
- case 0x4b: /* fmulq */
- CHECK_FPU_FEATURE(dc, FLOAT128);
- CHECK_FPU_FEATURE(dc, FMUL);
- gen_op_load_fpr_QT0(QFPREG(rs1));
- gen_op_load_fpr_QT1(QFPREG(rs2));
- gen_clear_float_exceptions();
- gen_helper_fmulq();
- gen_helper_check_ieee_exceptions();
- gen_op_store_QT0_fpr(QFPREG(rd));
- break;
- case 0x4d: /* fdivs */
- gen_clear_float_exceptions();
- gen_helper_fdivs(cpu_tmp32,
- cpu_fpr[rs1], cpu_fpr[rs2]);
- gen_helper_check_ieee_exceptions();
- tcg_gen_mov_i32(cpu_fpr[rd], cpu_tmp32);
- break;
- case 0x4e:
- gen_op_load_fpr_DT0(DFPREG(rs1));
- gen_op_load_fpr_DT1(DFPREG(rs2));
- gen_clear_float_exceptions();
- gen_helper_fdivd();
- gen_helper_check_ieee_exceptions();
- gen_op_store_DT0_fpr(DFPREG(rd));
- break;
- case 0x4f: /* fdivq */
- CHECK_FPU_FEATURE(dc, FLOAT128);
- gen_op_load_fpr_QT0(QFPREG(rs1));
- gen_op_load_fpr_QT1(QFPREG(rs2));
- gen_clear_float_exceptions();
- gen_helper_fdivq();
- gen_helper_check_ieee_exceptions();
- gen_op_store_QT0_fpr(QFPREG(rd));
- break;
- case 0x69: /* fsmuld */
- CHECK_FPU_FEATURE(dc, FSMULD);
- gen_clear_float_exceptions();
- gen_helper_fsmuld(cpu_fpr[rs1], cpu_fpr[rs2]);
- gen_helper_check_ieee_exceptions();
- gen_op_store_DT0_fpr(DFPREG(rd));
- break;
- case 0x6e: /* fdmulq */
- CHECK_FPU_FEATURE(dc, FLOAT128);
- gen_op_load_fpr_DT0(DFPREG(rs1));
- gen_op_load_fpr_DT1(DFPREG(rs2));
- gen_clear_float_exceptions();
- gen_helper_fdmulq();
- gen_helper_check_ieee_exceptions();
- gen_op_store_QT0_fpr(QFPREG(rd));
- break;
- case 0xc4: /* fitos */
- gen_clear_float_exceptions();
- gen_helper_fitos(cpu_tmp32, cpu_fpr[rs2]);
- gen_helper_check_ieee_exceptions();
- tcg_gen_mov_i32(cpu_fpr[rd], cpu_tmp32);
- break;
- case 0xc6: /* fdtos */
- gen_op_load_fpr_DT1(DFPREG(rs2));
- gen_clear_float_exceptions();
- gen_helper_fdtos(cpu_tmp32);
- gen_helper_check_ieee_exceptions();
- tcg_gen_mov_i32(cpu_fpr[rd], cpu_tmp32);
- break;
- case 0xc7: /* fqtos */
- CHECK_FPU_FEATURE(dc, FLOAT128);
- gen_op_load_fpr_QT1(QFPREG(rs2));
- gen_clear_float_exceptions();
- gen_helper_fqtos(cpu_tmp32);
- gen_helper_check_ieee_exceptions();
- tcg_gen_mov_i32(cpu_fpr[rd], cpu_tmp32);
- break;
- case 0xc8: /* fitod */
- gen_helper_fitod(cpu_fpr[rs2]);
- gen_op_store_DT0_fpr(DFPREG(rd));
- break;
- case 0xc9: /* fstod */
- gen_helper_fstod(cpu_fpr[rs2]);
- gen_op_store_DT0_fpr(DFPREG(rd));
- break;
- case 0xcb: /* fqtod */
- CHECK_FPU_FEATURE(dc, FLOAT128);
- gen_op_load_fpr_QT1(QFPREG(rs2));
- gen_clear_float_exceptions();
- gen_helper_fqtod();
- gen_helper_check_ieee_exceptions();
- gen_op_store_DT0_fpr(DFPREG(rd));
- break;
- case 0xcc: /* fitoq */
- CHECK_FPU_FEATURE(dc, FLOAT128);
- gen_helper_fitoq(cpu_fpr[rs2]);
- gen_op_store_QT0_fpr(QFPREG(rd));
- break;
- case 0xcd: /* fstoq */
- CHECK_FPU_FEATURE(dc, FLOAT128);
- gen_helper_fstoq(cpu_fpr[rs2]);
- gen_op_store_QT0_fpr(QFPREG(rd));
- break;
- case 0xce: /* fdtoq */
- CHECK_FPU_FEATURE(dc, FLOAT128);
- gen_op_load_fpr_DT1(DFPREG(rs2));
- gen_helper_fdtoq();
- gen_op_store_QT0_fpr(QFPREG(rd));
- break;
- case 0xd1: /* fstoi */
- gen_clear_float_exceptions();
- gen_helper_fstoi(cpu_tmp32, cpu_fpr[rs2]);
- gen_helper_check_ieee_exceptions();
- tcg_gen_mov_i32(cpu_fpr[rd], cpu_tmp32);
- break;
- case 0xd2: /* fdtoi */
- gen_op_load_fpr_DT1(DFPREG(rs2));
- gen_clear_float_exceptions();
- gen_helper_fdtoi(cpu_tmp32);
- gen_helper_check_ieee_exceptions();
- tcg_gen_mov_i32(cpu_fpr[rd], cpu_tmp32);
- break;
- case 0xd3: /* fqtoi */
- CHECK_FPU_FEATURE(dc, FLOAT128);
- gen_op_load_fpr_QT1(QFPREG(rs2));
- gen_clear_float_exceptions();
- gen_helper_fqtoi(cpu_tmp32);
- gen_helper_check_ieee_exceptions();
- tcg_gen_mov_i32(cpu_fpr[rd], cpu_tmp32);
- break;
+ case 0x1: /* fmovs */
+ tcg_gen_mov_i32(cpu_fpr[rd], cpu_fpr[rs2]);
+ break;
+ case 0x5: /* fnegs */
+ gen_helper_fnegs(cpu_fpr[rd], cpu_fpr[rs2]);
+ break;
+ case 0x9: /* fabss */
+ gen_helper_fabss(cpu_fpr[rd], cpu_fpr[rs2]);
+ break;
+ case 0x29: /* fsqrts */
+ CHECK_FPU_FEATURE(dc, FSQRT);
+ gen_clear_float_exceptions();
+ gen_helper_fsqrts(cpu_tmp32, cpu_fpr[rs2]);
+ gen_helper_check_ieee_exceptions();
+ tcg_gen_mov_i32(cpu_fpr[rd], cpu_tmp32);
+ break;
+ case 0x2a: /* fsqrtd */
+ CHECK_FPU_FEATURE(dc, FSQRT);
+ gen_op_load_fpr_DT1(DFPREG(rs2));
+ gen_clear_float_exceptions();
+ gen_helper_fsqrtd();
+ gen_helper_check_ieee_exceptions();
+ gen_op_store_DT0_fpr(DFPREG(rd));
+ break;
+ case 0x2b: /* fsqrtq */
+ CHECK_FPU_FEATURE(dc, FLOAT128);
+ gen_op_load_fpr_QT1(QFPREG(rs2));
+ gen_clear_float_exceptions();
+ gen_helper_fsqrtq();
+ gen_helper_check_ieee_exceptions();
+ gen_op_store_QT0_fpr(QFPREG(rd));
+ break;
+ case 0x41: /* fadds */
+ gen_clear_float_exceptions();
+ gen_helper_fadds(cpu_tmp32, cpu_fpr[rs1], cpu_fpr[rs2]);
+ gen_helper_check_ieee_exceptions();
+ tcg_gen_mov_i32(cpu_fpr[rd], cpu_tmp32);
+ break;
+ case 0x42: /* faddd */
+ gen_op_load_fpr_DT0(DFPREG(rs1));
+ gen_op_load_fpr_DT1(DFPREG(rs2));
+ gen_clear_float_exceptions();
+ gen_helper_faddd();
+ gen_helper_check_ieee_exceptions();
+ gen_op_store_DT0_fpr(DFPREG(rd));
+ break;
+ case 0x43: /* faddq */
+ CHECK_FPU_FEATURE(dc, FLOAT128);
+ gen_op_load_fpr_QT0(QFPREG(rs1));
+ gen_op_load_fpr_QT1(QFPREG(rs2));
+ gen_clear_float_exceptions();
+ gen_helper_faddq();
+ gen_helper_check_ieee_exceptions();
+ gen_op_store_QT0_fpr(QFPREG(rd));
+ break;
+ case 0x45: /* fsubs */
+ gen_clear_float_exceptions();
+ gen_helper_fsubs(cpu_tmp32, cpu_fpr[rs1], cpu_fpr[rs2]);
+ gen_helper_check_ieee_exceptions();
+ tcg_gen_mov_i32(cpu_fpr[rd], cpu_tmp32);
+ break;
+ case 0x46: /* fsubd */
+ gen_op_load_fpr_DT0(DFPREG(rs1));
+ gen_op_load_fpr_DT1(DFPREG(rs2));
+ gen_clear_float_exceptions();
+ gen_helper_fsubd();
+ gen_helper_check_ieee_exceptions();
+ gen_op_store_DT0_fpr(DFPREG(rd));
+ break;
+ case 0x47: /* fsubq */
+ CHECK_FPU_FEATURE(dc, FLOAT128);
+ gen_op_load_fpr_QT0(QFPREG(rs1));
+ gen_op_load_fpr_QT1(QFPREG(rs2));
+ gen_clear_float_exceptions();
+ gen_helper_fsubq();
+ gen_helper_check_ieee_exceptions();
+ gen_op_store_QT0_fpr(QFPREG(rd));
+ break;
+ case 0x49: /* fmuls */
+ CHECK_FPU_FEATURE(dc, FMUL);
+ gen_clear_float_exceptions();
+ gen_helper_fmuls(cpu_tmp32, cpu_fpr[rs1], cpu_fpr[rs2]);
+ gen_helper_check_ieee_exceptions();
+ tcg_gen_mov_i32(cpu_fpr[rd], cpu_tmp32);
+ break;
+ case 0x4a: /* fmuld */
+ CHECK_FPU_FEATURE(dc, FMUL);
+ gen_op_load_fpr_DT0(DFPREG(rs1));
+ gen_op_load_fpr_DT1(DFPREG(rs2));
+ gen_clear_float_exceptions();
+ gen_helper_fmuld();
+ gen_helper_check_ieee_exceptions();
+ gen_op_store_DT0_fpr(DFPREG(rd));
+ break;
+ case 0x4b: /* fmulq */
+ CHECK_FPU_FEATURE(dc, FLOAT128);
+ CHECK_FPU_FEATURE(dc, FMUL);
+ gen_op_load_fpr_QT0(QFPREG(rs1));
+ gen_op_load_fpr_QT1(QFPREG(rs2));
+ gen_clear_float_exceptions();
+ gen_helper_fmulq();
+ gen_helper_check_ieee_exceptions();
+ gen_op_store_QT0_fpr(QFPREG(rd));
+ break;
+ case 0x4d: /* fdivs */
+ gen_clear_float_exceptions();
+ gen_helper_fdivs(cpu_tmp32, cpu_fpr[rs1], cpu_fpr[rs2]);
+ gen_helper_check_ieee_exceptions();
+ tcg_gen_mov_i32(cpu_fpr[rd], cpu_tmp32);
+ break;
+ case 0x4e: /* fdivd */
+ gen_op_load_fpr_DT0(DFPREG(rs1));
+ gen_op_load_fpr_DT1(DFPREG(rs2));
+ gen_clear_float_exceptions();
+ gen_helper_fdivd();
+ gen_helper_check_ieee_exceptions();
+ gen_op_store_DT0_fpr(DFPREG(rd));
+ break;
+ case 0x4f: /* fdivq */
+ CHECK_FPU_FEATURE(dc, FLOAT128);
+ gen_op_load_fpr_QT0(QFPREG(rs1));
+ gen_op_load_fpr_QT1(QFPREG(rs2));
+ gen_clear_float_exceptions();
+ gen_helper_fdivq();
+ gen_helper_check_ieee_exceptions();
+ gen_op_store_QT0_fpr(QFPREG(rd));
+ break;
+ case 0x69: /* fsmuld */
+ CHECK_FPU_FEATURE(dc, FSMULD);
+ gen_clear_float_exceptions();
+ gen_helper_fsmuld(cpu_fpr[rs1], cpu_fpr[rs2]);
+ gen_helper_check_ieee_exceptions();
+ gen_op_store_DT0_fpr(DFPREG(rd));
+ break;
+ case 0x6e: /* fdmulq */
+ CHECK_FPU_FEATURE(dc, FLOAT128);
+ gen_op_load_fpr_DT0(DFPREG(rs1));
+ gen_op_load_fpr_DT1(DFPREG(rs2));
+ gen_clear_float_exceptions();
+ gen_helper_fdmulq();
+ gen_helper_check_ieee_exceptions();
+ gen_op_store_QT0_fpr(QFPREG(rd));
+ break;
+ case 0xc4: /* fitos */
+ gen_clear_float_exceptions();
+ gen_helper_fitos(cpu_tmp32, cpu_fpr[rs2]);
+ gen_helper_check_ieee_exceptions();
+ tcg_gen_mov_i32(cpu_fpr[rd], cpu_tmp32);
+ break;
+ case 0xc6: /* fdtos */
+ gen_op_load_fpr_DT1(DFPREG(rs2));
+ gen_clear_float_exceptions();
+ gen_helper_fdtos(cpu_tmp32);
+ gen_helper_check_ieee_exceptions();
+ tcg_gen_mov_i32(cpu_fpr[rd], cpu_tmp32);
+ break;
+ case 0xc7: /* fqtos */
+ CHECK_FPU_FEATURE(dc, FLOAT128);
+ gen_op_load_fpr_QT1(QFPREG(rs2));
+ gen_clear_float_exceptions();
+ gen_helper_fqtos(cpu_tmp32);
+ gen_helper_check_ieee_exceptions();
+ tcg_gen_mov_i32(cpu_fpr[rd], cpu_tmp32);
+ break;
+ case 0xc8: /* fitod */
+ gen_helper_fitod(cpu_fpr[rs2]);
+ gen_op_store_DT0_fpr(DFPREG(rd));
+ break;
+ case 0xc9: /* fstod */
+ gen_helper_fstod(cpu_fpr[rs2]);
+ gen_op_store_DT0_fpr(DFPREG(rd));
+ break;
+ case 0xcb: /* fqtod */
+ CHECK_FPU_FEATURE(dc, FLOAT128);
+ gen_op_load_fpr_QT1(QFPREG(rs2));
+ gen_clear_float_exceptions();
+ gen_helper_fqtod();
+ gen_helper_check_ieee_exceptions();
+ gen_op_store_DT0_fpr(DFPREG(rd));
+ break;
+ case 0xcc: /* fitoq */
+ CHECK_FPU_FEATURE(dc, FLOAT128);
+ gen_helper_fitoq(cpu_fpr[rs2]);
+ gen_op_store_QT0_fpr(QFPREG(rd));
+ break;
+ case 0xcd: /* fstoq */
+ CHECK_FPU_FEATURE(dc, FLOAT128);
+ gen_helper_fstoq(cpu_fpr[rs2]);
+ gen_op_store_QT0_fpr(QFPREG(rd));
+ break;
+ case 0xce: /* fdtoq */
+ CHECK_FPU_FEATURE(dc, FLOAT128);
+ gen_op_load_fpr_DT1(DFPREG(rs2));
+ gen_helper_fdtoq();
+ gen_op_store_QT0_fpr(QFPREG(rd));
+ break;
+ case 0xd1: /* fstoi */
+ gen_clear_float_exceptions();
+ gen_helper_fstoi(cpu_tmp32, cpu_fpr[rs2]);
+ gen_helper_check_ieee_exceptions();
+ tcg_gen_mov_i32(cpu_fpr[rd], cpu_tmp32);
+ break;
+ case 0xd2: /* fdtoi */
+ gen_op_load_fpr_DT1(DFPREG(rs2));
+ gen_clear_float_exceptions();
+ gen_helper_fdtoi(cpu_tmp32);
+ gen_helper_check_ieee_exceptions();
+ tcg_gen_mov_i32(cpu_fpr[rd], cpu_tmp32);
+ break;
+ case 0xd3: /* fqtoi */
+ CHECK_FPU_FEATURE(dc, FLOAT128);
+ gen_op_load_fpr_QT1(QFPREG(rs2));
+ gen_clear_float_exceptions();
+ gen_helper_fqtoi(cpu_tmp32);
+ gen_helper_check_ieee_exceptions();
+ tcg_gen_mov_i32(cpu_fpr[rd], cpu_tmp32);
+ break;
#ifdef TARGET_SPARC64
- case 0x2: /* V9 fmovd */
- tcg_gen_mov_i32(cpu_fpr[DFPREG(rd)],
- cpu_fpr[DFPREG(rs2)]);
- tcg_gen_mov_i32(cpu_fpr[DFPREG(rd) + 1],
- cpu_fpr[DFPREG(rs2) + 1]);
- break;
- case 0x3: /* V9 fmovq */
- CHECK_FPU_FEATURE(dc, FLOAT128);
- tcg_gen_mov_i32(cpu_fpr[QFPREG(rd)],
- cpu_fpr[QFPREG(rs2)]);
- tcg_gen_mov_i32(cpu_fpr[QFPREG(rd) + 1],
- cpu_fpr[QFPREG(rs2) + 1]);
- tcg_gen_mov_i32(cpu_fpr[QFPREG(rd) + 2],
- cpu_fpr[QFPREG(rs2) + 2]);
- tcg_gen_mov_i32(cpu_fpr[QFPREG(rd) + 3],
- cpu_fpr[QFPREG(rs2) + 3]);
- break;
- case 0x6: /* V9 fnegd */
- gen_op_load_fpr_DT1(DFPREG(rs2));
- gen_helper_fnegd();
- gen_op_store_DT0_fpr(DFPREG(rd));
- break;
- case 0x7: /* V9 fnegq */
- CHECK_FPU_FEATURE(dc, FLOAT128);
- gen_op_load_fpr_QT1(QFPREG(rs2));
- gen_helper_fnegq();
- gen_op_store_QT0_fpr(QFPREG(rd));
- break;
- case 0xa: /* V9 fabsd */
- gen_op_load_fpr_DT1(DFPREG(rs2));
- gen_helper_fabsd();
- gen_op_store_DT0_fpr(DFPREG(rd));
- break;
- case 0xb: /* V9 fabsq */
- CHECK_FPU_FEATURE(dc, FLOAT128);
- gen_op_load_fpr_QT1(QFPREG(rs2));
- gen_helper_fabsq();
- gen_op_store_QT0_fpr(QFPREG(rd));
- break;
- case 0x81: /* V9 fstox */
- gen_clear_float_exceptions();
- gen_helper_fstox(cpu_fpr[rs2]);
- gen_helper_check_ieee_exceptions();
- gen_op_store_DT0_fpr(DFPREG(rd));
- break;
- case 0x82: /* V9 fdtox */
- gen_op_load_fpr_DT1(DFPREG(rs2));
- gen_clear_float_exceptions();
- gen_helper_fdtox();
- gen_helper_check_ieee_exceptions();
- gen_op_store_DT0_fpr(DFPREG(rd));
- break;
- case 0x83: /* V9 fqtox */
- CHECK_FPU_FEATURE(dc, FLOAT128);
- gen_op_load_fpr_QT1(QFPREG(rs2));
- gen_clear_float_exceptions();
- gen_helper_fqtox();
- gen_helper_check_ieee_exceptions();
- gen_op_store_DT0_fpr(DFPREG(rd));
- break;
- case 0x84: /* V9 fxtos */
- gen_op_load_fpr_DT1(DFPREG(rs2));
- gen_clear_float_exceptions();
- gen_helper_fxtos(cpu_tmp32);
- gen_helper_check_ieee_exceptions();
- tcg_gen_mov_i32(cpu_fpr[rd], cpu_tmp32);
- break;
- case 0x88: /* V9 fxtod */
- gen_op_load_fpr_DT1(DFPREG(rs2));
- gen_clear_float_exceptions();
- gen_helper_fxtod();
- gen_helper_check_ieee_exceptions();
- gen_op_store_DT0_fpr(DFPREG(rd));
- break;
- case 0x8c: /* V9 fxtoq */
- CHECK_FPU_FEATURE(dc, FLOAT128);
- gen_op_load_fpr_DT1(DFPREG(rs2));
- gen_clear_float_exceptions();
- gen_helper_fxtoq();
- gen_helper_check_ieee_exceptions();
- gen_op_store_QT0_fpr(QFPREG(rd));
- break;
+ case 0x2: /* V9 fmovd */
+ tcg_gen_mov_i32(cpu_fpr[DFPREG(rd)], cpu_fpr[DFPREG(rs2)]);
+ tcg_gen_mov_i32(cpu_fpr[DFPREG(rd) + 1],
+ cpu_fpr[DFPREG(rs2) + 1]);
+ break;
+ case 0x3: /* V9 fmovq */
+ CHECK_FPU_FEATURE(dc, FLOAT128);
+ tcg_gen_mov_i32(cpu_fpr[QFPREG(rd)], cpu_fpr[QFPREG(rs2)]);
+ tcg_gen_mov_i32(cpu_fpr[QFPREG(rd) + 1],
+ cpu_fpr[QFPREG(rs2) + 1]);
+ tcg_gen_mov_i32(cpu_fpr[QFPREG(rd) + 2],
+ cpu_fpr[QFPREG(rs2) + 2]);
+ tcg_gen_mov_i32(cpu_fpr[QFPREG(rd) + 3],
+ cpu_fpr[QFPREG(rs2) + 3]);
+ break;
+ case 0x6: /* V9 fnegd */
+ gen_op_load_fpr_DT1(DFPREG(rs2));
+ gen_helper_fnegd();
+ gen_op_store_DT0_fpr(DFPREG(rd));
+ break;
+ case 0x7: /* V9 fnegq */
+ CHECK_FPU_FEATURE(dc, FLOAT128);
+ gen_op_load_fpr_QT1(QFPREG(rs2));
+ gen_helper_fnegq();
+ gen_op_store_QT0_fpr(QFPREG(rd));
+ break;
+ case 0xa: /* V9 fabsd */
+ gen_op_load_fpr_DT1(DFPREG(rs2));
+ gen_helper_fabsd();
+ gen_op_store_DT0_fpr(DFPREG(rd));
+ break;
+ case 0xb: /* V9 fabsq */
+ CHECK_FPU_FEATURE(dc, FLOAT128);
+ gen_op_load_fpr_QT1(QFPREG(rs2));
+ gen_helper_fabsq();
+ gen_op_store_QT0_fpr(QFPREG(rd));
+ break;
+ case 0x81: /* V9 fstox */
+ gen_clear_float_exceptions();
+ gen_helper_fstox(cpu_fpr[rs2]);
+ gen_helper_check_ieee_exceptions();
+ gen_op_store_DT0_fpr(DFPREG(rd));
+ break;
+ case 0x82: /* V9 fdtox */
+ gen_op_load_fpr_DT1(DFPREG(rs2));
+ gen_clear_float_exceptions();
+ gen_helper_fdtox();
+ gen_helper_check_ieee_exceptions();
+ gen_op_store_DT0_fpr(DFPREG(rd));
+ break;
+ case 0x83: /* V9 fqtox */
+ CHECK_FPU_FEATURE(dc, FLOAT128);
+ gen_op_load_fpr_QT1(QFPREG(rs2));
+ gen_clear_float_exceptions();
+ gen_helper_fqtox();
+ gen_helper_check_ieee_exceptions();
+ gen_op_store_DT0_fpr(DFPREG(rd));
+ break;
+ case 0x84: /* V9 fxtos */
+ gen_op_load_fpr_DT1(DFPREG(rs2));
+ gen_clear_float_exceptions();
+ gen_helper_fxtos(cpu_tmp32);
+ gen_helper_check_ieee_exceptions();
+ tcg_gen_mov_i32(cpu_fpr[rd], cpu_tmp32);
+ break;
+ case 0x88: /* V9 fxtod */
+ gen_op_load_fpr_DT1(DFPREG(rs2));
+ gen_clear_float_exceptions();
+ gen_helper_fxtod();
+ gen_helper_check_ieee_exceptions();
+ gen_op_store_DT0_fpr(DFPREG(rd));
+ break;
+ case 0x8c: /* V9 fxtoq */
+ CHECK_FPU_FEATURE(dc, FLOAT128);
+ gen_op_load_fpr_DT1(DFPREG(rs2));
+ gen_clear_float_exceptions();
+ gen_helper_fxtoq();
+ gen_helper_check_ieee_exceptions();
+ gen_op_store_QT0_fpr(QFPREG(rd));
+ break;
#endif
- default:
- goto illegal_insn;
+ default:
+ goto illegal_insn;
}
} else if (xop == 0x35) { /* FPU Operations */
#ifdef TARGET_SPARC64
@@ -2752,7 +2823,7 @@ static void disas_sparc_insn(DisasContext * dc)
int l1; \
\
l1 = gen_new_label(); \
- r_cond = tcg_temp_new(); \
+ r_cond = tcg_temp_new(); \
cond = GET_FIELD_SP(insn, 14, 17); \
gen_fcond(r_cond, fcc, cond); \
tcg_gen_brcondi_tl(TCG_COND_EQ, r_cond, \
@@ -2767,7 +2838,7 @@ static void disas_sparc_insn(DisasContext * dc)
int l1; \
\
l1 = gen_new_label(); \
- r_cond = tcg_temp_new(); \
+ r_cond = tcg_temp_new(); \
cond = GET_FIELD_SP(insn, 14, 17); \
gen_fcond(r_cond, fcc, cond); \
tcg_gen_brcondi_tl(TCG_COND_EQ, r_cond, \
@@ -2785,7 +2856,7 @@ static void disas_sparc_insn(DisasContext * dc)
int l1; \
\
l1 = gen_new_label(); \
- r_cond = tcg_temp_new(); \
+ r_cond = tcg_temp_new(); \
cond = GET_FIELD_SP(insn, 14, 17); \
gen_fcond(r_cond, fcc, cond); \
tcg_gen_brcondi_tl(TCG_COND_EQ, r_cond, \
@@ -2850,7 +2921,7 @@ static void disas_sparc_insn(DisasContext * dc)
int l1; \
\
l1 = gen_new_label(); \
- r_cond = tcg_temp_new(); \
+ r_cond = tcg_temp_new(); \
cond = GET_FIELD_SP(insn, 14, 17); \
gen_cond(r_cond, icc, cond); \
tcg_gen_brcondi_tl(TCG_COND_EQ, r_cond, \
@@ -2865,7 +2936,7 @@ static void disas_sparc_insn(DisasContext * dc)
int l1; \
\
l1 = gen_new_label(); \
- r_cond = tcg_temp_new(); \
+ r_cond = tcg_temp_new(); \
cond = GET_FIELD_SP(insn, 14, 17); \
gen_cond(r_cond, icc, cond); \
tcg_gen_brcondi_tl(TCG_COND_EQ, r_cond, \
@@ -2883,7 +2954,7 @@ static void disas_sparc_insn(DisasContext * dc)
int l1; \
\
l1 = gen_new_label(); \
- r_cond = tcg_temp_new(); \
+ r_cond = tcg_temp_new(); \
cond = GET_FIELD_SP(insn, 14, 17); \
gen_cond(r_cond, icc, cond); \
tcg_gen_brcondi_tl(TCG_COND_EQ, r_cond, \
@@ -2963,8 +3034,8 @@ static void disas_sparc_insn(DisasContext * dc)
if (IS_IMM) { /* immediate */
TCGv r_const;
- rs2 = GET_FIELDs(insn, 19, 31);
- r_const = tcg_const_tl((int)rs2);
+ simm = GET_FIELDs(insn, 19, 31);
+ r_const = tcg_const_tl(simm);
gen_movl_TN_reg(rd, r_const);
tcg_temp_free(r_const);
} else { /* register */
@@ -2975,8 +3046,8 @@ static void disas_sparc_insn(DisasContext * dc)
} else {
cpu_src1 = get_src1(insn, cpu_src1);
if (IS_IMM) { /* immediate */
- rs2 = GET_FIELDs(insn, 19, 31);
- tcg_gen_ori_tl(cpu_dst, cpu_src1, (int)rs2);
+ simm = GET_FIELDs(insn, 19, 31);
+ tcg_gen_ori_tl(cpu_dst, cpu_src1, simm);
gen_movl_TN_reg(rd, cpu_dst);
} else { /* register */
// or x, %g0, y -> mov T1, x; mov y, T1
@@ -2993,11 +3064,11 @@ static void disas_sparc_insn(DisasContext * dc)
} else if (xop == 0x25) { /* sll, V9 sllx */
cpu_src1 = get_src1(insn, cpu_src1);
if (IS_IMM) { /* immediate */
- rs2 = GET_FIELDs(insn, 20, 31);
+ simm = GET_FIELDs(insn, 20, 31);
if (insn & (1 << 12)) {
- tcg_gen_shli_i64(cpu_dst, cpu_src1, rs2 & 0x3f);
+ tcg_gen_shli_i64(cpu_dst, cpu_src1, simm & 0x3f);
} else {
- tcg_gen_shli_i64(cpu_dst, cpu_src1, rs2 & 0x1f);
+ tcg_gen_shli_i64(cpu_dst, cpu_src1, simm & 0x1f);
}
} else { /* register */
rs2 = GET_FIELD(insn, 27, 31);
@@ -3013,12 +3084,12 @@ static void disas_sparc_insn(DisasContext * dc)
} else if (xop == 0x26) { /* srl, V9 srlx */
cpu_src1 = get_src1(insn, cpu_src1);
if (IS_IMM) { /* immediate */
- rs2 = GET_FIELDs(insn, 20, 31);
+ simm = GET_FIELDs(insn, 20, 31);
if (insn & (1 << 12)) {
- tcg_gen_shri_i64(cpu_dst, cpu_src1, rs2 & 0x3f);
+ tcg_gen_shri_i64(cpu_dst, cpu_src1, simm & 0x3f);
} else {
tcg_gen_andi_i64(cpu_dst, cpu_src1, 0xffffffffULL);
- tcg_gen_shri_i64(cpu_dst, cpu_dst, rs2 & 0x1f);
+ tcg_gen_shri_i64(cpu_dst, cpu_dst, simm & 0x1f);
}
} else { /* register */
rs2 = GET_FIELD(insn, 27, 31);
@@ -3036,13 +3107,13 @@ static void disas_sparc_insn(DisasContext * dc)
} else if (xop == 0x27) { /* sra, V9 srax */
cpu_src1 = get_src1(insn, cpu_src1);
if (IS_IMM) { /* immediate */
- rs2 = GET_FIELDs(insn, 20, 31);
+ simm = GET_FIELDs(insn, 20, 31);
if (insn & (1 << 12)) {
- tcg_gen_sari_i64(cpu_dst, cpu_src1, rs2 & 0x3f);
+ tcg_gen_sari_i64(cpu_dst, cpu_src1, simm & 0x3f);
} else {
tcg_gen_andi_i64(cpu_dst, cpu_src1, 0xffffffffULL);
tcg_gen_ext32s_i64(cpu_dst, cpu_dst);
- tcg_gen_sari_i64(cpu_dst, cpu_dst, rs2 & 0x1f);
+ tcg_gen_sari_i64(cpu_dst, cpu_dst, simm & 0x1f);
}
} else { /* register */
rs2 = GET_FIELD(insn, 27, 31);
@@ -3060,86 +3131,164 @@ static void disas_sparc_insn(DisasContext * dc)
gen_movl_TN_reg(rd, cpu_dst);
#endif
} else if (xop < 0x36) {
- cpu_src1 = get_src1(insn, cpu_src1);
- cpu_src2 = get_src2(insn, cpu_src2);
if (xop < 0x20) {
+ cpu_src1 = get_src1(insn, cpu_src1);
+ cpu_src2 = get_src2(insn, cpu_src2);
switch (xop & ~0x10) {
- case 0x0:
- if (xop & 0x10)
- gen_op_add_cc(cpu_dst, cpu_src1, cpu_src2);
- else
- tcg_gen_add_tl(cpu_dst, cpu_src1, cpu_src2);
+ case 0x0: /* add */
+ if (IS_IMM) {
+ simm = GET_FIELDs(insn, 19, 31);
+ if (xop & 0x10) {
+ gen_op_addi_cc(cpu_dst, cpu_src1, simm);
+ } else {
+ tcg_gen_addi_tl(cpu_dst, cpu_src1, simm);
+ }
+ } else {
+ if (xop & 0x10) {
+ gen_op_add_cc(cpu_dst, cpu_src1, cpu_src2);
+ } else {
+ tcg_gen_add_tl(cpu_dst, cpu_src1, cpu_src2);
+ }
+ }
break;
- case 0x1:
- tcg_gen_and_tl(cpu_dst, cpu_src1, cpu_src2);
- if (xop & 0x10)
+ case 0x1: /* and */
+ if (IS_IMM) {
+ simm = GET_FIELDs(insn, 19, 31);
+ tcg_gen_andi_tl(cpu_dst, cpu_src1, simm);
+ } else {
+ tcg_gen_and_tl(cpu_dst, cpu_src1, cpu_src2);
+ }
+ if (xop & 0x10) {
gen_op_logic_cc(cpu_dst);
+ }
break;
- case 0x2:
- tcg_gen_or_tl(cpu_dst, cpu_src1, cpu_src2);
+ case 0x2: /* or */
+ if (IS_IMM) {
+ simm = GET_FIELDs(insn, 19, 31);
+ tcg_gen_ori_tl(cpu_dst, cpu_src1, simm);
+ } else {
+ tcg_gen_or_tl(cpu_dst, cpu_src1, cpu_src2);
+ }
if (xop & 0x10)
gen_op_logic_cc(cpu_dst);
break;
- case 0x3:
- tcg_gen_xor_tl(cpu_dst, cpu_src1, cpu_src2);
+ case 0x3: /* xor */
+ if (IS_IMM) {
+ simm = GET_FIELDs(insn, 19, 31);
+ tcg_gen_xori_tl(cpu_dst, cpu_src1, simm);
+ } else {
+ tcg_gen_xor_tl(cpu_dst, cpu_src1, cpu_src2);
+ }
if (xop & 0x10)
gen_op_logic_cc(cpu_dst);
break;
- case 0x4:
- if (xop & 0x10)
- gen_op_sub_cc(cpu_dst, cpu_src1, cpu_src2);
- else
- tcg_gen_sub_tl(cpu_dst, cpu_src1, cpu_src2);
+ case 0x4: /* sub */
+ if (IS_IMM) {
+ simm = GET_FIELDs(insn, 19, 31);
+ if (xop & 0x10) {
+ gen_op_subi_cc(cpu_dst, cpu_src1, simm);
+ } else {
+ tcg_gen_subi_tl(cpu_dst, cpu_src1, simm);
+ }
+ } else {
+ if (xop & 0x10) {
+ gen_op_sub_cc(cpu_dst, cpu_src1, cpu_src2);
+ } else {
+ tcg_gen_sub_tl(cpu_dst, cpu_src1, cpu_src2);
+ }
+ }
break;
- case 0x5:
- tcg_gen_andc_tl(cpu_dst, cpu_src1, cpu_src2);
+ case 0x5: /* andn */
+ if (IS_IMM) {
+ simm = GET_FIELDs(insn, 19, 31);
+ tcg_gen_andi_tl(cpu_dst, cpu_src1, ~simm);
+ } else {
+ tcg_gen_andc_tl(cpu_dst, cpu_src1, cpu_src2);
+ }
if (xop & 0x10)
gen_op_logic_cc(cpu_dst);
break;
- case 0x6:
- tcg_gen_orc_tl(cpu_dst, cpu_src1, cpu_src2);
+ case 0x6: /* orn */
+ if (IS_IMM) {
+ simm = GET_FIELDs(insn, 19, 31);
+ tcg_gen_ori_tl(cpu_dst, cpu_src1, ~simm);
+ } else {
+ tcg_gen_orc_tl(cpu_dst, cpu_src1, cpu_src2);
+ }
if (xop & 0x10)
gen_op_logic_cc(cpu_dst);
break;
- case 0x7:
- tcg_gen_not_tl(cpu_tmp0, cpu_src2);
- tcg_gen_xor_tl(cpu_dst, cpu_src1, cpu_tmp0);
+ case 0x7: /* xorn */
+ if (IS_IMM) {
+ simm = GET_FIELDs(insn, 19, 31);
+ tcg_gen_xori_tl(cpu_dst, cpu_src1, ~simm);
+ } else {
+ tcg_gen_not_tl(cpu_tmp0, cpu_src2);
+ tcg_gen_xor_tl(cpu_dst, cpu_src1, cpu_tmp0);
+ }
if (xop & 0x10)
gen_op_logic_cc(cpu_dst);
break;
- case 0x8:
- if (xop & 0x10)
- gen_op_addx_cc(cpu_dst, cpu_src1, cpu_src2);
- else {
- gen_mov_reg_C(cpu_tmp0, cpu_psr);
- tcg_gen_add_tl(cpu_tmp0, cpu_src2, cpu_tmp0);
- tcg_gen_add_tl(cpu_dst, cpu_src1, cpu_tmp0);
+ case 0x8: /* addx, V9 addc */
+ if (IS_IMM) {
+ simm = GET_FIELDs(insn, 19, 31);
+ if (xop & 0x10)
+ gen_op_addxi_cc(cpu_dst, cpu_src1, simm);
+ else {
+ gen_mov_reg_C(cpu_tmp0, cpu_psr);
+ tcg_gen_addi_tl(cpu_tmp0, cpu_tmp0, simm);
+ tcg_gen_add_tl(cpu_dst, cpu_src1, cpu_tmp0);
+ }
+ } else {
+ if (xop & 0x10)
+ gen_op_addx_cc(cpu_dst, cpu_src1, cpu_src2);
+ else {
+ gen_mov_reg_C(cpu_tmp0, cpu_psr);
+ tcg_gen_add_tl(cpu_tmp0, cpu_src2, cpu_tmp0);
+ tcg_gen_add_tl(cpu_dst, cpu_src1, cpu_tmp0);
+ }
}
break;
#ifdef TARGET_SPARC64
case 0x9: /* V9 mulx */
- tcg_gen_mul_i64(cpu_dst, cpu_src1, cpu_src2);
+ if (IS_IMM) {
+ simm = GET_FIELDs(insn, 19, 31);
+ tcg_gen_muli_i64(cpu_dst, cpu_src1, simm);
+ } else {
+ tcg_gen_mul_i64(cpu_dst, cpu_src1, cpu_src2);
+ }
break;
#endif
- case 0xa:
+ case 0xa: /* umul */
CHECK_IU_FEATURE(dc, MUL);
gen_op_umul(cpu_dst, cpu_src1, cpu_src2);
if (xop & 0x10)
gen_op_logic_cc(cpu_dst);
break;
- case 0xb:
+ case 0xb: /* smul */
CHECK_IU_FEATURE(dc, MUL);
gen_op_smul(cpu_dst, cpu_src1, cpu_src2);
if (xop & 0x10)
gen_op_logic_cc(cpu_dst);
break;
- case 0xc:
- if (xop & 0x10)
- gen_op_subx_cc(cpu_dst, cpu_src1, cpu_src2);
- else {
- gen_mov_reg_C(cpu_tmp0, cpu_psr);
- tcg_gen_add_tl(cpu_tmp0, cpu_src2, cpu_tmp0);
- tcg_gen_sub_tl(cpu_dst, cpu_src1, cpu_tmp0);
+ case 0xc: /* subx, V9 subc */
+ if (IS_IMM) {
+ simm = GET_FIELDs(insn, 19, 31);
+ if (xop & 0x10) {
+ gen_op_subxi_cc(cpu_dst, cpu_src1, simm);
+ } else {
+ gen_mov_reg_C(cpu_tmp0, cpu_psr);
+ tcg_gen_addi_tl(cpu_tmp0, cpu_tmp0, simm);
+ tcg_gen_sub_tl(cpu_dst, cpu_src1, cpu_tmp0);
+ }
+ } else {
+ if (xop & 0x10) {
+ gen_op_subx_cc(cpu_dst, cpu_src1, cpu_src2);
+ } else {
+ gen_mov_reg_C(cpu_tmp0, cpu_psr);
+ tcg_gen_add_tl(cpu_tmp0, cpu_src2, cpu_tmp0);
+ tcg_gen_sub_tl(cpu_dst, cpu_src1, cpu_tmp0);
+ }
}
break;
#ifdef TARGET_SPARC64
@@ -3150,13 +3299,13 @@ static void disas_sparc_insn(DisasContext * dc)
tcg_gen_divu_i64(cpu_dst, cpu_cc_src, cpu_cc_src2);
break;
#endif
- case 0xe:
+ case 0xe: /* udiv */
CHECK_IU_FEATURE(dc, DIV);
gen_helper_udiv(cpu_dst, cpu_src1, cpu_src2);
if (xop & 0x10)
gen_op_div_cc(cpu_dst);
break;
- case 0xf:
+ case 0xf: /* sdiv */
CHECK_IU_FEATURE(dc, DIV);
gen_helper_sdiv(cpu_dst, cpu_src1, cpu_src2);
if (xop & 0x10)
@@ -3167,6 +3316,8 @@ static void disas_sparc_insn(DisasContext * dc)
}
gen_movl_TN_reg(rd, cpu_dst);
} else {
+ cpu_src1 = get_src1(insn, cpu_src1);
+ cpu_src2 = get_src2(insn, cpu_src2);
switch (xop) {
case 0x20: /* taddcc */
gen_op_tadd_cc(cpu_dst, cpu_src1, cpu_src2);
@@ -3193,8 +3344,8 @@ static void disas_sparc_insn(DisasContext * dc)
#ifndef TARGET_SPARC64
case 0x25: /* sll */
if (IS_IMM) { /* immediate */
- rs2 = GET_FIELDs(insn, 20, 31);
- tcg_gen_shli_tl(cpu_dst, cpu_src1, rs2 & 0x1f);
+ simm = GET_FIELDs(insn, 20, 31);
+ tcg_gen_shli_tl(cpu_dst, cpu_src1, simm & 0x1f);
} else { /* register */
tcg_gen_andi_tl(cpu_tmp0, cpu_src2, 0x1f);
tcg_gen_shl_tl(cpu_dst, cpu_src1, cpu_tmp0);
@@ -3203,8 +3354,8 @@ static void disas_sparc_insn(DisasContext * dc)
break;
case 0x26: /* srl */
if (IS_IMM) { /* immediate */
- rs2 = GET_FIELDs(insn, 20, 31);
- tcg_gen_shri_tl(cpu_dst, cpu_src1, rs2 & 0x1f);
+ simm = GET_FIELDs(insn, 20, 31);
+ tcg_gen_shri_tl(cpu_dst, cpu_src1, simm & 0x1f);
} else { /* register */
tcg_gen_andi_tl(cpu_tmp0, cpu_src2, 0x1f);
tcg_gen_shr_tl(cpu_dst, cpu_src1, cpu_tmp0);
@@ -3213,8 +3364,8 @@ static void disas_sparc_insn(DisasContext * dc)
break;
case 0x27: /* sra */
if (IS_IMM) { /* immediate */
- rs2 = GET_FIELDs(insn, 20, 31);
- tcg_gen_sari_tl(cpu_dst, cpu_src1, rs2 & 0x1f);
+ simm = GET_FIELDs(insn, 20, 31);
+ tcg_gen_sari_tl(cpu_dst, cpu_src1, simm & 0x1f);
} else { /* register */
tcg_gen_andi_tl(cpu_tmp0, cpu_src2, 0x1f);
tcg_gen_sar_tl(cpu_dst, cpu_src1, cpu_tmp0);
@@ -3603,8 +3754,8 @@ static void disas_sparc_insn(DisasContext * dc)
if (IS_IMM) { /* immediate */
TCGv r_const;
- rs2 = GET_FIELD_SPs(insn, 0, 10);
- r_const = tcg_const_tl((int)rs2);
+ simm = GET_FIELD_SPs(insn, 0, 10);
+ r_const = tcg_const_tl(simm);
gen_movl_TN_reg(rd, r_const);
tcg_temp_free(r_const);
} else {
@@ -3640,8 +3791,8 @@ static void disas_sparc_insn(DisasContext * dc)
if (IS_IMM) { /* immediate */
TCGv r_const;
- rs2 = GET_FIELD_SPs(insn, 0, 9);
- r_const = tcg_const_tl((int)rs2);
+ simm = GET_FIELD_SPs(insn, 0, 9);
+ r_const = tcg_const_tl(simm);
gen_movl_TN_reg(rd, r_const);
tcg_temp_free(r_const);
} else {
@@ -4097,8 +4248,8 @@ static void disas_sparc_insn(DisasContext * dc)
save_state(dc, cpu_cond);
cpu_src1 = get_src1(insn, cpu_src1);
if (IS_IMM) { /* immediate */
- rs2 = GET_FIELDs(insn, 19, 31);
- tcg_gen_addi_tl(cpu_dst, cpu_src1, (int)rs2);
+ simm = GET_FIELDs(insn, 19, 31);
+ tcg_gen_addi_tl(cpu_dst, cpu_src1, simm);
} else { /* register */
rs2 = GET_FIELD(insn, 27, 31);
if (rs2) {
@@ -4119,8 +4270,8 @@ static void disas_sparc_insn(DisasContext * dc)
} else {
cpu_src1 = get_src1(insn, cpu_src1);
if (IS_IMM) { /* immediate */
- rs2 = GET_FIELDs(insn, 19, 31);
- tcg_gen_addi_tl(cpu_dst, cpu_src1, (int)rs2);
+ simm = GET_FIELDs(insn, 19, 31);
+ tcg_gen_addi_tl(cpu_dst, cpu_src1, simm);
} else { /* register */
rs2 = GET_FIELD(insn, 27, 31);
if (rs2) {
@@ -4219,8 +4370,8 @@ static void disas_sparc_insn(DisasContext * dc)
gen_movl_reg_TN(rs2, cpu_src2);
tcg_gen_mov_tl(cpu_addr, cpu_src1);
} else if (IS_IMM) { /* immediate */
- rs2 = GET_FIELDs(insn, 19, 31);
- tcg_gen_addi_tl(cpu_addr, cpu_src1, (int)rs2);
+ simm = GET_FIELDs(insn, 19, 31);
+ tcg_gen_addi_tl(cpu_addr, cpu_src1, simm);
} else { /* register */
rs2 = GET_FIELD(insn, 27, 31);
if (rs2 != 0) {
@@ -4233,19 +4384,19 @@ static void disas_sparc_insn(DisasContext * dc)
(xop > 0x17 && xop <= 0x1d ) ||
(xop > 0x2c && xop <= 0x33) || xop == 0x1f || xop == 0x3d) {
switch (xop) {
- case 0x0: /* load unsigned word */
+ case 0x0: /* ld, V9 lduw, load unsigned word */
gen_address_mask(dc, cpu_addr);
tcg_gen_qemu_ld32u(cpu_val, cpu_addr, dc->mem_idx);
break;
- case 0x1: /* load unsigned byte */
+ case 0x1: /* ldub, load unsigned byte */
gen_address_mask(dc, cpu_addr);
tcg_gen_qemu_ld8u(cpu_val, cpu_addr, dc->mem_idx);
break;
- case 0x2: /* load unsigned halfword */
+ case 0x2: /* lduh, load unsigned halfword */
gen_address_mask(dc, cpu_addr);
tcg_gen_qemu_ld16u(cpu_val, cpu_addr, dc->mem_idx);
break;
- case 0x3: /* load double word */
+ case 0x3: /* ldd, load double word */
if (rd & 1)
goto illegal_insn;
else {
@@ -4265,11 +4416,11 @@ static void disas_sparc_insn(DisasContext * dc)
tcg_gen_andi_tl(cpu_val, cpu_val, 0xffffffffULL);
}
break;
- case 0x9: /* load signed byte */
+ case 0x9: /* ldsb, load signed byte */
gen_address_mask(dc, cpu_addr);
tcg_gen_qemu_ld8s(cpu_val, cpu_addr, dc->mem_idx);
break;
- case 0xa: /* load signed halfword */
+ case 0xa: /* ldsh, load signed halfword */
gen_address_mask(dc, cpu_addr);
tcg_gen_qemu_ld16s(cpu_val, cpu_addr, dc->mem_idx);
break;
@@ -4284,7 +4435,7 @@ static void disas_sparc_insn(DisasContext * dc)
tcg_temp_free(r_const);
}
break;
- case 0x0f: /* swap register with memory. Also
+ case 0x0f: /* swap, swap register with memory. Also
atomically */
CHECK_IU_FEATURE(dc, SWAP);
gen_movl_reg_TN(rd, cpu_val);
@@ -4294,7 +4445,7 @@ static void disas_sparc_insn(DisasContext * dc)
tcg_gen_mov_tl(cpu_val, cpu_tmp0);
break;
#if !defined(CONFIG_USER_ONLY) || defined(TARGET_SPARC64)
- case 0x10: /* load word alternate */
+ case 0x10: /* lda, V9 lduwa, load word alternate */
#ifndef TARGET_SPARC64
if (IS_IMM)
goto illegal_insn;
@@ -4304,7 +4455,7 @@ static void disas_sparc_insn(DisasContext * dc)
save_state(dc, cpu_cond);
gen_ld_asi(cpu_val, cpu_addr, insn, 4, 0);
break;
- case 0x11: /* load unsigned byte alternate */
+ case 0x11: /* lduba, load unsigned byte alternate */
#ifndef TARGET_SPARC64
if (IS_IMM)
goto illegal_insn;
@@ -4314,7 +4465,7 @@ static void disas_sparc_insn(DisasContext * dc)
save_state(dc, cpu_cond);
gen_ld_asi(cpu_val, cpu_addr, insn, 1, 0);
break;
- case 0x12: /* load unsigned halfword alternate */
+ case 0x12: /* lduha, load unsigned halfword alternate */
#ifndef TARGET_SPARC64
if (IS_IMM)
goto illegal_insn;
@@ -4324,7 +4475,7 @@ static void disas_sparc_insn(DisasContext * dc)
save_state(dc, cpu_cond);
gen_ld_asi(cpu_val, cpu_addr, insn, 2, 0);
break;
- case 0x13: /* load double word alternate */
+ case 0x13: /* ldda, load double word alternate */
#ifndef TARGET_SPARC64
if (IS_IMM)
goto illegal_insn;
@@ -4336,7 +4487,7 @@ static void disas_sparc_insn(DisasContext * dc)
save_state(dc, cpu_cond);
gen_ldda_asi(cpu_val, cpu_addr, insn, rd);
goto skip_move;
- case 0x19: /* load signed byte alternate */
+ case 0x19: /* ldsba, load signed byte alternate */
#ifndef TARGET_SPARC64
if (IS_IMM)
goto illegal_insn;
@@ -4346,7 +4497,7 @@ static void disas_sparc_insn(DisasContext * dc)
save_state(dc, cpu_cond);
gen_ld_asi(cpu_val, cpu_addr, insn, 1, 1);
break;
- case 0x1a: /* load signed halfword alternate */
+ case 0x1a: /* ldsha, load signed halfword alternate */
#ifndef TARGET_SPARC64
if (IS_IMM)
goto illegal_insn;
@@ -4366,7 +4517,7 @@ static void disas_sparc_insn(DisasContext * dc)
save_state(dc, cpu_cond);
gen_ldstub_asi(cpu_val, cpu_addr, insn);
break;
- case 0x1f: /* swap reg with alt. memory. Also
+ case 0x1f: /* swapa, swap reg with alt. memory. Also
atomically */
CHECK_IU_FEATURE(dc, SWAP);
#ifndef TARGET_SPARC64
@@ -4434,7 +4585,7 @@ static void disas_sparc_insn(DisasContext * dc)
goto jmp_insn;
save_state(dc, cpu_cond);
switch (xop) {
- case 0x20: /* load fpreg */
+ case 0x20: /* ldf, load fpreg */
gen_address_mask(dc, cpu_addr);
tcg_gen_qemu_ld32u(cpu_tmp0, cpu_addr, dc->mem_idx);
tcg_gen_trunc_tl_i32(cpu_fpr[rd], cpu_tmp0);
@@ -4453,7 +4604,7 @@ static void disas_sparc_insn(DisasContext * dc)
}
#endif
break;
- case 0x22: /* load quad fpreg */
+ case 0x22: /* ldqf, load quad fpreg */
{
TCGv_i32 r_const;
@@ -4464,7 +4615,7 @@ static void disas_sparc_insn(DisasContext * dc)
gen_op_store_QT0_fpr(QFPREG(rd));
}
break;
- case 0x23: /* load double fpreg */
+ case 0x23: /* lddf, load double fpreg */
{
TCGv_i32 r_const;
@@ -4477,23 +4628,23 @@ static void disas_sparc_insn(DisasContext * dc)
default:
goto illegal_insn;
}
- } else if (xop < 8 || (xop >= 0x14 && xop < 0x18) || \
+ } else if (xop < 8 || (xop >= 0x14 && xop < 0x18) ||
xop == 0xe || xop == 0x1e) {
gen_movl_reg_TN(rd, cpu_val);
switch (xop) {
- case 0x4: /* store word */
+ case 0x4: /* st, store word */
gen_address_mask(dc, cpu_addr);
tcg_gen_qemu_st32(cpu_val, cpu_addr, dc->mem_idx);
break;
- case 0x5: /* store byte */
+ case 0x5: /* stb, store byte */
gen_address_mask(dc, cpu_addr);
tcg_gen_qemu_st8(cpu_val, cpu_addr, dc->mem_idx);
break;
- case 0x6: /* store halfword */
+ case 0x6: /* sth, store halfword */
gen_address_mask(dc, cpu_addr);
tcg_gen_qemu_st16(cpu_val, cpu_addr, dc->mem_idx);
break;
- case 0x7: /* store double word */
+ case 0x7: /* std, store double word */
if (rd & 1)
goto illegal_insn;
else {
@@ -4510,7 +4661,7 @@ static void disas_sparc_insn(DisasContext * dc)
}
break;
#if !defined(CONFIG_USER_ONLY) || defined(TARGET_SPARC64)
- case 0x14: /* store word alternate */
+ case 0x14: /* sta, V9 stwa, store word alternate */
#ifndef TARGET_SPARC64
if (IS_IMM)
goto illegal_insn;
@@ -4520,7 +4671,7 @@ static void disas_sparc_insn(DisasContext * dc)
save_state(dc, cpu_cond);
gen_st_asi(cpu_val, cpu_addr, insn, 4);
break;
- case 0x15: /* store byte alternate */
+ case 0x15: /* stba, store byte alternate */
#ifndef TARGET_SPARC64
if (IS_IMM)
goto illegal_insn;
@@ -4530,7 +4681,7 @@ static void disas_sparc_insn(DisasContext * dc)
save_state(dc, cpu_cond);
gen_st_asi(cpu_val, cpu_addr, insn, 1);
break;
- case 0x16: /* store halfword alternate */
+ case 0x16: /* stha, store halfword alternate */
#ifndef TARGET_SPARC64
if (IS_IMM)
goto illegal_insn;
@@ -4540,7 +4691,7 @@ static void disas_sparc_insn(DisasContext * dc)
save_state(dc, cpu_cond);
gen_st_asi(cpu_val, cpu_addr, insn, 2);
break;
- case 0x17: /* store double word alternate */
+ case 0x17: /* stda, store double word alternate */
#ifndef TARGET_SPARC64
if (IS_IMM)
goto illegal_insn;
@@ -4573,7 +4724,7 @@ static void disas_sparc_insn(DisasContext * dc)
goto jmp_insn;
save_state(dc, cpu_cond);
switch (xop) {
- case 0x24: /* store fpreg */
+ case 0x24: /* stf, store fpreg */
gen_address_mask(dc, cpu_addr);
tcg_gen_ext_i32_tl(cpu_tmp0, cpu_fpr[rd]);
tcg_gen_qemu_st32(cpu_tmp0, cpu_addr, dc->mem_idx);
@@ -4616,7 +4767,7 @@ static void disas_sparc_insn(DisasContext * dc)
goto nfq_insn;
#endif
#endif
- case 0x27: /* store double fpreg */
+ case 0x27: /* stdf, store double fpreg */
{
TCGv_i32 r_const;
@@ -4670,8 +4821,7 @@ static void disas_sparc_insn(DisasContext * dc)
default:
goto illegal_insn;
}
- }
- else
+ } else
goto illegal_insn;
}
break;
diff --git a/vl.c b/vl.c
index 3d6ebd9a5..042063493 100644
--- a/vl.c
+++ b/vl.c
@@ -139,6 +139,7 @@ int main(int argc, char **argv)
#include "hw/isa.h"
#include "hw/baum.h"
#include "hw/bt.h"
+#include "hw/watchdog.h"
#include "hw/smbios.h"
#include "hw/xen.h"
#include "bt-host.h"
@@ -258,6 +259,8 @@ int graphic_rotate = 0;
#ifndef _WIN32
int daemonize = 0;
#endif
+WatchdogTimerModel *watchdog = NULL;
+int watchdog_action = WDT_RESET;
const char *option_rom[MAX_OPTION_ROMS];
int nb_option_roms;
int semihosting_enabled = 0;
@@ -287,7 +290,7 @@ uint64_t node_cpumask[MAX_NODES];
static CPUState *cur_cpu;
static CPUState *next_cpu;
-static int event_pending = 1;
+static int timer_alarm_pending = 1;
/* Conversion factor from emulated instructions to virtual clock ticks. */
static int icount_time_shift;
/* Arbitrarily pick 1MIPS as the minimum allowable speed. */
@@ -300,16 +303,24 @@ static QEMUTimer *nographic_timer;
uint8_t qemu_uuid[16];
-/* KVM runs the main loop in a separate thread. If we update one of the lists
- * that are polled before or after select(), we need to make sure to break out
- * of the select() to ensure the new item is serviced.
- */
-static void main_loop_break(void)
+static int qemu_select(int max_fd, fd_set *rfds, fd_set *wfds, fd_set *xfds,
+ struct timeval *tv)
{
- if (kvm_enabled())
- qemu_kvm_notify_work();
+ int ret;
+
+ /* KVM holds a mutex while QEMU code is running, we need hooks to
+ release the mutex whenever QEMU code sleeps. */
+
+ kvm_sleep_begin();
+
+ ret = select(max_fd, rfds, wfds, xfds, tv);
+
+ kvm_sleep_end();
+
+ return ret;
}
+
/***********************************************************/
/* x86 ISA bus support */
@@ -952,17 +963,13 @@ static void qemu_rearm_alarm_timer(struct qemu_alarm_timer *t)
#define MIN_TIMER_REARM_US 250
static struct qemu_alarm_timer *alarm_timer;
-#ifndef _WIN32
-static int alarm_timer_rfd, alarm_timer_wfd;
-#endif
#ifdef _WIN32
struct qemu_alarm_win32 {
MMRESULT timerId;
- HANDLE host_alarm;
unsigned int period;
-} alarm_win32_data = {0, NULL, -1};
+} alarm_win32_data = {0, -1};
static int win32_start_timer(struct qemu_alarm_timer *t);
static void win32_stop_timer(struct qemu_alarm_timer *t);
@@ -1217,9 +1224,8 @@ void qemu_mod_timer(QEMUTimer *ts, int64_t expire_time)
qemu_rearm_alarm_timer(alarm_timer);
}
/* Interrupt execution to force deadline recalculation. */
- if (use_icount && cpu_single_env) {
- cpu_exit(cpu_single_env);
- }
+ if (use_icount)
+ qemu_notify_event();
}
}
@@ -1330,6 +1336,8 @@ static int timer_load(QEMUFile *f, void *opaque, int version_id)
return 0;
}
+static void qemu_event_increment(void);
+
#ifdef _WIN32
static void CALLBACK host_alarm_handler(UINT uTimerID, UINT uMsg,
DWORD_PTR dwUser, DWORD_PTR dw1,
@@ -1373,27 +1381,22 @@ static void host_alarm_handler(int host_signum)
qemu_get_clock(vm_clock))) ||
qemu_timer_expired(active_timers[QEMU_TIMER_REALTIME],
qemu_get_clock(rt_clock))) {
- CPUState *env = next_cpu;
-
-#ifdef _WIN32
- struct qemu_alarm_win32 *data = ((struct qemu_alarm_timer*)dwUser)->priv;
- SetEvent(data->host_alarm);
-#else
- static const char byte = 0;
- write(alarm_timer_wfd, &byte, sizeof(byte));
-#endif
+ qemu_event_increment();
alarm_timer->flags |= ALARM_FLAG_EXPIRED;
- if (env) {
+#ifndef CONFIG_IOTHREAD
+ if (next_cpu) {
/* stop the currently executing cpu because a timer occured */
- cpu_exit(env);
+ cpu_exit(next_cpu);
#ifdef CONFIG_KQEMU
- if (env->kqemu_enabled) {
- kqemu_cpu_interrupt(env);
+ if (next_cpu->kqemu_enabled) {
+ kqemu_cpu_interrupt(next_cpu);
}
#endif
}
- event_pending = 1;
+#endif
+ timer_alarm_pending = 1;
+ qemu_notify_event();
}
}
@@ -1669,24 +1672,6 @@ static void unix_stop_timer(struct qemu_alarm_timer *t)
#endif /* !defined(_WIN32) */
-static void try_to_rearm_timer(void *opaque)
-{
- struct qemu_alarm_timer *t = opaque;
-#ifndef _WIN32
- ssize_t len;
-
- /* Drain the notify pipe */
- do {
- char buffer[512];
- len = read(alarm_timer_rfd, buffer, sizeof(buffer));
- } while ((len == -1 && errno == EINTR) || len > 0);
-#endif
-
- if (t->flags & ALARM_FLAG_EXPIRED) {
- alarm_timer->flags &= ~ALARM_FLAG_EXPIRED;
- qemu_rearm_alarm_timer(alarm_timer);
- }
-}
#ifdef _WIN32
@@ -1696,12 +1681,6 @@ static int win32_start_timer(struct qemu_alarm_timer *t)
struct qemu_alarm_win32 *data = t->priv;
UINT flags;
- data->host_alarm = CreateEvent(NULL, FALSE, FALSE, NULL);
- if (!data->host_alarm) {
- perror("Failed CreateEvent");
- return -1;
- }
-
memset(&tc, 0, sizeof(tc));
timeGetDevCaps(&tc, sizeof(tc));
@@ -1724,14 +1703,10 @@ static int win32_start_timer(struct qemu_alarm_timer *t)
if (!data->timerId) {
perror("Failed to initialize win32 alarm timer");
-
timeEndPeriod(data->period);
- CloseHandle(data->host_alarm);
return -1;
}
- qemu_add_wait_object(data->host_alarm, try_to_rearm_timer, t);
-
return 0;
}
@@ -1741,8 +1716,6 @@ static void win32_stop_timer(struct qemu_alarm_timer *t)
timeKillEvent(data->timerId);
timeEndPeriod(data->period);
-
- CloseHandle(data->host_alarm);
}
static void win32_rearm_timer(struct qemu_alarm_timer *t)
@@ -1769,7 +1742,6 @@ static void win32_rearm_timer(struct qemu_alarm_timer *t)
perror("Failed to re-arm win32 alarm timer");
timeEndPeriod(data->period);
- CloseHandle(data->host_alarm);
exit(1);
}
}
@@ -1781,25 +1753,6 @@ static int init_timer_alarm(void)
struct qemu_alarm_timer *t = NULL;
int i, err = -1;
-#ifndef _WIN32
- int fds[2];
-
- err = pipe(fds);
- if (err == -1)
- return -errno;
-
- err = fcntl_setfl(fds[0], O_NONBLOCK);
- if (err < 0)
- goto fail;
-
- err = fcntl_setfl(fds[1], O_NONBLOCK);
- if (err < 0)
- goto fail;
-
- alarm_timer_rfd = fds[0];
- alarm_timer_wfd = fds[1];
-#endif
-
for (i = 0; alarm_timers[i].name; i++) {
t = &alarm_timers[i];
@@ -1813,20 +1766,11 @@ static int init_timer_alarm(void)
goto fail;
}
-#ifndef _WIN32
- qemu_set_fd_handler2(alarm_timer_rfd, NULL,
- try_to_rearm_timer, NULL, t);
-#endif
-
alarm_timer = t;
return 0;
fail:
-#ifndef _WIN32
- close(fds[0]);
- close(fds[1]);
-#endif
return err;
}
@@ -1957,29 +1901,45 @@ int get_param_value(char *buf, int buf_size,
return 0;
}
-int check_params(char *buf, int buf_size,
- const char * const *params, const char *str)
+int check_params(const char * const *params, const char *str)
{
+ int name_buf_size = 1;
const char *p;
- int i;
+ char *name_buf;
+ int i, len;
+ int ret = 0;
+
+ for (i = 0; params[i] != NULL; i++) {
+ len = strlen(params[i]) + 1;
+ if (len > name_buf_size) {
+ name_buf_size = len;
+ }
+ }
+ name_buf = qemu_malloc(name_buf_size);
p = str;
while (*p != '\0') {
- p = get_opt_name(buf, buf_size, p, '=');
- if (*p != '=')
- return -1;
+ p = get_opt_name(name_buf, name_buf_size, p, '=');
+ if (*p != '=') {
+ ret = -1;
+ break;
+ }
p++;
for(i = 0; params[i] != NULL; i++)
- if (!strcmp(params[i], buf))
+ if (!strcmp(params[i], name_buf))
break;
- if (params[i] == NULL)
- return -1;
+ if (params[i] == NULL) {
+ ret = -1;
+ break;
+ }
p = get_opt_value(NULL, 0, p);
if (*p != ',')
break;
p++;
}
- return 0;
+
+ qemu_free(name_buf);
+ return ret;
}
/***********************************************************/
@@ -2332,7 +2292,7 @@ int drive_init(struct drive_opt *arg, int snapshot, void *opaque)
"cache", "format", "serial", "werror",
"boot", NULL };
- if (check_params(buf, sizeof(buf), params, str) < 0) {
+ if (check_params(params, str) < 0) {
fprintf(stderr, "qemu: unknown parameter '%s' in '%s'\n",
buf, str);
return -1;
@@ -3075,7 +3035,7 @@ int qemu_set_fd_handler2(int fd,
ioh->opaque = opaque;
ioh->deleted = 0;
}
- main_loop_break();
+ qemu_notify_event();
return 0;
}
@@ -3457,15 +3417,7 @@ static int ram_load(QEMUFile *f, void *opaque, int version_id)
void qemu_service_io(void)
{
- CPUState *env = cpu_single_env;
- if (env) {
- cpu_exit(env);
-#ifdef CONFIG_KQEMU
- if (env->kqemu_enabled) {
- kqemu_cpu_interrupt(env);
- }
-#endif
- }
+ qemu_notify_event();
}
/***********************************************************/
@@ -3533,16 +3485,12 @@ void qemu_bh_schedule_idle(QEMUBH *bh)
void qemu_bh_schedule(QEMUBH *bh)
{
- CPUState *env = cpu_single_env;
if (bh->scheduled)
return;
bh->scheduled = 1;
bh->idle = 0;
/* stop the currently executing CPU to execute the BH ASAP */
- if (env) {
- cpu_exit(env);
- }
- main_loop_break();
+ qemu_notify_event();
}
void qemu_bh_cancel(QEMUBH *bh)
@@ -3667,26 +3615,17 @@ static void vm_state_notify(int running, int reason)
}
}
+static void resume_all_vcpus(void);
+static void pause_all_vcpus(void);
+
void vm_start(void)
{
if (!vm_running) {
cpu_enable_ticks();
vm_running = 1;
vm_state_notify(1, 0);
- if (kvm_enabled())
- qemu_kvm_resume_all_threads();
qemu_rearm_alarm_timer(alarm_timer);
- }
-}
-
-void vm_stop(int reason)
-{
- if (vm_running) {
- cpu_disable_ticks();
- vm_running = 0;
- if (kvm_enabled())
- qemu_kvm_pause_all_threads();
- vm_state_notify(0, reason);
+ resume_all_vcpus();
}
}
@@ -3702,6 +3641,8 @@ static QEMUResetEntry *first_reset_entry;
static int reset_requested;
static int shutdown_requested;
static int powerdown_requested;
+static int debug_requested;
+static int vmstop_requested;
int qemu_shutdown_requested(void)
{
@@ -3724,6 +3665,30 @@ int qemu_powerdown_requested(void)
return r;
}
+static int qemu_debug_requested(void)
+{
+ int r = debug_requested;
+ debug_requested = 0;
+ return r;
+}
+
+static int qemu_vmstop_requested(void)
+{
+ int r = vmstop_requested;
+ vmstop_requested = 0;
+ return r;
+}
+
+static void do_vm_stop(int reason)
+{
+ if (vm_running) {
+ cpu_disable_ticks();
+ vm_running = 0;
+ pause_all_vcpus();
+ vm_state_notify(0, reason);
+ }
+}
+
void qemu_register_reset(QEMUResetHandler *func, void *opaque)
{
QEMUResetEntry **pre, *re;
@@ -3761,39 +3726,488 @@ void qemu_system_reset_request(void)
qemu_kvm_cpu_stop(cpu_single_env);
cpu_exit(cpu_single_env);
}
+ qemu_notify_event();
}
void qemu_system_shutdown_request(void)
{
shutdown_requested = 1;
- if (cpu_single_env)
- cpu_exit(cpu_single_env);
+ qemu_notify_event();
}
void qemu_system_powerdown_request(void)
{
powerdown_requested = 1;
+ qemu_notify_event();
+}
+
+#ifdef CONFIG_IOTHREAD
+static void qemu_system_vmstop_request(int reason)
+{
+ vmstop_requested = reason;
+ qemu_notify_event();
+}
+#endif
+
+#ifndef _WIN32
+static int io_thread_fd = -1;
+
+static void qemu_event_increment(void)
+{
+ static const char byte = 0;
+
+ if (io_thread_fd == -1)
+ return;
+
+ write(io_thread_fd, &byte, sizeof(byte));
+}
+
+static void qemu_event_read(void *opaque)
+{
+ int fd = (unsigned long)opaque;
+ ssize_t len;
+
+ /* Drain the notify pipe */
+ do {
+ char buffer[512];
+ len = read(fd, buffer, sizeof(buffer));
+ } while ((len == -1 && errno == EINTR) || len > 0);
+}
+
+static int qemu_event_init(void)
+{
+ int err;
+ int fds[2];
+
+ err = pipe(fds);
+ if (err == -1)
+ return -errno;
+
+ err = fcntl_setfl(fds[0], O_NONBLOCK);
+ if (err < 0)
+ goto fail;
+
+ err = fcntl_setfl(fds[1], O_NONBLOCK);
+ if (err < 0)
+ goto fail;
+
+ qemu_set_fd_handler2(fds[0], NULL, qemu_event_read, NULL,
+ (void *)(unsigned long)fds[0]);
+
+ io_thread_fd = fds[1];
+ return 0;
+
+fail:
+ close(fds[0]);
+ close(fds[1]);
+ return err;
+}
+#else
+HANDLE qemu_event_handle;
+
+static void dummy_event_handler(void *opaque)
+{
+}
+
+static int qemu_event_init(void)
+{
+ qemu_event_handle = CreateEvent(NULL, FALSE, FALSE, NULL);
+ if (!qemu_event_handle) {
+ perror("Failed CreateEvent");
+ return -1;
+ }
+ qemu_add_wait_object(qemu_event_handle, dummy_event_handler, NULL);
+ return 0;
+}
+
+static void qemu_event_increment(void)
+{
+ SetEvent(qemu_event_handle);
+}
+#endif
+
+static int cpu_can_run(CPUState *env)
+{
+ if (env->stop)
+ return 0;
+ if (env->stopped)
+ return 0;
+ return 1;
+}
+
+#ifndef CONFIG_IOTHREAD
+static int qemu_init_main_loop(void)
+{
+ return qemu_event_init();
+}
+
+void qemu_init_vcpu(void *_env)
+{
+ CPUState *env = _env;
+
+ if (kvm_enabled())
+ kvm_init_vcpu(env);
+ return;
+}
+
+int qemu_cpu_self(void *env)
+{
+ return 1;
+}
+
+static void resume_all_vcpus(void)
+{
+}
+
+static void pause_all_vcpus(void)
+{
+}
+
+void qemu_cpu_kick(void *env)
+{
+ return;
+}
+
+void qemu_notify_event(void)
+{
+ CPUState *env = cpu_single_env;
+
+ if (kvm_enabled()) {
+ qemu_kvm_notify_work();
+ return;
+ }
+ if (env) {
+ cpu_exit(env);
+#ifdef USE_KQEMU
+ if (env->kqemu_enabled)
+ kqemu_cpu_interrupt(env);
+#endif
+ }
+}
+
+#define qemu_mutex_lock_iothread() do { } while (0)
+#define qemu_mutex_unlock_iothread() do { } while (0)
+
+void vm_stop(int reason)
+{
+ do_vm_stop(reason);
+}
+
+#else /* CONFIG_IOTHREAD */
+
+#include "qemu-thread.h"
+
+QemuMutex qemu_global_mutex;
+static QemuMutex qemu_fair_mutex;
+
+static QemuThread io_thread;
+
+static QemuThread *tcg_cpu_thread;
+static QemuCond *tcg_halt_cond;
+
+static int qemu_system_ready;
+/* cpu creation */
+static QemuCond qemu_cpu_cond;
+/* system init */
+static QemuCond qemu_system_cond;
+static QemuCond qemu_pause_cond;
+
+static void block_io_signals(void);
+static void unblock_io_signals(void);
+static int tcg_has_work(void);
+
+static int qemu_init_main_loop(void)
+{
+ int ret;
+
+ ret = qemu_event_init();
+ if (ret)
+ return ret;
+
+ qemu_cond_init(&qemu_pause_cond);
+ qemu_mutex_init(&qemu_fair_mutex);
+ qemu_mutex_init(&qemu_global_mutex);
+ qemu_mutex_lock(&qemu_global_mutex);
+
+ unblock_io_signals();
+ qemu_thread_self(&io_thread);
+
+ return 0;
+}
+
+static void qemu_wait_io_event(CPUState *env)
+{
+ while (!tcg_has_work())
+ qemu_cond_timedwait(env->halt_cond, &qemu_global_mutex, 1000);
+
+ qemu_mutex_unlock(&qemu_global_mutex);
+
+ /*
+ * Users of qemu_global_mutex can be starved, having no chance
+ * to acquire it since this path will get to it first.
+ * So use another lock to provide fairness.
+ */
+ qemu_mutex_lock(&qemu_fair_mutex);
+ qemu_mutex_unlock(&qemu_fair_mutex);
+
+ qemu_mutex_lock(&qemu_global_mutex);
+ if (env->stop) {
+ env->stop = 0;
+ env->stopped = 1;
+ qemu_cond_signal(&qemu_pause_cond);
+ }
+}
+
+static int qemu_cpu_exec(CPUState *env);
+
+static void *kvm_cpu_thread_fn(void *arg)
+{
+ CPUState *env = arg;
+
+ block_io_signals();
+ qemu_thread_self(env->thread);
+
+ /* signal CPU creation */
+ qemu_mutex_lock(&qemu_global_mutex);
+ env->created = 1;
+ qemu_cond_signal(&qemu_cpu_cond);
+
+ /* and wait for machine initialization */
+ while (!qemu_system_ready)
+ qemu_cond_timedwait(&qemu_system_cond, &qemu_global_mutex, 100);
+
+ while (1) {
+ if (cpu_can_run(env))
+ qemu_cpu_exec(env);
+ qemu_wait_io_event(env);
+ }
+
+ return NULL;
+}
+
+static void tcg_cpu_exec(void);
+
+static void *tcg_cpu_thread_fn(void *arg)
+{
+ CPUState *env = arg;
+
+ block_io_signals();
+ qemu_thread_self(env->thread);
+
+ /* signal CPU creation */
+ qemu_mutex_lock(&qemu_global_mutex);
+ for (env = first_cpu; env != NULL; env = env->next_cpu)
+ env->created = 1;
+ qemu_cond_signal(&qemu_cpu_cond);
+
+ /* and wait for machine initialization */
+ while (!qemu_system_ready)
+ qemu_cond_timedwait(&qemu_system_cond, &qemu_global_mutex, 100);
+
+ while (1) {
+ tcg_cpu_exec();
+ qemu_wait_io_event(cur_cpu);
+ }
+
+ return NULL;
+}
+
+void qemu_cpu_kick(void *_env)
+{
+ CPUState *env = _env;
+ qemu_cond_broadcast(env->halt_cond);
+ if (kvm_enabled())
+ qemu_thread_signal(env->thread, SIGUSR1);
+}
+
+int qemu_cpu_self(void *env)
+{
+ return (cpu_single_env != NULL);
+}
+
+static void cpu_signal(int sig)
+{
if (cpu_single_env)
cpu_exit(cpu_single_env);
}
-static int qemu_select(int max_fd, fd_set *rfds, fd_set *wfds, fd_set *xfds,
- struct timeval *tv)
+static void block_io_signals(void)
{
- int ret;
+ sigset_t set;
+ struct sigaction sigact;
- /* KVM holds a mutex while QEMU code is running, we need hooks to
- release the mutex whenever QEMU code sleeps. */
+ sigemptyset(&set);
+ sigaddset(&set, SIGUSR2);
+ sigaddset(&set, SIGIO);
+ sigaddset(&set, SIGALRM);
+ pthread_sigmask(SIG_BLOCK, &set, NULL);
- kvm_sleep_begin();
+ sigemptyset(&set);
+ sigaddset(&set, SIGUSR1);
+ pthread_sigmask(SIG_UNBLOCK, &set, NULL);
- ret = select(max_fd, rfds, wfds, xfds, tv);
+ memset(&sigact, 0, sizeof(sigact));
+ sigact.sa_handler = cpu_signal;
+ sigaction(SIGUSR1, &sigact, NULL);
+}
- kvm_sleep_end();
+static void unblock_io_signals(void)
+{
+ sigset_t set;
- return ret;
+ sigemptyset(&set);
+ sigaddset(&set, SIGUSR2);
+ sigaddset(&set, SIGIO);
+ sigaddset(&set, SIGALRM);
+ pthread_sigmask(SIG_UNBLOCK, &set, NULL);
+
+ sigemptyset(&set);
+ sigaddset(&set, SIGUSR1);
+ pthread_sigmask(SIG_BLOCK, &set, NULL);
+}
+
+static void qemu_signal_lock(unsigned int msecs)
+{
+ qemu_mutex_lock(&qemu_fair_mutex);
+
+ while (qemu_mutex_trylock(&qemu_global_mutex)) {
+ qemu_thread_signal(tcg_cpu_thread, SIGUSR1);
+ if (!qemu_mutex_timedlock(&qemu_global_mutex, msecs))
+ break;
+ }
+ qemu_mutex_unlock(&qemu_fair_mutex);
+}
+
+static void qemu_mutex_lock_iothread(void)
+{
+ if (kvm_enabled()) {
+ qemu_mutex_lock(&qemu_fair_mutex);
+ qemu_mutex_lock(&qemu_global_mutex);
+ qemu_mutex_unlock(&qemu_fair_mutex);
+ } else
+ qemu_signal_lock(100);
+}
+
+static void qemu_mutex_unlock_iothread(void)
+{
+ qemu_mutex_unlock(&qemu_global_mutex);
+}
+
+static int all_vcpus_paused(void)
+{
+ CPUState *penv = first_cpu;
+
+ while (penv) {
+ if (!penv->stopped)
+ return 0;
+ penv = (CPUState *)penv->next_cpu;
+ }
+
+ return 1;
+}
+
+static void pause_all_vcpus(void)
+{
+ CPUState *penv = first_cpu;
+
+ while (penv) {
+ penv->stop = 1;
+ qemu_thread_signal(penv->thread, SIGUSR1);
+ qemu_cpu_kick(penv);
+ penv = (CPUState *)penv->next_cpu;
+ }
+
+ while (!all_vcpus_paused()) {
+ qemu_cond_timedwait(&qemu_pause_cond, &qemu_global_mutex, 100);
+ penv = first_cpu;
+ while (penv) {
+ qemu_thread_signal(penv->thread, SIGUSR1);
+ penv = (CPUState *)penv->next_cpu;
+ }
+ }
+}
+
+static void resume_all_vcpus(void)
+{
+ CPUState *penv = first_cpu;
+
+ while (penv) {
+ penv->stop = 0;
+ penv->stopped = 0;
+ qemu_thread_signal(penv->thread, SIGUSR1);
+ qemu_cpu_kick(penv);
+ penv = (CPUState *)penv->next_cpu;
+ }
+}
+
+static void tcg_init_vcpu(void *_env)
+{
+ CPUState *env = _env;
+ /* share a single thread for all cpus with TCG */
+ if (!tcg_cpu_thread) {
+ env->thread = qemu_mallocz(sizeof(QemuThread));
+ env->halt_cond = qemu_mallocz(sizeof(QemuCond));
+ qemu_cond_init(env->halt_cond);
+ qemu_thread_create(env->thread, tcg_cpu_thread_fn, env);
+ while (env->created == 0)
+ qemu_cond_timedwait(&qemu_cpu_cond, &qemu_global_mutex, 100);
+ tcg_cpu_thread = env->thread;
+ tcg_halt_cond = env->halt_cond;
+ } else {
+ env->thread = tcg_cpu_thread;
+ env->halt_cond = tcg_halt_cond;
+ }
+}
+
+static void kvm_start_vcpu(CPUState *env)
+{
+ kvm_init_vcpu(env);
+ env->thread = qemu_mallocz(sizeof(QemuThread));
+ env->halt_cond = qemu_mallocz(sizeof(QemuCond));
+ qemu_cond_init(env->halt_cond);
+ qemu_thread_create(env->thread, kvm_cpu_thread_fn, env);
+ while (env->created == 0)
+ qemu_cond_timedwait(&qemu_cpu_cond, &qemu_global_mutex, 100);
+}
+
+void qemu_init_vcpu(void *_env)
+{
+ CPUState *env = _env;
+
+ if (kvm_enabled())
+ kvm_start_vcpu(env);
+ else
+ tcg_init_vcpu(env);
+}
+
+void qemu_notify_event(void)
+{
+ qemu_event_increment();
}
+void vm_stop(int reason)
+{
+ QemuThread me;
+ qemu_thread_self(&me);
+
+ if (!qemu_thread_equal(&me, &io_thread)) {
+ qemu_system_vmstop_request(reason);
+ /*
+ * FIXME: should not return to device code in case
+ * vm_stop() has been requested.
+ */
+ if (cpu_single_env) {
+ cpu_exit(cpu_single_env);
+ cpu_single_env->stop = 1;
+ }
+ return;
+ }
+ do_vm_stop(reason);
+}
+
+#endif
+
+
#ifdef _WIN32
static void host_main_loop_wait(int *timeout)
{
@@ -3923,11 +4337,18 @@ void main_loop_wait(int timeout)
}
#endif
+ /* rearm timer, if not periodic */
+ if (alarm_timer->flags & ALARM_FLAG_EXPIRED) {
+ alarm_timer->flags &= ~ALARM_FLAG_EXPIRED;
+ qemu_rearm_alarm_timer(alarm_timer);
+ }
+
/* vm time timers */
- if (vm_running && (!cur_cpu
- || likely(!(cur_cpu->singlestep_enabled & SSTEP_NOTIMER))))
- qemu_run_timers(&active_timers[QEMU_TIMER_VIRTUAL],
- qemu_get_clock(vm_clock));
+ if (vm_running) {
+ if (!cur_cpu || likely(!(cur_cpu->singlestep_enabled & SSTEP_NOTIMER)))
+ qemu_run_timers(&active_timers[QEMU_TIMER_VIRTUAL],
+ qemu_get_clock(vm_clock));
+ }
/* real time timers */
qemu_run_timers(&active_timers[QEMU_TIMER_REALTIME],
@@ -3939,162 +4360,214 @@ void main_loop_wait(int timeout)
}
-static int main_loop(void)
+static int qemu_cpu_exec(CPUState *env)
{
- int ret, timeout;
+ int ret;
#ifdef CONFIG_PROFILER
int64_t ti;
#endif
+
+#ifdef CONFIG_PROFILER
+ ti = profile_getclock();
+#endif
+ if (use_icount) {
+ int64_t count;
+ int decr;
+ qemu_icount -= (env->icount_decr.u16.low + env->icount_extra);
+ env->icount_decr.u16.low = 0;
+ env->icount_extra = 0;
+ count = qemu_next_deadline();
+ count = (count + (1 << icount_time_shift) - 1)
+ >> icount_time_shift;
+ qemu_icount += count;
+ decr = (count > 0xffff) ? 0xffff : count;
+ count -= decr;
+ env->icount_decr.u16.low = decr;
+ env->icount_extra = count;
+ }
+ ret = cpu_exec(env);
+#ifdef CONFIG_PROFILER
+ qemu_time += profile_getclock() - ti;
+#endif
+ if (use_icount) {
+ /* Fold pending instructions back into the
+ instruction counter, and clear the interrupt flag. */
+ qemu_icount -= (env->icount_decr.u16.low
+ + env->icount_extra);
+ env->icount_decr.u32 = 0;
+ env->icount_extra = 0;
+ }
+ return ret;
+}
+
+static void tcg_cpu_exec(void)
+{
+ int ret = 0;
+
+ if (next_cpu == NULL)
+ next_cpu = first_cpu;
+ for (; next_cpu != NULL; next_cpu = next_cpu->next_cpu) {
+ CPUState *env = cur_cpu = next_cpu;
+
+ if (!vm_running)
+ break;
+ if (timer_alarm_pending) {
+ timer_alarm_pending = 0;
+ break;
+ }
+ if (cpu_can_run(env))
+ ret = qemu_cpu_exec(env);
+#ifndef CONFIG_GDBSTUB
+ if (ret == EXCP_DEBUG) {
+ gdb_set_stop_cpu(env);
+ debug_requested = 1;
+ break;
+ }
+#endif
+ }
+}
+
+static int cpu_has_work(CPUState *env)
+{
+ if (env->stop)
+ return 1;
+ if (env->stopped)
+ return 0;
+ if (!env->halted)
+ return 1;
+ if (qemu_cpu_has_work(env))
+ return 1;
+ return 0;
+}
+
+static int tcg_has_work(void)
+{
CPUState *env;
+ for (env = first_cpu; env != NULL; env = env->next_cpu)
+ if (cpu_has_work(env))
+ return 1;
+ return 0;
+}
+
+static int qemu_calculate_timeout(void)
+{
+ int timeout;
- if (kvm_enabled()) {
- kvm_main_loop();
- cpu_disable_ticks();
- return 0;
+ if (!vm_running)
+ timeout = 5000;
+ else if (tcg_has_work())
+ timeout = 0;
+ else if (!use_icount)
+ timeout = 5000;
+ else {
+ /* XXX: use timeout computed from timers */
+ int64_t add;
+ int64_t delta;
+ /* Advance virtual time to the next event. */
+ if (use_icount == 1) {
+ /* When not using an adaptive execution frequency
+ we tend to get badly out of sync with real time,
+ so just delay for a reasonable amount of time. */
+ delta = 0;
+ } else {
+ delta = cpu_get_icount() - cpu_get_clock();
+ }
+ if (delta > 0) {
+ /* If virtual time is ahead of real time then just
+ wait for IO. */
+ timeout = (delta / 1000000) + 1;
+ } else {
+ /* Wait for either IO to occur or the next
+ timer event. */
+ add = qemu_next_deadline();
+ /* We advance the timer before checking for IO.
+ Limit the amount we advance so that early IO
+ activity won't get the guest too far ahead. */
+ if (add > 10000000)
+ add = 10000000;
+ delta += add;
+ add = (add + (1 << icount_time_shift) - 1)
+ >> icount_time_shift;
+ qemu_icount += add;
+ timeout = delta / 1000000;
+ if (timeout < 0)
+ timeout = 0;
+ }
}
- cur_cpu = first_cpu;
- next_cpu = cur_cpu->next_cpu ?: first_cpu;
- for(;;) {
- if (vm_running) {
+ return timeout;
+}
- for(;;) {
- /* get next cpu */
- env = next_cpu;
-#ifdef CONFIG_PROFILER
- ti = profile_getclock();
+static int vm_can_run(void)
+{
+ if (powerdown_requested)
+ return 0;
+ if (reset_requested)
+ return 0;
+ if (shutdown_requested)
+ return 0;
+ if (debug_requested)
+ return 0;
+ return 1;
+}
+
+static void main_loop(void)
+{
+ int r;
+
+ if (kvm_enabled()) {
+ kvm_main_loop();
+ cpu_disable_ticks();
+ return;
+ }
+
+#ifdef CONFIG_IOTHREAD
+ qemu_system_ready = 1;
+ qemu_cond_broadcast(&qemu_system_cond);
#endif
- if (use_icount) {
- int64_t count;
- int decr;
- qemu_icount -= (env->icount_decr.u16.low + env->icount_extra);
- env->icount_decr.u16.low = 0;
- env->icount_extra = 0;
- count = qemu_next_deadline();
- count = (count + (1 << icount_time_shift) - 1)
- >> icount_time_shift;
- qemu_icount += count;
- decr = (count > 0xffff) ? 0xffff : count;
- count -= decr;
- env->icount_decr.u16.low = decr;
- env->icount_extra = count;
- }
- ret = cpu_exec(env);
+
+ for (;;) {
+ do {
#ifdef CONFIG_PROFILER
- qemu_time += profile_getclock() - ti;
+ int64_t ti;
#endif
- if (use_icount) {
- /* Fold pending instructions back into the
- instruction counter, and clear the interrupt flag. */
- qemu_icount -= (env->icount_decr.u16.low
- + env->icount_extra);
- env->icount_decr.u32 = 0;
- env->icount_extra = 0;
- }
- next_cpu = env->next_cpu ?: first_cpu;
- if (event_pending && likely(ret != EXCP_DEBUG)) {
- ret = EXCP_INTERRUPT;
- event_pending = 0;
- break;
- }
- if (ret == EXCP_HLT) {
- /* Give the next CPU a chance to run. */
- cur_cpu = env;
- continue;
- }
- if (ret != EXCP_HALTED)
- break;
- /* all CPUs are halted ? */
- if (env == cur_cpu)
- break;
- }
- cur_cpu = env;
-
- if (shutdown_requested) {
- ret = EXCP_INTERRUPT;
- if (no_shutdown) {
- vm_stop(0);
- no_shutdown = 0;
- }
- else
- break;
- }
- if (reset_requested) {
- reset_requested = 0;
- qemu_system_reset();
- ret = EXCP_INTERRUPT;
- }
- if (powerdown_requested) {
- powerdown_requested = 0;
- qemu_system_powerdown();
- ret = EXCP_INTERRUPT;
- }
-#ifdef CONFIG_GDBSTUB
- if (unlikely(ret == EXCP_DEBUG)) {
- gdb_set_stop_cpu(cur_cpu);
- vm_stop(EXCP_DEBUG);
- }
+#ifndef CONFIG_IOTHREAD
+ tcg_cpu_exec();
#endif
- /* If all cpus are halted then wait until the next IRQ */
- /* XXX: use timeout computed from timers */
- if (ret == EXCP_HALTED) {
- if (use_icount) {
- int64_t add;
- int64_t delta;
- /* Advance virtual time to the next event. */
- if (use_icount == 1) {
- /* When not using an adaptive execution frequency
- we tend to get badly out of sync with real time,
- so just delay for a reasonable amount of time. */
- delta = 0;
- } else {
- delta = cpu_get_icount() - cpu_get_clock();
- }
- if (delta > 0) {
- /* If virtual time is ahead of real time then just
- wait for IO. */
- timeout = (delta / 1000000) + 1;
- } else {
- /* Wait for either IO to occur or the next
- timer event. */
- add = qemu_next_deadline();
- /* We advance the timer before checking for IO.
- Limit the amount we advance so that early IO
- activity won't get the guest too far ahead. */
- if (add > 10000000)
- add = 10000000;
- delta += add;
- add = (add + (1 << icount_time_shift) - 1)
- >> icount_time_shift;
- qemu_icount += add;
- timeout = delta / 1000000;
- if (timeout < 0)
- timeout = 0;
- }
- } else {
- timeout = 5000;
- }
- } else {
- timeout = 0;
- }
- } else {
- if (shutdown_requested) {
- ret = EXCP_INTERRUPT;
- break;
- }
- timeout = 5000;
- }
#ifdef CONFIG_PROFILER
- ti = profile_getclock();
+ ti = profile_getclock();
+#endif
+#ifdef CONFIG_IOTHREAD
+ main_loop_wait(1000);
+#else
+ main_loop_wait(qemu_calculate_timeout());
#endif
- main_loop_wait(timeout);
#ifdef CONFIG_PROFILER
- dev_time += profile_getclock() - ti;
+ dev_time += profile_getclock() - ti;
#endif
+ } while (vm_can_run());
+
+ if (qemu_debug_requested())
+ vm_stop(EXCP_DEBUG);
+ if (qemu_shutdown_requested()) {
+ if (no_shutdown) {
+ vm_stop(0);
+ no_shutdown = 0;
+ } else
+ break;
+ }
+ if (qemu_reset_requested()) {
+ pause_all_vcpus();
+ qemu_system_reset();
+ resume_all_vcpus();
+ }
+ if (qemu_powerdown_requested())
+ qemu_system_powerdown();
+ if ((r = qemu_vmstop_requested()))
+ vm_stop(r);
}
- cpu_disable_ticks();
- return ret;
+ pause_all_vcpus();
}
static void version(void)
@@ -4625,6 +5098,8 @@ int main(int argc, char **argv, char **envp)
tb_size = 0;
autostart= 1;
+ register_watchdogs();
+
optind = 1;
for(;;) {
if (optind >= argc)
@@ -5016,6 +5491,17 @@ int main(int argc, char **argv, char **envp)
serial_devices[serial_device_index] = optarg;
serial_device_index++;
break;
+ case QEMU_OPTION_watchdog:
+ i = select_watchdog(optarg);
+ if (i > 0)
+ exit (i == 1 ? 1 : 0);
+ break;
+ case QEMU_OPTION_watchdog_action:
+ if (select_watchdog_action(optarg) == -1) {
+ fprintf(stderr, "Unknown -watchdog-action parameter\n");
+ exit(1);
+ }
+ break;
case QEMU_OPTION_virtiocon:
if (virtio_console_index >= MAX_VIRTIO_CONSOLES) {
fprintf(stderr, "qemu: too many virtio consoles\n");
@@ -5398,6 +5884,10 @@ int main(int argc, char **argv, char **envp)
if (smp_cpus > 1)
kqemu_allowed = 0;
#endif
+ if (qemu_init_main_loop()) {
+ fprintf(stderr, "qemu_init_main_loop failed\n");
+ exit(1);
+ }
linux_boot = (kernel_filename != NULL);
net_boot = (boot_devices_bitmap >> ('n' - 'a')) & 0xF;
diff --git a/vnc.c b/vnc.c
index ab1f04448..b11e22ba5 100644
--- a/vnc.c
+++ b/vnc.c
@@ -366,17 +366,13 @@ static void vnc_resize(VncState *vs)
memset(vs->guest.dirty, 0xFF, sizeof(vs->guest.dirty));
/* server surface */
- if (!vs->server.ds) {
- vs->server.ds = default_allocator.create_displaysurface(ds_get_width(ds),
- ds_get_height(ds));
- } else {
- default_allocator.resize_displaysurface(vs->server.ds,
- ds_get_width(ds), ds_get_height(ds));
- }
- if (vs->server.ds->data == NULL) {
- fprintf(stderr, "vnc: memory allocation failed\n");
- exit(1);
- }
+ if (!vs->server.ds)
+ vs->server.ds = qemu_mallocz(sizeof(*vs->server.ds));
+ if (vs->server.ds->data)
+ qemu_free(vs->server.ds->data);
+ *(vs->server.ds) = *(ds->surface);
+ vs->server.ds->data = qemu_mallocz(vs->server.ds->linesize *
+ vs->server.ds->height);
memset(vs->server.dirty, 0xFF, sizeof(vs->guest.dirty));
}
@@ -687,7 +683,7 @@ static int find_and_clear_dirty_height(struct VncSurface *s,
{
int h;
- for (h = 1; h < (s->ds->height - y) && h < 1; h++) {
+ for (h = 1; h < (s->ds->height - y); h++) {
int tmp_x;
if (!vnc_get_bit(s->dirty[y + h], last_x))
break;
@@ -705,7 +701,7 @@ static void vnc_update_client(void *opaque)
int y;
uint8_t *guest_row;
uint8_t *server_row;
- int cmp_bytes = 16 * ds_get_bytes_per_pixel(vs->ds);
+ int cmp_bytes;
uint32_t width_mask[VNC_DIRTY_WORDS];
int n_rectangles;
int saved_offset;
@@ -725,6 +721,7 @@ static void vnc_update_client(void *opaque)
* Update server dirty map.
*/
vnc_set_bits(width_mask, (ds_get_width(vs->ds) / 16), VNC_DIRTY_WORDS);
+ cmp_bytes = 16 * ds_get_bytes_per_pixel(vs->ds);
guest_row = vs->guest.ds->data;
server_row = vs->server.ds->data;
for (y = 0; y < vs->guest.ds->height; y++) {
@@ -918,7 +915,8 @@ int vnc_client_io_error(VncState *vs, int ret, int last_errno)
if (!vs->vd->clients)
dcl->idle = 1;
- default_allocator.free_displaysurface(vs->server.ds);
+ qemu_free(vs->server.ds->data);
+ qemu_free(vs->server.ds);
qemu_free(vs->guest.ds);
qemu_free(vs);
@@ -1345,30 +1343,39 @@ static void do_key_event(VncState *vs, int down, int keycode, int sym)
case 0xb8: /* Right ALT */
break;
case 0xc8:
+ case 0x48:
kbd_put_keysym(QEMU_KEY_UP);
break;
case 0xd0:
+ case 0x50:
kbd_put_keysym(QEMU_KEY_DOWN);
break;
case 0xcb:
+ case 0x4b:
kbd_put_keysym(QEMU_KEY_LEFT);
break;
case 0xcd:
+ case 0x4d:
kbd_put_keysym(QEMU_KEY_RIGHT);
break;
case 0xd3:
+ case 0x53:
kbd_put_keysym(QEMU_KEY_DELETE);
break;
case 0xc7:
+ case 0x47:
kbd_put_keysym(QEMU_KEY_HOME);
break;
case 0xcf:
+ case 0x4f:
kbd_put_keysym(QEMU_KEY_END);
break;
case 0xc9:
+ case 0x49:
kbd_put_keysym(QEMU_KEY_PAGEUP);
break;
case 0xd1:
+ case 0x51:
kbd_put_keysym(QEMU_KEY_PAGEDOWN);
break;
default:
@@ -1415,8 +1422,8 @@ static void framebuffer_update_request(VncState *vs, int incremental,
int i;
vs->need_update = 1;
- vs->force_update = 1;
if (!incremental) {
+ vs->force_update = 1;
for (i = 0; i < h; i++) {
vnc_set_bits(vs->guest.dirty[y_position + i],
(ds_get_width(vs->ds) / 16), VNC_DIRTY_WORDS);