Compare commits
84
Commits
v8.2.7
...
stable-1.4
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
89400a80f5 | ||
|
|
e85b521519 | ||
|
|
f890185392 | ||
|
|
745f6c0ef7 | ||
|
|
0182df5ae5 | ||
|
|
7f28f0f1f6 | ||
|
|
45bbe1fa89 | ||
|
|
06efdc4f4d | ||
|
|
0c70b5ad59 | ||
|
|
b90fd157f7 | ||
|
|
7322cb17fa | ||
|
|
1d7723ffc7 | ||
|
|
67b460a404 | ||
|
|
84247bbe28 | ||
|
|
2ebcc590c9 | ||
|
|
69001b3145 | ||
|
|
3accab7365 | ||
|
|
60259539ee | ||
|
|
93399d0827 | ||
|
|
074dd56a01 | ||
|
|
d10d2510b9 | ||
|
|
5613bda4ac | ||
|
|
c5675a98bb | ||
|
|
e355efd962 | ||
|
|
4d7f4556fc | ||
|
|
0486c27a36 | ||
|
|
57105f7480 | ||
|
|
6e8865313f | ||
|
|
6d0b135a98 | ||
|
|
d89f9ba43b | ||
|
|
46f9071a23 | ||
|
|
f85e082a36 | ||
|
|
da78a1bc7a | ||
|
|
2b92aa36d1 | ||
|
|
e4cce2d3e9 | ||
|
|
d15b1aa30c | ||
|
|
65fe29ec00 | ||
|
|
888e036eb4 | ||
|
|
d019dd928c | ||
|
|
dac077f0e6 | ||
|
|
b09a673164 | ||
|
|
79a4dd4085 | ||
|
|
57e929c19c | ||
|
|
27c71355fb | ||
|
|
283b7de6a5 | ||
|
|
a1cb89f3fe | ||
|
|
68f9df5990 | ||
|
|
0135796271 | ||
|
|
799a34a48b | ||
|
|
8378910554 | ||
|
|
7a238b9fbd | ||
|
|
02493ee490 | ||
|
|
7d47b243d6 | ||
|
|
02ea844746 | ||
|
|
0fcf00b55c | ||
|
|
5610ef5863 | ||
|
|
7a687aed28 | ||
|
|
b91aee5810 | ||
|
|
e09b99b54f | ||
|
|
611c7f2c3a | ||
|
|
4e4566ce78 | ||
|
|
43e00611bc | ||
|
|
3c3de7c6b4 | ||
|
|
b0da310a69 | ||
|
|
d26efd2d39 | ||
|
|
f305d504ab | ||
|
|
d3652a1b28 | ||
|
|
51943504d5 | ||
|
|
4d1cdb9efd | ||
|
|
c3b81e01b8 | ||
|
|
99b1f39bd2 | ||
|
|
f23ab037c7 | ||
|
|
0c918dd600 | ||
|
|
a8b090ef08 | ||
|
|
4a38944326 | ||
|
|
b7ff1a7a00 | ||
|
|
d49fed4c55 | ||
|
|
cebb8ebe41 | ||
|
|
3b39a11cde | ||
|
|
ec9f828341 | ||
|
|
332e93417a | ||
|
|
e6b795f34e | ||
|
|
51968b8503 | ||
|
|
80d8b5da48 |
+1
-10
@@ -16,16 +16,7 @@ block-obj-y += qapi-types.o qapi-visit.o
|
||||
|
||||
block-obj-y += qemu-coroutine.o qemu-coroutine-lock.o qemu-coroutine-io.o
|
||||
block-obj-y += qemu-coroutine-sleep.o
|
||||
ifeq ($(CONFIG_UCONTEXT_COROUTINE),y)
|
||||
block-obj-$(CONFIG_POSIX) += coroutine-ucontext.o
|
||||
else
|
||||
ifeq ($(CONFIG_SIGALTSTACK_COROUTINE),y)
|
||||
block-obj-$(CONFIG_POSIX) += coroutine-sigaltstack.o
|
||||
else
|
||||
block-obj-$(CONFIG_POSIX) += coroutine-gthread.o
|
||||
endif
|
||||
endif
|
||||
block-obj-$(CONFIG_WIN32) += coroutine-win32.o
|
||||
block-obj-y += coroutine-$(CONFIG_COROUTINE_BACKEND).o
|
||||
|
||||
ifeq ($(CONFIG_VIRTIO)$(CONFIG_VIRTFS)$(CONFIG_PCI),yyy)
|
||||
# Lots of the fsdev/9pcode is pulled in by vl.c via qemu_fsdev_add.
|
||||
|
||||
@@ -41,6 +41,9 @@ static void entropy_available(void *opaque)
|
||||
ssize_t len;
|
||||
|
||||
len = read(s->fd, buffer, s->size);
|
||||
if (len < 0 && errno == EAGAIN) {
|
||||
return;
|
||||
}
|
||||
g_assert(len != -1);
|
||||
|
||||
s->receive_func(s->opaque, buffer, len);
|
||||
|
||||
+2
-2
@@ -274,7 +274,7 @@ static int nbd_co_send_request(BDRVNBDState *s, struct nbd_request *request,
|
||||
ret = qemu_co_sendv(s->sock, qiov->iov, qiov->niov,
|
||||
offset, request->len);
|
||||
if (ret != request->len) {
|
||||
return -EIO;
|
||||
rc = -EIO;
|
||||
}
|
||||
}
|
||||
qemu_aio_set_fd_handler(s->sock, nbd_reply_ready, NULL,
|
||||
@@ -350,7 +350,7 @@ static int nbd_establish_connection(BlockDriverState *bs)
|
||||
|
||||
/* Now that we're connected, set the socket to be non-blocking and
|
||||
* kick the reply mechanism. */
|
||||
socket_set_nonblock(sock);
|
||||
qemu_set_nonblock(sock);
|
||||
qemu_aio_set_fd_handler(sock, nbd_reply_ready, NULL,
|
||||
nbd_have_request, s);
|
||||
|
||||
|
||||
@@ -454,6 +454,9 @@ int qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset,
|
||||
*cluster_offset &= L2E_COMPRESSED_OFFSET_SIZE_MASK;
|
||||
break;
|
||||
case QCOW2_CLUSTER_ZERO:
|
||||
if (s->qcow_version < 3) {
|
||||
return -EIO;
|
||||
}
|
||||
c = count_contiguous_clusters(nb_clusters, s->cluster_size,
|
||||
&l2_table[l2_index], 0,
|
||||
QCOW_OFLAG_COMPRESSED | QCOW_OFLAG_ZERO);
|
||||
|
||||
@@ -201,7 +201,10 @@ static int alloc_refcount_block(BlockDriverState *bs,
|
||||
*refcount_block = NULL;
|
||||
|
||||
/* We write to the refcount table, so we might depend on L2 tables */
|
||||
qcow2_cache_flush(bs, s->l2_table_cache);
|
||||
ret = qcow2_cache_flush(bs, s->l2_table_cache);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Allocate the refcount block itself and mark it as used */
|
||||
int64_t new_block = alloc_clusters_noref(bs, s->cluster_size);
|
||||
@@ -237,7 +240,10 @@ static int alloc_refcount_block(BlockDriverState *bs,
|
||||
goto fail_block;
|
||||
}
|
||||
|
||||
bdrv_flush(bs->file);
|
||||
ret = qcow2_cache_flush(bs, s->refcount_block_cache);
|
||||
if (ret < 0) {
|
||||
goto fail_block;
|
||||
}
|
||||
|
||||
/* Initialize the new refcount block only after updating its refcount,
|
||||
* update_refcount uses the refcount cache itself */
|
||||
|
||||
@@ -180,11 +180,14 @@ static int qcow2_write_snapshots(BlockDriverState *bs)
|
||||
|
||||
/* Allocate space for the new snapshot list */
|
||||
snapshots_offset = qcow2_alloc_clusters(bs, snapshots_size);
|
||||
bdrv_flush(bs->file);
|
||||
offset = snapshots_offset;
|
||||
if (offset < 0) {
|
||||
return offset;
|
||||
}
|
||||
ret = bdrv_flush(bs);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Write all snapshots to the new list */
|
||||
for(i = 0; i < s->nb_snapshots; i++) {
|
||||
|
||||
+1
-5
@@ -584,7 +584,7 @@ static int coroutine_fn qcow2_co_is_allocated(BlockDriverState *bs,
|
||||
*pnum = 0;
|
||||
}
|
||||
|
||||
return (cluster_offset != 0);
|
||||
return (cluster_offset != 0) || (ret == QCOW2_CLUSTER_ZERO);
|
||||
}
|
||||
|
||||
/* handle reading after the end of the backing file */
|
||||
@@ -665,10 +665,6 @@ static coroutine_fn int qcow2_co_readv(BlockDriverState *bs, int64_t sector_num,
|
||||
break;
|
||||
|
||||
case QCOW2_CLUSTER_ZERO:
|
||||
if (s->qcow_version < 3) {
|
||||
ret = -EIO;
|
||||
goto fail;
|
||||
}
|
||||
qemu_iovec_memset(&hd_qiov, 0, 0, 512 * cur_nr_sectors);
|
||||
break;
|
||||
|
||||
|
||||
+33
-4
@@ -63,7 +63,8 @@
|
||||
typedef enum {
|
||||
RBD_AIO_READ,
|
||||
RBD_AIO_WRITE,
|
||||
RBD_AIO_DISCARD
|
||||
RBD_AIO_DISCARD,
|
||||
RBD_AIO_FLUSH
|
||||
} RBDAIOCmd;
|
||||
|
||||
typedef struct RBDAIOCB {
|
||||
@@ -379,8 +380,7 @@ static void qemu_rbd_complete_aio(RADOSCB *rcb)
|
||||
|
||||
r = rcb->ret;
|
||||
|
||||
if (acb->cmd == RBD_AIO_WRITE ||
|
||||
acb->cmd == RBD_AIO_DISCARD) {
|
||||
if (acb->cmd != RBD_AIO_READ) {
|
||||
if (r < 0) {
|
||||
acb->ret = r;
|
||||
acb->error = 1;
|
||||
@@ -658,6 +658,16 @@ static int rbd_aio_discard_wrapper(rbd_image_t image,
|
||||
#endif
|
||||
}
|
||||
|
||||
static int rbd_aio_flush_wrapper(rbd_image_t image,
|
||||
rbd_completion_t comp)
|
||||
{
|
||||
#ifdef LIBRBD_SUPPORTS_AIO_FLUSH
|
||||
return rbd_aio_flush(image, comp);
|
||||
#else
|
||||
return -ENOTSUP;
|
||||
#endif
|
||||
}
|
||||
|
||||
static BlockDriverAIOCB *rbd_start_aio(BlockDriverState *bs,
|
||||
int64_t sector_num,
|
||||
QEMUIOVector *qiov,
|
||||
@@ -678,7 +688,7 @@ static BlockDriverAIOCB *rbd_start_aio(BlockDriverState *bs,
|
||||
acb = qemu_aio_get(&rbd_aiocb_info, bs, cb, opaque);
|
||||
acb->cmd = cmd;
|
||||
acb->qiov = qiov;
|
||||
if (cmd == RBD_AIO_DISCARD) {
|
||||
if (cmd == RBD_AIO_DISCARD || cmd == RBD_AIO_FLUSH) {
|
||||
acb->bounce = NULL;
|
||||
} else {
|
||||
acb->bounce = qemu_blockalign(bs, qiov->size);
|
||||
@@ -722,6 +732,9 @@ static BlockDriverAIOCB *rbd_start_aio(BlockDriverState *bs,
|
||||
case RBD_AIO_DISCARD:
|
||||
r = rbd_aio_discard_wrapper(s->image, off, size, c);
|
||||
break;
|
||||
case RBD_AIO_FLUSH:
|
||||
r = rbd_aio_flush_wrapper(s->image, c);
|
||||
break;
|
||||
default:
|
||||
r = -EINVAL;
|
||||
}
|
||||
@@ -761,6 +774,16 @@ static BlockDriverAIOCB *qemu_rbd_aio_writev(BlockDriverState *bs,
|
||||
RBD_AIO_WRITE);
|
||||
}
|
||||
|
||||
#ifdef LIBRBD_SUPPORTS_AIO_FLUSH
|
||||
static BlockDriverAIOCB *qemu_rbd_aio_flush(BlockDriverState *bs,
|
||||
BlockDriverCompletionFunc *cb,
|
||||
void *opaque)
|
||||
{
|
||||
return rbd_start_aio(bs, 0, NULL, 0, cb, opaque, RBD_AIO_FLUSH);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static int qemu_rbd_co_flush(BlockDriverState *bs)
|
||||
{
|
||||
#if LIBRBD_VERSION_CODE >= LIBRBD_VERSION(0, 1, 1)
|
||||
@@ -771,6 +794,7 @@ static int qemu_rbd_co_flush(BlockDriverState *bs)
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
static int qemu_rbd_getinfo(BlockDriverState *bs, BlockDriverInfo *bdi)
|
||||
{
|
||||
@@ -948,7 +972,12 @@ static BlockDriver bdrv_rbd = {
|
||||
|
||||
.bdrv_aio_readv = qemu_rbd_aio_readv,
|
||||
.bdrv_aio_writev = qemu_rbd_aio_writev,
|
||||
|
||||
#ifdef LIBRBD_SUPPORTS_AIO_FLUSH
|
||||
.bdrv_aio_flush = qemu_rbd_aio_flush,
|
||||
#else
|
||||
.bdrv_co_flush_to_disk = qemu_rbd_co_flush,
|
||||
#endif
|
||||
|
||||
#ifdef LIBRBD_SUPPORTS_DISCARD
|
||||
.bdrv_aio_discard = qemu_rbd_aio_discard,
|
||||
|
||||
+3
-3
@@ -549,7 +549,7 @@ static coroutine_fn void do_co_req(void *opaque)
|
||||
co = qemu_coroutine_self();
|
||||
qemu_aio_set_fd_handler(sockfd, NULL, restart_co_req, NULL, co);
|
||||
|
||||
socket_set_block(sockfd);
|
||||
qemu_set_block(sockfd);
|
||||
ret = send_co_req(sockfd, hdr, data, wlen);
|
||||
if (ret < 0) {
|
||||
goto out;
|
||||
@@ -579,7 +579,7 @@ static coroutine_fn void do_co_req(void *opaque)
|
||||
ret = 0;
|
||||
out:
|
||||
qemu_aio_set_fd_handler(sockfd, NULL, NULL, NULL, NULL);
|
||||
socket_set_nonblock(sockfd);
|
||||
qemu_set_nonblock(sockfd);
|
||||
|
||||
srco->ret = ret;
|
||||
srco->finished = true;
|
||||
@@ -812,7 +812,7 @@ static int get_sheep_fd(BDRVSheepdogState *s)
|
||||
return fd;
|
||||
}
|
||||
|
||||
socket_set_nonblock(fd);
|
||||
qemu_set_nonblock(fd);
|
||||
|
||||
ret = set_nodelay(fd);
|
||||
if (ret) {
|
||||
|
||||
@@ -1043,6 +1043,9 @@ void qmp_block_resize(const char *device, int64_t size, Error **errp)
|
||||
return;
|
||||
}
|
||||
|
||||
/* complete all in-flight operations before resizing the device */
|
||||
bdrv_drain_all();
|
||||
|
||||
switch (bdrv_truncate(bs, size)) {
|
||||
case 0:
|
||||
break;
|
||||
|
||||
@@ -1435,6 +1435,7 @@ fi
|
||||
if test "$seccomp" != "no" ; then
|
||||
if $pkg_config --atleast-version=1.0.0 libseccomp --modversion >/dev/null 2>&1; then
|
||||
libs_softmmu="$libs_softmmu `$pkg_config --libs libseccomp`"
|
||||
QEMU_CFLAGS="$QEMU_CFLAGS `$pkg_config --cflags libseccomp`"
|
||||
seccomp="yes"
|
||||
else
|
||||
if test "$seccomp" = "yes"; then
|
||||
@@ -2759,7 +2760,13 @@ if test "$libiscsi" != "no" ; then
|
||||
#include <iscsi/iscsi.h>
|
||||
int main(void) { iscsi_unmap_sync(NULL,0,0,0,NULL,0); return 0; }
|
||||
EOF
|
||||
if compile_prog "" "-liscsi" ; then
|
||||
if $pkg_config --atleast-version=1.7.0 libiscsi --modversion >/dev/null 2>&1; then
|
||||
libiscsi="yes"
|
||||
libiscsi_cflags=$($pkg_config --cflags libiscsi 2>/dev/null)
|
||||
libiscsi_libs=$($pkg_config --libs libiscsi 2>/dev/null)
|
||||
CFLAGS="$CFLAGS $libiscsi_cflags"
|
||||
LIBS="$LIBS $libiscsi_libs"
|
||||
elif compile_prog "" "-liscsi" ; then
|
||||
libiscsi="yes"
|
||||
LIBS="$LIBS -liscsi"
|
||||
else
|
||||
@@ -2827,7 +2834,7 @@ EOF
|
||||
spice_cflags=$($pkg_config --cflags spice-protocol spice-server 2>/dev/null)
|
||||
spice_libs=$($pkg_config --libs spice-protocol spice-server 2>/dev/null)
|
||||
if $pkg_config --atleast-version=0.12.0 spice-server >/dev/null 2>&1 && \
|
||||
$pkg_config --atleast-version=0.12.2 spice-protocol > /dev/null 2>&1 && \
|
||||
$pkg_config --atleast-version=0.12.3 spice-protocol > /dev/null 2>&1 && \
|
||||
compile_prog "$spice_cflags" "$spice_libs" ; then
|
||||
spice="yes"
|
||||
libs_softmmu="$libs_softmmu $spice_libs"
|
||||
@@ -3029,34 +3036,67 @@ fi
|
||||
##########################################
|
||||
# check and set a backend for coroutine
|
||||
|
||||
# default is ucontext, but always fallback to gthread
|
||||
# windows autodetected by make
|
||||
if test "$coroutine" = "" -o "$coroutine" = "ucontext"; then
|
||||
if test "$darwin" != "yes"; then
|
||||
cat > $TMPC << EOF
|
||||
# We prefer ucontext, but it's not always possible. The fallback
|
||||
# is sigcontext. gthread is not selectable except explicitly, because
|
||||
# it is not functional enough to run QEMU proper. (It is occasionally
|
||||
# useful for debugging purposes.) On Windows the only valid backend
|
||||
# is the Windows-specific one.
|
||||
|
||||
ucontext_works=no
|
||||
if test "$darwin" != "yes"; then
|
||||
cat > $TMPC << EOF
|
||||
#include <ucontext.h>
|
||||
#ifdef __stub_makecontext
|
||||
#error Ignoring glibc stub makecontext which will always fail
|
||||
#endif
|
||||
int main(void) { makecontext(0, 0, 0); return 0; }
|
||||
EOF
|
||||
if compile_prog "" "" ; then
|
||||
coroutine_backend=ucontext
|
||||
else
|
||||
coroutine_backend=gthread
|
||||
fi
|
||||
if compile_prog "" "" ; then
|
||||
ucontext_works=yes
|
||||
fi
|
||||
fi
|
||||
|
||||
if test "$coroutine" = ""; then
|
||||
if test "$mingw32" = "yes"; then
|
||||
coroutine=win32
|
||||
elif test "$ucontext_works" = "yes"; then
|
||||
coroutine=ucontext
|
||||
else
|
||||
coroutine=sigaltstack
|
||||
fi
|
||||
elif test "$coroutine" = "gthread" ; then
|
||||
coroutine_backend=gthread
|
||||
elif test "$coroutine" = "windows" ; then
|
||||
coroutine_backend=windows
|
||||
elif test "$coroutine" = "sigaltstack" ; then
|
||||
coroutine_backend=sigaltstack
|
||||
else
|
||||
echo
|
||||
echo "Error: unknown coroutine backend $coroutine"
|
||||
echo
|
||||
exit 1
|
||||
case $coroutine in
|
||||
windows)
|
||||
if test "$mingw32" != "yes"; then
|
||||
echo
|
||||
echo "Error: 'windows' coroutine backend only valid for Windows"
|
||||
echo
|
||||
exit 1
|
||||
fi
|
||||
# Unfortunately the user visible backend name doesn't match the
|
||||
# coroutine-*.c filename for this case, so we have to adjust it here.
|
||||
coroutine=win32
|
||||
;;
|
||||
ucontext)
|
||||
if test "$ucontext_works" != "yes"; then
|
||||
feature_not_found "ucontext"
|
||||
fi
|
||||
;;
|
||||
gthread|sigaltstack)
|
||||
if test "$mingw32" = "yes"; then
|
||||
echo
|
||||
echo "Error: only the 'windows' coroutine backend is valid for Windows"
|
||||
echo
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
echo
|
||||
echo "Error: unknown coroutine backend $coroutine"
|
||||
echo
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
|
||||
##########################################
|
||||
@@ -3339,7 +3379,7 @@ echo "OpenGL support $opengl"
|
||||
echo "libiscsi support $libiscsi"
|
||||
echo "build guest agent $guest_agent"
|
||||
echo "seccomp support $seccomp"
|
||||
echo "coroutine backend $coroutine_backend"
|
||||
echo "coroutine backend $coroutine"
|
||||
echo "GlusterFS support $glusterfs"
|
||||
echo "virtio-blk-data-plane $virtio_blk_data_plane"
|
||||
echo "gcov $gcov_tool"
|
||||
@@ -3662,11 +3702,7 @@ if test "$rbd" = "yes" ; then
|
||||
echo "CONFIG_RBD=y" >> $config_host_mak
|
||||
fi
|
||||
|
||||
if test "$coroutine_backend" = "ucontext" ; then
|
||||
echo "CONFIG_UCONTEXT_COROUTINE=y" >> $config_host_mak
|
||||
elif test "$coroutine_backend" = "sigaltstack" ; then
|
||||
echo "CONFIG_SIGALTSTACK_COROUTINE=y" >> $config_host_mak
|
||||
fi
|
||||
echo "CONFIG_COROUTINE_BACKEND=$coroutine" >> $config_host_mak
|
||||
|
||||
if test "$open_by_handle_at" = "yes" ; then
|
||||
echo "CONFIG_OPEN_BY_HANDLE=y" >> $config_host_mak
|
||||
|
||||
+44
-14
@@ -51,12 +51,32 @@ void cpu_resume_from_signal(CPUArchState *env, void *puc)
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Execute a TB, and fix up the CPU state afterwards if necessary */
|
||||
static inline tcg_target_ulong cpu_tb_exec(CPUArchState *env, uint8_t *tb_ptr)
|
||||
{
|
||||
tcg_target_ulong next_tb = tcg_qemu_tb_exec(env, tb_ptr);
|
||||
if ((next_tb & TB_EXIT_MASK) > TB_EXIT_IDX1) {
|
||||
/* We didn't start executing this TB (eg because the instruction
|
||||
* counter hit zero); we must restore the guest PC to the address
|
||||
* of the start of the TB.
|
||||
*/
|
||||
TranslationBlock *tb = (TranslationBlock *)(next_tb & ~TB_EXIT_MASK);
|
||||
cpu_pc_from_tb(env, tb);
|
||||
}
|
||||
if ((next_tb & TB_EXIT_MASK) == TB_EXIT_REQUESTED) {
|
||||
/* We were asked to stop executing TBs (probably a pending
|
||||
* interrupt. We've now stopped, so clear the flag.
|
||||
*/
|
||||
env->tcg_exit_req = 0;
|
||||
}
|
||||
return next_tb;
|
||||
}
|
||||
|
||||
/* Execute the code without caching the generated code. An interpreter
|
||||
could be used if available. */
|
||||
static void cpu_exec_nocache(CPUArchState *env, int max_cycles,
|
||||
TranslationBlock *orig_tb)
|
||||
{
|
||||
tcg_target_ulong next_tb;
|
||||
TranslationBlock *tb;
|
||||
|
||||
/* Should never happen.
|
||||
@@ -68,14 +88,8 @@ static void cpu_exec_nocache(CPUArchState *env, int max_cycles,
|
||||
max_cycles);
|
||||
env->current_tb = tb;
|
||||
/* execute the generated code */
|
||||
next_tb = tcg_qemu_tb_exec(env, tb->tc_ptr);
|
||||
cpu_tb_exec(env, tb->tc_ptr);
|
||||
env->current_tb = NULL;
|
||||
|
||||
if ((next_tb & 3) == 2) {
|
||||
/* Restore PC. This may happen if async event occurs before
|
||||
the TB starts executing. */
|
||||
cpu_pc_from_tb(env, tb);
|
||||
}
|
||||
tb_phys_invalidate(tb, -1);
|
||||
tb_free(tb);
|
||||
}
|
||||
@@ -583,7 +597,8 @@ int cpu_exec(CPUArchState *env)
|
||||
spans two pages, we cannot safely do a direct
|
||||
jump. */
|
||||
if (next_tb != 0 && tb->page_addr[1] == -1) {
|
||||
tb_add_jump((TranslationBlock *)(next_tb & ~3), next_tb & 3, tb);
|
||||
tb_add_jump((TranslationBlock *)(next_tb & ~TB_EXIT_MASK),
|
||||
next_tb & TB_EXIT_MASK, tb);
|
||||
}
|
||||
spin_unlock(&tb_lock);
|
||||
|
||||
@@ -596,13 +611,24 @@ int cpu_exec(CPUArchState *env)
|
||||
if (likely(!env->exit_request)) {
|
||||
tc_ptr = tb->tc_ptr;
|
||||
/* execute the generated code */
|
||||
next_tb = tcg_qemu_tb_exec(env, tc_ptr);
|
||||
if ((next_tb & 3) == 2) {
|
||||
next_tb = cpu_tb_exec(env, tc_ptr);
|
||||
switch (next_tb & TB_EXIT_MASK) {
|
||||
case TB_EXIT_REQUESTED:
|
||||
/* Something asked us to stop executing
|
||||
* chained TBs; just continue round the main
|
||||
* loop. Whatever requested the exit will also
|
||||
* have set something else (eg exit_request or
|
||||
* interrupt_request) which we will handle
|
||||
* next time around the loop.
|
||||
*/
|
||||
tb = (TranslationBlock *)(next_tb & ~TB_EXIT_MASK);
|
||||
next_tb = 0;
|
||||
break;
|
||||
case TB_EXIT_ICOUNT_EXPIRED:
|
||||
{
|
||||
/* Instruction counter expired. */
|
||||
int insns_left;
|
||||
tb = (TranslationBlock *)(next_tb & ~3);
|
||||
/* Restore PC. */
|
||||
cpu_pc_from_tb(env, tb);
|
||||
tb = (TranslationBlock *)(next_tb & ~TB_EXIT_MASK);
|
||||
insns_left = env->icount_decr.u32;
|
||||
if (env->icount_extra && insns_left >= 0) {
|
||||
/* Refill decrementer and continue execution. */
|
||||
@@ -623,6 +649,10 @@ int cpu_exec(CPUArchState *env)
|
||||
next_tb = 0;
|
||||
cpu_loop_exit(env);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
env->current_tb = NULL;
|
||||
|
||||
@@ -493,7 +493,7 @@ void cpu_reset_interrupt(CPUArchState *env, int mask)
|
||||
void cpu_exit(CPUArchState *env)
|
||||
{
|
||||
env->exit_request = 1;
|
||||
cpu_unlink_tb(env);
|
||||
env->tcg_exit_req = 1;
|
||||
}
|
||||
|
||||
void cpu_abort(CPUArchState *env, const char *fmt, ...)
|
||||
|
||||
@@ -284,7 +284,7 @@ static ssize_t local_readlink(FsContext *fs_ctx, V9fsPath *fs_path,
|
||||
if ((fs_ctx->export_flags & V9FS_SM_MAPPED) ||
|
||||
(fs_ctx->export_flags & V9FS_SM_MAPPED_FILE)) {
|
||||
int fd;
|
||||
fd = open(rpath(fs_ctx, path, buffer), O_RDONLY);
|
||||
fd = open(rpath(fs_ctx, path, buffer), O_RDONLY | O_NOFOLLOW);
|
||||
if (fd == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
+1
-1
@@ -659,7 +659,7 @@ static mode_t v9mode_to_mode(uint32_t mode, V9fsString *extension)
|
||||
ret |= S_IFIFO;
|
||||
}
|
||||
if (mode & P9_STAT_MODE_DEVICE) {
|
||||
if (extension && extension->data[0] == 'c') {
|
||||
if (extension->size && extension->data[0] == 'c') {
|
||||
ret |= S_IFCHR;
|
||||
} else {
|
||||
ret |= S_IFBLK;
|
||||
|
||||
@@ -472,8 +472,9 @@ static const MemoryRegionOps acpi_pm_cnt_ops = {
|
||||
.endianness = DEVICE_LITTLE_ENDIAN,
|
||||
};
|
||||
|
||||
void acpi_pm1_cnt_init(ACPIREGS *ar, MemoryRegion *parent)
|
||||
void acpi_pm1_cnt_init(ACPIREGS *ar, MemoryRegion *parent, uint8_t s4_val)
|
||||
{
|
||||
ar->pm1.cnt.s4_val = s4_val;
|
||||
ar->wakeup.notify = acpi_notify_wakeup;
|
||||
qemu_register_wakeup_notifier(&ar->wakeup);
|
||||
memory_region_init_io(&ar->pm1.cnt.io, &acpi_pm_cnt_ops, ar, "acpi-cnt", 2);
|
||||
|
||||
@@ -142,7 +142,7 @@ void acpi_pm1_evt_init(ACPIREGS *ar, acpi_update_sci_fn update_sci,
|
||||
MemoryRegion *parent);
|
||||
|
||||
/* PM1a_CNT: piix and ich9 don't implement PM1b CNT. */
|
||||
void acpi_pm1_cnt_init(ACPIREGS *ar, MemoryRegion *parent);
|
||||
void acpi_pm1_cnt_init(ACPIREGS *ar, MemoryRegion *parent, uint8_t s4_val);
|
||||
void acpi_pm1_cnt_update(ACPIREGS *ar,
|
||||
bool sci_enable, bool sci_disable);
|
||||
void acpi_pm1_cnt_reset(ACPIREGS *ar);
|
||||
|
||||
+1
-1
@@ -212,7 +212,7 @@ void ich9_pm_init(PCIDevice *lpc_pci, ICH9LPCPMRegs *pm,
|
||||
|
||||
acpi_pm_tmr_init(&pm->acpi_regs, ich9_pm_update_sci_fn, &pm->io);
|
||||
acpi_pm1_evt_init(&pm->acpi_regs, ich9_pm_update_sci_fn, &pm->io);
|
||||
acpi_pm1_cnt_init(&pm->acpi_regs, &pm->io);
|
||||
acpi_pm1_cnt_init(&pm->acpi_regs, &pm->io, 2);
|
||||
|
||||
acpi_gpe_init(&pm->acpi_regs, ICH9_PMIO_GPE0_LEN);
|
||||
memory_region_init_io(&pm->io_gpe, &ich9_gpe_ops, pm, "apci-gpe0",
|
||||
|
||||
+1
-1
@@ -418,7 +418,7 @@ static int piix4_pm_initfn(PCIDevice *dev)
|
||||
|
||||
acpi_pm_tmr_init(&s->ar, pm_tmr_timer, &s->io);
|
||||
acpi_pm1_evt_init(&s->ar, pm_tmr_timer, &s->io);
|
||||
acpi_pm1_cnt_init(&s->ar, &s->io);
|
||||
acpi_pm1_cnt_init(&s->ar, &s->io, s->s4_val);
|
||||
acpi_gpe_init(&s->ar, GPE_LEN);
|
||||
|
||||
s->powerdown_notifier.notify = piix4_pm_powerdown_req;
|
||||
|
||||
+1
-1
@@ -188,7 +188,7 @@ static int macio_newworld_initfn(PCIDevice *d)
|
||||
sysbus_dev = SYS_BUS_DEVICE(&ns->ide[1]);
|
||||
sysbus_connect_irq(sysbus_dev, 0, ns->irqs[3]);
|
||||
sysbus_connect_irq(sysbus_dev, 1, ns->irqs[4]);
|
||||
macio_ide_register_dma(&ns->ide[0], s->dbdma, 0x1a);
|
||||
macio_ide_register_dma(&ns->ide[1], s->dbdma, 0x1a);
|
||||
ret = qdev_init(DEVICE(&ns->ide[1]));
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
|
||||
+1
-1
@@ -96,7 +96,7 @@ typedef struct DeviceClass {
|
||||
/* Private to qdev / bus. */
|
||||
qdev_initfn init; /* TODO remove, once users are converted to realize */
|
||||
qdev_event unplug;
|
||||
qdev_event exit;
|
||||
qdev_event exit; /* TODO remove, once users are converted to unrealize */
|
||||
const char *bus_type;
|
||||
} DeviceClass;
|
||||
|
||||
|
||||
@@ -180,6 +180,19 @@ static void device_realize(DeviceState *dev, Error **err)
|
||||
}
|
||||
}
|
||||
|
||||
static void device_unrealize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_GET_CLASS(dev);
|
||||
|
||||
if (dc->exit) {
|
||||
int rc = dc->exit(dev);
|
||||
if (rc < 0) {
|
||||
error_setg(errp, "Device exit failed.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void qdev_set_legacy_instance_id(DeviceState *dev, int alias_id,
|
||||
int required_for_version)
|
||||
{
|
||||
@@ -692,6 +705,9 @@ static void device_set_realized(Object *obj, bool value, Error **err)
|
||||
device_reset(dev);
|
||||
}
|
||||
} else if (!value && dev->realized) {
|
||||
if (qdev_get_vmsd(dev)) {
|
||||
vmstate_unregister(dev, qdev_get_vmsd(dev), dev);
|
||||
}
|
||||
if (dc->unrealize) {
|
||||
dc->unrealize(dev, &local_err);
|
||||
}
|
||||
@@ -758,7 +774,6 @@ static void device_class_base_init(ObjectClass *class, void *data)
|
||||
static void device_unparent(Object *obj)
|
||||
{
|
||||
DeviceState *dev = DEVICE(obj);
|
||||
DeviceClass *dc = DEVICE_GET_CLASS(dev);
|
||||
BusState *bus;
|
||||
|
||||
while (dev->num_child_bus) {
|
||||
@@ -766,12 +781,7 @@ static void device_unparent(Object *obj)
|
||||
qbus_free(bus);
|
||||
}
|
||||
if (dev->realized) {
|
||||
if (qdev_get_vmsd(dev)) {
|
||||
vmstate_unregister(dev, qdev_get_vmsd(dev), dev);
|
||||
}
|
||||
if (dc->exit) {
|
||||
dc->exit(dev);
|
||||
}
|
||||
object_property_set_bool(obj, false, "realized", NULL);
|
||||
}
|
||||
if (dev->parent_bus) {
|
||||
bus_remove_child(dev->parent_bus, dev);
|
||||
@@ -786,6 +796,7 @@ static void device_class_init(ObjectClass *class, void *data)
|
||||
|
||||
class->unparent = device_unparent;
|
||||
dc->realize = device_realize;
|
||||
dc->unrealize = device_unrealize;
|
||||
}
|
||||
|
||||
void device_reset(DeviceState *dev)
|
||||
|
||||
+2
-1
@@ -118,7 +118,8 @@ static void qxl_render_update_area_unlocked(PCIQXLDevice *qxl)
|
||||
qxl->guest_primary.surface.height,
|
||||
qxl->guest_primary.bits_pp,
|
||||
qxl->guest_primary.abs_stride,
|
||||
qxl->guest_primary.data);
|
||||
qxl->guest_primary.data,
|
||||
false);
|
||||
} else {
|
||||
qemu_resize_displaysurface(vga->ds,
|
||||
qxl->guest_primary.surface.width,
|
||||
|
||||
@@ -1075,8 +1075,8 @@ static void qxl_enter_vga_mode(PCIQXLDevice *d)
|
||||
trace_qxl_enter_vga_mode(d->id);
|
||||
qemu_spice_create_host_primary(&d->ssd);
|
||||
d->mode = QXL_MODE_VGA;
|
||||
dpy_gfx_resize(d->ssd.ds);
|
||||
vga_dirty_log_start(&d->vga);
|
||||
vga_hw_update();
|
||||
}
|
||||
|
||||
static void qxl_exit_vga_mode(PCIQXLDevice *d)
|
||||
|
||||
@@ -402,6 +402,7 @@ static const VirtIOBindings virtio_s390_bindings = {
|
||||
|
||||
static Property s390_virtio_net_properties[] = {
|
||||
DEFINE_NIC_PROPERTIES(VirtIOS390Device, nic),
|
||||
DEFINE_VIRTIO_NET_FEATURES(VirtIOS390Device, host_features),
|
||||
DEFINE_PROP_UINT32("x-txtimer", VirtIOS390Device,
|
||||
net.txtimer, TX_TIMER_INTERVAL),
|
||||
DEFINE_PROP_INT32("x-txburst", VirtIOS390Device,
|
||||
|
||||
@@ -31,6 +31,9 @@ static int virtio_ccw_hcall_notify(const uint64_t *args)
|
||||
if (!sch || !css_subch_visible(sch)) {
|
||||
return -EINVAL;
|
||||
}
|
||||
if (queue >= VIRTIO_PCI_QUEUE_MAX) {
|
||||
return -EINVAL;
|
||||
}
|
||||
virtio_queue_notify(virtio_ccw_get_vdev(sch), queue);
|
||||
return 0;
|
||||
|
||||
|
||||
@@ -662,10 +662,16 @@ static void virtio_ccw_notify(DeviceState *d, uint16_t vector)
|
||||
}
|
||||
|
||||
if (vector < VIRTIO_PCI_QUEUE_MAX) {
|
||||
if (!dev->indicators) {
|
||||
return;
|
||||
}
|
||||
indicators = ldq_phys(dev->indicators);
|
||||
indicators |= 1ULL << vector;
|
||||
stq_phys(dev->indicators, indicators);
|
||||
} else {
|
||||
if (!dev->indicators2) {
|
||||
return;
|
||||
}
|
||||
vector = 0;
|
||||
indicators = ldq_phys(dev->indicators2);
|
||||
indicators |= 1ULL << vector;
|
||||
|
||||
@@ -1508,6 +1508,10 @@ void scsi_req_unref(SCSIRequest *req)
|
||||
will start the next chunk or complete the command. */
|
||||
void scsi_req_continue(SCSIRequest *req)
|
||||
{
|
||||
if (req->io_canceled) {
|
||||
trace_scsi_req_continue_canceled(req->dev->id, req->lun, req->tag);
|
||||
return;
|
||||
}
|
||||
trace_scsi_req_continue(req->dev->id, req->lun, req->tag);
|
||||
if (req->cmd.mode == SCSI_XFER_TO_DEV) {
|
||||
req->ops->write_data(req);
|
||||
|
||||
+28
-8
@@ -176,6 +176,9 @@ static void scsi_aio_complete(void *opaque, int ret)
|
||||
assert(r->req.aiocb != NULL);
|
||||
r->req.aiocb = NULL;
|
||||
bdrv_acct_done(s->qdev.conf.bs, &r->acct);
|
||||
if (r->req.io_canceled) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (ret < 0) {
|
||||
if (scsi_handle_rw_error(r, -ret)) {
|
||||
@@ -221,6 +224,10 @@ static void scsi_write_do_fua(SCSIDiskReq *r)
|
||||
{
|
||||
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
|
||||
|
||||
if (r->req.io_canceled) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (scsi_is_cmd_fua(&r->req.cmd)) {
|
||||
bdrv_acct_start(s->qdev.conf.bs, &r->acct, 0, BDRV_ACCT_FLUSH);
|
||||
r->req.aiocb = bdrv_aio_flush(s->qdev.conf.bs, scsi_aio_complete, r);
|
||||
@@ -228,6 +235,8 @@ static void scsi_write_do_fua(SCSIDiskReq *r)
|
||||
}
|
||||
|
||||
scsi_req_complete(&r->req, GOOD);
|
||||
|
||||
done:
|
||||
if (!r->req.io_canceled) {
|
||||
scsi_req_unref(&r->req);
|
||||
}
|
||||
@@ -241,6 +250,9 @@ static void scsi_dma_complete(void *opaque, int ret)
|
||||
assert(r->req.aiocb != NULL);
|
||||
r->req.aiocb = NULL;
|
||||
bdrv_acct_done(s->qdev.conf.bs, &r->acct);
|
||||
if (r->req.io_canceled) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (ret < 0) {
|
||||
if (scsi_handle_rw_error(r, -ret)) {
|
||||
@@ -272,6 +284,9 @@ static void scsi_read_complete(void * opaque, int ret)
|
||||
assert(r->req.aiocb != NULL);
|
||||
r->req.aiocb = NULL;
|
||||
bdrv_acct_done(s->qdev.conf.bs, &r->acct);
|
||||
if (r->req.io_canceled) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (ret < 0) {
|
||||
if (scsi_handle_rw_error(r, -ret)) {
|
||||
@@ -303,6 +318,9 @@ static void scsi_do_read(void *opaque, int ret)
|
||||
r->req.aiocb = NULL;
|
||||
bdrv_acct_done(s->qdev.conf.bs, &r->acct);
|
||||
}
|
||||
if (r->req.io_canceled) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (ret < 0) {
|
||||
if (scsi_handle_rw_error(r, -ret)) {
|
||||
@@ -310,10 +328,6 @@ static void scsi_do_read(void *opaque, int ret)
|
||||
}
|
||||
}
|
||||
|
||||
if (r->req.io_canceled) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* The request is used as the AIO opaque value, so add a ref. */
|
||||
scsi_req_ref(&r->req);
|
||||
|
||||
@@ -421,6 +435,9 @@ static void scsi_write_complete(void * opaque, int ret)
|
||||
r->req.aiocb = NULL;
|
||||
bdrv_acct_done(s->qdev.conf.bs, &r->acct);
|
||||
}
|
||||
if (r->req.io_canceled) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (ret < 0) {
|
||||
if (scsi_handle_rw_error(r, -ret)) {
|
||||
@@ -1476,13 +1493,17 @@ static void scsi_unmap_complete(void *opaque, int ret)
|
||||
uint32_t nb_sectors;
|
||||
|
||||
r->req.aiocb = NULL;
|
||||
if (r->req.io_canceled) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (ret < 0) {
|
||||
if (scsi_handle_rw_error(r, -ret)) {
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
if (data->count > 0 && !r->req.io_canceled) {
|
||||
if (data->count > 0) {
|
||||
sector_num = ldq_be_p(&data->inbuf[0]);
|
||||
nb_sectors = ldl_be_p(&data->inbuf[8]) & 0xffffffffULL;
|
||||
if (!check_lba_range(s, sector_num, nb_sectors)) {
|
||||
@@ -1499,10 +1520,9 @@ static void scsi_unmap_complete(void *opaque, int ret)
|
||||
return;
|
||||
}
|
||||
|
||||
scsi_req_complete(&r->req, GOOD);
|
||||
|
||||
done:
|
||||
if (data->count == 0) {
|
||||
scsi_req_complete(&r->req, GOOD);
|
||||
}
|
||||
if (!r->req.io_canceled) {
|
||||
scsi_req_unref(&r->req);
|
||||
}
|
||||
|
||||
@@ -260,6 +260,7 @@ static void *spapr_create_fdt_skel(const char *cpu_model,
|
||||
_FDT((fdt_begin_node(fdt, "")));
|
||||
_FDT((fdt_property_string(fdt, "device_type", "chrp")));
|
||||
_FDT((fdt_property_string(fdt, "model", "IBM pSeries (emulated by qemu)")));
|
||||
_FDT((fdt_property_string(fdt, "compatible", "qemu,pseries")));
|
||||
|
||||
_FDT((fdt_property_cell(fdt, "#address-cells", 0x2)));
|
||||
_FDT((fdt_property_cell(fdt, "#size-cells", 0x2)));
|
||||
|
||||
@@ -175,11 +175,19 @@ static ssize_t spapr_vlan_receive(NetClientState *nc, const uint8_t *buf,
|
||||
return size;
|
||||
}
|
||||
|
||||
static void spapr_vlan_cleanup(NetClientState *nc)
|
||||
{
|
||||
VIOsPAPRVLANDevice *dev = qemu_get_nic_opaque(nc);
|
||||
|
||||
dev->nic = NULL;
|
||||
}
|
||||
|
||||
static NetClientInfo net_spapr_vlan_info = {
|
||||
.type = NET_CLIENT_OPTIONS_KIND_NIC,
|
||||
.size = sizeof(NICState),
|
||||
.can_receive = spapr_vlan_can_receive,
|
||||
.receive = spapr_vlan_receive,
|
||||
.cleanup = spapr_vlan_cleanup,
|
||||
};
|
||||
|
||||
static void spapr_vlan_reset(VIOsPAPRDevice *sdev)
|
||||
|
||||
+1
-1
@@ -236,7 +236,7 @@ static const USBDescDevice desc_device_tablet2 = {
|
||||
.bNumInterfaces = 1,
|
||||
.bConfigurationValue = 1,
|
||||
.iConfiguration = STR_CONFIG_TABLET,
|
||||
.bmAttributes = 0xa0,
|
||||
.bmAttributes = 0x80,
|
||||
.bMaxPower = 50,
|
||||
.nif = 1,
|
||||
.ifs = &desc_iface_tablet2,
|
||||
|
||||
@@ -1985,6 +1985,10 @@ static int usbredir_post_load(void *priv, int version_id)
|
||||
{
|
||||
USBRedirDevice *dev = priv;
|
||||
|
||||
if (dev->parser == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch (dev->device_info.speed) {
|
||||
case usb_redir_speed_low:
|
||||
dev->dev.speed = USB_SPEED_LOW;
|
||||
|
||||
@@ -1643,6 +1643,11 @@ static void vga_draw_graphic(VGACommonState *s, int full_update)
|
||||
uint8_t *d;
|
||||
uint32_t v, addr1, addr;
|
||||
vga_draw_line_func *vga_draw_line;
|
||||
#if defined(HOST_WORDS_BIGENDIAN) == defined(TARGET_WORDS_BIGENDIAN)
|
||||
static const bool byteswap = false;
|
||||
#else
|
||||
static const bool byteswap = true;
|
||||
#endif
|
||||
|
||||
full_update |= update_basic_params(s);
|
||||
|
||||
@@ -1685,18 +1690,11 @@ static void vga_draw_graphic(VGACommonState *s, int full_update)
|
||||
disp_width != s->last_width ||
|
||||
height != s->last_height ||
|
||||
s->last_depth != depth) {
|
||||
#if defined(HOST_WORDS_BIGENDIAN) == defined(TARGET_WORDS_BIGENDIAN)
|
||||
if (depth == 16 || depth == 32) {
|
||||
#else
|
||||
if (depth == 32) {
|
||||
#endif
|
||||
if (depth == 32 || (depth == 16 && !byteswap)) {
|
||||
qemu_free_displaysurface(s->ds);
|
||||
s->ds->surface = qemu_create_displaysurface_from(disp_width, height, depth,
|
||||
s->line_offset,
|
||||
s->vram_ptr + (s->start_addr * 4));
|
||||
#if defined(HOST_WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN)
|
||||
s->ds->surface->pf = qemu_different_endianness_pixelformat(depth);
|
||||
#endif
|
||||
s->vram_ptr + (s->start_addr * 4), byteswap);
|
||||
dpy_gfx_resize(s->ds);
|
||||
} else {
|
||||
qemu_console_resize(s->ds, disp_width, height);
|
||||
@@ -1715,7 +1713,7 @@ static void vga_draw_graphic(VGACommonState *s, int full_update)
|
||||
s->ds->surface = qemu_create_displaysurface_from(disp_width,
|
||||
height, depth,
|
||||
s->line_offset,
|
||||
s->vram_ptr + (s->start_addr * 4));
|
||||
s->vram_ptr + (s->start_addr * 4), byteswap);
|
||||
dpy_gfx_setdata(s->ds);
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -291,7 +291,7 @@ static void virtio_balloon_set_config(VirtIODevice *vdev,
|
||||
dev->actual = le32_to_cpu(config.actual);
|
||||
if (dev->actual != oldactual) {
|
||||
qemu_balloon_changed(ram_size -
|
||||
(dev->actual << VIRTIO_BALLOON_PFN_SHIFT));
|
||||
((ram_addr_t) dev->actual << VIRTIO_BALLOON_PFN_SHIFT));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+3
-1
@@ -36,6 +36,7 @@ typedef struct VirtIOBlock
|
||||
VirtIOBlkConf *blk;
|
||||
unsigned short sector_mask;
|
||||
DeviceState *qdev;
|
||||
VMChangeStateEntry *change;
|
||||
#ifdef CONFIG_VIRTIO_BLK_DATA_PLANE
|
||||
VirtIOBlockDataPlane *dataplane;
|
||||
#endif
|
||||
@@ -681,7 +682,7 @@ VirtIODevice *virtio_blk_init(DeviceState *dev, VirtIOBlkConf *blk)
|
||||
}
|
||||
#endif
|
||||
|
||||
qemu_add_vm_change_state_handler(virtio_blk_dma_restart_cb, s);
|
||||
s->change = qemu_add_vm_change_state_handler(virtio_blk_dma_restart_cb, s);
|
||||
s->qdev = dev;
|
||||
register_savevm(dev, "virtio-blk", virtio_blk_id++, 2,
|
||||
virtio_blk_save, virtio_blk_load, s);
|
||||
@@ -702,6 +703,7 @@ void virtio_blk_exit(VirtIODevice *vdev)
|
||||
virtio_blk_data_plane_destroy(s->dataplane);
|
||||
s->dataplane = NULL;
|
||||
#endif
|
||||
qemu_del_vm_change_state_handler(s->change);
|
||||
unregister_savevm(s->qdev, "virtio-blk", s);
|
||||
blockdev_mark_auto_del(s->bs);
|
||||
virtio_cleanup(vdev);
|
||||
|
||||
+4
-2
@@ -44,7 +44,7 @@ typedef struct VirtIONet
|
||||
VirtIODevice vdev;
|
||||
uint8_t mac[ETH_ALEN];
|
||||
uint16_t status;
|
||||
VirtIONetQueue vqs[MAX_QUEUE_NUM];
|
||||
VirtIONetQueue *vqs;
|
||||
VirtQueue *ctrl_vq;
|
||||
NICState *nic;
|
||||
uint32_t tx_timeout;
|
||||
@@ -1326,8 +1326,9 @@ VirtIODevice *virtio_net_init(DeviceState *dev, NICConf *conf,
|
||||
n->vdev.set_status = virtio_net_set_status;
|
||||
n->vdev.guest_notifier_mask = virtio_net_guest_notifier_mask;
|
||||
n->vdev.guest_notifier_pending = virtio_net_guest_notifier_pending;
|
||||
n->max_queues = MAX(conf->queues, 1);
|
||||
n->vqs = g_malloc0(sizeof(VirtIONetQueue) * n->max_queues);
|
||||
n->vqs[0].rx_vq = virtio_add_queue(&n->vdev, 256, virtio_net_handle_rx);
|
||||
n->max_queues = conf->queues;
|
||||
n->curr_queues = 1;
|
||||
n->vqs[0].n = n;
|
||||
n->tx_timeout = net->txtimer;
|
||||
@@ -1412,6 +1413,7 @@ void virtio_net_exit(VirtIODevice *vdev)
|
||||
}
|
||||
}
|
||||
|
||||
g_free(n->vqs);
|
||||
qemu_del_nic(n->nic);
|
||||
virtio_cleanup(&n->vdev);
|
||||
}
|
||||
|
||||
+1
-1
@@ -1074,7 +1074,7 @@ static void vmsvga_screen_dump(void *opaque, const char *filename, bool cswitch,
|
||||
ds_get_height(s->vga.ds),
|
||||
32,
|
||||
ds_get_linesize(s->vga.ds),
|
||||
s->vga.vram_ptr);
|
||||
s->vga.vram_ptr, false);
|
||||
ppm_save(filename, ds, errp);
|
||||
g_free(ds);
|
||||
}
|
||||
|
||||
+1
-1
@@ -362,7 +362,7 @@ static int vt82c686b_pm_initfn(PCIDevice *dev)
|
||||
|
||||
acpi_pm_tmr_init(&s->ar, pm_tmr_timer, &s->io);
|
||||
acpi_pm1_evt_init(&s->ar, pm_tmr_timer, &s->io);
|
||||
acpi_pm1_cnt_init(&s->ar, &s->io);
|
||||
acpi_pm1_cnt_init(&s->ar, &s->io, 2);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
+2
-1
@@ -756,7 +756,8 @@ static void xenfb_update(void *opaque)
|
||||
qemu_free_displaysurface(xenfb->c.ds);
|
||||
xenfb->c.ds->surface = qemu_create_displaysurface_from
|
||||
(xenfb->width, xenfb->height, xenfb->depth,
|
||||
xenfb->row_stride, xenfb->pixels + xenfb->offset);
|
||||
xenfb->row_stride, xenfb->pixels + xenfb->offset,
|
||||
false);
|
||||
break;
|
||||
default:
|
||||
/* we must convert stuff */
|
||||
|
||||
@@ -161,6 +161,7 @@ typedef struct CPUWatchpoint {
|
||||
uint32_t halted; /* Nonzero if the CPU is in suspend state */ \
|
||||
uint32_t interrupt_request; \
|
||||
volatile sig_atomic_t exit_request; \
|
||||
volatile sig_atomic_t tcg_exit_req; \
|
||||
CPU_COMMON_TLB \
|
||||
struct TranslationBlock *tb_jmp_cache[TB_JMP_CACHE_SIZE]; \
|
||||
/* buffer for temporaries in the code generator */ \
|
||||
|
||||
@@ -7,10 +7,18 @@
|
||||
|
||||
static TCGArg *icount_arg;
|
||||
static int icount_label;
|
||||
static int exitreq_label;
|
||||
|
||||
static inline void gen_icount_start(void)
|
||||
{
|
||||
TCGv_i32 count;
|
||||
TCGv_i32 flag;
|
||||
|
||||
exitreq_label = gen_new_label();
|
||||
flag = tcg_temp_local_new_i32();
|
||||
tcg_gen_ld_i32(flag, cpu_env, offsetof(CPUArchState, tcg_exit_req));
|
||||
tcg_gen_brcondi_i32(TCG_COND_NE, flag, 0, exitreq_label);
|
||||
tcg_temp_free_i32(flag);
|
||||
|
||||
if (!use_icount)
|
||||
return;
|
||||
@@ -29,10 +37,13 @@ static inline void gen_icount_start(void)
|
||||
|
||||
static void gen_icount_end(TranslationBlock *tb, int num_insns)
|
||||
{
|
||||
gen_set_label(exitreq_label);
|
||||
tcg_gen_exit_tb((tcg_target_long)tb + TB_EXIT_REQUESTED);
|
||||
|
||||
if (use_icount) {
|
||||
*icount_arg = num_insns;
|
||||
gen_set_label(icount_label);
|
||||
tcg_gen_exit_tb((tcg_target_long)tb + 2);
|
||||
tcg_gen_exit_tb((tcg_target_long)tb + TB_EXIT_ICOUNT_EXPIRED);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -72,7 +72,7 @@ struct NetClientState {
|
||||
};
|
||||
|
||||
typedef struct NICState {
|
||||
NetClientState ncs[MAX_QUEUE_NUM];
|
||||
NetClientState *ncs;
|
||||
NICConf *conf;
|
||||
void *opaque;
|
||||
bool peer_deleted;
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
#define cat(x,y) x ## y
|
||||
#define cat2(x,y) cat(x,y)
|
||||
#define QEMU_BUILD_BUG_ON(x) \
|
||||
typedef char cat2(qemu_build_bug_on__,__LINE__)[(x)?-1:1];
|
||||
typedef char cat2(qemu_build_bug_on__,__LINE__)[(x)?-1:1] __attribute__((unused));
|
||||
|
||||
#if defined __GNUC__
|
||||
# if !QEMU_GNUC_PREREQ(4, 4)
|
||||
|
||||
@@ -34,8 +34,8 @@ int inet_aton(const char *cp, struct in_addr *ia);
|
||||
int qemu_socket(int domain, int type, int protocol);
|
||||
int qemu_accept(int s, struct sockaddr *addr, socklen_t *addrlen);
|
||||
int socket_set_cork(int fd, int v);
|
||||
void socket_set_block(int fd);
|
||||
void socket_set_nonblock(int fd);
|
||||
void qemu_set_block(int fd);
|
||||
void qemu_set_nonblock(int fd);
|
||||
int send_all(int fd, const void *buf, int len1);
|
||||
|
||||
/* callback function for nonblocking connect
|
||||
|
||||
@@ -117,8 +117,7 @@ extern int use_rt_clock;
|
||||
|
||||
static inline int64_t get_clock(void)
|
||||
{
|
||||
#if defined(__linux__) || (defined(__FreeBSD__) && __FreeBSD_version >= 500000) \
|
||||
|| defined(__DragonFly__) || defined(__FreeBSD_kernel__)
|
||||
#ifdef CLOCK_MONOTONIC
|
||||
if (use_rt_clock) {
|
||||
struct timespec ts;
|
||||
clock_gettime(CLOCK_MONOTONIC, &ts);
|
||||
|
||||
@@ -184,7 +184,8 @@ struct DisplayState {
|
||||
void register_displaystate(DisplayState *ds);
|
||||
DisplayState *get_displaystate(void);
|
||||
DisplaySurface* qemu_create_displaysurface_from(int width, int height, int bpp,
|
||||
int linesize, uint8_t *data);
|
||||
int linesize, uint8_t *data,
|
||||
bool byteswap);
|
||||
PixelFormat qemu_different_endianness_pixelformat(int bpp);
|
||||
PixelFormat qemu_default_pixelformat(int bpp);
|
||||
|
||||
|
||||
@@ -1436,6 +1436,12 @@ if( cmd == val ) { \
|
||||
gemu_log("FUTEX_PRIVATE_FLAG|");
|
||||
cmd &= ~FUTEX_PRIVATE_FLAG;
|
||||
}
|
||||
#endif
|
||||
#ifdef FUTEX_CLOCK_REALTIME
|
||||
if (cmd & FUTEX_CLOCK_REALTIME) {
|
||||
gemu_log("FUTEX_CLOCK_REALTIME|");
|
||||
cmd &= ~FUTEX_CLOCK_REALTIME;
|
||||
}
|
||||
#endif
|
||||
print_op(FUTEX_WAIT)
|
||||
print_op(FUTEX_WAKE)
|
||||
|
||||
+17
-3
@@ -1776,7 +1776,7 @@ static struct iovec *lock_iovec(int type, abi_ulong target_addr,
|
||||
errno = 0;
|
||||
return NULL;
|
||||
}
|
||||
if (count > IOV_MAX) {
|
||||
if (count < 0 || count > IOV_MAX) {
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
@@ -4920,6 +4920,7 @@ static int do_futex(target_ulong uaddr, int op, int val, target_ulong timeout,
|
||||
#endif
|
||||
switch (base_op) {
|
||||
case FUTEX_WAIT:
|
||||
case FUTEX_WAIT_BITSET:
|
||||
if (timeout) {
|
||||
pts = &ts;
|
||||
target_to_host_timespec(pts, timeout);
|
||||
@@ -4927,7 +4928,7 @@ static int do_futex(target_ulong uaddr, int op, int val, target_ulong timeout,
|
||||
pts = NULL;
|
||||
}
|
||||
return get_errno(sys_futex(g2h(uaddr), op, tswap32(val),
|
||||
pts, NULL, 0));
|
||||
pts, NULL, val3));
|
||||
case FUTEX_WAKE:
|
||||
return get_errno(sys_futex(g2h(uaddr), op, val, NULL, NULL, 0));
|
||||
case FUTEX_FD:
|
||||
@@ -8550,7 +8551,20 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
|
||||
|
||||
#ifdef TARGET_NR_set_robust_list
|
||||
case TARGET_NR_set_robust_list:
|
||||
goto unimplemented_nowarn;
|
||||
case TARGET_NR_get_robust_list:
|
||||
/* The ABI for supporting robust futexes has userspace pass
|
||||
* the kernel a pointer to a linked list which is updated by
|
||||
* userspace after the syscall; the list is walked by the kernel
|
||||
* when the thread exits. Since the linked list in QEMU guest
|
||||
* memory isn't a valid linked list for the host and we have
|
||||
* no way to reliably intercept the thread-death event, we can't
|
||||
* support these. Silently return ENOSYS so that guest userspace
|
||||
* falls back to a non-robust futex implementation (which should
|
||||
* be OK except in the corner case of the guest crashing while
|
||||
* holding a mutex that is shared with another process via
|
||||
* shared memory).
|
||||
*/
|
||||
goto unimplemented_nowarn;
|
||||
#endif
|
||||
|
||||
#if defined(TARGET_NR_utimensat) && defined(__NR_utimensat)
|
||||
|
||||
+1
-1
@@ -60,7 +60,7 @@ static void tcp_wait_for_connect(int fd, void *opaque)
|
||||
} else {
|
||||
DPRINTF("migrate connect success\n");
|
||||
s->fd = fd;
|
||||
socket_set_block(s->fd);
|
||||
qemu_set_block(s->fd);
|
||||
migrate_fd_connect(s);
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -60,7 +60,7 @@ static void unix_wait_for_connect(int fd, void *opaque)
|
||||
} else {
|
||||
DPRINTF("migrate connect success\n");
|
||||
s->fd = fd;
|
||||
socket_set_block(s->fd);
|
||||
qemu_set_block(s->fd);
|
||||
migrate_fd_connect(s);
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -120,7 +120,7 @@ void process_incoming_migration(QEMUFile *f)
|
||||
int fd = qemu_get_fd(f);
|
||||
|
||||
assert(fd != -1);
|
||||
socket_set_nonblock(fd);
|
||||
qemu_set_nonblock(fd);
|
||||
qemu_coroutine_enter(co, f);
|
||||
}
|
||||
|
||||
|
||||
@@ -393,7 +393,7 @@ static int nbd_send_negotiate(NBDClient *client)
|
||||
[28 .. 151] reserved (0)
|
||||
*/
|
||||
|
||||
socket_set_block(csock);
|
||||
qemu_set_block(csock);
|
||||
rc = -EINVAL;
|
||||
|
||||
TRACE("Beginning negotiation.");
|
||||
@@ -436,7 +436,7 @@ static int nbd_send_negotiate(NBDClient *client)
|
||||
TRACE("Negotiation succeeded.");
|
||||
rc = 0;
|
||||
fail:
|
||||
socket_set_nonblock(csock);
|
||||
qemu_set_nonblock(csock);
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -450,7 +450,7 @@ int nbd_receive_negotiate(int csock, const char *name, uint32_t *flags,
|
||||
|
||||
TRACE("Receiving negotiation.");
|
||||
|
||||
socket_set_block(csock);
|
||||
qemu_set_block(csock);
|
||||
rc = -EINVAL;
|
||||
|
||||
if (read_sync(csock, buf, 8) != 8) {
|
||||
@@ -565,7 +565,7 @@ int nbd_receive_negotiate(int csock, const char *name, uint32_t *flags,
|
||||
rc = 0;
|
||||
|
||||
fail:
|
||||
socket_set_nonblock(csock);
|
||||
qemu_set_nonblock(csock);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
@@ -235,23 +235,20 @@ NICState *qemu_new_nic(NetClientInfo *info,
|
||||
const char *name,
|
||||
void *opaque)
|
||||
{
|
||||
NetClientState *nc;
|
||||
NetClientState **peers = conf->peers.ncs;
|
||||
NICState *nic;
|
||||
int i;
|
||||
int i, queues = MAX(1, conf->queues);
|
||||
|
||||
assert(info->type == NET_CLIENT_OPTIONS_KIND_NIC);
|
||||
assert(info->size >= sizeof(NICState));
|
||||
|
||||
nc = qemu_new_net_client(info, peers[0], model, name);
|
||||
nc->queue_index = 0;
|
||||
|
||||
nic = qemu_get_nic(nc);
|
||||
nic = g_malloc0(info->size + sizeof(NetClientState) * queues);
|
||||
nic->ncs = (void *)nic + info->size;
|
||||
nic->conf = conf;
|
||||
nic->opaque = opaque;
|
||||
|
||||
for (i = 1; i < conf->queues; i++) {
|
||||
qemu_net_client_setup(&nic->ncs[i], info, peers[i], model, nc->name,
|
||||
for (i = 0; i < queues; i++) {
|
||||
qemu_net_client_setup(&nic->ncs[i], info, peers[i], model, name,
|
||||
NULL);
|
||||
nic->ncs[i].queue_index = i;
|
||||
}
|
||||
@@ -261,7 +258,7 @@ NICState *qemu_new_nic(NetClientInfo *info,
|
||||
|
||||
NetClientState *qemu_get_subqueue(NICState *nic, int queue_index)
|
||||
{
|
||||
return &nic->ncs[queue_index];
|
||||
return nic->ncs + queue_index;
|
||||
}
|
||||
|
||||
NetClientState *qemu_get_queue(NICState *nic)
|
||||
@@ -273,7 +270,7 @@ NICState *qemu_get_nic(NetClientState *nc)
|
||||
{
|
||||
NetClientState *nc0 = nc - nc->queue_index;
|
||||
|
||||
return DO_UPCAST(NICState, ncs[0], nc0);
|
||||
return (NICState *)((void *)nc0 - nc->info->size);
|
||||
}
|
||||
|
||||
void *qemu_get_nic_opaque(NetClientState *nc)
|
||||
@@ -368,6 +365,8 @@ void qemu_del_nic(NICState *nic)
|
||||
qemu_cleanup_net_client(nc);
|
||||
qemu_free_net_client(nc);
|
||||
}
|
||||
|
||||
g_free(nic);
|
||||
}
|
||||
|
||||
void qemu_foreach_nic(qemu_nic_foreach func, void *opaque)
|
||||
|
||||
+9
-4
@@ -309,7 +309,7 @@ static int net_socket_mcast_create(struct sockaddr_in *mcastaddr, struct in_addr
|
||||
}
|
||||
}
|
||||
|
||||
socket_set_nonblock(fd);
|
||||
qemu_set_nonblock(fd);
|
||||
return fd;
|
||||
fail:
|
||||
if (fd >= 0)
|
||||
@@ -517,7 +517,7 @@ static int net_socket_listen_init(NetClientState *peer,
|
||||
perror("socket");
|
||||
return -1;
|
||||
}
|
||||
socket_set_nonblock(fd);
|
||||
qemu_set_nonblock(fd);
|
||||
|
||||
/* allow fast reuse */
|
||||
val = 1;
|
||||
@@ -563,7 +563,7 @@ static int net_socket_connect_init(NetClientState *peer,
|
||||
perror("socket");
|
||||
return -1;
|
||||
}
|
||||
socket_set_nonblock(fd);
|
||||
qemu_set_nonblock(fd);
|
||||
|
||||
connected = 0;
|
||||
for(;;) {
|
||||
@@ -672,6 +672,7 @@ static int net_socket_udp_init(NetClientState *peer,
|
||||
closesocket(fd);
|
||||
return -1;
|
||||
}
|
||||
qemu_set_nonblock(fd);
|
||||
|
||||
s = net_socket_fd_init(peer, model, name, fd, 0);
|
||||
if (!s) {
|
||||
@@ -710,7 +711,11 @@ int net_init_socket(const NetClientOptions *opts, const char *name,
|
||||
int fd;
|
||||
|
||||
fd = monitor_handle_fd_param(cur_mon, sock->fd);
|
||||
if (fd == -1 || !net_socket_fd_init(peer, "socket", name, fd, 1)) {
|
||||
if (fd == -1) {
|
||||
return -1;
|
||||
}
|
||||
qemu_set_nonblock(fd);
|
||||
if (!net_socket_fd_init(peer, "socket", name, fd, 1)) {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
|
||||
@@ -628,7 +628,7 @@ static int net_init_tap_one(const NetdevTapOptions *tap, NetClientState *peer,
|
||||
vhostfdname || (tap->has_vhostforce && tap->vhostforce)) {
|
||||
int vhostfd;
|
||||
|
||||
if (tap->has_vhostfd) {
|
||||
if (tap->has_vhostfd || tap->has_vhostfds) {
|
||||
vhostfd = monitor_handle_fd_param(cur_mon, vhostfdname);
|
||||
if (vhostfd == -1) {
|
||||
return -1;
|
||||
@@ -693,6 +693,13 @@ int net_init_tap(const NetClientOptions *opts, const char *name,
|
||||
queues = tap->has_queues ? tap->queues : 1;
|
||||
vhostfdname = tap->has_vhostfd ? tap->vhostfd : NULL;
|
||||
|
||||
/* QEMU vlans does not support multiqueue tap, in this case peer is set.
|
||||
* For -netdev, peer is always NULL. */
|
||||
if (peer && (tap->has_queues || tap->has_fds || tap->has_vhostfds)) {
|
||||
error_report("Multiqueue tap cannnot be used with QEMU vlans");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (tap->has_fd) {
|
||||
if (tap->has_ifname || tap->has_script || tap->has_downscript ||
|
||||
tap->has_vnet_hdr || tap->has_helper || tap->has_queues ||
|
||||
|
||||
+12
@@ -23,6 +23,7 @@
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
#include <windows.h>
|
||||
#include <mmsystem.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <signal.h>
|
||||
@@ -67,6 +68,13 @@ static BOOL WINAPI qemu_ctrl_handler(DWORD type)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static TIMECAPS mm_tc;
|
||||
|
||||
static void os_undo_timer_resolution(void)
|
||||
{
|
||||
timeEndPeriod(mm_tc.wPeriodMin);
|
||||
}
|
||||
|
||||
void os_setup_early_signal_handling(void)
|
||||
{
|
||||
/* Note: cpu_interrupt() is currently not SMP safe, so we force
|
||||
@@ -88,6 +96,10 @@ void os_setup_early_signal_handling(void)
|
||||
SetProcessAffinityMask(h, mask);
|
||||
}
|
||||
}
|
||||
|
||||
timeGetDevCaps(&mm_tc, sizeof(mm_tc));
|
||||
timeBeginPeriod(mm_tc.wPeriodMin);
|
||||
atexit(os_undo_timer_resolution);
|
||||
}
|
||||
|
||||
/* Look for support files in the same directory as the executable. */
|
||||
|
||||
@@ -152,6 +152,9 @@ void cache_insert(PageCache *cache, uint64_t addr, uint8_t *pdata)
|
||||
/* actual update of entry */
|
||||
it = cache_get_by_addr(cache, addr);
|
||||
|
||||
/* free old cached data if any */
|
||||
g_free(it->it_data);
|
||||
|
||||
if (!it->it_data) {
|
||||
cache->num_items++;
|
||||
}
|
||||
@@ -208,6 +211,7 @@ int64_t cache_resize(PageCache *cache, int64_t new_num_pages)
|
||||
}
|
||||
}
|
||||
|
||||
g_free(cache->page_cache);
|
||||
cache->page_cache = new_cache->page_cache;
|
||||
cache->max_num_items = new_cache->max_num_items;
|
||||
cache->num_items = new_cache->num_items;
|
||||
|
||||
Binary file not shown.
@@ -2504,6 +2504,9 @@
|
||||
#
|
||||
# @fd: #optional file descriptor of an already opened tap
|
||||
#
|
||||
# @fds: #optional multiple file descriptors of already opened multiqueue capable
|
||||
# tap
|
||||
#
|
||||
# @script: #optional script to initialize the interface
|
||||
#
|
||||
# @downscript: #optional script to shut down the interface
|
||||
@@ -2518,8 +2521,13 @@
|
||||
#
|
||||
# @vhostfd: #optional file descriptor of an already opened vhost net device
|
||||
#
|
||||
# @vhostfds: #optional file descriptors of multiple already opened vhost net
|
||||
# devices
|
||||
#
|
||||
# @vhostforce: #optional vhost on for non-MSIX virtio guests
|
||||
#
|
||||
# @queues: #optional number of queues to be created for multiqueue capable tap
|
||||
#
|
||||
# Since 1.2
|
||||
##
|
||||
{ 'type': 'NetdevTapOptions',
|
||||
|
||||
@@ -367,6 +367,24 @@ int main(int argc, char **argv)
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* Linux uses the lowest enslaved MAC address as the MAC address of
|
||||
* the bridge. Set MAC address to a high value so that it doesn't
|
||||
* affect the MAC address of the bridge.
|
||||
*/
|
||||
if (ioctl(ctlfd, SIOCGIFHWADDR, &ifr) < 0) {
|
||||
fprintf(stderr, "failed to get MAC address of device `%s': %s\n",
|
||||
iface, strerror(errno));
|
||||
ret = EXIT_FAILURE;
|
||||
goto cleanup;
|
||||
}
|
||||
ifr.ifr_hwaddr.sa_data[0] = 0xFE;
|
||||
if (ioctl(ctlfd, SIOCSIFHWADDR, &ifr) < 0) {
|
||||
fprintf(stderr, "failed to set MAC address of device `%s': %s\n",
|
||||
iface, strerror(errno));
|
||||
ret = EXIT_FAILURE;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* add the interface to the bridge */
|
||||
prep_ifreq(&ifr, bridge);
|
||||
ifindex = if_nametoindex(iface);
|
||||
|
||||
+8
-5
@@ -2252,6 +2252,9 @@ static void unix_process_msgfd(CharDriverState *chr, struct msghdr *msg)
|
||||
if (fd < 0)
|
||||
continue;
|
||||
|
||||
/* O_NONBLOCK is preserved across SCM_RIGHTS so reset it */
|
||||
qemu_set_block(fd);
|
||||
|
||||
#ifndef MSG_CMSG_CLOEXEC
|
||||
qemu_set_cloexec(fd);
|
||||
#endif
|
||||
@@ -2377,7 +2380,7 @@ static int tcp_chr_add_client(CharDriverState *chr, int fd)
|
||||
if (s->fd != -1)
|
||||
return -1;
|
||||
|
||||
socket_set_nonblock(fd);
|
||||
qemu_set_nonblock(fd);
|
||||
if (s->do_nodelay)
|
||||
socket_set_nodelay(fd);
|
||||
s->fd = fd;
|
||||
@@ -2482,7 +2485,7 @@ static CharDriverState *qemu_chr_open_socket_fd(int fd, bool do_nodelay,
|
||||
s->do_nodelay = do_nodelay;
|
||||
getnameinfo((struct sockaddr *) &ss, ss_len, host, sizeof(host),
|
||||
serv, sizeof(serv), NI_NUMERICHOST | NI_NUMERICSERV);
|
||||
snprintf(chr->filename, 256, "%s:%s:%s%s%s%s",
|
||||
snprintf(chr->filename, 256, "%s:%s%s%s:%s%s",
|
||||
is_telnet ? "telnet" : "tcp",
|
||||
left, host, right, serv,
|
||||
is_listen ? ",server" : "");
|
||||
@@ -2512,7 +2515,7 @@ static CharDriverState *qemu_chr_open_socket_fd(int fd, bool do_nodelay,
|
||||
printf("QEMU waiting for connection on: %s\n",
|
||||
chr->filename);
|
||||
tcp_chr_accept(chr);
|
||||
socket_set_nonblock(s->listen_fd);
|
||||
qemu_set_nonblock(s->listen_fd);
|
||||
}
|
||||
return chr;
|
||||
}
|
||||
@@ -2554,7 +2557,7 @@ static CharDriverState *qemu_chr_open_socket(QemuOpts *opts)
|
||||
}
|
||||
|
||||
if (!is_waitconnect)
|
||||
socket_set_nonblock(fd);
|
||||
qemu_set_nonblock(fd);
|
||||
|
||||
chr = qemu_chr_open_socket_fd(fd, do_nodelay, is_listen, is_telnet,
|
||||
is_waitconnect, &local_err);
|
||||
@@ -3328,7 +3331,7 @@ static CharDriverState *qmp_chardev_open_serial(ChardevHostdev *serial,
|
||||
if (error_is_set(errp)) {
|
||||
return NULL;
|
||||
}
|
||||
socket_set_nonblock(fd);
|
||||
qemu_set_nonblock(fd);
|
||||
return qemu_chr_open_tty_fd(fd);
|
||||
#else
|
||||
error_setg(errp, "character device backend type 'serial' not supported");
|
||||
|
||||
+18
-2
@@ -305,6 +305,7 @@ static void nbd_accept(void *opaque)
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
BlockDriverState *bs;
|
||||
BlockDriver *drv;
|
||||
off_t dev_offset = 0;
|
||||
uint32_t nbdflags = 0;
|
||||
bool disconnect = false;
|
||||
@@ -312,7 +313,7 @@ int main(int argc, char **argv)
|
||||
char *device = NULL;
|
||||
int port = NBD_DEFAULT_PORT;
|
||||
off_t fd_size;
|
||||
const char *sopt = "hVb:o:p:rsnP:c:dvk:e:t";
|
||||
const char *sopt = "hVb:o:p:rsnP:c:dvk:e:f:t";
|
||||
struct option lopt[] = {
|
||||
{ "help", 0, NULL, 'h' },
|
||||
{ "version", 0, NULL, 'V' },
|
||||
@@ -331,6 +332,7 @@ int main(int argc, char **argv)
|
||||
{ "aio", 1, NULL, QEMU_NBD_OPT_AIO },
|
||||
#endif
|
||||
{ "shared", 1, NULL, 'e' },
|
||||
{ "format", 1, NULL, 'f' },
|
||||
{ "persistent", 0, NULL, 't' },
|
||||
{ "verbose", 0, NULL, 'v' },
|
||||
{ NULL, 0, NULL, 0 }
|
||||
@@ -348,6 +350,7 @@ int main(int argc, char **argv)
|
||||
bool seen_aio = false;
|
||||
#endif
|
||||
pthread_t client_thread;
|
||||
const char *fmt = NULL;
|
||||
|
||||
/* The client thread uses SIGTERM to interrupt the server. A signal
|
||||
* handler ensures that "qemu-nbd -v -c" exits with a nice status code.
|
||||
@@ -442,6 +445,9 @@ int main(int argc, char **argv)
|
||||
errx(EXIT_FAILURE, "Shared device number must be greater than 0\n");
|
||||
}
|
||||
break;
|
||||
case 'f':
|
||||
fmt = optarg;
|
||||
break;
|
||||
case 't':
|
||||
persistent = 1;
|
||||
break;
|
||||
@@ -543,9 +549,19 @@ int main(int argc, char **argv)
|
||||
bdrv_init();
|
||||
atexit(bdrv_close_all);
|
||||
|
||||
if (fmt) {
|
||||
drv = bdrv_find_format(fmt);
|
||||
if (!drv) {
|
||||
errx(EXIT_FAILURE, "Unknown file format '%s'", fmt);
|
||||
}
|
||||
} else {
|
||||
drv = NULL;
|
||||
}
|
||||
|
||||
bs = bdrv_new("hda");
|
||||
srcpath = argv[optind];
|
||||
if ((ret = bdrv_open(bs, srcpath, flags, NULL)) < 0) {
|
||||
ret = bdrv_open(bs, srcpath, flags, drv);
|
||||
if (ret < 0) {
|
||||
errno = -ret;
|
||||
err(EXIT_FAILURE, "Failed to bdrv_open '%s'", argv[optind]);
|
||||
}
|
||||
|
||||
@@ -41,6 +41,8 @@ Export QEMU disk image using NBD protocol.
|
||||
disconnect the specified device
|
||||
@item -e, --shared=@var{num}
|
||||
device can be shared by @var{num} clients (default @samp{1})
|
||||
@item -f, --format=@var{fmt}
|
||||
force block driver for format @var{fmt} instead of auto-detecting
|
||||
@item -t, --persistent
|
||||
don't exit on the last connection
|
||||
@item -v, --verbose
|
||||
|
||||
+50
-34
@@ -537,13 +537,15 @@ STEXI
|
||||
@end table
|
||||
ETEXI
|
||||
|
||||
STEXI
|
||||
USB options:
|
||||
@table @option
|
||||
ETEXI
|
||||
|
||||
DEF("usb", 0, QEMU_OPTION_usb,
|
||||
"-usb enable the USB driver (will be the default soon)\n",
|
||||
QEMU_ARCH_ALL)
|
||||
STEXI
|
||||
USB options:
|
||||
@table @option
|
||||
|
||||
@item -usb
|
||||
@findex -usb
|
||||
Enable the USB driver (will be the default soon)
|
||||
@@ -610,9 +612,15 @@ possible drivers and properties, use @code{-device help} and
|
||||
@code{-device @var{driver},help}.
|
||||
ETEXI
|
||||
|
||||
STEXI
|
||||
@end table
|
||||
ETEXI
|
||||
DEFHEADING()
|
||||
|
||||
DEFHEADING(File system options:)
|
||||
STEXI
|
||||
@table @option
|
||||
ETEXI
|
||||
|
||||
DEF("fsdev", HAS_ARG, QEMU_OPTION_fsdev,
|
||||
"-fsdev fsdriver,id=id[,path=path,][security_model={mapped-xattr|mapped-file|passthrough|none}]\n"
|
||||
@@ -676,9 +684,15 @@ Specifies the tag name to be used by the guest to mount this export point
|
||||
|
||||
ETEXI
|
||||
|
||||
STEXI
|
||||
@end table
|
||||
ETEXI
|
||||
DEFHEADING()
|
||||
|
||||
DEFHEADING(Virtual File system pass-through options:)
|
||||
STEXI
|
||||
@table @option
|
||||
ETEXI
|
||||
|
||||
DEF("virtfs", HAS_ARG, QEMU_OPTION_virtfs,
|
||||
"-virtfs local,path=path,mount_tag=tag,security_model=[mapped-xattr|mapped-file|passthrough|none]\n"
|
||||
@@ -769,11 +783,9 @@ ETEXI
|
||||
STEXI
|
||||
@end table
|
||||
ETEXI
|
||||
|
||||
DEFHEADING()
|
||||
|
||||
DEFHEADING(Display options:)
|
||||
|
||||
STEXI
|
||||
@table @option
|
||||
ETEXI
|
||||
@@ -1215,7 +1227,6 @@ ETEXI
|
||||
STEXI
|
||||
@end table
|
||||
ETEXI
|
||||
|
||||
ARCHHEADING(, QEMU_ARCH_I386)
|
||||
|
||||
ARCHHEADING(i386 target only:, QEMU_ARCH_I386)
|
||||
@@ -1301,10 +1312,10 @@ Specify SMBIOS type 0 fields
|
||||
Specify SMBIOS type 1 fields
|
||||
ETEXI
|
||||
|
||||
DEFHEADING()
|
||||
STEXI
|
||||
@end table
|
||||
ETEXI
|
||||
DEFHEADING()
|
||||
|
||||
DEFHEADING(Network options:)
|
||||
STEXI
|
||||
@@ -1338,7 +1349,7 @@ DEF("net", HAS_ARG, QEMU_OPTION_net,
|
||||
"-net tap[,vlan=n][,name=str],ifname=name\n"
|
||||
" connect the host TAP network interface to VLAN 'n'\n"
|
||||
#else
|
||||
"-net tap[,vlan=n][,name=str][,fd=h][,ifname=name][,script=file][,downscript=dfile][,helper=helper][,sndbuf=nbytes][,vnet_hdr=on|off][,vhost=on|off][,vhostfd=h][,vhostforce=on|off]\n"
|
||||
"-net tap[,vlan=n][,name=str][,fd=h][,fds=x:y:...:z][,ifname=name][,script=file][,downscript=dfile][,helper=helper][,sndbuf=nbytes][,vnet_hdr=on|off][,vhost=on|off][,vhostfd=h][,vhostfds=x:y:...:z][,vhostforce=on|off][,queues=n]\n"
|
||||
" connect the host TAP network interface to VLAN 'n'\n"
|
||||
" use network scripts 'file' (default=" DEFAULT_NETWORK_SCRIPT ")\n"
|
||||
" to configure it and 'dfile' (default=" DEFAULT_NETWORK_DOWN_SCRIPT ")\n"
|
||||
@@ -1347,6 +1358,7 @@ DEF("net", HAS_ARG, QEMU_OPTION_net,
|
||||
" use network helper 'helper' (default=" DEFAULT_BRIDGE_HELPER ") to\n"
|
||||
" configure it\n"
|
||||
" use 'fd=h' to connect to an already opened TAP interface\n"
|
||||
" use 'fds=x:y:...:z' to connect to already opened multiqueue capable TAP interfaces\n"
|
||||
" use 'sndbuf=nbytes' to limit the size of the send buffer (the\n"
|
||||
" default is disabled 'sndbuf=0' to enable flow control set 'sndbuf=1048576')\n"
|
||||
" use vnet_hdr=off to avoid enabling the IFF_VNET_HDR tap flag\n"
|
||||
@@ -1355,6 +1367,8 @@ DEF("net", HAS_ARG, QEMU_OPTION_net,
|
||||
" (only has effect for virtio guests which use MSIX)\n"
|
||||
" use vhostforce=on to force vhost on for non-MSIX virtio guests\n"
|
||||
" use 'vhostfd=h' to connect to an already opened vhost net device\n"
|
||||
" use 'vhostfds=x:y:...:z to connect to multiple already opened vhost net devices\n"
|
||||
" use 'queues=n' to specify the number of queues to be created for multiqueue TAP\n"
|
||||
"-net bridge[,vlan=n][,name=str][,br=bridge][,helper=helper]\n"
|
||||
" connects a host TAP network interface to a host bridge device 'br'\n"
|
||||
" (default=" DEFAULT_BRIDGE_INTERFACE ") using the program 'helper'\n"
|
||||
@@ -1718,13 +1732,19 @@ libpcap, so it can be analyzed with tools such as tcpdump or Wireshark.
|
||||
Indicate that no network devices should be configured. It is used to
|
||||
override the default configuration (@option{-net nic -net user}) which
|
||||
is activated if no @option{-net} options are provided.
|
||||
|
||||
@end table
|
||||
ETEXI
|
||||
|
||||
STEXI
|
||||
@end table
|
||||
ETEXI
|
||||
DEFHEADING()
|
||||
|
||||
DEFHEADING(Character device options:)
|
||||
STEXI
|
||||
|
||||
The general form of a character device option is:
|
||||
@table @option
|
||||
ETEXI
|
||||
|
||||
DEF("chardev", HAS_ARG, QEMU_OPTION_chardev,
|
||||
"-chardev null,id=id[,mux=on|off]\n"
|
||||
@@ -1766,10 +1786,6 @@ DEF("chardev", HAS_ARG, QEMU_OPTION_chardev,
|
||||
)
|
||||
|
||||
STEXI
|
||||
|
||||
The general form of a character device option is:
|
||||
@table @option
|
||||
|
||||
@item -chardev @var{backend} ,id=@var{id} [,mux=on|off] [,@var{options}]
|
||||
@findex -chardev
|
||||
Backend is one of:
|
||||
@@ -1990,14 +2006,15 @@ Connect to a spice virtual machine channel, such as vdiport.
|
||||
|
||||
Connect to a spice port, allowing a Spice client to handle the traffic
|
||||
identified by a name (preferably a fqdn).
|
||||
|
||||
@end table
|
||||
ETEXI
|
||||
|
||||
STEXI
|
||||
@end table
|
||||
ETEXI
|
||||
DEFHEADING()
|
||||
|
||||
STEXI
|
||||
DEFHEADING(Device URL Syntax:)
|
||||
STEXI
|
||||
|
||||
In addition to using normal file images for the emulated storage devices,
|
||||
QEMU can also use networked resources such as iSCSI devices. These are
|
||||
@@ -2075,18 +2092,13 @@ QEMU supports using either local sheepdog devices or remote networked
|
||||
devices.
|
||||
|
||||
Syntax for specifying a sheepdog device
|
||||
@table @list
|
||||
``sheepdog:<vdiname>''
|
||||
|
||||
``sheepdog:<vdiname>:<snapid>''
|
||||
|
||||
``sheepdog:<vdiname>:<tag>''
|
||||
|
||||
``sheepdog:<host>:<port>:<vdiname>''
|
||||
|
||||
``sheepdog:<host>:<port>:<vdiname>:<snapid>''
|
||||
|
||||
``sheepdog:<host>:<port>:<vdiname>:<tag>''
|
||||
@table @code
|
||||
@item sheepdog:<vdiname>
|
||||
@item sheepdog:<vdiname>:<snapid>
|
||||
@item sheepdog:<vdiname>:<tag>
|
||||
@item sheepdog:<host>:<port>:<vdiname>
|
||||
@item sheepdog:<host>:<port>:<vdiname>:<snapid>
|
||||
@item sheepdog:<host>:<port>:<vdiname>:<tag>
|
||||
@end table
|
||||
|
||||
Example
|
||||
@@ -2113,10 +2125,16 @@ qemu-system-x86_84 --drive file=gluster://192.0.2.1/testvol/a.img
|
||||
@end example
|
||||
|
||||
See also @url{http://www.gluster.org}.
|
||||
ETEXI
|
||||
|
||||
STEXI
|
||||
@end table
|
||||
ETEXI
|
||||
|
||||
DEFHEADING(Bluetooth(R) options:)
|
||||
STEXI
|
||||
@table @option
|
||||
ETEXI
|
||||
|
||||
DEF("bt", HAS_ARG, QEMU_OPTION_bt, \
|
||||
"-bt hci,null dumb bluetooth HCI - doesn't respond to commands\n" \
|
||||
@@ -2130,8 +2148,6 @@ DEF("bt", HAS_ARG, QEMU_OPTION_bt, \
|
||||
" emulate a bluetooth device 'dev' in scatternet 'n'\n",
|
||||
QEMU_ARCH_ALL)
|
||||
STEXI
|
||||
@table @option
|
||||
|
||||
@item -bt hci[...]
|
||||
@findex -bt
|
||||
Defines the function of the corresponding Bluetooth HCI. -bt options
|
||||
@@ -2183,9 +2199,11 @@ currently:
|
||||
@item keyboard
|
||||
Virtual wireless keyboard implementing the HIDP bluetooth profile.
|
||||
@end table
|
||||
@end table
|
||||
ETEXI
|
||||
|
||||
STEXI
|
||||
@end table
|
||||
ETEXI
|
||||
DEFHEADING()
|
||||
|
||||
DEFHEADING(Linux/Multiboot boot specific:)
|
||||
@@ -2242,11 +2260,9 @@ ETEXI
|
||||
STEXI
|
||||
@end table
|
||||
ETEXI
|
||||
|
||||
DEFHEADING()
|
||||
|
||||
DEFHEADING(Debug/Expert options:)
|
||||
|
||||
STEXI
|
||||
@table @option
|
||||
ETEXI
|
||||
|
||||
+6
-18
@@ -624,28 +624,14 @@ static void CALLBACK mm_alarm_handler(UINT uTimerID, UINT uMsg,
|
||||
static int mm_start_timer(struct qemu_alarm_timer *t)
|
||||
{
|
||||
timeGetDevCaps(&mm_tc, sizeof(mm_tc));
|
||||
|
||||
timeBeginPeriod(mm_tc.wPeriodMin);
|
||||
|
||||
mm_timer = timeSetEvent(mm_tc.wPeriodMin, /* interval (ms) */
|
||||
mm_tc.wPeriodMin, /* resolution */
|
||||
mm_alarm_handler, /* function */
|
||||
(DWORD_PTR)t, /* parameter */
|
||||
TIME_ONESHOT | TIME_CALLBACK_FUNCTION);
|
||||
|
||||
if (!mm_timer) {
|
||||
fprintf(stderr, "Failed to initialize win32 alarm timer\n");
|
||||
timeEndPeriod(mm_tc.wPeriodMin);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void mm_stop_timer(struct qemu_alarm_timer *t)
|
||||
{
|
||||
timeKillEvent(mm_timer);
|
||||
timeEndPeriod(mm_tc.wPeriodMin);
|
||||
if (mm_timer) {
|
||||
timeKillEvent(mm_timer);
|
||||
}
|
||||
}
|
||||
|
||||
static void mm_rearm_timer(struct qemu_alarm_timer *t, int64_t delta)
|
||||
@@ -657,7 +643,9 @@ static void mm_rearm_timer(struct qemu_alarm_timer *t, int64_t delta)
|
||||
nearest_delta_ms = mm_tc.wPeriodMax;
|
||||
}
|
||||
|
||||
timeKillEvent(mm_timer);
|
||||
if (mm_timer) {
|
||||
timeKillEvent(mm_timer);
|
||||
}
|
||||
mm_timer = timeSetEvent((UINT)nearest_delta_ms,
|
||||
mm_tc.wPeriodMin,
|
||||
mm_alarm_handler,
|
||||
|
||||
+148
-10
@@ -129,14 +129,22 @@ static struct {
|
||||
QTAILQ_HEAD(, GuestFileHandle) filehandles;
|
||||
} guest_file_state;
|
||||
|
||||
static void guest_file_handle_add(FILE *fh)
|
||||
static int64_t guest_file_handle_add(FILE *fh, Error **errp)
|
||||
{
|
||||
GuestFileHandle *gfh;
|
||||
int64_t handle;
|
||||
|
||||
handle = ga_get_fd_handle(ga_state, errp);
|
||||
if (error_is_set(errp)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
gfh = g_malloc0(sizeof(GuestFileHandle));
|
||||
gfh->id = fileno(fh);
|
||||
gfh->id = handle;
|
||||
gfh->fh = fh;
|
||||
QTAILQ_INSERT_TAIL(&guest_file_state.filehandles, gfh, next);
|
||||
|
||||
return handle;
|
||||
}
|
||||
|
||||
static GuestFileHandle *guest_file_handle_find(int64_t id, Error **err)
|
||||
@@ -154,20 +162,145 @@ static GuestFileHandle *guest_file_handle_find(int64_t id, Error **err)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
typedef const char * const ccpc;
|
||||
|
||||
#ifndef O_BINARY
|
||||
#define O_BINARY 0
|
||||
#endif
|
||||
|
||||
/* http://pubs.opengroup.org/onlinepubs/9699919799/functions/fopen.html */
|
||||
static const struct {
|
||||
ccpc *forms;
|
||||
int oflag_base;
|
||||
} guest_file_open_modes[] = {
|
||||
{ (ccpc[]){ "r", NULL }, O_RDONLY },
|
||||
{ (ccpc[]){ "rb", NULL }, O_RDONLY | O_BINARY },
|
||||
{ (ccpc[]){ "w", NULL }, O_WRONLY | O_CREAT | O_TRUNC },
|
||||
{ (ccpc[]){ "wb", NULL }, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY },
|
||||
{ (ccpc[]){ "a", NULL }, O_WRONLY | O_CREAT | O_APPEND },
|
||||
{ (ccpc[]){ "ab", NULL }, O_WRONLY | O_CREAT | O_APPEND | O_BINARY },
|
||||
{ (ccpc[]){ "r+", NULL }, O_RDWR },
|
||||
{ (ccpc[]){ "rb+", "r+b", NULL }, O_RDWR | O_BINARY },
|
||||
{ (ccpc[]){ "w+", NULL }, O_RDWR | O_CREAT | O_TRUNC },
|
||||
{ (ccpc[]){ "wb+", "w+b", NULL }, O_RDWR | O_CREAT | O_TRUNC | O_BINARY },
|
||||
{ (ccpc[]){ "a+", NULL }, O_RDWR | O_CREAT | O_APPEND },
|
||||
{ (ccpc[]){ "ab+", "a+b", NULL }, O_RDWR | O_CREAT | O_APPEND | O_BINARY }
|
||||
};
|
||||
|
||||
static int
|
||||
find_open_flag(const char *mode_str, Error **err)
|
||||
{
|
||||
unsigned mode;
|
||||
|
||||
for (mode = 0; mode < ARRAY_SIZE(guest_file_open_modes); ++mode) {
|
||||
ccpc *form;
|
||||
|
||||
form = guest_file_open_modes[mode].forms;
|
||||
while (*form != NULL && strcmp(*form, mode_str) != 0) {
|
||||
++form;
|
||||
}
|
||||
if (*form != NULL) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (mode == ARRAY_SIZE(guest_file_open_modes)) {
|
||||
error_setg(err, "invalid file open mode '%s'", mode_str);
|
||||
return -1;
|
||||
}
|
||||
return guest_file_open_modes[mode].oflag_base | O_NOCTTY | O_NONBLOCK;
|
||||
}
|
||||
|
||||
#define DEFAULT_NEW_FILE_MODE (S_IRUSR | S_IWUSR | \
|
||||
S_IRGRP | S_IWGRP | \
|
||||
S_IROTH | S_IWOTH)
|
||||
|
||||
static FILE *
|
||||
safe_open_or_create(const char *path, const char *mode, Error **err)
|
||||
{
|
||||
Error *local_err = NULL;
|
||||
int oflag;
|
||||
|
||||
oflag = find_open_flag(mode, &local_err);
|
||||
if (local_err == NULL) {
|
||||
int fd;
|
||||
|
||||
/* If the caller wants / allows creation of a new file, we implement it
|
||||
* with a two step process: open() + (open() / fchmod()).
|
||||
*
|
||||
* First we insist on creating the file exclusively as a new file. If
|
||||
* that succeeds, we're free to set any file-mode bits on it. (The
|
||||
* motivation is that we want to set those file-mode bits independently
|
||||
* of the current umask.)
|
||||
*
|
||||
* If the exclusive creation fails because the file already exists
|
||||
* (EEXIST is not possible for any other reason), we just attempt to
|
||||
* open the file, but in this case we won't be allowed to change the
|
||||
* file-mode bits on the preexistent file.
|
||||
*
|
||||
* The pathname should never disappear between the two open()s in
|
||||
* practice. If it happens, then someone very likely tried to race us.
|
||||
* In this case just go ahead and report the ENOENT from the second
|
||||
* open() to the caller.
|
||||
*
|
||||
* If the caller wants to open a preexistent file, then the first
|
||||
* open() is decisive and its third argument is ignored, and the second
|
||||
* open() and the fchmod() are never called.
|
||||
*/
|
||||
fd = open(path, oflag | ((oflag & O_CREAT) ? O_EXCL : 0), 0);
|
||||
if (fd == -1 && errno == EEXIST) {
|
||||
oflag &= ~(unsigned)O_CREAT;
|
||||
fd = open(path, oflag);
|
||||
}
|
||||
|
||||
if (fd == -1) {
|
||||
error_setg_errno(&local_err, errno, "failed to open file '%s' "
|
||||
"(mode: '%s')", path, mode);
|
||||
} else {
|
||||
qemu_set_cloexec(fd);
|
||||
|
||||
if ((oflag & O_CREAT) && fchmod(fd, DEFAULT_NEW_FILE_MODE) == -1) {
|
||||
error_setg_errno(&local_err, errno, "failed to set permission "
|
||||
"0%03o on new file '%s' (mode: '%s')",
|
||||
(unsigned)DEFAULT_NEW_FILE_MODE, path, mode);
|
||||
} else {
|
||||
FILE *f;
|
||||
|
||||
f = fdopen(fd, mode);
|
||||
if (f == NULL) {
|
||||
error_setg_errno(&local_err, errno, "failed to associate "
|
||||
"stdio stream with file descriptor %d, "
|
||||
"file '%s' (mode: '%s')", fd, path, mode);
|
||||
} else {
|
||||
return f;
|
||||
}
|
||||
}
|
||||
|
||||
close(fd);
|
||||
if (oflag & O_CREAT) {
|
||||
unlink(path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
error_propagate(err, local_err);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int64_t qmp_guest_file_open(const char *path, bool has_mode, const char *mode, Error **err)
|
||||
{
|
||||
FILE *fh;
|
||||
Error *local_err = NULL;
|
||||
int fd;
|
||||
int64_t ret = -1;
|
||||
int64_t ret = -1, handle;
|
||||
|
||||
if (!has_mode) {
|
||||
mode = "r";
|
||||
}
|
||||
slog("guest-file-open called, filepath: %s, mode: %s", path, mode);
|
||||
fh = fopen(path, mode);
|
||||
if (!fh) {
|
||||
error_setg_errno(err, errno, "failed to open file '%s' (mode: '%s')",
|
||||
path, mode);
|
||||
fh = safe_open_or_create(path, mode, &local_err);
|
||||
if (local_err != NULL) {
|
||||
error_propagate(err, local_err);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -184,9 +317,14 @@ int64_t qmp_guest_file_open(const char *path, bool has_mode, const char *mode, E
|
||||
return -1;
|
||||
}
|
||||
|
||||
guest_file_handle_add(fh);
|
||||
slog("guest-file-open, handle: %d", fd);
|
||||
return fd;
|
||||
handle = guest_file_handle_add(fh, err);
|
||||
if (error_is_set(err)) {
|
||||
fclose(fh);
|
||||
return -1;
|
||||
}
|
||||
|
||||
slog("guest-file-open, handle: %d", handle);
|
||||
return handle;
|
||||
}
|
||||
|
||||
void qmp_guest_file_close(int64_t handle, Error **err)
|
||||
|
||||
@@ -35,6 +35,7 @@ bool ga_is_frozen(GAState *s);
|
||||
void ga_set_frozen(GAState *s);
|
||||
void ga_unset_frozen(GAState *s);
|
||||
const char *ga_fsfreeze_hook(GAState *s);
|
||||
int64_t ga_get_fd_handle(GAState *s, Error **errp);
|
||||
|
||||
#ifndef _WIN32
|
||||
void reopen_fd_to_null(int fd);
|
||||
|
||||
+186
-1
@@ -15,6 +15,7 @@
|
||||
#include <stdbool.h>
|
||||
#include <glib.h>
|
||||
#include <getopt.h>
|
||||
#include <glib/gstdio.h>
|
||||
#ifndef _WIN32
|
||||
#include <syslog.h>
|
||||
#include <sys/wait.h>
|
||||
@@ -30,6 +31,7 @@
|
||||
#include "qapi/qmp/qerror.h"
|
||||
#include "qapi/qmp/dispatch.h"
|
||||
#include "qga/channel.h"
|
||||
#include "qemu/bswap.h"
|
||||
#ifdef _WIN32
|
||||
#include "qga/service-win32.h"
|
||||
#include <windows.h>
|
||||
@@ -53,6 +55,11 @@
|
||||
#endif
|
||||
#define QGA_SENTINEL_BYTE 0xFF
|
||||
|
||||
typedef struct GAPersistentState {
|
||||
#define QGA_PSTATE_DEFAULT_FD_COUNTER 1000
|
||||
int64_t fd_counter;
|
||||
} GAPersistentState;
|
||||
|
||||
struct GAState {
|
||||
JSONMessageParser parser;
|
||||
GMainLoop *main_loop;
|
||||
@@ -76,6 +83,8 @@ struct GAState {
|
||||
#ifdef CONFIG_FSFREEZE
|
||||
const char *fsfreeze_hook;
|
||||
#endif
|
||||
const gchar *pstate_filepath;
|
||||
GAPersistentState pstate;
|
||||
};
|
||||
|
||||
struct GAState *ga_state;
|
||||
@@ -85,6 +94,7 @@ static const char *ga_freeze_whitelist[] = {
|
||||
"guest-ping",
|
||||
"guest-info",
|
||||
"guest-sync",
|
||||
"guest-sync-delimited",
|
||||
"guest-fsfreeze-status",
|
||||
"guest-fsfreeze-thaw",
|
||||
NULL
|
||||
@@ -468,7 +478,7 @@ static void become_daemon(const char *pidfile)
|
||||
}
|
||||
}
|
||||
|
||||
umask(0);
|
||||
umask(S_IRWXG | S_IRWXO);
|
||||
sid = setsid();
|
||||
if (sid < 0) {
|
||||
goto fail;
|
||||
@@ -724,6 +734,171 @@ VOID WINAPI service_main(DWORD argc, TCHAR *argv[])
|
||||
}
|
||||
#endif
|
||||
|
||||
static void set_persistent_state_defaults(GAPersistentState *pstate)
|
||||
{
|
||||
g_assert(pstate);
|
||||
pstate->fd_counter = QGA_PSTATE_DEFAULT_FD_COUNTER;
|
||||
}
|
||||
|
||||
static void persistent_state_from_keyfile(GAPersistentState *pstate,
|
||||
GKeyFile *keyfile)
|
||||
{
|
||||
g_assert(pstate);
|
||||
g_assert(keyfile);
|
||||
/* if any fields are missing, either because the file was tampered with
|
||||
* by agents of chaos, or because the field wasn't present at the time the
|
||||
* file was created, the best we can ever do is start over with the default
|
||||
* values. so load them now, and ignore any errors in accessing key-value
|
||||
* pairs
|
||||
*/
|
||||
set_persistent_state_defaults(pstate);
|
||||
|
||||
if (g_key_file_has_key(keyfile, "global", "fd_counter", NULL)) {
|
||||
pstate->fd_counter =
|
||||
g_key_file_get_integer(keyfile, "global", "fd_counter", NULL);
|
||||
}
|
||||
}
|
||||
|
||||
static void persistent_state_to_keyfile(const GAPersistentState *pstate,
|
||||
GKeyFile *keyfile)
|
||||
{
|
||||
g_assert(pstate);
|
||||
g_assert(keyfile);
|
||||
|
||||
g_key_file_set_integer(keyfile, "global", "fd_counter", pstate->fd_counter);
|
||||
}
|
||||
|
||||
static gboolean write_persistent_state(const GAPersistentState *pstate,
|
||||
const gchar *path)
|
||||
{
|
||||
GKeyFile *keyfile = g_key_file_new();
|
||||
GError *gerr = NULL;
|
||||
gboolean ret = true;
|
||||
gchar *data = NULL;
|
||||
gsize data_len;
|
||||
|
||||
g_assert(pstate);
|
||||
|
||||
persistent_state_to_keyfile(pstate, keyfile);
|
||||
data = g_key_file_to_data(keyfile, &data_len, &gerr);
|
||||
if (gerr) {
|
||||
g_critical("failed to convert persistent state to string: %s",
|
||||
gerr->message);
|
||||
ret = false;
|
||||
goto out;
|
||||
}
|
||||
|
||||
g_file_set_contents(path, data, data_len, &gerr);
|
||||
if (gerr) {
|
||||
g_critical("failed to write persistent state to %s: %s",
|
||||
path, gerr->message);
|
||||
ret = false;
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
if (gerr) {
|
||||
g_error_free(gerr);
|
||||
}
|
||||
if (keyfile) {
|
||||
g_key_file_free(keyfile);
|
||||
}
|
||||
g_free(data);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static gboolean read_persistent_state(GAPersistentState *pstate,
|
||||
const gchar *path, gboolean frozen)
|
||||
{
|
||||
GKeyFile *keyfile = NULL;
|
||||
GError *gerr = NULL;
|
||||
struct stat st;
|
||||
gboolean ret = true;
|
||||
|
||||
g_assert(pstate);
|
||||
|
||||
if (stat(path, &st) == -1) {
|
||||
/* it's okay if state file doesn't exist, but any other error
|
||||
* indicates a permissions issue or some other misconfiguration
|
||||
* that we likely won't be able to recover from.
|
||||
*/
|
||||
if (errno != ENOENT) {
|
||||
g_critical("unable to access state file at path %s: %s",
|
||||
path, strerror(errno));
|
||||
ret = false;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* file doesn't exist. initialize state to default values and
|
||||
* attempt to save now. (we could wait till later when we have
|
||||
* modified state we need to commit, but if there's a problem,
|
||||
* such as a missing parent directory, we want to catch it now)
|
||||
*
|
||||
* there is a potential scenario where someone either managed to
|
||||
* update the agent from a version that didn't use a key store
|
||||
* while qemu-ga thought the filesystem was frozen, or
|
||||
* deleted the key store prior to issuing a fsfreeze, prior
|
||||
* to restarting the agent. in this case we go ahead and defer
|
||||
* initial creation till we actually have modified state to
|
||||
* write, otherwise fail to recover from freeze.
|
||||
*/
|
||||
set_persistent_state_defaults(pstate);
|
||||
if (!frozen) {
|
||||
ret = write_persistent_state(pstate, path);
|
||||
if (!ret) {
|
||||
g_critical("unable to create state file at path %s", path);
|
||||
ret = false;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
ret = true;
|
||||
goto out;
|
||||
}
|
||||
|
||||
keyfile = g_key_file_new();
|
||||
g_key_file_load_from_file(keyfile, path, 0, &gerr);
|
||||
if (gerr) {
|
||||
g_critical("error loading persistent state from path: %s, %s",
|
||||
path, gerr->message);
|
||||
ret = false;
|
||||
goto out;
|
||||
}
|
||||
|
||||
persistent_state_from_keyfile(pstate, keyfile);
|
||||
|
||||
out:
|
||||
if (keyfile) {
|
||||
g_key_file_free(keyfile);
|
||||
}
|
||||
if (gerr) {
|
||||
g_error_free(gerr);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int64_t ga_get_fd_handle(GAState *s, Error **errp)
|
||||
{
|
||||
int64_t handle;
|
||||
|
||||
g_assert(s->pstate_filepath);
|
||||
/* we blacklist commands and avoid operations that potentially require
|
||||
* writing to disk when we're in a frozen state. this includes opening
|
||||
* new files, so we should never get here in that situation
|
||||
*/
|
||||
g_assert(!ga_is_frozen(s));
|
||||
|
||||
handle = s->pstate.fd_counter++;
|
||||
if (s->pstate.fd_counter < 0) {
|
||||
s->pstate.fd_counter = 0;
|
||||
}
|
||||
if (!write_persistent_state(&s->pstate, s->pstate_filepath)) {
|
||||
error_setg(errp, "failed to commit persistent state to disk");
|
||||
}
|
||||
|
||||
return handle;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
const char *sopt = "hVvdm:p:l:f:F::b:s:t:";
|
||||
@@ -853,7 +1028,9 @@ int main(int argc, char **argv)
|
||||
ga_enable_logging(s);
|
||||
s->state_filepath_isfrozen = g_strdup_printf("%s/qga.state.isfrozen",
|
||||
state_dir);
|
||||
s->pstate_filepath = g_strdup_printf("%s/qga.state", state_dir);
|
||||
s->frozen = false;
|
||||
|
||||
#ifndef _WIN32
|
||||
/* check if a previous instance of qemu-ga exited with filesystems' state
|
||||
* marked as frozen. this could be a stale value (a non-qemu-ga process
|
||||
@@ -910,6 +1087,14 @@ int main(int argc, char **argv)
|
||||
}
|
||||
}
|
||||
|
||||
/* load persistent state from disk */
|
||||
if (!read_persistent_state(&s->pstate,
|
||||
s->pstate_filepath,
|
||||
ga_is_frozen(s))) {
|
||||
g_critical("failed to load persistent state");
|
||||
goto out_bad;
|
||||
}
|
||||
|
||||
if (blacklist) {
|
||||
s->blacklist = blacklist;
|
||||
do {
|
||||
|
||||
+1
-1
@@ -822,7 +822,7 @@ Example:
|
||||
-> { "execute": "netdev_add", "arguments": { "type": "user", "id": "netdev1" } }
|
||||
<- { "return": {} }
|
||||
|
||||
Note: The supported device options are the same ones supported by the '-net'
|
||||
Note: The supported device options are the same ones supported by the '-netdev'
|
||||
command-line argument, which are listed in the '-help' output or QEMU's
|
||||
manual
|
||||
|
||||
|
||||
+1
-1
Submodule roms/seabios updated: 4bd8aebf35...88cb66ea54
+1
-1
@@ -215,7 +215,7 @@ fork_exec(struct socket *so, const char *ex, int do_pty)
|
||||
setsockopt(so->s, SOL_SOCKET, SO_REUSEADDR, (char *)&opt, sizeof(int));
|
||||
opt = 1;
|
||||
setsockopt(so->s, SOL_SOCKET, SO_OOBINLINE, (char *)&opt, sizeof(int));
|
||||
socket_set_nonblock(so->s);
|
||||
qemu_set_nonblock(so->s);
|
||||
|
||||
/* Append the telnet options now */
|
||||
if (so->so_m != NULL && do_pty == 1) {
|
||||
|
||||
+2
-2
@@ -336,7 +336,7 @@ int tcp_fconnect(struct socket *so)
|
||||
int opt, s=so->s;
|
||||
struct sockaddr_in addr;
|
||||
|
||||
socket_set_nonblock(s);
|
||||
qemu_set_nonblock(s);
|
||||
opt = 1;
|
||||
setsockopt(s,SOL_SOCKET,SO_REUSEADDR,(char *)&opt,sizeof(opt ));
|
||||
opt = 1;
|
||||
@@ -424,7 +424,7 @@ tcp_connect(struct socket *inso)
|
||||
tcp_close(sototcpcb(so)); /* This will sofree() as well */
|
||||
return;
|
||||
}
|
||||
socket_set_nonblock(s);
|
||||
qemu_set_nonblock(s);
|
||||
opt = 1;
|
||||
setsockopt(s,SOL_SOCKET,SO_REUSEADDR,(char *)&opt,sizeof(int));
|
||||
opt = 1;
|
||||
|
||||
+3
-3
@@ -2091,14 +2091,14 @@ void x86_cpu_realize(Object *obj, Error **errp)
|
||||
env->cpuid_ext3_features &= TCG_EXT3_FEATURES;
|
||||
env->cpuid_svm_features &= TCG_SVM_FEATURES;
|
||||
} else {
|
||||
#ifdef CONFIG_KVM
|
||||
filter_features_for_kvm(cpu);
|
||||
#endif
|
||||
if (check_cpuid && kvm_check_features_against_host(cpu)
|
||||
&& enforce_cpuid) {
|
||||
error_setg(errp, "Host's CPU doesn't support requested features");
|
||||
return;
|
||||
}
|
||||
#ifdef CONFIG_KVM
|
||||
filter_features_for_kvm(cpu);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
|
||||
+59
-58
@@ -44,7 +44,8 @@ typedef union {
|
||||
|
||||
/*** MIPS DSP internal functions begin ***/
|
||||
#define MIPSDSP_ABS(x) (((x) >= 0) ? x : -x)
|
||||
#define MIPSDSP_OVERFLOW(a, b, c, d) (!(!((a ^ b ^ -1) & (a ^ c) & d)))
|
||||
#define MIPSDSP_OVERFLOW_ADD(a, b, c, d) (~(a ^ b) & (a ^ c) & d)
|
||||
#define MIPSDSP_OVERFLOW_SUB(a, b, c, d) ((a ^ b) & (a ^ c) & d)
|
||||
|
||||
static inline void set_DSPControl_overflow_flag(uint32_t flag, int position,
|
||||
CPUMIPSState *env)
|
||||
@@ -142,7 +143,7 @@ static inline int16_t mipsdsp_add_i16(int16_t a, int16_t b, CPUMIPSState *env)
|
||||
|
||||
tempI = a + b;
|
||||
|
||||
if (MIPSDSP_OVERFLOW(a, b, tempI, 0x8000)) {
|
||||
if (MIPSDSP_OVERFLOW_ADD(a, b, tempI, 0x8000)) {
|
||||
set_DSPControl_overflow_flag(1, 20, env);
|
||||
}
|
||||
|
||||
@@ -156,7 +157,7 @@ static inline int16_t mipsdsp_sat_add_i16(int16_t a, int16_t b,
|
||||
|
||||
tempS = a + b;
|
||||
|
||||
if (MIPSDSP_OVERFLOW(a, b, tempS, 0x8000)) {
|
||||
if (MIPSDSP_OVERFLOW_ADD(a, b, tempS, 0x8000)) {
|
||||
if (a > 0) {
|
||||
tempS = 0x7FFF;
|
||||
} else {
|
||||
@@ -175,7 +176,7 @@ static inline int32_t mipsdsp_sat_add_i32(int32_t a, int32_t b,
|
||||
|
||||
tempI = a + b;
|
||||
|
||||
if (MIPSDSP_OVERFLOW(a, b, tempI, 0x80000000)) {
|
||||
if (MIPSDSP_OVERFLOW_ADD(a, b, tempI, 0x80000000)) {
|
||||
if (a > 0) {
|
||||
tempI = 0x7FFFFFFF;
|
||||
} else {
|
||||
@@ -516,13 +517,8 @@ static inline void mipsdsp_rndrashift_short_acc(int64_t *p,
|
||||
|
||||
acc = ((int64_t)env->active_tc.HI[ac] << 32) |
|
||||
((int64_t)env->active_tc.LO[ac] & 0xFFFFFFFF);
|
||||
if (shift == 0) {
|
||||
p[0] = acc << 1;
|
||||
p[1] = (acc >> 63) & 0x01;
|
||||
} else {
|
||||
p[0] = acc >> (shift - 1);
|
||||
p[1] = 0;
|
||||
}
|
||||
p[0] = (shift == 0) ? (acc << 1) : (acc >> (shift - 1));
|
||||
p[1] = (acc >> 63) & 0x01;
|
||||
}
|
||||
|
||||
/* 128 bits long. p[0] is LO, p[1] is HI */
|
||||
@@ -652,7 +648,7 @@ static inline int32_t mipsdsp_sat16_mul_q15_q15(uint16_t a, uint16_t b,
|
||||
temp = 0x7FFF0000;
|
||||
set_DSPControl_overflow_flag(1, 21, env);
|
||||
} else {
|
||||
temp = ((uint32_t)a * (uint32_t)b);
|
||||
temp = (int16_t)a * (int16_t)b;
|
||||
temp = temp << 1;
|
||||
}
|
||||
|
||||
@@ -858,7 +854,7 @@ static inline uint16_t mipsdsp_sub_i16(int16_t a, int16_t b, CPUMIPSState *env)
|
||||
int16_t temp;
|
||||
|
||||
temp = a - b;
|
||||
if (MIPSDSP_OVERFLOW(a, -b, temp, 0x8000)) {
|
||||
if (MIPSDSP_OVERFLOW_SUB(a, b, temp, 0x8000)) {
|
||||
set_DSPControl_overflow_flag(1, 20, env);
|
||||
}
|
||||
|
||||
@@ -871,8 +867,8 @@ static inline uint16_t mipsdsp_sat16_sub(int16_t a, int16_t b,
|
||||
int16_t temp;
|
||||
|
||||
temp = a - b;
|
||||
if (MIPSDSP_OVERFLOW(a, -b, temp, 0x8000)) {
|
||||
if (a > 0) {
|
||||
if (MIPSDSP_OVERFLOW_SUB(a, b, temp, 0x8000)) {
|
||||
if (a >= 0) {
|
||||
temp = 0x7FFF;
|
||||
} else {
|
||||
temp = 0x8000;
|
||||
@@ -889,8 +885,8 @@ static inline uint32_t mipsdsp_sat32_sub(int32_t a, int32_t b,
|
||||
int32_t temp;
|
||||
|
||||
temp = a - b;
|
||||
if (MIPSDSP_OVERFLOW(a, -b, temp, 0x80000000)) {
|
||||
if (a > 0) {
|
||||
if (MIPSDSP_OVERFLOW_SUB(a, b, temp, 0x80000000)) {
|
||||
if (a >= 0) {
|
||||
temp = 0x7FFFFFFF;
|
||||
} else {
|
||||
temp = 0x80000000;
|
||||
@@ -1004,7 +1000,7 @@ static inline uint32_t mipsdsp_sub32(int32_t a, int32_t b, CPUMIPSState *env)
|
||||
int32_t temp;
|
||||
|
||||
temp = a - b;
|
||||
if (MIPSDSP_OVERFLOW(a, -b, temp, 0x80000000)) {
|
||||
if (MIPSDSP_OVERFLOW_SUB(a, b, temp, 0x80000000)) {
|
||||
set_DSPControl_overflow_flag(1, 20, env);
|
||||
}
|
||||
|
||||
@@ -1017,7 +1013,7 @@ static inline int32_t mipsdsp_add_i32(int32_t a, int32_t b, CPUMIPSState *env)
|
||||
|
||||
temp = a + b;
|
||||
|
||||
if (MIPSDSP_OVERFLOW(a, b, temp, 0x80000000)) {
|
||||
if (MIPSDSP_OVERFLOW_ADD(a, b, temp, 0x80000000)) {
|
||||
set_DSPControl_overflow_flag(1, 20, env);
|
||||
}
|
||||
|
||||
@@ -2488,37 +2484,42 @@ DP_QH(dpsq_s_w_qh, 0, 1);
|
||||
#endif
|
||||
|
||||
#define DP_L_W(name, is_add) \
|
||||
void helper_##name(uint32_t ac, target_ulong rs, target_ulong rt, \
|
||||
CPUMIPSState *env) \
|
||||
{ \
|
||||
int32_t temp63; \
|
||||
int64_t dotp, acc; \
|
||||
uint64_t temp; \
|
||||
\
|
||||
dotp = mipsdsp_mul_q31_q31(ac, rs, rt, env); \
|
||||
acc = ((uint64_t)env->active_tc.HI[ac] << 32) | \
|
||||
((uint64_t)env->active_tc.LO[ac] & MIPSDSP_LLO); \
|
||||
if (!is_add) { \
|
||||
dotp = -dotp; \
|
||||
} \
|
||||
\
|
||||
temp = acc + dotp; \
|
||||
if (MIPSDSP_OVERFLOW((uint64_t)acc, (uint64_t)dotp, temp, \
|
||||
(0x01ull << 63))) { \
|
||||
temp63 = (temp >> 63) & 0x01; \
|
||||
if (temp63 == 1) { \
|
||||
temp = (0x01ull << 63) - 1; \
|
||||
} else { \
|
||||
temp = 0x01ull << 63; \
|
||||
} \
|
||||
\
|
||||
set_DSPControl_overflow_flag(1, 16 + ac, env); \
|
||||
} \
|
||||
\
|
||||
env->active_tc.HI[ac] = (target_long)(int32_t) \
|
||||
((temp & MIPSDSP_LHI) >> 32); \
|
||||
env->active_tc.LO[ac] = (target_long)(int32_t) \
|
||||
(temp & MIPSDSP_LLO); \
|
||||
void helper_##name(uint32_t ac, target_ulong rs, target_ulong rt, \
|
||||
CPUMIPSState *env) \
|
||||
{ \
|
||||
int32_t temp63; \
|
||||
int64_t dotp, acc; \
|
||||
uint64_t temp; \
|
||||
bool overflow; \
|
||||
\
|
||||
dotp = mipsdsp_mul_q31_q31(ac, rs, rt, env); \
|
||||
acc = ((uint64_t)env->active_tc.HI[ac] << 32) | \
|
||||
((uint64_t)env->active_tc.LO[ac] & MIPSDSP_LLO); \
|
||||
if (is_add) { \
|
||||
temp = acc + dotp; \
|
||||
overflow = MIPSDSP_OVERFLOW_ADD((uint64_t)acc, (uint64_t)dotp, \
|
||||
temp, (0x01ull << 63)); \
|
||||
} else { \
|
||||
temp = acc - dotp; \
|
||||
overflow = MIPSDSP_OVERFLOW_SUB((uint64_t)acc, (uint64_t)dotp, \
|
||||
temp, (0x01ull << 63)); \
|
||||
} \
|
||||
\
|
||||
if (overflow) { \
|
||||
temp63 = (temp >> 63) & 0x01; \
|
||||
if (temp63 == 1) { \
|
||||
temp = (0x01ull << 63) - 1; \
|
||||
} else { \
|
||||
temp = 0x01ull << 63; \
|
||||
} \
|
||||
\
|
||||
set_DSPControl_overflow_flag(1, 16 + ac, env); \
|
||||
} \
|
||||
\
|
||||
env->active_tc.HI[ac] = (target_long)(int32_t) \
|
||||
((temp & MIPSDSP_LHI) >> 32); \
|
||||
env->active_tc.LO[ac] = (target_long)(int32_t) \
|
||||
(temp & MIPSDSP_LLO); \
|
||||
}
|
||||
|
||||
DP_L_W(dpaq_sa_l_w, 1);
|
||||
@@ -2689,7 +2690,7 @@ MAQ_SA_W(maq_sa_w_phr, 0);
|
||||
target_ulong helper_##name(target_ulong rs, target_ulong rt, \
|
||||
CPUMIPSState *env) \
|
||||
{ \
|
||||
uint32_t rs_t, rt_t; \
|
||||
int32_t rs_t, rt_t; \
|
||||
int32_t tempI; \
|
||||
int64_t tempL; \
|
||||
\
|
||||
@@ -3155,8 +3156,8 @@ target_ulong helper_extr_w(target_ulong ac, target_ulong shift,
|
||||
tempDL[1] += 1;
|
||||
}
|
||||
|
||||
if ((!(tempDL[1] == 0 && (tempDL[0] & MIPSDSP_LHI) == 0x00)) &&
|
||||
(!(tempDL[1] == 1 && (tempDL[0] & MIPSDSP_LHI) == MIPSDSP_LHI))) {
|
||||
if (((tempDL[1] & 0x01) != 0 || (tempDL[0] & MIPSDSP_LHI) != 0) &&
|
||||
((tempDL[1] & 0x01) != 1 || (tempDL[0] & MIPSDSP_LHI) != MIPSDSP_LHI)) {
|
||||
set_DSPControl_overflow_flag(1, 23, env);
|
||||
}
|
||||
|
||||
@@ -3181,8 +3182,8 @@ target_ulong helper_extr_r_w(target_ulong ac, target_ulong shift,
|
||||
tempDL[1] += 1;
|
||||
}
|
||||
|
||||
if ((tempDL[1] != 0 || (tempDL[0] & MIPSDSP_LHI) != 0) &&
|
||||
(tempDL[1] != 1 && (tempDL[0] & MIPSDSP_LHI) != MIPSDSP_LHI)) {
|
||||
if (((tempDL[1] & 0x01) != 0 || (tempDL[0] & MIPSDSP_LHI) != 0) &&
|
||||
((tempDL[1] & 0x01) != 1 || (tempDL[0] & MIPSDSP_LHI) != MIPSDSP_LHI)) {
|
||||
set_DSPControl_overflow_flag(1, 23, env);
|
||||
}
|
||||
|
||||
@@ -3208,9 +3209,9 @@ target_ulong helper_extr_rs_w(target_ulong ac, target_ulong shift,
|
||||
}
|
||||
tempI = tempDL[0] >> 1;
|
||||
|
||||
if ((tempDL[1] != 0 || (tempDL[0] & MIPSDSP_LHI) != 0) &&
|
||||
(tempDL[1] != 1 || (tempDL[0] & MIPSDSP_LHI) != MIPSDSP_LHI)) {
|
||||
temp64 = tempDL[1];
|
||||
if (((tempDL[1] & 0x01) != 0 || (tempDL[0] & MIPSDSP_LHI) != 0) &&
|
||||
((tempDL[1] & 0x01) != 1 || (tempDL[0] & MIPSDSP_LHI) != MIPSDSP_LHI)) {
|
||||
temp64 = tempDL[1] & 0x01;
|
||||
if (temp64 == 0) {
|
||||
tempI = 0x7FFFFFFF;
|
||||
} else {
|
||||
|
||||
@@ -24,8 +24,8 @@ DEF_HELPER_FLAGS_1(clz, TCG_CALL_NO_RWG_SE, tl, tl)
|
||||
#ifdef TARGET_MIPS64
|
||||
DEF_HELPER_FLAGS_1(dclo, TCG_CALL_NO_RWG_SE, tl, tl)
|
||||
DEF_HELPER_FLAGS_1(dclz, TCG_CALL_NO_RWG_SE, tl, tl)
|
||||
DEF_HELPER_3(dmult, void, env, tl, tl)
|
||||
DEF_HELPER_3(dmultu, void, env, tl, tl)
|
||||
DEF_HELPER_4(dmult, void, env, tl, tl, int)
|
||||
DEF_HELPER_4(dmultu, void, env, tl, tl, int)
|
||||
#endif
|
||||
|
||||
DEF_HELPER_3(muls, tl, env, tl, tl)
|
||||
|
||||
@@ -268,14 +268,16 @@ target_ulong helper_mulshiu(CPUMIPSState *env, target_ulong arg1,
|
||||
}
|
||||
|
||||
#ifdef TARGET_MIPS64
|
||||
void helper_dmult(CPUMIPSState *env, target_ulong arg1, target_ulong arg2)
|
||||
void helper_dmult(CPUMIPSState *env, target_ulong arg1,
|
||||
target_ulong arg2, int acc)
|
||||
{
|
||||
muls64(&(env->active_tc.LO[0]), &(env->active_tc.HI[0]), arg1, arg2);
|
||||
muls64(&(env->active_tc.LO[acc]), &(env->active_tc.HI[acc]), arg1, arg2);
|
||||
}
|
||||
|
||||
void helper_dmultu(CPUMIPSState *env, target_ulong arg1, target_ulong arg2)
|
||||
void helper_dmultu(CPUMIPSState *env, target_ulong arg1,
|
||||
target_ulong arg2, int acc)
|
||||
{
|
||||
mulu64(&(env->active_tc.LO[0]), &(env->active_tc.HI[0]), arg1, arg2);
|
||||
mulu64(&(env->active_tc.LO[acc]), &(env->active_tc.HI[acc]), arg1, arg2);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
+64
-84
@@ -2582,10 +2582,9 @@ static void gen_shift(DisasContext *ctx, uint32_t opc,
|
||||
}
|
||||
|
||||
/* Arithmetic on HI/LO registers */
|
||||
static void gen_HILO (DisasContext *ctx, uint32_t opc, int reg)
|
||||
static void gen_HILO(DisasContext *ctx, uint32_t opc, int acc, int reg)
|
||||
{
|
||||
const char *opn = "hilo";
|
||||
unsigned int acc;
|
||||
|
||||
if (reg == 0 && (opc == OPC_MFHI || opc == OPC_MFLO)) {
|
||||
/* Treat as NOP. */
|
||||
@@ -2593,12 +2592,6 @@ static void gen_HILO (DisasContext *ctx, uint32_t opc, int reg)
|
||||
return;
|
||||
}
|
||||
|
||||
if (opc == OPC_MFHI || opc == OPC_MFLO) {
|
||||
acc = ((ctx->opcode) >> 21) & 0x03;
|
||||
} else {
|
||||
acc = ((ctx->opcode) >> 11) & 0x03;
|
||||
}
|
||||
|
||||
if (acc != 0) {
|
||||
check_dsp(ctx);
|
||||
}
|
||||
@@ -2661,12 +2654,11 @@ static void gen_HILO (DisasContext *ctx, uint32_t opc, int reg)
|
||||
MIPS_DEBUG("%s %s", opn, regnames[reg]);
|
||||
}
|
||||
|
||||
static void gen_muldiv (DisasContext *ctx, uint32_t opc,
|
||||
int rs, int rt)
|
||||
static void gen_muldiv(DisasContext *ctx, uint32_t opc,
|
||||
int acc, int rs, int rt)
|
||||
{
|
||||
const char *opn = "mul/div";
|
||||
TCGv t0, t1;
|
||||
unsigned int acc;
|
||||
|
||||
t0 = tcg_temp_new();
|
||||
t1 = tcg_temp_new();
|
||||
@@ -2674,6 +2666,10 @@ static void gen_muldiv (DisasContext *ctx, uint32_t opc,
|
||||
gen_load_gpr(t0, rs);
|
||||
gen_load_gpr(t1, rt);
|
||||
|
||||
if (acc != 0) {
|
||||
check_dsp(ctx);
|
||||
}
|
||||
|
||||
switch (opc) {
|
||||
case OPC_DIV:
|
||||
{
|
||||
@@ -2688,10 +2684,10 @@ static void gen_muldiv (DisasContext *ctx, uint32_t opc,
|
||||
tcg_gen_or_tl(t2, t2, t3);
|
||||
tcg_gen_movi_tl(t3, 0);
|
||||
tcg_gen_movcond_tl(TCG_COND_NE, t1, t2, t3, t2, t1);
|
||||
tcg_gen_div_tl(cpu_LO[0], t0, t1);
|
||||
tcg_gen_rem_tl(cpu_HI[0], t0, t1);
|
||||
tcg_gen_ext32s_tl(cpu_LO[0], cpu_LO[0]);
|
||||
tcg_gen_ext32s_tl(cpu_HI[0], cpu_HI[0]);
|
||||
tcg_gen_div_tl(cpu_LO[acc], t0, t1);
|
||||
tcg_gen_rem_tl(cpu_HI[acc], t0, t1);
|
||||
tcg_gen_ext32s_tl(cpu_LO[acc], cpu_LO[acc]);
|
||||
tcg_gen_ext32s_tl(cpu_HI[acc], cpu_HI[acc]);
|
||||
tcg_temp_free(t3);
|
||||
tcg_temp_free(t2);
|
||||
}
|
||||
@@ -2704,10 +2700,10 @@ static void gen_muldiv (DisasContext *ctx, uint32_t opc,
|
||||
tcg_gen_ext32u_tl(t0, t0);
|
||||
tcg_gen_ext32u_tl(t1, t1);
|
||||
tcg_gen_movcond_tl(TCG_COND_EQ, t1, t1, t2, t3, t1);
|
||||
tcg_gen_divu_tl(cpu_LO[0], t0, t1);
|
||||
tcg_gen_remu_tl(cpu_HI[0], t0, t1);
|
||||
tcg_gen_ext32s_tl(cpu_LO[0], cpu_LO[0]);
|
||||
tcg_gen_ext32s_tl(cpu_HI[0], cpu_HI[0]);
|
||||
tcg_gen_divu_tl(cpu_LO[acc], t0, t1);
|
||||
tcg_gen_remu_tl(cpu_HI[acc], t0, t1);
|
||||
tcg_gen_ext32s_tl(cpu_LO[acc], cpu_LO[acc]);
|
||||
tcg_gen_ext32s_tl(cpu_HI[acc], cpu_HI[acc]);
|
||||
tcg_temp_free(t3);
|
||||
tcg_temp_free(t2);
|
||||
}
|
||||
@@ -2717,11 +2713,6 @@ static void gen_muldiv (DisasContext *ctx, uint32_t opc,
|
||||
{
|
||||
TCGv_i64 t2 = tcg_temp_new_i64();
|
||||
TCGv_i64 t3 = tcg_temp_new_i64();
|
||||
acc = ((ctx->opcode) >> 11) & 0x03;
|
||||
if (acc != 0) {
|
||||
check_dsp(ctx);
|
||||
}
|
||||
|
||||
tcg_gen_ext_tl_i64(t2, t0);
|
||||
tcg_gen_ext_tl_i64(t3, t1);
|
||||
tcg_gen_mul_i64(t2, t2, t3);
|
||||
@@ -2739,11 +2730,6 @@ static void gen_muldiv (DisasContext *ctx, uint32_t opc,
|
||||
{
|
||||
TCGv_i64 t2 = tcg_temp_new_i64();
|
||||
TCGv_i64 t3 = tcg_temp_new_i64();
|
||||
acc = ((ctx->opcode) >> 11) & 0x03;
|
||||
if (acc != 0) {
|
||||
check_dsp(ctx);
|
||||
}
|
||||
|
||||
tcg_gen_ext32u_tl(t0, t0);
|
||||
tcg_gen_ext32u_tl(t1, t1);
|
||||
tcg_gen_extu_tl_i64(t2, t0);
|
||||
@@ -2771,8 +2757,8 @@ static void gen_muldiv (DisasContext *ctx, uint32_t opc,
|
||||
tcg_gen_or_tl(t2, t2, t3);
|
||||
tcg_gen_movi_tl(t3, 0);
|
||||
tcg_gen_movcond_tl(TCG_COND_NE, t1, t2, t3, t2, t1);
|
||||
tcg_gen_div_tl(cpu_LO[0], t0, t1);
|
||||
tcg_gen_rem_tl(cpu_HI[0], t0, t1);
|
||||
tcg_gen_div_tl(cpu_LO[acc], t0, t1);
|
||||
tcg_gen_rem_tl(cpu_HI[acc], t0, t1);
|
||||
tcg_temp_free(t3);
|
||||
tcg_temp_free(t2);
|
||||
}
|
||||
@@ -2783,19 +2769,19 @@ static void gen_muldiv (DisasContext *ctx, uint32_t opc,
|
||||
TCGv t2 = tcg_const_tl(0);
|
||||
TCGv t3 = tcg_const_tl(1);
|
||||
tcg_gen_movcond_tl(TCG_COND_EQ, t1, t1, t2, t3, t1);
|
||||
tcg_gen_divu_i64(cpu_LO[0], t0, t1);
|
||||
tcg_gen_remu_i64(cpu_HI[0], t0, t1);
|
||||
tcg_gen_divu_i64(cpu_LO[acc], t0, t1);
|
||||
tcg_gen_remu_i64(cpu_HI[acc], t0, t1);
|
||||
tcg_temp_free(t3);
|
||||
tcg_temp_free(t2);
|
||||
}
|
||||
opn = "ddivu";
|
||||
break;
|
||||
case OPC_DMULT:
|
||||
gen_helper_dmult(cpu_env, t0, t1);
|
||||
gen_helper_0e2i(dmult, t0, t1, acc);
|
||||
opn = "dmult";
|
||||
break;
|
||||
case OPC_DMULTU:
|
||||
gen_helper_dmultu(cpu_env, t0, t1);
|
||||
gen_helper_0e2i(dmultu, t0, t1, acc);
|
||||
opn = "dmultu";
|
||||
break;
|
||||
#endif
|
||||
@@ -2803,10 +2789,6 @@ static void gen_muldiv (DisasContext *ctx, uint32_t opc,
|
||||
{
|
||||
TCGv_i64 t2 = tcg_temp_new_i64();
|
||||
TCGv_i64 t3 = tcg_temp_new_i64();
|
||||
acc = ((ctx->opcode) >> 11) & 0x03;
|
||||
if (acc != 0) {
|
||||
check_dsp(ctx);
|
||||
}
|
||||
|
||||
tcg_gen_ext_tl_i64(t2, t0);
|
||||
tcg_gen_ext_tl_i64(t3, t1);
|
||||
@@ -2827,10 +2809,6 @@ static void gen_muldiv (DisasContext *ctx, uint32_t opc,
|
||||
{
|
||||
TCGv_i64 t2 = tcg_temp_new_i64();
|
||||
TCGv_i64 t3 = tcg_temp_new_i64();
|
||||
acc = ((ctx->opcode) >> 11) & 0x03;
|
||||
if (acc != 0) {
|
||||
check_dsp(ctx);
|
||||
}
|
||||
|
||||
tcg_gen_ext32u_tl(t0, t0);
|
||||
tcg_gen_ext32u_tl(t1, t1);
|
||||
@@ -2853,10 +2831,6 @@ static void gen_muldiv (DisasContext *ctx, uint32_t opc,
|
||||
{
|
||||
TCGv_i64 t2 = tcg_temp_new_i64();
|
||||
TCGv_i64 t3 = tcg_temp_new_i64();
|
||||
acc = ((ctx->opcode) >> 11) & 0x03;
|
||||
if (acc != 0) {
|
||||
check_dsp(ctx);
|
||||
}
|
||||
|
||||
tcg_gen_ext_tl_i64(t2, t0);
|
||||
tcg_gen_ext_tl_i64(t3, t1);
|
||||
@@ -2877,10 +2851,6 @@ static void gen_muldiv (DisasContext *ctx, uint32_t opc,
|
||||
{
|
||||
TCGv_i64 t2 = tcg_temp_new_i64();
|
||||
TCGv_i64 t3 = tcg_temp_new_i64();
|
||||
acc = ((ctx->opcode) >> 11) & 0x03;
|
||||
if (acc != 0) {
|
||||
check_dsp(ctx);
|
||||
}
|
||||
|
||||
tcg_gen_ext32u_tl(t0, t0);
|
||||
tcg_gen_ext32u_tl(t1, t1);
|
||||
@@ -10143,7 +10113,7 @@ static int decode_mips16_opc (CPUMIPSState *env, DisasContext *ctx,
|
||||
gen_logic(ctx, OPC_NOR, rx, ry, 0);
|
||||
break;
|
||||
case RR_MFHI:
|
||||
gen_HILO(ctx, OPC_MFHI, rx);
|
||||
gen_HILO(ctx, OPC_MFHI, 0, rx);
|
||||
break;
|
||||
case RR_CNVT:
|
||||
switch (cnvt_op) {
|
||||
@@ -10175,7 +10145,7 @@ static int decode_mips16_opc (CPUMIPSState *env, DisasContext *ctx,
|
||||
}
|
||||
break;
|
||||
case RR_MFLO:
|
||||
gen_HILO(ctx, OPC_MFLO, rx);
|
||||
gen_HILO(ctx, OPC_MFLO, 0, rx);
|
||||
break;
|
||||
#if defined (TARGET_MIPS64)
|
||||
case RR_DSRA:
|
||||
@@ -10196,33 +10166,33 @@ static int decode_mips16_opc (CPUMIPSState *env, DisasContext *ctx,
|
||||
break;
|
||||
#endif
|
||||
case RR_MULT:
|
||||
gen_muldiv(ctx, OPC_MULT, rx, ry);
|
||||
gen_muldiv(ctx, OPC_MULT, 0, rx, ry);
|
||||
break;
|
||||
case RR_MULTU:
|
||||
gen_muldiv(ctx, OPC_MULTU, rx, ry);
|
||||
gen_muldiv(ctx, OPC_MULTU, 0, rx, ry);
|
||||
break;
|
||||
case RR_DIV:
|
||||
gen_muldiv(ctx, OPC_DIV, rx, ry);
|
||||
gen_muldiv(ctx, OPC_DIV, 0, rx, ry);
|
||||
break;
|
||||
case RR_DIVU:
|
||||
gen_muldiv(ctx, OPC_DIVU, rx, ry);
|
||||
gen_muldiv(ctx, OPC_DIVU, 0, rx, ry);
|
||||
break;
|
||||
#if defined (TARGET_MIPS64)
|
||||
case RR_DMULT:
|
||||
check_mips_64(ctx);
|
||||
gen_muldiv(ctx, OPC_DMULT, rx, ry);
|
||||
gen_muldiv(ctx, OPC_DMULT, 0, rx, ry);
|
||||
break;
|
||||
case RR_DMULTU:
|
||||
check_mips_64(ctx);
|
||||
gen_muldiv(ctx, OPC_DMULTU, rx, ry);
|
||||
gen_muldiv(ctx, OPC_DMULTU, 0, rx, ry);
|
||||
break;
|
||||
case RR_DDIV:
|
||||
check_mips_64(ctx);
|
||||
gen_muldiv(ctx, OPC_DDIV, rx, ry);
|
||||
gen_muldiv(ctx, OPC_DDIV, 0, rx, ry);
|
||||
break;
|
||||
case RR_DDIVU:
|
||||
check_mips_64(ctx);
|
||||
gen_muldiv(ctx, OPC_DDIVU, rx, ry);
|
||||
gen_muldiv(ctx, OPC_DDIVU, 0, rx, ry);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
@@ -10931,11 +10901,11 @@ static void gen_pool16c_insn(DisasContext *ctx, int *is_branch)
|
||||
break;
|
||||
case MFHI16 + 0:
|
||||
case MFHI16 + 1:
|
||||
gen_HILO(ctx, OPC_MFHI, uMIPS_RS5(ctx->opcode));
|
||||
gen_HILO(ctx, OPC_MFHI, 0, uMIPS_RS5(ctx->opcode));
|
||||
break;
|
||||
case MFLO16 + 0:
|
||||
case MFLO16 + 1:
|
||||
gen_HILO(ctx, OPC_MFLO, uMIPS_RS5(ctx->opcode));
|
||||
gen_HILO(ctx, OPC_MFLO, 0, uMIPS_RS5(ctx->opcode));
|
||||
break;
|
||||
case BREAK16:
|
||||
generate_exception(ctx, EXCP_BREAK);
|
||||
@@ -11133,30 +11103,34 @@ static void gen_pool32axf (CPUMIPSState *env, DisasContext *ctx, int rt, int rs,
|
||||
break;
|
||||
case MULT:
|
||||
mips32_op = OPC_MULT;
|
||||
goto do_muldiv;
|
||||
goto do_mul;
|
||||
case MULTU:
|
||||
mips32_op = OPC_MULTU;
|
||||
goto do_muldiv;
|
||||
goto do_mul;
|
||||
case DIV:
|
||||
mips32_op = OPC_DIV;
|
||||
goto do_muldiv;
|
||||
goto do_div;
|
||||
case DIVU:
|
||||
mips32_op = OPC_DIVU;
|
||||
goto do_muldiv;
|
||||
goto do_div;
|
||||
do_div:
|
||||
check_insn(ctx, ISA_MIPS32);
|
||||
gen_muldiv(ctx, mips32_op, 0, rs, rt);
|
||||
break;
|
||||
case MADD:
|
||||
mips32_op = OPC_MADD;
|
||||
goto do_muldiv;
|
||||
goto do_mul;
|
||||
case MADDU:
|
||||
mips32_op = OPC_MADDU;
|
||||
goto do_muldiv;
|
||||
goto do_mul;
|
||||
case MSUB:
|
||||
mips32_op = OPC_MSUB;
|
||||
goto do_muldiv;
|
||||
goto do_mul;
|
||||
case MSUBU:
|
||||
mips32_op = OPC_MSUBU;
|
||||
do_muldiv:
|
||||
do_mul:
|
||||
check_insn(ctx, ISA_MIPS32);
|
||||
gen_muldiv(ctx, mips32_op, rs, rt);
|
||||
gen_muldiv(ctx, mips32_op, (ctx->opcode >> 14) & 3, rs, rt);
|
||||
break;
|
||||
default:
|
||||
goto pool32axf_invalid;
|
||||
@@ -11293,18 +11267,18 @@ static void gen_pool32axf (CPUMIPSState *env, DisasContext *ctx, int rt, int rs,
|
||||
}
|
||||
break;
|
||||
case 0x35:
|
||||
switch (minor) {
|
||||
switch (minor & 3) {
|
||||
case MFHI32:
|
||||
gen_HILO(ctx, OPC_MFHI, rs);
|
||||
gen_HILO(ctx, OPC_MFHI, minor >> 2, rs);
|
||||
break;
|
||||
case MFLO32:
|
||||
gen_HILO(ctx, OPC_MFLO, rs);
|
||||
gen_HILO(ctx, OPC_MFLO, minor >> 2, rs);
|
||||
break;
|
||||
case MTHI32:
|
||||
gen_HILO(ctx, OPC_MTHI, rs);
|
||||
gen_HILO(ctx, OPC_MTHI, minor >> 2, rs);
|
||||
break;
|
||||
case MTLO32:
|
||||
gen_HILO(ctx, OPC_MTLO, rs);
|
||||
gen_HILO(ctx, OPC_MTLO, minor >> 2, rs);
|
||||
break;
|
||||
default:
|
||||
goto pool32axf_invalid;
|
||||
@@ -14477,13 +14451,19 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx, int *is_branch)
|
||||
case OPC_XOR:
|
||||
gen_logic(ctx, op1, rd, rs, rt);
|
||||
break;
|
||||
case OPC_MULT ... OPC_DIVU:
|
||||
case OPC_MULT:
|
||||
case OPC_MULTU:
|
||||
if (sa) {
|
||||
check_insn(ctx, INSN_VR54XX);
|
||||
op1 = MASK_MUL_VR54XX(ctx->opcode);
|
||||
gen_mul_vr54xx(ctx, op1, rd, rs, rt);
|
||||
} else
|
||||
gen_muldiv(ctx, op1, rs, rt);
|
||||
} else {
|
||||
gen_muldiv(ctx, op1, rd & 3, rs, rt);
|
||||
}
|
||||
break;
|
||||
case OPC_DIV:
|
||||
case OPC_DIVU:
|
||||
gen_muldiv(ctx, op1, 0, rs, rt);
|
||||
break;
|
||||
case OPC_JR ... OPC_JALR:
|
||||
gen_compute_branch(ctx, op1, 4, rs, rd, sa);
|
||||
@@ -14495,11 +14475,11 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx, int *is_branch)
|
||||
break;
|
||||
case OPC_MFHI: /* Move from HI/LO */
|
||||
case OPC_MFLO:
|
||||
gen_HILO(ctx, op1, rd);
|
||||
gen_HILO(ctx, op1, rs & 3, rd);
|
||||
break;
|
||||
case OPC_MTHI:
|
||||
case OPC_MTLO: /* Move to HI/LO */
|
||||
gen_HILO(ctx, op1, rs);
|
||||
gen_HILO(ctx, op1, rd & 3, rs);
|
||||
break;
|
||||
case OPC_PMON: /* Pmon entry point, also R4010 selsl */
|
||||
#ifdef MIPS_STRICT_STANDARD
|
||||
@@ -14619,7 +14599,7 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx, int *is_branch)
|
||||
case OPC_DMULT ... OPC_DDIVU:
|
||||
check_insn(ctx, ISA_MIPS3);
|
||||
check_mips_64(ctx);
|
||||
gen_muldiv(ctx, op1, rs, rt);
|
||||
gen_muldiv(ctx, op1, 0, rs, rt);
|
||||
break;
|
||||
#endif
|
||||
default: /* Invalid */
|
||||
@@ -14634,7 +14614,7 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx, int *is_branch)
|
||||
case OPC_MADD ... OPC_MADDU: /* Multiply and add/sub */
|
||||
case OPC_MSUB ... OPC_MSUBU:
|
||||
check_insn(ctx, ISA_MIPS32);
|
||||
gen_muldiv(ctx, op1, rs, rt);
|
||||
gen_muldiv(ctx, op1, rd & 3, rs, rt);
|
||||
break;
|
||||
case OPC_MUL:
|
||||
gen_arith(ctx, op1, rd, rs, rt);
|
||||
|
||||
@@ -4916,11 +4916,6 @@ static void init_proc_603E (CPUPPCState *env)
|
||||
SPR_NOACCESS, SPR_NOACCESS,
|
||||
&spr_read_generic, &spr_write_generic,
|
||||
0x00000000);
|
||||
/* XXX : not implemented */
|
||||
spr_register(env, SPR_IABR, "IABR",
|
||||
SPR_NOACCESS, SPR_NOACCESS,
|
||||
&spr_read_generic, &spr_write_generic,
|
||||
0x00000000);
|
||||
/* Memory management */
|
||||
gen_low_BATs(env);
|
||||
gen_6xx_7xx_soft_tlb(env, 64, 2);
|
||||
@@ -7282,7 +7277,7 @@ enum {
|
||||
#define CPU_POWERPC_MPC8545E_v10 CPU_POWERPC_e500v2_v10
|
||||
#define CPU_POWERPC_MPC8545E_v20 CPU_POWERPC_e500v2_v20
|
||||
#define CPU_POWERPC_MPC8545E_v21 CPU_POWERPC_e500v2_v21
|
||||
#define CPU_POWERPC_MPC8547E CPU_POWERPC_MPC8545E_v21
|
||||
#define CPU_POWERPC_MPC8547E CPU_POWERPC_MPC8547E_v21
|
||||
#define CPU_POWERPC_MPC8547E_v10 CPU_POWERPC_e500v2_v10
|
||||
#define CPU_POWERPC_MPC8547E_v20 CPU_POWERPC_e500v2_v20
|
||||
#define CPU_POWERPC_MPC8547E_v21 CPU_POWERPC_e500v2_v21
|
||||
@@ -8243,7 +8238,7 @@ static const ppc_def_t ppc_defs[] = {
|
||||
/* PowerPC G2LE GP1 core */
|
||||
POWERPC_DEF("G2leGP1", CPU_POWERPC_G2LEgp1, G2LE),
|
||||
/* PowerPC G2LE GP3 core */
|
||||
POWERPC_DEF("G2leGP3", CPU_POWERPC_G2LEgp1, G2LE),
|
||||
POWERPC_DEF("G2leGP3", CPU_POWERPC_G2LEgp3, G2LE),
|
||||
/* PowerPC MPC603 microcontrollers */
|
||||
/* MPC8240 */
|
||||
POWERPC_DEF("MPC8240", CPU_POWERPC_MPC8240, 603E),
|
||||
|
||||
@@ -1024,6 +1024,7 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr,
|
||||
/* Simplify LT/GE comparisons vs zero to a single compare
|
||||
vs the high word of the input. */
|
||||
s->gen_opc_buf[op_index] = INDEX_op_setcond_i32;
|
||||
reset_temp(args[0]);
|
||||
gen_args[0] = args[0];
|
||||
gen_args[1] = args[2];
|
||||
gen_args[2] = args[4];
|
||||
|
||||
@@ -660,7 +660,54 @@ TCGv_i64 tcg_const_local_i64(int64_t val);
|
||||
|
||||
extern uint8_t *code_gen_prologue;
|
||||
|
||||
/* TCG targets may use a different definition of tcg_qemu_tb_exec. */
|
||||
/**
|
||||
* tcg_qemu_tb_exec:
|
||||
* @env: CPUArchState * for the CPU
|
||||
* @tb_ptr: address of generated code for the TB to execute
|
||||
*
|
||||
* Start executing code from a given translation block.
|
||||
* Where translation blocks have been linked, execution
|
||||
* may proceed from the given TB into successive ones.
|
||||
* Control eventually returns only when some action is needed
|
||||
* from the top-level loop: either control must pass to a TB
|
||||
* which has not yet been directly linked, or an asynchronous
|
||||
* event such as an interrupt needs handling.
|
||||
*
|
||||
* The return value is a pointer to the next TB to execute
|
||||
* (if known; otherwise zero). This pointer is assumed to be
|
||||
* 4-aligned, and the bottom two bits are used to return further
|
||||
* information:
|
||||
* 0, 1: the link between this TB and the next is via the specified
|
||||
* TB index (0 or 1). That is, we left the TB via (the equivalent
|
||||
* of) "goto_tb <index>". The main loop uses this to determine
|
||||
* how to link the TB just executed to the next.
|
||||
* 2: we are using instruction counting code generation, and we
|
||||
* did not start executing this TB because the instruction counter
|
||||
* would hit zero midway through it. In this case the next-TB pointer
|
||||
* returned is the TB we were about to execute, and the caller must
|
||||
* arrange to execute the remaining count of instructions.
|
||||
* 3: we stopped because the CPU's exit_request flag was set
|
||||
* (usually meaning that there is an interrupt that needs to be
|
||||
* handled). The next-TB pointer returned is the TB we were
|
||||
* about to execute when we noticed the pending exit request.
|
||||
*
|
||||
* If the bottom two bits indicate an exit-via-index then the CPU
|
||||
* state is correctly synchronised and ready for execution of the next
|
||||
* TB (and in particular the guest PC is the address to execute next).
|
||||
* Otherwise, we gave up on execution of this TB before it started, and
|
||||
* the caller must fix up the CPU state by calling cpu_pc_from_tb()
|
||||
* with the next-TB pointer we return.
|
||||
*
|
||||
* Note that TCG targets may use a different definition of tcg_qemu_tb_exec
|
||||
* to this default (which just calls the prologue.code emitted by
|
||||
* tcg_target_qemu_prologue()).
|
||||
*/
|
||||
#define TB_EXIT_MASK 3
|
||||
#define TB_EXIT_IDX0 0
|
||||
#define TB_EXIT_IDX1 1
|
||||
#define TB_EXIT_ICOUNT_EXPIRED 2
|
||||
#define TB_EXIT_REQUESTED 3
|
||||
|
||||
#if !defined(tcg_qemu_tb_exec)
|
||||
# define tcg_qemu_tb_exec(env, tb_ptr) \
|
||||
((tcg_target_ulong (*)(void *, void *))code_gen_prologue)(env, tb_ptr)
|
||||
|
||||
+1
-13
@@ -24,19 +24,7 @@ gcov-files-test-string-input-visitor-y = qapi/string-input-visitor.c
|
||||
check-unit-y += tests/test-string-output-visitor$(EXESUF)
|
||||
gcov-files-test-string-output-visitor-y = qapi/string-output-visitor.c
|
||||
check-unit-y += tests/test-coroutine$(EXESUF)
|
||||
ifeq ($(CONFIG_WIN32),y)
|
||||
gcov-files-test-coroutine-y = coroutine-win32.c
|
||||
else
|
||||
ifeq ($(CONFIG_UCONTEXT_COROUTINE),y)
|
||||
gcov-files-test-coroutine-y = coroutine-ucontext.c
|
||||
else
|
||||
ifeq ($(CONFIG_SIGALTSTACK_COROUTINE),y)
|
||||
gcov-files-test-coroutine-y = coroutine-sigaltstack.c
|
||||
else
|
||||
gcov-files-test-coroutine-y = coroutine-gthread.c
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
gcov-files-test-coroutine-y = coroutine-$(CONFIG_COROUTINE_BACKEND).c
|
||||
check-unit-y += tests/test-visitor-serialization$(EXESUF)
|
||||
check-unit-y += tests/test-iov$(EXESUF)
|
||||
gcov-files-test-iov-y = util/iov.c
|
||||
|
||||
Executable
+75
@@ -0,0 +1,75 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# Test qemu-img rebase with zero clusters
|
||||
#
|
||||
# Copyright (C) 2013 Red Hat, Inc.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
# creator
|
||||
owner=pbonzini@redhat.com
|
||||
|
||||
seq=`basename $0`
|
||||
echo "QA output created by $seq"
|
||||
|
||||
here=`pwd`
|
||||
tmp=/tmp/$$
|
||||
status=1 # failure is the default!
|
||||
|
||||
_cleanup()
|
||||
{
|
||||
_cleanup_test_img
|
||||
rm -f $TEST_IMG.old
|
||||
rm -f $TEST_IMG.new
|
||||
}
|
||||
trap "_cleanup; exit \$status" 0 1 2 3 15
|
||||
|
||||
# get standard environment, filters and checks
|
||||
. ./common.rc
|
||||
. ./common.filter
|
||||
|
||||
_supported_fmt qcow2 qed
|
||||
_supported_proto file
|
||||
_supported_os Linux
|
||||
|
||||
if test "$IMGFMT" = qcow2 && test $IMGOPTS = ""; then
|
||||
IMGOPTS=compat=1.1
|
||||
fi
|
||||
|
||||
echo
|
||||
echo "== Creating images =="
|
||||
|
||||
size=10M
|
||||
_make_test_img $size
|
||||
$QEMU_IO -c "write -P 0x40 0 1048576" $TEST_IMG | _filter_qemu_io
|
||||
mv $TEST_IMG $TEST_IMG.old
|
||||
|
||||
_make_test_img $size
|
||||
$QEMU_IO -c "write -P 0x5a 0 1048576" $TEST_IMG | _filter_qemu_io
|
||||
mv $TEST_IMG $TEST_IMG.new
|
||||
|
||||
_make_test_img -b $TEST_IMG.old $size
|
||||
$QEMU_IO -c "write -z 0 1048576" $TEST_IMG | _filter_qemu_io
|
||||
|
||||
echo
|
||||
echo "== Rebasing the image =="
|
||||
|
||||
$QEMU_IMG rebase -b $TEST_IMG.new $TEST_IMG
|
||||
$QEMU_IO -c "read -P 0x00 0 1048576" $TEST_IMG | _filter_qemu_io
|
||||
|
||||
# success, all done
|
||||
echo "*** done"
|
||||
rm -f $seq.full
|
||||
status=0
|
||||
@@ -0,0 +1,17 @@
|
||||
QA output created by 050
|
||||
|
||||
== Creating images ==
|
||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=10485760
|
||||
wrote 1048576/1048576 bytes at offset 0
|
||||
1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=10485760
|
||||
wrote 1048576/1048576 bytes at offset 0
|
||||
1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=10485760 backing_file='TEST_DIR/t.IMGFMT.old'
|
||||
wrote 1048576/1048576 bytes at offset 0
|
||||
1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
|
||||
== Rebasing the image ==
|
||||
read 1048576/1048576 bytes at offset 0
|
||||
1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
*** done
|
||||
@@ -54,3 +54,4 @@
|
||||
045 rw auto
|
||||
046 rw auto aio
|
||||
047 rw auto
|
||||
050 rw auto backing quick
|
||||
|
||||
+2
-2
@@ -387,8 +387,8 @@ int main(int argc, char **argv)
|
||||
qtest_add_func("/rtc/alarm-time", alarm_time);
|
||||
qtest_add_func("/rtc/set-year/20xx", set_year_20xx);
|
||||
qtest_add_func("/rtc/set-year/1980", set_year_1980);
|
||||
qtest_add_func("/rtc/register_b_set_flag", register_b_set_flag);
|
||||
qtest_add_func("/rtc/fuzz-registers", fuzz_registers);
|
||||
qtest_add_func("/rtc/misc/register_b_set_flag", register_b_set_flag);
|
||||
qtest_add_func("/rtc/misc/fuzz-registers", fuzz_registers);
|
||||
ret = g_test_run();
|
||||
|
||||
if (s) {
|
||||
|
||||
@@ -67,5 +67,28 @@ int main()
|
||||
assert(dsp == 0);
|
||||
assert(result == rt);
|
||||
|
||||
/* Clear dspcontrol */
|
||||
dsp = 0;
|
||||
__asm
|
||||
("wrdsp %0\n\t"
|
||||
:
|
||||
: "r"(dsp)
|
||||
);
|
||||
|
||||
ach = 0xFFFFFFFF;
|
||||
acl = 0xFFFFFFFF;
|
||||
result = 0;
|
||||
__asm
|
||||
("mthi %2, $ac1\n\t"
|
||||
"mtlo %3, $ac1\n\t"
|
||||
"extr_r.w %0, $ac1, 0x1F\n\t"
|
||||
"rddsp %1\n\t"
|
||||
: "=r"(rt), "=r"(dsp)
|
||||
: "r"(ach), "r"(acl)
|
||||
);
|
||||
dsp = (dsp >> 23) & 0x01;
|
||||
assert(dsp == 0);
|
||||
assert(result == rt);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -67,5 +67,51 @@ int main()
|
||||
assert(dsp == 0);
|
||||
assert(result == rt);
|
||||
|
||||
/* Clear dspcontrol */
|
||||
dsp = 0;
|
||||
__asm
|
||||
("wrdsp %0\n\t"
|
||||
:
|
||||
: "r"(dsp)
|
||||
);
|
||||
|
||||
ach = 0x80000000;
|
||||
acl = 0x00000000;
|
||||
result = 0x80000000;
|
||||
__asm
|
||||
("mthi %2, $ac1\n\t"
|
||||
"mtlo %3, $ac1\n\t"
|
||||
"extr_rs.w %0, $ac1, 0x1F\n\t"
|
||||
"rddsp %1\n\t"
|
||||
: "=r"(rt), "=r"(dsp)
|
||||
: "r"(ach), "r"(acl)
|
||||
);
|
||||
dsp = (dsp >> 23) & 0x01;
|
||||
assert(dsp == 1);
|
||||
assert(result == rt);
|
||||
|
||||
/* Clear dspcontrol */
|
||||
dsp = 0;
|
||||
__asm
|
||||
("wrdsp %0\n\t"
|
||||
:
|
||||
: "r"(dsp)
|
||||
);
|
||||
|
||||
ach = 0xFFFFFFFF;
|
||||
acl = 0xFFFFFFFF;
|
||||
result = 0;
|
||||
__asm
|
||||
("mthi %2, $ac1\n\t"
|
||||
"mtlo %3, $ac1\n\t"
|
||||
"extr_rs.w %0, $ac1, 0x1F\n\t"
|
||||
"rddsp %1\n\t"
|
||||
: "=r"(rt), "=r"(dsp)
|
||||
: "r"(ach), "r"(acl)
|
||||
);
|
||||
dsp = (dsp >> 23) & 0x01;
|
||||
assert(dsp == 0);
|
||||
assert(result == rt);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -67,5 +67,28 @@ int main()
|
||||
assert(dsp == 0);
|
||||
assert(result == rt);
|
||||
|
||||
/* Clear dspcontrol */
|
||||
dsp = 0;
|
||||
__asm
|
||||
("wrdsp %0\n\t"
|
||||
:
|
||||
: "r"(dsp)
|
||||
);
|
||||
|
||||
ach = 0xFFFFFFFF;
|
||||
acl = 0xFFFFFFFF;
|
||||
result = 0xFFFFFFFF;
|
||||
__asm
|
||||
("mthi %2, $ac1\n\t"
|
||||
"mtlo %3, $ac1\n\t"
|
||||
"extr.w %0, $ac1, 0x1F\n\t"
|
||||
"rddsp %1\n\t"
|
||||
: "=r"(rt), "=r"(dsp)
|
||||
: "r"(ach), "r"(acl)
|
||||
);
|
||||
dsp = (dsp >> 23) & 0x01;
|
||||
assert(dsp == 0);
|
||||
assert(result == rt);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -12,7 +12,8 @@ int main()
|
||||
resultdsp = 0x01;
|
||||
|
||||
__asm
|
||||
("subq_s.ph %0, %2, %3\n\t"
|
||||
("wrdsp $0\n\t"
|
||||
"subq_s.ph %0, %2, %3\n\t"
|
||||
"rddsp %1\n\t"
|
||||
: "=r"(rd), "=r"(dsp)
|
||||
: "r"(rs), "r"(rt)
|
||||
@@ -27,7 +28,24 @@ int main()
|
||||
resultdsp = 0x01;
|
||||
|
||||
__asm
|
||||
("subq_s.ph %0, %2, %3\n\t"
|
||||
("wrdsp $0\n\t"
|
||||
"subq_s.ph %0, %2, %3\n\t"
|
||||
"rddsp %1\n\t"
|
||||
: "=r"(rd), "=r"(dsp)
|
||||
: "r"(rs), "r"(rt)
|
||||
);
|
||||
dsp = (dsp >> 20) & 0x01;
|
||||
assert(dsp == resultdsp);
|
||||
assert(rd == result);
|
||||
|
||||
rs = 0x12340000;
|
||||
rt = 0x87658000;
|
||||
result = 0x7FFF7FFF;
|
||||
resultdsp = 0x01;
|
||||
|
||||
__asm
|
||||
("wrdsp $0\n\t"
|
||||
"subq_s.ph %0, %2, %3\n\t"
|
||||
"rddsp %1\n\t"
|
||||
: "=r"(rd), "=r"(dsp)
|
||||
: "r"(rs), "r"(rt)
|
||||
|
||||
@@ -12,7 +12,8 @@ int main()
|
||||
resultdsp = 0x01;
|
||||
|
||||
__asm
|
||||
("subq_s.w %0, %2, %3\n\t"
|
||||
("wrdsp $0\n\t"
|
||||
"subq_s.w %0, %2, %3\n\t"
|
||||
"rddsp %1\n\t"
|
||||
: "=r"(rd), "=r"(dsp)
|
||||
: "r"(rs), "r"(rt)
|
||||
@@ -24,10 +25,11 @@ int main()
|
||||
rs = 0x66666;
|
||||
rt = 0x55555;
|
||||
result = 0x11111;
|
||||
resultdsp = 0x01;
|
||||
resultdsp = 0x0;
|
||||
|
||||
__asm
|
||||
("subq_s.w %0, %2, %3\n\t"
|
||||
("wrdsp $0\n\t"
|
||||
"subq_s.w %0, %2, %3\n\t"
|
||||
"rddsp %1\n\t"
|
||||
: "=r"(rd), "=r"(dsp)
|
||||
: "r"(rs), "r"(rt)
|
||||
@@ -36,23 +38,37 @@ int main()
|
||||
assert(dsp == resultdsp);
|
||||
assert(rd == result);
|
||||
|
||||
|
||||
#if 0
|
||||
rs = 0x35555555;
|
||||
rt = 0xf5555555;
|
||||
result = 0x80000000;
|
||||
rs = 0x0;
|
||||
rt = 0x80000000;
|
||||
result = 0x7FFFFFFF;
|
||||
resultdsp = 0x01;
|
||||
|
||||
__asm
|
||||
("subq_s.w %0, %2, %3\n\t"
|
||||
("wrdsp $0\n\t"
|
||||
"subq_s.w %0, %2, %3\n\t"
|
||||
"rddsp %1\n\t"
|
||||
: "=r"(rd), "=r"(dsp)
|
||||
: "r"(rs), "r"(rt)
|
||||
);
|
||||
|
||||
dsp = (dsp >> 20) & 0x01;
|
||||
assert(dsp == resultdsp);
|
||||
assert(rd == result);
|
||||
#endif
|
||||
|
||||
rs = 0x80000000;
|
||||
rt = 0x80000000;
|
||||
result = 0;
|
||||
resultdsp = 0x00;
|
||||
|
||||
__asm
|
||||
("wrdsp $0\n\t"
|
||||
"subq_s.w %0, %2, %3\n\t"
|
||||
"rddsp %1\n\t"
|
||||
: "=r"(rd), "=r"(dsp)
|
||||
: "r"(rs), "r"(rt)
|
||||
);
|
||||
dsp = (dsp >> 20) & 0x01;
|
||||
assert(dsp == resultdsp);
|
||||
assert(rd == result);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ int main()
|
||||
|
||||
rs = 0x80001234;
|
||||
rt = 0x80004321;
|
||||
result = 0x80005555;
|
||||
result = 0x7FFFAAAB;
|
||||
|
||||
__asm
|
||||
("mulq_rs.w %0, %1, %2\n\t"
|
||||
|
||||
@@ -6,6 +6,21 @@ int main()
|
||||
int rd, rs, rt, dsp;
|
||||
int result, resultdsp;
|
||||
|
||||
rs = 0x80000000;
|
||||
rt = 0x0ffc0000;
|
||||
result = 0xF0040000;
|
||||
resultdsp = 0;
|
||||
|
||||
__asm
|
||||
("mulq_s.ph %0, %2, %3\n\t"
|
||||
"rddsp %1\n\t"
|
||||
: "=r"(rd), "=r"(dsp)
|
||||
: "r"(rs), "r"(rt)
|
||||
);
|
||||
dsp = (dsp >> 21) & 0x01;
|
||||
assert(rd == result);
|
||||
assert(dsp == resultdsp);
|
||||
|
||||
rs = 0x80001234;
|
||||
rt = 0x80004321;
|
||||
result = 0x7FFF098B;
|
||||
|
||||
@@ -8,7 +8,7 @@ int main()
|
||||
|
||||
rs = 0x80001234;
|
||||
rt = 0x80004321;
|
||||
result = 0x80005555;
|
||||
result = 0x7FFFAAAB;
|
||||
|
||||
__asm
|
||||
("mulq_s.w %0, %1, %2\n\t"
|
||||
|
||||
@@ -183,7 +183,7 @@ static void perf_nesting(void)
|
||||
double duration;
|
||||
|
||||
maxcycles = 100000000;
|
||||
maxnesting = 20000;
|
||||
maxnesting = 1000;
|
||||
Coroutine *root;
|
||||
NestData nd = {
|
||||
.n_enter = 0,
|
||||
|
||||
@@ -460,6 +460,7 @@ scsi_req_data(int target, int lun, int tag, int len) "target %d lun %d tag %d le
|
||||
scsi_req_data_canceled(int target, int lun, int tag, int len) "target %d lun %d tag %d len %d"
|
||||
scsi_req_dequeue(int target, int lun, int tag) "target %d lun %d tag %d"
|
||||
scsi_req_continue(int target, int lun, int tag) "target %d lun %d tag %d"
|
||||
scsi_req_continue_canceled(int target, int lun, int tag) "target %d lun %d tag %d"
|
||||
scsi_req_parsed(int target, int lun, int tag, int cmd, int mode, int xfer) "target %d lun %d tag %d command %d dir %d length %d"
|
||||
scsi_req_parsed_lba(int target, int lun, int tag, int cmd, uint64_t lba) "target %d lun %d tag %d command %d lba %"PRIu64
|
||||
scsi_req_parse_bad(int target, int lun, int tag, int cmd) "target %d lun %d tag %d command %d"
|
||||
|
||||
+4
-73
@@ -1310,10 +1310,10 @@ static void tb_link_page(TranslationBlock *tb, tb_page_addr_t phys_pc,
|
||||
/* check whether the given addr is in TCG generated code buffer or not */
|
||||
bool is_tcg_gen_code(uintptr_t tc_ptr)
|
||||
{
|
||||
/* This can be called during code generation, code_gen_buffer_max_size
|
||||
/* This can be called during code generation, code_gen_buffer_size
|
||||
is used instead of code_gen_ptr for upper boundary checking */
|
||||
return (tc_ptr >= (uintptr_t)code_gen_buffer &&
|
||||
tc_ptr < (uintptr_t)(code_gen_buffer + code_gen_buffer_max_size));
|
||||
tc_ptr < (uintptr_t)(code_gen_buffer + code_gen_buffer_size));
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1350,55 +1350,6 @@ static TranslationBlock *tb_find_pc(uintptr_t tc_ptr)
|
||||
return &tbs[m_max];
|
||||
}
|
||||
|
||||
static void tb_reset_jump_recursive(TranslationBlock *tb);
|
||||
|
||||
static inline void tb_reset_jump_recursive2(TranslationBlock *tb, int n)
|
||||
{
|
||||
TranslationBlock *tb1, *tb_next, **ptb;
|
||||
unsigned int n1;
|
||||
|
||||
tb1 = tb->jmp_next[n];
|
||||
if (tb1 != NULL) {
|
||||
/* find head of list */
|
||||
for (;;) {
|
||||
n1 = (uintptr_t)tb1 & 3;
|
||||
tb1 = (TranslationBlock *)((uintptr_t)tb1 & ~3);
|
||||
if (n1 == 2) {
|
||||
break;
|
||||
}
|
||||
tb1 = tb1->jmp_next[n1];
|
||||
}
|
||||
/* we are now sure now that tb jumps to tb1 */
|
||||
tb_next = tb1;
|
||||
|
||||
/* remove tb from the jmp_first list */
|
||||
ptb = &tb_next->jmp_first;
|
||||
for (;;) {
|
||||
tb1 = *ptb;
|
||||
n1 = (uintptr_t)tb1 & 3;
|
||||
tb1 = (TranslationBlock *)((uintptr_t)tb1 & ~3);
|
||||
if (n1 == n && tb1 == tb) {
|
||||
break;
|
||||
}
|
||||
ptb = &tb1->jmp_next[n1];
|
||||
}
|
||||
*ptb = tb->jmp_next[n];
|
||||
tb->jmp_next[n] = NULL;
|
||||
|
||||
/* suppress the jump to next tb in generated code */
|
||||
tb_reset_jump(tb, n);
|
||||
|
||||
/* suppress jumps in the tb on which we could have jumped */
|
||||
tb_reset_jump_recursive(tb_next);
|
||||
}
|
||||
}
|
||||
|
||||
static void tb_reset_jump_recursive(TranslationBlock *tb)
|
||||
{
|
||||
tb_reset_jump_recursive2(tb, 0);
|
||||
tb_reset_jump_recursive2(tb, 1);
|
||||
}
|
||||
|
||||
#if defined(TARGET_HAS_ICE) && !defined(CONFIG_USER_ONLY)
|
||||
void tb_invalidate_phys_addr(hwaddr addr)
|
||||
{
|
||||
@@ -1417,26 +1368,6 @@ void tb_invalidate_phys_addr(hwaddr addr)
|
||||
}
|
||||
#endif /* TARGET_HAS_ICE && !defined(CONFIG_USER_ONLY) */
|
||||
|
||||
void cpu_unlink_tb(CPUArchState *env)
|
||||
{
|
||||
/* FIXME: TB unchaining isn't SMP safe. For now just ignore the
|
||||
problem and hope the cpu will stop of its own accord. For userspace
|
||||
emulation this often isn't actually as bad as it sounds. Often
|
||||
signals are used primarily to interrupt blocking syscalls. */
|
||||
TranslationBlock *tb;
|
||||
static spinlock_t interrupt_lock = SPIN_LOCK_UNLOCKED;
|
||||
|
||||
spin_lock(&interrupt_lock);
|
||||
tb = env->current_tb;
|
||||
/* if the cpu is currently executing code, we must unlink it and
|
||||
all the potentially executing TB */
|
||||
if (tb) {
|
||||
env->current_tb = NULL;
|
||||
tb_reset_jump_recursive(tb);
|
||||
}
|
||||
spin_unlock(&interrupt_lock);
|
||||
}
|
||||
|
||||
void tb_check_watchpoint(CPUArchState *env)
|
||||
{
|
||||
TranslationBlock *tb;
|
||||
@@ -1476,7 +1407,7 @@ static void tcg_handle_interrupt(CPUArchState *env, int mask)
|
||||
cpu_abort(env, "Raised interrupt while not in I/O function");
|
||||
}
|
||||
} else {
|
||||
cpu_unlink_tb(env);
|
||||
env->tcg_exit_req = 1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1617,7 +1548,7 @@ void dump_exec_info(FILE *f, fprintf_function cpu_fprintf)
|
||||
void cpu_interrupt(CPUArchState *env, int mask)
|
||||
{
|
||||
env->interrupt_request |= mask;
|
||||
cpu_unlink_tb(env);
|
||||
env->tcg_exit_req = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
+7
-2
@@ -1339,11 +1339,16 @@ DisplaySurface *qemu_resize_displaysurface(DisplayState *ds,
|
||||
}
|
||||
|
||||
DisplaySurface *qemu_create_displaysurface_from(int width, int height, int bpp,
|
||||
int linesize, uint8_t *data)
|
||||
int linesize, uint8_t *data,
|
||||
bool byteswap)
|
||||
{
|
||||
DisplaySurface *surface = g_new0(DisplaySurface, 1);
|
||||
|
||||
surface->pf = qemu_default_pixelformat(bpp);
|
||||
if (byteswap) {
|
||||
surface->pf = qemu_different_endianness_pixelformat(bpp);
|
||||
} else {
|
||||
surface->pf = qemu_default_pixelformat(bpp);
|
||||
}
|
||||
|
||||
surface->format = qemu_pixman_get_format(&surface->pf);
|
||||
assert(surface->format != 0);
|
||||
|
||||
@@ -2726,7 +2726,7 @@ static void vnc_connect(VncDisplay *vd, int csock, int skipauth, bool websocket)
|
||||
|
||||
VNC_DEBUG("New client on socket %d\n", csock);
|
||||
dcl->idle = 0;
|
||||
socket_set_nonblock(vs->csock);
|
||||
qemu_set_nonblock(vs->csock);
|
||||
#ifdef CONFIG_VNC_WS
|
||||
if (websocket) {
|
||||
vs->websocket = 1;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user