Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1332b8dd43 | ||
|
|
07d46408cb | ||
|
|
dc5390a0ca | ||
|
|
7b4804c965 | ||
|
|
dfcbb9ef24 | ||
|
|
d5cf8bed29 | ||
|
|
5479d911bc | ||
|
|
5b5655fdb7 | ||
|
|
7e5f59326d | ||
|
|
f6abce29cc | ||
|
|
37751067b1 | ||
|
|
cb4c222add | ||
|
|
6fee9efc2e | ||
|
|
55b88e61ed | ||
|
|
cbae108098 | ||
|
|
125b95d79e | ||
|
|
bbdcc89678 | ||
|
|
8216663a5c | ||
|
|
51da750063 | ||
|
|
c513ee1b91 | ||
|
|
1a78b89bcf | ||
|
|
dd784cb65d | ||
|
|
fcbb086ae5 | ||
|
|
6e29509abc | ||
|
|
e2dfadfd07 | ||
|
|
1cfe45956e | ||
|
|
35a67d2aa8 | ||
|
|
9666bd2b79 | ||
|
|
4e6240e184 | ||
|
|
516bdbc234 | ||
|
|
1c5005c450 | ||
|
|
6e7e387b79 | ||
|
|
ab995895ad | ||
|
|
15b41461ea | ||
|
|
5d53ff200b | ||
|
|
4f01537ced | ||
|
|
fbeb0a160c | ||
|
|
1b2a52712b | ||
|
|
eb546a3f49 | ||
|
|
390da29ce5 | ||
|
|
0764b8a8e3 | ||
|
|
733511728a | ||
|
|
77e03229ca | ||
|
|
7fc1bcb65f | ||
|
|
be88ed87a6 | ||
|
|
c02844b8e8 | ||
|
|
196601e759 | ||
|
|
20cd0c8655 | ||
|
|
627aa460ba | ||
|
|
cd461c8445 | ||
|
|
b57b102a81 | ||
|
|
f7a1ff69ba | ||
|
|
6983d1657d | ||
|
|
46f03be3ed | ||
|
|
9c2b8194ac | ||
|
|
e961fa43e9 | ||
|
|
2702763548 | ||
|
|
2befb8a9c7 | ||
|
|
3168476965 | ||
|
|
35fface50f | ||
|
|
3cdfd68e4e | ||
|
|
d3e9e0fb29 | ||
|
|
12e4886108 | ||
|
|
1e4ec0958e | ||
|
|
38f36fc568 | ||
|
|
dc2abb61af | ||
|
|
6c49ccaaba | ||
|
|
b7ff2c5600 | ||
|
|
c4ed8c5610 | ||
|
|
43ca6c1a9b | ||
|
|
693ceca987 | ||
|
|
9f0db88ca9 | ||
|
|
bf26b6acc1 | ||
|
|
0041b5a014 | ||
|
|
783b2fc0a9 | ||
|
|
78bebf8692 | ||
|
|
eaa20895b7 | ||
|
|
edba203229 | ||
|
|
1652e5b97f | ||
|
|
80ccf1e485 | ||
|
|
73d604a4bc | ||
|
|
784ebe52bd | ||
|
|
ef9b43bb8e | ||
|
|
358dd25fb0 | ||
|
|
5b51920fbd | ||
|
|
242370f8bd | ||
|
|
b0a0ec47ba | ||
|
|
e3b3cff998 | ||
|
|
4dbeff3d48 | ||
|
|
ca52ee4a9b | ||
|
|
4a76c5665b | ||
|
|
de74e73d91 | ||
|
|
efbcf7cead | ||
|
|
f6f4703c5a | ||
|
|
cf794e4774 | ||
|
|
f8fb5928a8 | ||
|
|
de742b16b3 | ||
|
|
509525dc67 | ||
|
|
1ced8cd541 | ||
|
|
a85b8ec872 | ||
|
|
25bdc64b62 | ||
|
|
96ff214a2a | ||
|
|
2a1ce7c374 | ||
|
|
ddf4412bf4 | ||
|
|
a69a002dcd | ||
|
|
13fc21ae3d | ||
|
|
aee1039c61 | ||
|
|
0d835791f0 | ||
|
|
8996768ebc | ||
|
|
7820b9b7a0 | ||
|
|
b5c6660ea6 | ||
|
|
313e746958 | ||
|
|
98f3488c1b | ||
|
|
3097bcbf37 | ||
|
|
273111ca71 | ||
|
|
389f6655ca | ||
|
|
2d281e030d | ||
|
|
35ca0f7cbc | ||
|
|
31e20693ea | ||
|
|
0ba8be81f8 | ||
|
|
c440c89ecb | ||
|
|
6ad78a085e | ||
|
|
8f1eb52422 | ||
|
|
5ae5473e2e | ||
|
|
37a8b9205f | ||
|
|
5dc46b3ff8 | ||
|
|
4db93405e5 | ||
|
|
f0ae5d6d5f | ||
|
|
81c0ebf107 | ||
|
|
94b544f127 | ||
|
|
420a8d8735 | ||
|
|
151d593c7d | ||
|
|
16f1f95ebd | ||
|
|
eae7509be9 |
@@ -13,7 +13,7 @@
|
||||
.cirrus_build_job:
|
||||
extends: .base_job_template
|
||||
stage: build
|
||||
image: registry.gitlab.com/libvirt/libvirt-ci/cirrus-run:master
|
||||
image: registry.gitlab.com/libvirt/libvirt-ci/cirrus-run:latest
|
||||
needs: []
|
||||
# 20 mins larger than "timeout_in" in cirrus/build.yml
|
||||
# as there's often a 5-10 minute delay before Cirrus CI
|
||||
@@ -52,11 +52,12 @@ x64-freebsd-13-build:
|
||||
NAME: freebsd-13
|
||||
CIRRUS_VM_INSTANCE_TYPE: freebsd_instance
|
||||
CIRRUS_VM_IMAGE_SELECTOR: image_family
|
||||
CIRRUS_VM_IMAGE_NAME: freebsd-13-2
|
||||
CIRRUS_VM_IMAGE_NAME: freebsd-13-3
|
||||
CIRRUS_VM_CPUS: 8
|
||||
CIRRUS_VM_RAM: 8G
|
||||
UPDATE_COMMAND: pkg update; pkg upgrade -y
|
||||
INSTALL_COMMAND: pkg install -y
|
||||
CONFIGURE_ARGS: --target-list-exclude=arm-softmmu,i386-softmmu,microblaze-softmmu,mips64el-softmmu,mipsel-softmmu,mips-softmmu,ppc-softmmu,sh4eb-softmmu,xtensa-softmmu
|
||||
TEST_TARGETS: check
|
||||
|
||||
aarch64-macos-13-base-build:
|
||||
@@ -72,6 +73,7 @@ aarch64-macos-13-base-build:
|
||||
INSTALL_COMMAND: brew install
|
||||
PATH_EXTRA: /opt/homebrew/ccache/libexec:/opt/homebrew/gettext/bin
|
||||
PKG_CONFIG_PATH: /opt/homebrew/curl/lib/pkgconfig:/opt/homebrew/ncurses/lib/pkgconfig:/opt/homebrew/readline/lib/pkgconfig
|
||||
CONFIGURE_ARGS: --target-list-exclude=arm-softmmu,i386-softmmu,microblazeel-softmmu,mips64-softmmu,mipsel-softmmu,mips-softmmu,ppc-softmmu,sh4-softmmu,xtensaeb-softmmu
|
||||
TEST_TARGETS: check-unit check-block check-qapi-schema check-softfloat check-qtest-x86_64
|
||||
|
||||
aarch64-macos-14-base-build:
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "sysemu/cryptodev.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "qapi/error.h"
|
||||
#include "standard-headers/linux/virtio_crypto.h"
|
||||
#include "crypto/cipher.h"
|
||||
@@ -396,8 +397,8 @@ static int cryptodev_builtin_create_session(
|
||||
case VIRTIO_CRYPTO_HASH_CREATE_SESSION:
|
||||
case VIRTIO_CRYPTO_MAC_CREATE_SESSION:
|
||||
default:
|
||||
error_setg(&local_error, "Unsupported opcode :%" PRIu32 "",
|
||||
sess_info->op_code);
|
||||
error_report("Unsupported opcode :%" PRIu32 "",
|
||||
sess_info->op_code);
|
||||
return -VIRTIO_CRYPTO_NOTSUPP;
|
||||
}
|
||||
|
||||
@@ -427,7 +428,9 @@ static int cryptodev_builtin_close_session(
|
||||
CRYPTODEV_BACKEND_BUILTIN(backend);
|
||||
CryptoDevBackendBuiltinSession *session;
|
||||
|
||||
assert(session_id < MAX_NUM_SESSIONS && builtin->sessions[session_id]);
|
||||
if (session_id >= MAX_NUM_SESSIONS || !builtin->sessions[session_id]) {
|
||||
return -VIRTIO_CRYPTO_INVSESS;
|
||||
}
|
||||
|
||||
session = builtin->sessions[session_id];
|
||||
if (session->cipher) {
|
||||
@@ -552,8 +555,8 @@ static int cryptodev_builtin_operation(
|
||||
|
||||
if (op_info->session_id >= MAX_NUM_SESSIONS ||
|
||||
builtin->sessions[op_info->session_id] == NULL) {
|
||||
error_setg(&local_error, "Cannot find a valid session id: %" PRIu64 "",
|
||||
op_info->session_id);
|
||||
error_report("Cannot find a valid session id: %" PRIu64 "",
|
||||
op_info->session_id);
|
||||
return -VIRTIO_CRYPTO_INVSESS;
|
||||
}
|
||||
|
||||
|
||||
+7
-11
@@ -613,14 +613,14 @@ BlockDriverState *bdrv_next(BdrvNextIterator *it)
|
||||
/* Must be called from the main loop */
|
||||
assert(qemu_get_current_aio_context() == qemu_get_aio_context());
|
||||
|
||||
old_bs = it->bs;
|
||||
|
||||
/* First, return all root nodes of BlockBackends. In order to avoid
|
||||
* returning a BDS twice when multiple BBs refer to it, we only return it
|
||||
* if the BB is the first one in the parent list of the BDS. */
|
||||
if (it->phase == BDRV_NEXT_BACKEND_ROOTS) {
|
||||
BlockBackend *old_blk = it->blk;
|
||||
|
||||
old_bs = old_blk ? blk_bs(old_blk) : NULL;
|
||||
|
||||
do {
|
||||
it->blk = blk_all_next(it->blk);
|
||||
bs = it->blk ? blk_bs(it->blk) : NULL;
|
||||
@@ -634,11 +634,10 @@ BlockDriverState *bdrv_next(BdrvNextIterator *it)
|
||||
if (bs) {
|
||||
bdrv_ref(bs);
|
||||
bdrv_unref(old_bs);
|
||||
it->bs = bs;
|
||||
return bs;
|
||||
}
|
||||
it->phase = BDRV_NEXT_MONITOR_OWNED;
|
||||
} else {
|
||||
old_bs = it->bs;
|
||||
}
|
||||
|
||||
/* Then return the monitor-owned BDSes without a BB attached. Ignore all
|
||||
@@ -678,13 +677,10 @@ void bdrv_next_cleanup(BdrvNextIterator *it)
|
||||
/* Must be called from the main loop */
|
||||
assert(qemu_get_current_aio_context() == qemu_get_aio_context());
|
||||
|
||||
if (it->phase == BDRV_NEXT_BACKEND_ROOTS) {
|
||||
if (it->blk) {
|
||||
bdrv_unref(blk_bs(it->blk));
|
||||
blk_unref(it->blk);
|
||||
}
|
||||
} else {
|
||||
bdrv_unref(it->bs);
|
||||
bdrv_unref(it->bs);
|
||||
|
||||
if (it->phase == BDRV_NEXT_BACKEND_ROOTS && it->blk) {
|
||||
blk_unref(it->blk);
|
||||
}
|
||||
|
||||
bdrv_next_reset(it);
|
||||
|
||||
+19
-12
@@ -1756,22 +1756,29 @@ static int bdrv_pad_request(BlockDriverState *bs,
|
||||
return 0;
|
||||
}
|
||||
|
||||
sliced_iov = qemu_iovec_slice(*qiov, *qiov_offset, *bytes,
|
||||
&sliced_head, &sliced_tail,
|
||||
&sliced_niov);
|
||||
/*
|
||||
* For prefetching in stream_populate(), no qiov is passed along, because
|
||||
* only copy-on-read matters.
|
||||
*/
|
||||
if (qiov && *qiov) {
|
||||
sliced_iov = qemu_iovec_slice(*qiov, *qiov_offset, *bytes,
|
||||
&sliced_head, &sliced_tail,
|
||||
&sliced_niov);
|
||||
|
||||
/* Guaranteed by bdrv_check_request32() */
|
||||
assert(*bytes <= SIZE_MAX);
|
||||
ret = bdrv_create_padded_qiov(bs, pad, sliced_iov, sliced_niov,
|
||||
sliced_head, *bytes);
|
||||
if (ret < 0) {
|
||||
bdrv_padding_finalize(pad);
|
||||
return ret;
|
||||
/* Guaranteed by bdrv_check_request32() */
|
||||
assert(*bytes <= SIZE_MAX);
|
||||
ret = bdrv_create_padded_qiov(bs, pad, sliced_iov, sliced_niov,
|
||||
sliced_head, *bytes);
|
||||
if (ret < 0) {
|
||||
bdrv_padding_finalize(pad);
|
||||
return ret;
|
||||
}
|
||||
*qiov = &pad->local_qiov;
|
||||
*qiov_offset = 0;
|
||||
}
|
||||
|
||||
*bytes += pad->head + pad->tail;
|
||||
*offset -= pad->head;
|
||||
*qiov = &pad->local_qiov;
|
||||
*qiov_offset = 0;
|
||||
if (padded) {
|
||||
*padded = true;
|
||||
}
|
||||
|
||||
+6
-4
@@ -479,9 +479,9 @@ static unsigned mirror_perform(MirrorBlockJob *s, int64_t offset,
|
||||
return bytes_handled;
|
||||
}
|
||||
|
||||
static void coroutine_fn GRAPH_RDLOCK mirror_iteration(MirrorBlockJob *s)
|
||||
static void coroutine_fn GRAPH_UNLOCKED mirror_iteration(MirrorBlockJob *s)
|
||||
{
|
||||
BlockDriverState *source = s->mirror_top_bs->backing->bs;
|
||||
BlockDriverState *source;
|
||||
MirrorOp *pseudo_op;
|
||||
int64_t offset;
|
||||
/* At least the first dirty chunk is mirrored in one iteration. */
|
||||
@@ -489,6 +489,10 @@ static void coroutine_fn GRAPH_RDLOCK mirror_iteration(MirrorBlockJob *s)
|
||||
bool write_zeroes_ok = bdrv_can_write_zeroes_with_unmap(blk_bs(s->target));
|
||||
int max_io_bytes = MAX(s->buf_size / MAX_IN_FLIGHT, MAX_IO_BYTES);
|
||||
|
||||
bdrv_graph_co_rdlock();
|
||||
source = s->mirror_top_bs->backing->bs;
|
||||
bdrv_graph_co_rdunlock();
|
||||
|
||||
bdrv_dirty_bitmap_lock(s->dirty_bitmap);
|
||||
offset = bdrv_dirty_iter_next(s->dbi);
|
||||
if (offset < 0) {
|
||||
@@ -1078,9 +1082,7 @@ static int coroutine_fn mirror_run(Job *job, Error **errp)
|
||||
mirror_wait_for_free_in_flight_slot(s);
|
||||
continue;
|
||||
} else if (cnt != 0) {
|
||||
bdrv_graph_co_rdlock();
|
||||
mirror_iteration(s);
|
||||
bdrv_graph_co_rdunlock();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -492,9 +492,9 @@ static gboolean tcp_chr_read(QIOChannel *chan, GIOCondition cond, void *opaque)
|
||||
s->max_size <= 0) {
|
||||
return TRUE;
|
||||
}
|
||||
len = tcp_chr_read_poll(opaque);
|
||||
if (len > sizeof(buf)) {
|
||||
len = sizeof(buf);
|
||||
len = sizeof(buf);
|
||||
if (len > s->max_size) {
|
||||
len = s->max_size;
|
||||
}
|
||||
size = tcp_chr_recv(chr, (void *)buf, len);
|
||||
if (size == 0 || (size == -1 && errno != EAGAIN)) {
|
||||
|
||||
@@ -1676,7 +1676,7 @@ mkdir -p tests/tcg
|
||||
echo "# Automatically generated by configure - do not modify" > $config_host_mak
|
||||
echo "SRC_PATH=$source_path" >> $config_host_mak
|
||||
if test "$plugins" = "yes" ; then
|
||||
echo "CONFIG_PLUGIN=y" >> tests/tcg/$config_host_mak
|
||||
echo "CONFIG_PLUGIN=y" >> $config_host_mak
|
||||
fi
|
||||
|
||||
tcg_tests_targets=
|
||||
|
||||
+4
-6
@@ -29,7 +29,6 @@
|
||||
import os
|
||||
import sys
|
||||
import sphinx
|
||||
from distutils.version import LooseVersion
|
||||
from sphinx.errors import ConfigError
|
||||
|
||||
# The per-manual conf.py will set qemu_docdir for a single-manual build;
|
||||
@@ -165,11 +164,10 @@ html_theme = 'sphinx_rtd_theme'
|
||||
# Theme options are theme-specific and customize the look and feel of a theme
|
||||
# further. For a list of options available for each theme, see the
|
||||
# documentation.
|
||||
if LooseVersion(sphinx_rtd_theme.__version__) >= LooseVersion("0.4.3"):
|
||||
html_theme_options = {
|
||||
"style_nav_header_background": "#802400",
|
||||
"navigation_with_keys": True,
|
||||
}
|
||||
html_theme_options = {
|
||||
"style_nav_header_background": "#802400",
|
||||
"navigation_with_keys": True,
|
||||
}
|
||||
|
||||
html_logo = os.path.join(qemu_docdir, "../ui/icons/qemu_128x128.png")
|
||||
|
||||
|
||||
+5
-1
@@ -78,6 +78,7 @@ static void build_hmat_lb(GArray *table_data, HMAT_LB_Info *hmat_lb,
|
||||
uint32_t *initiator_list)
|
||||
{
|
||||
int i, index;
|
||||
uint32_t initiator_to_index[MAX_NODES] = {};
|
||||
HMAT_LB_Data *lb_data;
|
||||
uint16_t *entry_list;
|
||||
uint32_t base;
|
||||
@@ -121,6 +122,8 @@ static void build_hmat_lb(GArray *table_data, HMAT_LB_Info *hmat_lb,
|
||||
/* Initiator Proximity Domain List */
|
||||
for (i = 0; i < num_initiator; i++) {
|
||||
build_append_int_noprefix(table_data, initiator_list[i], 4);
|
||||
/* Reverse mapping for array possitions */
|
||||
initiator_to_index[initiator_list[i]] = i;
|
||||
}
|
||||
|
||||
/* Target Proximity Domain List */
|
||||
@@ -132,7 +135,8 @@ static void build_hmat_lb(GArray *table_data, HMAT_LB_Info *hmat_lb,
|
||||
entry_list = g_new0(uint16_t, num_initiator * num_target);
|
||||
for (i = 0; i < hmat_lb->list->len; i++) {
|
||||
lb_data = &g_array_index(hmat_lb->list, HMAT_LB_Data, i);
|
||||
index = lb_data->initiator * num_target + lb_data->target;
|
||||
index = initiator_to_index[lb_data->initiator] * num_target +
|
||||
lb_data->target;
|
||||
|
||||
entry_list[index] = (uint16_t)(lb_data->data / hmat_lb->base);
|
||||
}
|
||||
|
||||
+2
-1
@@ -24,6 +24,7 @@
|
||||
#include "hw/qdev-clock.h"
|
||||
#include "hw/qdev-properties.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qemu/bswap.h"
|
||||
#include "qemu/units.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
|
||||
@@ -377,7 +378,7 @@ static void npcm7xx_init_fuses(NPCM7xxState *s)
|
||||
* The initial mask of disabled modules indicates the chip derivative (e.g.
|
||||
* NPCM750 or NPCM730).
|
||||
*/
|
||||
value = tswap32(nc->disabled_modules);
|
||||
value = cpu_to_le32(nc->disabled_modules);
|
||||
npcm7xx_otp_array_write(&s->fuse_array, &value, NPCM7XX_FUSE_DERIVATIVE,
|
||||
sizeof(value));
|
||||
}
|
||||
|
||||
+65
-71
@@ -243,12 +243,13 @@ static void virtio_snd_handle_pcm_info(VirtIOSound *s,
|
||||
memset(&pcm_info[i].padding, 0, 5);
|
||||
}
|
||||
|
||||
cmd->payload_size = sizeof(virtio_snd_pcm_info) * count;
|
||||
cmd->resp.code = cpu_to_le32(VIRTIO_SND_S_OK);
|
||||
iov_from_buf(cmd->elem->in_sg,
|
||||
cmd->elem->in_num,
|
||||
sizeof(virtio_snd_hdr),
|
||||
pcm_info,
|
||||
sizeof(virtio_snd_pcm_info) * count);
|
||||
cmd->payload_size);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -455,7 +456,6 @@ static uint32_t virtio_snd_pcm_prepare(VirtIOSound *s, uint32_t stream_id)
|
||||
stream->s = s;
|
||||
qemu_mutex_init(&stream->queue_mutex);
|
||||
QSIMPLEQ_INIT(&stream->queue);
|
||||
QSIMPLEQ_INIT(&stream->invalid);
|
||||
|
||||
/*
|
||||
* stream_id >= s->snd_conf.streams was checked before so this is
|
||||
@@ -610,9 +610,6 @@ static size_t virtio_snd_pcm_get_io_msgs_count(VirtIOSoundPCMStream *stream)
|
||||
QSIMPLEQ_FOREACH_SAFE(buffer, &stream->queue, entry, next) {
|
||||
count += 1;
|
||||
}
|
||||
QSIMPLEQ_FOREACH_SAFE(buffer, &stream->invalid, entry, next) {
|
||||
count += 1;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
@@ -749,7 +746,8 @@ process_cmd(VirtIOSound *s, virtio_snd_ctrl_command *cmd)
|
||||
0,
|
||||
&cmd->resp,
|
||||
sizeof(virtio_snd_hdr));
|
||||
virtqueue_push(cmd->vq, cmd->elem, sizeof(virtio_snd_hdr));
|
||||
virtqueue_push(cmd->vq, cmd->elem,
|
||||
sizeof(virtio_snd_hdr) + cmd->payload_size);
|
||||
virtio_notify(VIRTIO_DEVICE(s), cmd->vq);
|
||||
}
|
||||
|
||||
@@ -808,6 +806,7 @@ static void virtio_snd_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq)
|
||||
cmd->elem = elem;
|
||||
cmd->vq = vq;
|
||||
cmd->resp.code = cpu_to_le32(VIRTIO_SND_S_OK);
|
||||
/* implicit cmd->payload_size = 0; */
|
||||
QTAILQ_INSERT_TAIL(&s->cmdq, cmd, next);
|
||||
elem = virtqueue_pop(vq, sizeof(VirtQueueElement));
|
||||
}
|
||||
@@ -828,47 +827,36 @@ static void virtio_snd_handle_event(VirtIODevice *vdev, VirtQueue *vq)
|
||||
trace_virtio_snd_handle_event();
|
||||
}
|
||||
|
||||
/*
|
||||
* Must only be called if vsnd->invalid is not empty.
|
||||
*/
|
||||
static inline void empty_invalid_queue(VirtIODevice *vdev, VirtQueue *vq)
|
||||
{
|
||||
VirtIOSoundPCMBuffer *buffer = NULL;
|
||||
VirtIOSoundPCMStream *stream = NULL;
|
||||
virtio_snd_pcm_status resp = { 0 };
|
||||
VirtIOSound *vsnd = VIRTIO_SND(vdev);
|
||||
bool any = false;
|
||||
|
||||
for (uint32_t i = 0; i < vsnd->snd_conf.streams; i++) {
|
||||
stream = vsnd->pcm->streams[i];
|
||||
if (stream) {
|
||||
any = false;
|
||||
WITH_QEMU_LOCK_GUARD(&stream->queue_mutex) {
|
||||
while (!QSIMPLEQ_EMPTY(&stream->invalid)) {
|
||||
buffer = QSIMPLEQ_FIRST(&stream->invalid);
|
||||
if (buffer->vq != vq) {
|
||||
break;
|
||||
}
|
||||
any = true;
|
||||
resp.status = cpu_to_le32(VIRTIO_SND_S_BAD_MSG);
|
||||
iov_from_buf(buffer->elem->in_sg,
|
||||
buffer->elem->in_num,
|
||||
0,
|
||||
&resp,
|
||||
sizeof(virtio_snd_pcm_status));
|
||||
virtqueue_push(vq,
|
||||
buffer->elem,
|
||||
sizeof(virtio_snd_pcm_status));
|
||||
QSIMPLEQ_REMOVE_HEAD(&stream->invalid, entry);
|
||||
virtio_snd_pcm_buffer_free(buffer);
|
||||
}
|
||||
if (any) {
|
||||
/*
|
||||
* Notify vq about virtio_snd_pcm_status responses.
|
||||
* Buffer responses must be notified separately later.
|
||||
*/
|
||||
virtio_notify(vdev, vq);
|
||||
}
|
||||
}
|
||||
}
|
||||
g_assert(!QSIMPLEQ_EMPTY(&vsnd->invalid));
|
||||
|
||||
while (!QSIMPLEQ_EMPTY(&vsnd->invalid)) {
|
||||
buffer = QSIMPLEQ_FIRST(&vsnd->invalid);
|
||||
/* If buffer->vq != vq, our logic is fundamentally wrong, so bail out */
|
||||
g_assert(buffer->vq == vq);
|
||||
|
||||
resp.status = cpu_to_le32(VIRTIO_SND_S_BAD_MSG);
|
||||
iov_from_buf(buffer->elem->in_sg,
|
||||
buffer->elem->in_num,
|
||||
0,
|
||||
&resp,
|
||||
sizeof(virtio_snd_pcm_status));
|
||||
virtqueue_push(vq,
|
||||
buffer->elem,
|
||||
sizeof(virtio_snd_pcm_status));
|
||||
QSIMPLEQ_REMOVE_HEAD(&vsnd->invalid, entry);
|
||||
virtio_snd_pcm_buffer_free(buffer);
|
||||
}
|
||||
/* Notify vq about virtio_snd_pcm_status responses. */
|
||||
virtio_notify(vdev, vq);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -880,15 +868,14 @@ static inline void empty_invalid_queue(VirtIODevice *vdev, VirtQueue *vq)
|
||||
*/
|
||||
static void virtio_snd_handle_tx_xfer(VirtIODevice *vdev, VirtQueue *vq)
|
||||
{
|
||||
VirtIOSound *s = VIRTIO_SND(vdev);
|
||||
VirtIOSoundPCMStream *stream = NULL;
|
||||
VirtIOSound *vsnd = VIRTIO_SND(vdev);
|
||||
VirtIOSoundPCMBuffer *buffer;
|
||||
VirtQueueElement *elem;
|
||||
size_t msg_sz, size;
|
||||
virtio_snd_pcm_xfer hdr;
|
||||
uint32_t stream_id;
|
||||
/*
|
||||
* If any of the I/O messages are invalid, put them in stream->invalid and
|
||||
* If any of the I/O messages are invalid, put them in vsnd->invalid and
|
||||
* return them after the for loop.
|
||||
*/
|
||||
bool must_empty_invalid_queue = false;
|
||||
@@ -899,6 +886,8 @@ static void virtio_snd_handle_tx_xfer(VirtIODevice *vdev, VirtQueue *vq)
|
||||
trace_virtio_snd_handle_tx_xfer();
|
||||
|
||||
for (;;) {
|
||||
VirtIOSoundPCMStream *stream;
|
||||
|
||||
elem = virtqueue_pop(vq, sizeof(VirtQueueElement));
|
||||
if (!elem) {
|
||||
break;
|
||||
@@ -914,12 +903,12 @@ static void virtio_snd_handle_tx_xfer(VirtIODevice *vdev, VirtQueue *vq)
|
||||
}
|
||||
stream_id = le32_to_cpu(hdr.stream_id);
|
||||
|
||||
if (stream_id >= s->snd_conf.streams
|
||||
|| s->pcm->streams[stream_id] == NULL) {
|
||||
if (stream_id >= vsnd->snd_conf.streams
|
||||
|| vsnd->pcm->streams[stream_id] == NULL) {
|
||||
goto tx_err;
|
||||
}
|
||||
|
||||
stream = s->pcm->streams[stream_id];
|
||||
stream = vsnd->pcm->streams[stream_id];
|
||||
if (stream->info.direction != VIRTIO_SND_D_OUTPUT) {
|
||||
goto tx_err;
|
||||
}
|
||||
@@ -939,13 +928,11 @@ static void virtio_snd_handle_tx_xfer(VirtIODevice *vdev, VirtQueue *vq)
|
||||
continue;
|
||||
|
||||
tx_err:
|
||||
WITH_QEMU_LOCK_GUARD(&stream->queue_mutex) {
|
||||
must_empty_invalid_queue = true;
|
||||
buffer = g_malloc0(sizeof(VirtIOSoundPCMBuffer));
|
||||
buffer->elem = elem;
|
||||
buffer->vq = vq;
|
||||
QSIMPLEQ_INSERT_TAIL(&stream->invalid, buffer, entry);
|
||||
}
|
||||
must_empty_invalid_queue = true;
|
||||
buffer = g_malloc0(sizeof(VirtIOSoundPCMBuffer));
|
||||
buffer->elem = elem;
|
||||
buffer->vq = vq;
|
||||
QSIMPLEQ_INSERT_TAIL(&vsnd->invalid, buffer, entry);
|
||||
}
|
||||
|
||||
if (must_empty_invalid_queue) {
|
||||
@@ -962,15 +949,14 @@ tx_err:
|
||||
*/
|
||||
static void virtio_snd_handle_rx_xfer(VirtIODevice *vdev, VirtQueue *vq)
|
||||
{
|
||||
VirtIOSound *s = VIRTIO_SND(vdev);
|
||||
VirtIOSoundPCMStream *stream = NULL;
|
||||
VirtIOSound *vsnd = VIRTIO_SND(vdev);
|
||||
VirtIOSoundPCMBuffer *buffer;
|
||||
VirtQueueElement *elem;
|
||||
size_t msg_sz, size;
|
||||
virtio_snd_pcm_xfer hdr;
|
||||
uint32_t stream_id;
|
||||
/*
|
||||
* if any of the I/O messages are invalid, put them in stream->invalid and
|
||||
* if any of the I/O messages are invalid, put them in vsnd->invalid and
|
||||
* return them after the for loop.
|
||||
*/
|
||||
bool must_empty_invalid_queue = false;
|
||||
@@ -981,6 +967,8 @@ static void virtio_snd_handle_rx_xfer(VirtIODevice *vdev, VirtQueue *vq)
|
||||
trace_virtio_snd_handle_rx_xfer();
|
||||
|
||||
for (;;) {
|
||||
VirtIOSoundPCMStream *stream;
|
||||
|
||||
elem = virtqueue_pop(vq, sizeof(VirtQueueElement));
|
||||
if (!elem) {
|
||||
break;
|
||||
@@ -996,12 +984,12 @@ static void virtio_snd_handle_rx_xfer(VirtIODevice *vdev, VirtQueue *vq)
|
||||
}
|
||||
stream_id = le32_to_cpu(hdr.stream_id);
|
||||
|
||||
if (stream_id >= s->snd_conf.streams
|
||||
|| !s->pcm->streams[stream_id]) {
|
||||
if (stream_id >= vsnd->snd_conf.streams
|
||||
|| !vsnd->pcm->streams[stream_id]) {
|
||||
goto rx_err;
|
||||
}
|
||||
|
||||
stream = s->pcm->streams[stream_id];
|
||||
stream = vsnd->pcm->streams[stream_id];
|
||||
if (stream == NULL || stream->info.direction != VIRTIO_SND_D_INPUT) {
|
||||
goto rx_err;
|
||||
}
|
||||
@@ -1018,13 +1006,11 @@ static void virtio_snd_handle_rx_xfer(VirtIODevice *vdev, VirtQueue *vq)
|
||||
continue;
|
||||
|
||||
rx_err:
|
||||
WITH_QEMU_LOCK_GUARD(&stream->queue_mutex) {
|
||||
must_empty_invalid_queue = true;
|
||||
buffer = g_malloc0(sizeof(VirtIOSoundPCMBuffer));
|
||||
buffer->elem = elem;
|
||||
buffer->vq = vq;
|
||||
QSIMPLEQ_INSERT_TAIL(&stream->invalid, buffer, entry);
|
||||
}
|
||||
must_empty_invalid_queue = true;
|
||||
buffer = g_malloc0(sizeof(VirtIOSoundPCMBuffer));
|
||||
buffer->elem = elem;
|
||||
buffer->vq = vq;
|
||||
QSIMPLEQ_INSERT_TAIL(&vsnd->invalid, buffer, entry);
|
||||
}
|
||||
|
||||
if (must_empty_invalid_queue) {
|
||||
@@ -1124,6 +1110,7 @@ static void virtio_snd_realize(DeviceState *dev, Error **errp)
|
||||
virtio_add_queue(vdev, 64, virtio_snd_handle_rx_xfer);
|
||||
qemu_mutex_init(&vsnd->cmdq_mutex);
|
||||
QTAILQ_INIT(&vsnd->cmdq);
|
||||
QSIMPLEQ_INIT(&vsnd->invalid);
|
||||
|
||||
for (uint32_t i = 0; i < vsnd->snd_conf.streams; i++) {
|
||||
status = virtio_snd_set_pcm_params(vsnd, i, &default_params);
|
||||
@@ -1373,13 +1360,20 @@ static void virtio_snd_unrealize(DeviceState *dev)
|
||||
|
||||
static void virtio_snd_reset(VirtIODevice *vdev)
|
||||
{
|
||||
VirtIOSound *s = VIRTIO_SND(vdev);
|
||||
VirtIOSound *vsnd = VIRTIO_SND(vdev);
|
||||
virtio_snd_ctrl_command *cmd;
|
||||
|
||||
WITH_QEMU_LOCK_GUARD(&s->cmdq_mutex) {
|
||||
while (!QTAILQ_EMPTY(&s->cmdq)) {
|
||||
cmd = QTAILQ_FIRST(&s->cmdq);
|
||||
QTAILQ_REMOVE(&s->cmdq, cmd, next);
|
||||
/*
|
||||
* Sanity check that the invalid buffer message queue is emptied at the end
|
||||
* of every virtio_snd_handle_tx_xfer/virtio_snd_handle_rx_xfer call, and
|
||||
* must be empty otherwise.
|
||||
*/
|
||||
g_assert(QSIMPLEQ_EMPTY(&vsnd->invalid));
|
||||
|
||||
WITH_QEMU_LOCK_GUARD(&vsnd->cmdq_mutex) {
|
||||
while (!QTAILQ_EMPTY(&vsnd->cmdq)) {
|
||||
cmd = QTAILQ_FIRST(&vsnd->cmdq);
|
||||
QTAILQ_REMOVE(&vsnd->cmdq, cmd, next);
|
||||
virtio_snd_ctrl_cmd_free(cmd);
|
||||
}
|
||||
}
|
||||
|
||||
+38
-17
@@ -84,7 +84,11 @@ struct NANDFlashState {
|
||||
|
||||
void (*blk_write)(NANDFlashState *s);
|
||||
void (*blk_erase)(NANDFlashState *s);
|
||||
void (*blk_load)(NANDFlashState *s, uint64_t addr, int offset);
|
||||
/*
|
||||
* Returns %true when block containing (@addr + @offset) is
|
||||
* successfully loaded, otherwise %false.
|
||||
*/
|
||||
bool (*blk_load)(NANDFlashState *s, uint64_t addr, unsigned offset);
|
||||
|
||||
uint32_t ioaddr_vmstate;
|
||||
};
|
||||
@@ -243,9 +247,30 @@ static inline void nand_pushio_byte(NANDFlashState *s, uint8_t value)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* nand_load_block: Load block containing (s->addr + @offset).
|
||||
* Returns length of data available at @offset in this block.
|
||||
*/
|
||||
static unsigned nand_load_block(NANDFlashState *s, unsigned offset)
|
||||
{
|
||||
unsigned iolen;
|
||||
|
||||
if (!s->blk_load(s, s->addr, offset)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
iolen = (1 << s->page_shift);
|
||||
if (s->gnd) {
|
||||
iolen += 1 << s->oob_shift;
|
||||
}
|
||||
assert(offset <= iolen);
|
||||
iolen -= offset;
|
||||
|
||||
return iolen;
|
||||
}
|
||||
|
||||
static void nand_command(NANDFlashState *s)
|
||||
{
|
||||
unsigned int offset;
|
||||
switch (s->cmd) {
|
||||
case NAND_CMD_READ0:
|
||||
s->iolen = 0;
|
||||
@@ -271,12 +296,7 @@ static void nand_command(NANDFlashState *s)
|
||||
case NAND_CMD_NOSERIALREAD2:
|
||||
if (!(nand_flash_ids[s->chip_id].options & NAND_SAMSUNG_LP))
|
||||
break;
|
||||
offset = s->addr & ((1 << s->addr_shift) - 1);
|
||||
s->blk_load(s, s->addr, offset);
|
||||
if (s->gnd)
|
||||
s->iolen = (1 << s->page_shift) - offset;
|
||||
else
|
||||
s->iolen = (1 << s->page_shift) + (1 << s->oob_shift) - offset;
|
||||
s->iolen = nand_load_block(s, s->addr & ((1 << s->addr_shift) - 1));
|
||||
break;
|
||||
|
||||
case NAND_CMD_RESET:
|
||||
@@ -597,12 +617,7 @@ uint32_t nand_getio(DeviceState *dev)
|
||||
if (!s->iolen && s->cmd == NAND_CMD_READ0) {
|
||||
offset = (int) (s->addr & ((1 << s->addr_shift) - 1)) + s->offset;
|
||||
s->offset = 0;
|
||||
|
||||
s->blk_load(s, s->addr, offset);
|
||||
if (s->gnd)
|
||||
s->iolen = (1 << s->page_shift) - offset;
|
||||
else
|
||||
s->iolen = (1 << s->page_shift) + (1 << s->oob_shift) - offset;
|
||||
s->iolen = nand_load_block(s, offset);
|
||||
}
|
||||
|
||||
if (s->ce || s->iolen <= 0) {
|
||||
@@ -763,11 +778,15 @@ static void glue(nand_blk_erase_, NAND_PAGE_SIZE)(NANDFlashState *s)
|
||||
}
|
||||
}
|
||||
|
||||
static void glue(nand_blk_load_, NAND_PAGE_SIZE)(NANDFlashState *s,
|
||||
uint64_t addr, int offset)
|
||||
static bool glue(nand_blk_load_, NAND_PAGE_SIZE)(NANDFlashState *s,
|
||||
uint64_t addr, unsigned offset)
|
||||
{
|
||||
if (PAGE(addr) >= s->pages) {
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (offset > NAND_PAGE_SIZE + OOB_SIZE) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (s->blk) {
|
||||
@@ -795,6 +814,8 @@ static void glue(nand_blk_load_, NAND_PAGE_SIZE)(NANDFlashState *s,
|
||||
offset, NAND_PAGE_SIZE + OOB_SIZE - offset);
|
||||
s->ioaddr = s->io;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void glue(nand_init_, NAND_PAGE_SIZE)(NANDFlashState *s)
|
||||
|
||||
@@ -783,7 +783,8 @@ static void virtio_blk_handle_zone_report(VirtIOBlockReq *req,
|
||||
sizeof(struct virtio_blk_zone_report) +
|
||||
sizeof(struct virtio_blk_zone_descriptor)) {
|
||||
virtio_error(vdev, "in buffer too small for zone report");
|
||||
return;
|
||||
err_status = VIRTIO_BLK_S_ZONE_INVALID_CMD;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* start byte offset of the zone report */
|
||||
|
||||
@@ -985,8 +985,7 @@ static void virtser_port_device_realize(DeviceState *dev, Error **errp)
|
||||
return;
|
||||
}
|
||||
|
||||
port->bh = qemu_bh_new_guarded(flush_queued_data_bh, port,
|
||||
&dev->mem_reentrancy_guard);
|
||||
port->bh = virtio_bh_new_guarded(dev, flush_queued_data_bh, port);
|
||||
port->elem = NULL;
|
||||
}
|
||||
|
||||
|
||||
@@ -97,6 +97,7 @@ GlobalProperty hw_compat_5_2[] = {
|
||||
{ "PIIX4_PM", "smm-compat", "on"},
|
||||
{ "virtio-blk-device", "report-discard-granularity", "off" },
|
||||
{ "virtio-net-pci-base", "vectors", "3"},
|
||||
{ "nvme", "msix-exclusive-bar", "on"},
|
||||
};
|
||||
const size_t hw_compat_5_2_len = G_N_ELEMENTS(hw_compat_5_2);
|
||||
|
||||
|
||||
@@ -1463,10 +1463,8 @@ void virtio_gpu_device_realize(DeviceState *qdev, Error **errp)
|
||||
|
||||
g->ctrl_vq = virtio_get_queue(vdev, 0);
|
||||
g->cursor_vq = virtio_get_queue(vdev, 1);
|
||||
g->ctrl_bh = qemu_bh_new_guarded(virtio_gpu_ctrl_bh, g,
|
||||
&qdev->mem_reentrancy_guard);
|
||||
g->cursor_bh = qemu_bh_new_guarded(virtio_gpu_cursor_bh, g,
|
||||
&qdev->mem_reentrancy_guard);
|
||||
g->ctrl_bh = virtio_bh_new_guarded(qdev, virtio_gpu_ctrl_bh, g);
|
||||
g->cursor_bh = virtio_bh_new_guarded(qdev, virtio_gpu_cursor_bh, g);
|
||||
g->reset_bh = qemu_bh_new(virtio_gpu_reset_bh, g);
|
||||
qemu_cond_init(&g->reset_cond);
|
||||
QTAILQ_INIT(&g->reslist);
|
||||
|
||||
+10
-10
@@ -175,24 +175,24 @@ static uint64_t xlnx_dpdma_desc_get_source_address(DPDMADescriptor *desc,
|
||||
|
||||
switch (frag) {
|
||||
case 0:
|
||||
addr = desc->source_address
|
||||
+ (extract32(desc->address_extension, 16, 12) << 20);
|
||||
addr = (uint64_t)desc->source_address
|
||||
+ (extract64(desc->address_extension, 16, 16) << 32);
|
||||
break;
|
||||
case 1:
|
||||
addr = desc->source_address2
|
||||
+ (extract32(desc->address_extension_23, 0, 12) << 8);
|
||||
addr = (uint64_t)desc->source_address2
|
||||
+ (extract64(desc->address_extension_23, 0, 16) << 32);
|
||||
break;
|
||||
case 2:
|
||||
addr = desc->source_address3
|
||||
+ (extract32(desc->address_extension_23, 16, 12) << 20);
|
||||
addr = (uint64_t)desc->source_address3
|
||||
+ (extract64(desc->address_extension_23, 16, 16) << 32);
|
||||
break;
|
||||
case 3:
|
||||
addr = desc->source_address4
|
||||
+ (extract32(desc->address_extension_45, 0, 12) << 8);
|
||||
addr = (uint64_t)desc->source_address4
|
||||
+ (extract64(desc->address_extension_45, 0, 16) << 32);
|
||||
break;
|
||||
case 4:
|
||||
addr = desc->source_address5
|
||||
+ (extract32(desc->address_extension_45, 16, 12) << 20);
|
||||
addr = (uint64_t)desc->source_address5
|
||||
+ (extract64(desc->address_extension_45, 16, 16) << 32);
|
||||
break;
|
||||
default:
|
||||
addr = 0;
|
||||
|
||||
@@ -1067,7 +1067,7 @@ static uint64_t icc_hppir0_value(GICv3CPUState *cs, CPUARMState *env)
|
||||
*/
|
||||
bool irq_is_secure;
|
||||
|
||||
if (cs->hppi.prio == 0xff) {
|
||||
if (icc_no_enabled_hppi(cs)) {
|
||||
return INTID_SPURIOUS;
|
||||
}
|
||||
|
||||
@@ -1104,7 +1104,7 @@ static uint64_t icc_hppir1_value(GICv3CPUState *cs, CPUARMState *env)
|
||||
*/
|
||||
bool irq_is_secure;
|
||||
|
||||
if (cs->hppi.prio == 0xff) {
|
||||
if (icc_no_enabled_hppi(cs)) {
|
||||
return INTID_SPURIOUS;
|
||||
}
|
||||
|
||||
|
||||
@@ -463,6 +463,7 @@ static uint32_t riscv_aplic_idc_claimi(RISCVAPLICState *aplic, uint32_t idc)
|
||||
|
||||
if (!topi) {
|
||||
aplic->iforce[idc] = 0;
|
||||
riscv_aplic_idc_update(aplic, idc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
+2
-1
@@ -613,7 +613,7 @@ void via_isa_set_irq(PCIDevice *d, int pin, int level)
|
||||
ViaISAState *s = VIA_ISA(pci_get_function_0(d));
|
||||
uint8_t irq = d->config[PCI_INTERRUPT_LINE], max_irq = 15;
|
||||
int f = PCI_FUNC(d->devfn);
|
||||
uint16_t mask = BIT(f);
|
||||
uint16_t mask;
|
||||
|
||||
switch (f) {
|
||||
case 0: /* PIRQ/PINT inputs */
|
||||
@@ -628,6 +628,7 @@ void via_isa_set_irq(PCIDevice *d, int pin, int level)
|
||||
}
|
||||
|
||||
/* Keep track of the state of all sources */
|
||||
mask = BIT(f);
|
||||
if (level) {
|
||||
s->irq_state[0] |= mask;
|
||||
} else {
|
||||
|
||||
@@ -274,6 +274,7 @@ static void qdev_applesmc_isa_reset(DeviceState *dev)
|
||||
/* Remove existing entries */
|
||||
QLIST_FOREACH_SAFE(d, &s->data_def, node, next) {
|
||||
QLIST_REMOVE(d, node);
|
||||
g_free(d);
|
||||
}
|
||||
s->status = 0x00;
|
||||
s->status_1e = 0x00;
|
||||
|
||||
+7
-53
@@ -123,14 +123,6 @@ e1000e_intmgr_timer_resume(E1000IntrDelayTimer *timer)
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
e1000e_intmgr_timer_pause(E1000IntrDelayTimer *timer)
|
||||
{
|
||||
if (timer->running) {
|
||||
timer_del(timer->timer);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
e1000e_intrmgr_stop_timer(E1000IntrDelayTimer *timer)
|
||||
{
|
||||
@@ -398,24 +390,6 @@ e1000e_intrmgr_resume(E1000ECore *core)
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
e1000e_intrmgr_pause(E1000ECore *core)
|
||||
{
|
||||
int i;
|
||||
|
||||
e1000e_intmgr_timer_pause(&core->radv);
|
||||
e1000e_intmgr_timer_pause(&core->rdtr);
|
||||
e1000e_intmgr_timer_pause(&core->raid);
|
||||
e1000e_intmgr_timer_pause(&core->tidv);
|
||||
e1000e_intmgr_timer_pause(&core->tadv);
|
||||
|
||||
e1000e_intmgr_timer_pause(&core->itr);
|
||||
|
||||
for (i = 0; i < E1000E_MSIX_VEC_NUM; i++) {
|
||||
e1000e_intmgr_timer_pause(&core->eitr[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
e1000e_intrmgr_reset(E1000ECore *core)
|
||||
{
|
||||
@@ -3334,12 +3308,6 @@ e1000e_core_read(E1000ECore *core, hwaddr addr, unsigned size)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void
|
||||
e1000e_autoneg_pause(E1000ECore *core)
|
||||
{
|
||||
timer_del(core->autoneg_timer);
|
||||
}
|
||||
|
||||
static void
|
||||
e1000e_autoneg_resume(E1000ECore *core)
|
||||
{
|
||||
@@ -3351,22 +3319,6 @@ e1000e_autoneg_resume(E1000ECore *core)
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
e1000e_vm_state_change(void *opaque, bool running, RunState state)
|
||||
{
|
||||
E1000ECore *core = opaque;
|
||||
|
||||
if (running) {
|
||||
trace_e1000e_vm_state_running();
|
||||
e1000e_intrmgr_resume(core);
|
||||
e1000e_autoneg_resume(core);
|
||||
} else {
|
||||
trace_e1000e_vm_state_stopped();
|
||||
e1000e_autoneg_pause(core);
|
||||
e1000e_intrmgr_pause(core);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
e1000e_core_pci_realize(E1000ECore *core,
|
||||
const uint16_t *eeprom_templ,
|
||||
@@ -3379,9 +3331,6 @@ e1000e_core_pci_realize(E1000ECore *core,
|
||||
e1000e_autoneg_timer, core);
|
||||
e1000e_intrmgr_pci_realize(core);
|
||||
|
||||
core->vmstate =
|
||||
qemu_add_vm_change_state_handler(e1000e_vm_state_change, core);
|
||||
|
||||
for (i = 0; i < E1000E_NUM_QUEUES; i++) {
|
||||
net_tx_pkt_init(&core->tx[i].tx_pkt, E1000E_MAX_TX_FRAGS);
|
||||
}
|
||||
@@ -3405,8 +3354,6 @@ e1000e_core_pci_uninit(E1000ECore *core)
|
||||
|
||||
e1000e_intrmgr_pci_unint(core);
|
||||
|
||||
qemu_del_vm_change_state_handler(core->vmstate);
|
||||
|
||||
for (i = 0; i < E1000E_NUM_QUEUES; i++) {
|
||||
net_tx_pkt_uninit(core->tx[i].tx_pkt);
|
||||
}
|
||||
@@ -3576,5 +3523,12 @@ e1000e_core_post_load(E1000ECore *core)
|
||||
*/
|
||||
nc->link_down = (core->mac[STATUS] & E1000_STATUS_LU) == 0;
|
||||
|
||||
/*
|
||||
* we need to restart intrmgr timers, as an older version of
|
||||
* QEMU can have stopped them before migration
|
||||
*/
|
||||
e1000e_intrmgr_resume(core);
|
||||
e1000e_autoneg_resume(core);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -98,8 +98,6 @@ struct E1000Core {
|
||||
|
||||
E1000IntrDelayTimer eitr[E1000E_MSIX_VEC_NUM];
|
||||
|
||||
VMChangeStateEntry *vmstate;
|
||||
|
||||
uint32_t itr_guest_value;
|
||||
uint32_t eitr_guest_value[E1000E_MSIX_VEC_NUM];
|
||||
|
||||
|
||||
+7
-44
@@ -160,14 +160,6 @@ igb_intmgr_timer_resume(IGBIntrDelayTimer *timer)
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
igb_intmgr_timer_pause(IGBIntrDelayTimer *timer)
|
||||
{
|
||||
if (timer->running) {
|
||||
timer_del(timer->timer);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
igb_intrmgr_on_msix_throttling_timer(void *opaque)
|
||||
{
|
||||
@@ -212,16 +204,6 @@ igb_intrmgr_resume(IGBCore *core)
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
igb_intrmgr_pause(IGBCore *core)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < IGB_INTR_NUM; i++) {
|
||||
igb_intmgr_timer_pause(&core->eitr[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
igb_intrmgr_reset(IGBCore *core)
|
||||
{
|
||||
@@ -4290,12 +4272,6 @@ igb_core_read(IGBCore *core, hwaddr addr, unsigned size)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void
|
||||
igb_autoneg_pause(IGBCore *core)
|
||||
{
|
||||
timer_del(core->autoneg_timer);
|
||||
}
|
||||
|
||||
static void
|
||||
igb_autoneg_resume(IGBCore *core)
|
||||
{
|
||||
@@ -4307,22 +4283,6 @@ igb_autoneg_resume(IGBCore *core)
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
igb_vm_state_change(void *opaque, bool running, RunState state)
|
||||
{
|
||||
IGBCore *core = opaque;
|
||||
|
||||
if (running) {
|
||||
trace_e1000e_vm_state_running();
|
||||
igb_intrmgr_resume(core);
|
||||
igb_autoneg_resume(core);
|
||||
} else {
|
||||
trace_e1000e_vm_state_stopped();
|
||||
igb_autoneg_pause(core);
|
||||
igb_intrmgr_pause(core);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
igb_core_pci_realize(IGBCore *core,
|
||||
const uint16_t *eeprom_templ,
|
||||
@@ -4335,8 +4295,6 @@ igb_core_pci_realize(IGBCore *core,
|
||||
igb_autoneg_timer, core);
|
||||
igb_intrmgr_pci_realize(core);
|
||||
|
||||
core->vmstate = qemu_add_vm_change_state_handler(igb_vm_state_change, core);
|
||||
|
||||
for (i = 0; i < IGB_NUM_QUEUES; i++) {
|
||||
net_tx_pkt_init(&core->tx[i].tx_pkt, E1000E_MAX_TX_FRAGS);
|
||||
}
|
||||
@@ -4360,8 +4318,6 @@ igb_core_pci_uninit(IGBCore *core)
|
||||
|
||||
igb_intrmgr_pci_unint(core);
|
||||
|
||||
qemu_del_vm_change_state_handler(core->vmstate);
|
||||
|
||||
for (i = 0; i < IGB_NUM_QUEUES; i++) {
|
||||
net_tx_pkt_uninit(core->tx[i].tx_pkt);
|
||||
}
|
||||
@@ -4586,5 +4542,12 @@ igb_core_post_load(IGBCore *core)
|
||||
*/
|
||||
nc->link_down = (core->mac[STATUS] & E1000_STATUS_LU) == 0;
|
||||
|
||||
/*
|
||||
* we need to restart intrmgr timers, as an older version of
|
||||
* QEMU can have stopped them before migration
|
||||
*/
|
||||
igb_intrmgr_resume(core);
|
||||
igb_autoneg_resume(core);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -90,8 +90,6 @@ struct IGBCore {
|
||||
|
||||
IGBIntrDelayTimer eitr[IGB_INTR_NUM];
|
||||
|
||||
VMChangeStateEntry *vmstate;
|
||||
|
||||
uint32_t eitr_guest_value[IGB_INTR_NUM];
|
||||
|
||||
uint8_t permanent_mac[ETH_ALEN];
|
||||
|
||||
+24
-4
@@ -150,6 +150,12 @@ do { printf("lan9118: " fmt , ## __VA_ARGS__); } while (0)
|
||||
|
||||
#define GPT_TIMER_EN 0x20000000
|
||||
|
||||
/*
|
||||
* The MAC Interface Layer (MIL), within the MAC, contains a 2K Byte transmit
|
||||
* and a 128 Byte receive FIFO which is separate from the TX and RX FIFOs.
|
||||
*/
|
||||
#define MIL_TXFIFO_SIZE 2048
|
||||
|
||||
enum tx_state {
|
||||
TX_IDLE,
|
||||
TX_B,
|
||||
@@ -166,7 +172,7 @@ typedef struct {
|
||||
int32_t pad;
|
||||
int32_t fifo_used;
|
||||
int32_t len;
|
||||
uint8_t data[2048];
|
||||
uint8_t data[MIL_TXFIFO_SIZE];
|
||||
} LAN9118Packet;
|
||||
|
||||
static const VMStateDescription vmstate_lan9118_packet = {
|
||||
@@ -182,7 +188,7 @@ static const VMStateDescription vmstate_lan9118_packet = {
|
||||
VMSTATE_INT32(pad, LAN9118Packet),
|
||||
VMSTATE_INT32(fifo_used, LAN9118Packet),
|
||||
VMSTATE_INT32(len, LAN9118Packet),
|
||||
VMSTATE_UINT8_ARRAY(data, LAN9118Packet, 2048),
|
||||
VMSTATE_UINT8_ARRAY(data, LAN9118Packet, MIL_TXFIFO_SIZE),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
@@ -544,7 +550,7 @@ static ssize_t lan9118_receive(NetClientState *nc, const uint8_t *buf,
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (size >= 2048 || size < 14) {
|
||||
if (size >= MIL_TXFIFO_SIZE || size < 14) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -793,8 +799,22 @@ static void tx_fifo_push(lan9118_state *s, uint32_t val)
|
||||
/* Documentation is somewhat unclear on the ordering of bytes
|
||||
in FIFO words. Empirical results show it to be little-endian.
|
||||
*/
|
||||
/* TODO: FIFO overflow checking. */
|
||||
while (n--) {
|
||||
if (s->txp->len == MIL_TXFIFO_SIZE) {
|
||||
/*
|
||||
* No more space in the FIFO. The datasheet is not
|
||||
* precise about this case. We choose what is easiest
|
||||
* to model: the packet is truncated, and TXE is raised.
|
||||
*
|
||||
* Note, it could be a fragmented packet, but we currently
|
||||
* do not handle that (see earlier TX_B case).
|
||||
*/
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"MIL TX FIFO overrun, discarding %u byte%s\n",
|
||||
n, n > 1 ? "s" : "");
|
||||
s->int_sts |= TXE_INT;
|
||||
break;
|
||||
}
|
||||
s->txp->data[s->txp->len] = val & 0xff;
|
||||
s->txp->len++;
|
||||
val >>= 8;
|
||||
|
||||
@@ -141,6 +141,10 @@ bool net_tx_pkt_update_sctp_checksum(struct NetTxPkt *pkt)
|
||||
uint32_t csum = 0;
|
||||
struct iovec *pl_start_frag = pkt->vec + NET_TX_PKT_PL_START_FRAG;
|
||||
|
||||
if (iov_size(pl_start_frag, pkt->payload_frags) < 8 + sizeof(csum)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (iov_from_buf(pl_start_frag, pkt->payload_frags, 8, &csum, sizeof(csum)) < sizeof(csum)) {
|
||||
return false;
|
||||
}
|
||||
@@ -833,6 +837,7 @@ bool net_tx_pkt_send_custom(struct NetTxPkt *pkt, bool offload,
|
||||
|
||||
if (offload || gso_type == VIRTIO_NET_HDR_GSO_NONE) {
|
||||
if (!offload && pkt->virt_hdr.flags & VIRTIO_NET_HDR_F_NEEDS_CSUM) {
|
||||
pkt->virt_hdr.flags &= ~VIRTIO_NET_HDR_F_NEEDS_CSUM;
|
||||
net_tx_pkt_do_sw_csum(pkt, &pkt->vec[NET_TX_PKT_L2HDR_FRAG],
|
||||
pkt->payload_frags + NET_TX_PKT_PL_START_FRAG - 1,
|
||||
pkt->payload_len);
|
||||
|
||||
+1
-1
@@ -632,7 +632,7 @@ static inline int ladr_match(PCNetState *s, const uint8_t *buf, int size)
|
||||
{
|
||||
struct qemu_ether_header *hdr = (void *)buf;
|
||||
if ((*(hdr->ether_dhost)&0x01) &&
|
||||
((uint64_t *)&s->csr[8])[0] != 0LL) {
|
||||
(s->csr[8] | s->csr[9] | s->csr[10] | s->csr[11]) != 0) {
|
||||
uint8_t ladr[8] = {
|
||||
s->csr[8] & 0xff, s->csr[8] >> 8,
|
||||
s->csr[9] & 0xff, s->csr[9] >> 8,
|
||||
|
||||
@@ -541,6 +541,16 @@ int vhost_set_vring_enable(NetClientState *nc, int enable)
|
||||
VHostNetState *net = get_vhost_net(nc);
|
||||
const VhostOps *vhost_ops = net->dev.vhost_ops;
|
||||
|
||||
/*
|
||||
* vhost-vdpa network devices need to enable dataplane virtqueues after
|
||||
* DRIVER_OK, so they can recover device state before starting dataplane.
|
||||
* Because of that, we don't enable virtqueues here and leave it to
|
||||
* net/vhost-vdpa.c.
|
||||
*/
|
||||
if (nc->info->type == NET_CLIENT_DRIVER_VHOST_VDPA) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
nc->vring_enable = enable;
|
||||
|
||||
if (vhost_ops && vhost_ops->vhost_set_vring_enable) {
|
||||
|
||||
+6
-2
@@ -2809,6 +2809,10 @@ static void virtio_net_handle_tx_bh(VirtIODevice *vdev, VirtQueue *vq)
|
||||
VirtIONet *n = VIRTIO_NET(vdev);
|
||||
VirtIONetQueue *q = &n->vqs[vq2q(virtio_get_queue_index(vq))];
|
||||
|
||||
if (unlikely(n->vhost_started)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (unlikely((n->status & VIRTIO_NET_S_LINK_UP) == 0)) {
|
||||
virtio_net_drop_tx_queue_data(vdev, vq);
|
||||
return;
|
||||
@@ -3370,7 +3374,7 @@ static bool virtio_net_guest_notifier_pending(VirtIODevice *vdev, int idx)
|
||||
VirtIONet *n = VIRTIO_NET(vdev);
|
||||
NetClientState *nc;
|
||||
assert(n->vhost_started);
|
||||
if (!virtio_vdev_has_feature(vdev, VIRTIO_NET_F_MQ) && idx == 2) {
|
||||
if (!n->multiqueue && idx == 2) {
|
||||
/* Must guard against invalid features and bogus queue index
|
||||
* from being set by malicious guest, or penetrated through
|
||||
* buggy migration stream.
|
||||
@@ -3402,7 +3406,7 @@ static void virtio_net_guest_notifier_mask(VirtIODevice *vdev, int idx,
|
||||
VirtIONet *n = VIRTIO_NET(vdev);
|
||||
NetClientState *nc;
|
||||
assert(n->vhost_started);
|
||||
if (!virtio_vdev_has_feature(vdev, VIRTIO_NET_F_MQ) && idx == 2) {
|
||||
if (!n->multiqueue && idx == 2) {
|
||||
/* Must guard against invalid features and bogus queue index
|
||||
* from being set by malicious guest, or penetrated through
|
||||
* buggy migration stream.
|
||||
|
||||
+67
-46
@@ -2855,7 +2855,7 @@ static inline uint16_t nvme_check_copy_mcl(NvmeNamespace *ns,
|
||||
uint32_t nlb;
|
||||
nvme_copy_source_range_parse(iocb->ranges, idx, iocb->format, NULL,
|
||||
&nlb, NULL, NULL, NULL);
|
||||
copy_len += nlb + 1;
|
||||
copy_len += nlb;
|
||||
}
|
||||
|
||||
if (copy_len > ns->id_ns.mcl) {
|
||||
@@ -7798,6 +7798,11 @@ static bool nvme_check_params(NvmeCtrl *n, Error **errp)
|
||||
}
|
||||
|
||||
if (n->pmr.dev) {
|
||||
if (params->msix_exclusive_bar) {
|
||||
error_setg(errp, "not enough BARs available to enable PMR");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (host_memory_backend_is_mapped(n->pmr.dev)) {
|
||||
error_setg(errp, "can't use already busy memdev: %s",
|
||||
object_get_canonical_path_component(OBJECT(n->pmr.dev)));
|
||||
@@ -8003,13 +8008,18 @@ static void nvme_init_pmr(NvmeCtrl *n, PCIDevice *pci_dev)
|
||||
memory_region_set_enabled(&n->pmr.dev->mr, false);
|
||||
}
|
||||
|
||||
static uint64_t nvme_bar_size(unsigned total_queues, unsigned total_irqs,
|
||||
unsigned *msix_table_offset,
|
||||
unsigned *msix_pba_offset)
|
||||
static uint64_t nvme_mbar_size(unsigned total_queues, unsigned total_irqs,
|
||||
unsigned *msix_table_offset,
|
||||
unsigned *msix_pba_offset)
|
||||
{
|
||||
uint64_t bar_size, msix_table_size, msix_pba_size;
|
||||
uint64_t bar_size, msix_table_size;
|
||||
|
||||
bar_size = sizeof(NvmeBar) + 2 * total_queues * NVME_DB_SIZE;
|
||||
|
||||
if (total_irqs == 0) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
bar_size = QEMU_ALIGN_UP(bar_size, 4 * KiB);
|
||||
|
||||
if (msix_table_offset) {
|
||||
@@ -8024,11 +8034,10 @@ static uint64_t nvme_bar_size(unsigned total_queues, unsigned total_irqs,
|
||||
*msix_pba_offset = bar_size;
|
||||
}
|
||||
|
||||
msix_pba_size = QEMU_ALIGN_UP(total_irqs, 64) / 8;
|
||||
bar_size += msix_pba_size;
|
||||
bar_size += QEMU_ALIGN_UP(total_irqs, 64) / 8;
|
||||
|
||||
bar_size = pow2ceil(bar_size);
|
||||
return bar_size;
|
||||
out:
|
||||
return pow2ceil(bar_size);
|
||||
}
|
||||
|
||||
static void nvme_init_sriov(NvmeCtrl *n, PCIDevice *pci_dev, uint16_t offset)
|
||||
@@ -8036,7 +8045,7 @@ static void nvme_init_sriov(NvmeCtrl *n, PCIDevice *pci_dev, uint16_t offset)
|
||||
uint16_t vf_dev_id = n->params.use_intel_id ?
|
||||
PCI_DEVICE_ID_INTEL_NVME : PCI_DEVICE_ID_REDHAT_NVME;
|
||||
NvmePriCtrlCap *cap = &n->pri_ctrl_cap;
|
||||
uint64_t bar_size = nvme_bar_size(le16_to_cpu(cap->vqfrsm),
|
||||
uint64_t bar_size = nvme_mbar_size(le16_to_cpu(cap->vqfrsm),
|
||||
le16_to_cpu(cap->vifrsm),
|
||||
NULL, NULL);
|
||||
|
||||
@@ -8075,7 +8084,7 @@ static bool nvme_init_pci(NvmeCtrl *n, PCIDevice *pci_dev, Error **errp)
|
||||
ERRP_GUARD();
|
||||
uint8_t *pci_conf = pci_dev->config;
|
||||
uint64_t bar_size;
|
||||
unsigned msix_table_offset, msix_pba_offset;
|
||||
unsigned msix_table_offset = 0, msix_pba_offset = 0;
|
||||
int ret;
|
||||
|
||||
pci_conf[PCI_INTERRUPT_PIN] = 1;
|
||||
@@ -8097,24 +8106,38 @@ static bool nvme_init_pci(NvmeCtrl *n, PCIDevice *pci_dev, Error **errp)
|
||||
pcie_ari_init(pci_dev, 0x100);
|
||||
}
|
||||
|
||||
/* add one to max_ioqpairs to account for the admin queue pair */
|
||||
bar_size = nvme_bar_size(n->params.max_ioqpairs + 1, n->params.msix_qsize,
|
||||
&msix_table_offset, &msix_pba_offset);
|
||||
|
||||
memory_region_init(&n->bar0, OBJECT(n), "nvme-bar0", bar_size);
|
||||
memory_region_init_io(&n->iomem, OBJECT(n), &nvme_mmio_ops, n, "nvme",
|
||||
msix_table_offset);
|
||||
memory_region_add_subregion(&n->bar0, 0, &n->iomem);
|
||||
|
||||
if (pci_is_vf(pci_dev)) {
|
||||
pcie_sriov_vf_register_bar(pci_dev, 0, &n->bar0);
|
||||
} else {
|
||||
if (n->params.msix_exclusive_bar && !pci_is_vf(pci_dev)) {
|
||||
bar_size = nvme_mbar_size(n->params.max_ioqpairs + 1, 0, NULL, NULL);
|
||||
memory_region_init_io(&n->iomem, OBJECT(n), &nvme_mmio_ops, n, "nvme",
|
||||
bar_size);
|
||||
pci_register_bar(pci_dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY |
|
||||
PCI_BASE_ADDRESS_MEM_TYPE_64, &n->bar0);
|
||||
PCI_BASE_ADDRESS_MEM_TYPE_64, &n->iomem);
|
||||
ret = msix_init_exclusive_bar(pci_dev, n->params.msix_qsize, 4, errp);
|
||||
} else {
|
||||
assert(n->params.msix_qsize >= 1);
|
||||
|
||||
/* add one to max_ioqpairs to account for the admin queue pair */
|
||||
bar_size = nvme_mbar_size(n->params.max_ioqpairs + 1,
|
||||
n->params.msix_qsize, &msix_table_offset,
|
||||
&msix_pba_offset);
|
||||
|
||||
memory_region_init(&n->bar0, OBJECT(n), "nvme-bar0", bar_size);
|
||||
memory_region_init_io(&n->iomem, OBJECT(n), &nvme_mmio_ops, n, "nvme",
|
||||
msix_table_offset);
|
||||
memory_region_add_subregion(&n->bar0, 0, &n->iomem);
|
||||
|
||||
if (pci_is_vf(pci_dev)) {
|
||||
pcie_sriov_vf_register_bar(pci_dev, 0, &n->bar0);
|
||||
} else {
|
||||
pci_register_bar(pci_dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY |
|
||||
PCI_BASE_ADDRESS_MEM_TYPE_64, &n->bar0);
|
||||
}
|
||||
|
||||
ret = msix_init(pci_dev, n->params.msix_qsize,
|
||||
&n->bar0, 0, msix_table_offset,
|
||||
&n->bar0, 0, msix_pba_offset, 0, errp);
|
||||
}
|
||||
ret = msix_init(pci_dev, n->params.msix_qsize,
|
||||
&n->bar0, 0, msix_table_offset,
|
||||
&n->bar0, 0, msix_pba_offset, 0, errp);
|
||||
|
||||
if (ret == -ENOTSUP) {
|
||||
/* report that msix is not supported, but do not error out */
|
||||
warn_report_err(*errp);
|
||||
@@ -8309,9 +8332,15 @@ static void nvme_realize(PCIDevice *pci_dev, Error **errp)
|
||||
if (pci_is_vf(pci_dev)) {
|
||||
/*
|
||||
* VFs derive settings from the parent. PF's lifespan exceeds
|
||||
* that of VF's, so it's safe to share params.serial.
|
||||
* that of VF's.
|
||||
*/
|
||||
memcpy(&n->params, &pn->params, sizeof(NvmeParams));
|
||||
|
||||
/*
|
||||
* Set PF's serial value to a new string memory to prevent 'serial'
|
||||
* property object release of PF when a VF is removed from the system.
|
||||
*/
|
||||
n->params.serial = g_strdup(pn->params.serial);
|
||||
n->subsys = pn->subsys;
|
||||
}
|
||||
|
||||
@@ -8412,6 +8441,8 @@ static Property nvme_props[] = {
|
||||
params.sriov_max_vi_per_vf, 0),
|
||||
DEFINE_PROP_UINT8("sriov_max_vq_per_vf", NvmeCtrl,
|
||||
params.sriov_max_vq_per_vf, 0),
|
||||
DEFINE_PROP_BOOL("msix-exclusive-bar", NvmeCtrl, params.msix_exclusive_bar,
|
||||
false),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
@@ -8466,36 +8497,26 @@ static void nvme_pci_reset(DeviceState *qdev)
|
||||
nvme_ctrl_reset(n, NVME_RESET_FUNCTION);
|
||||
}
|
||||
|
||||
static void nvme_sriov_pre_write_ctrl(PCIDevice *dev, uint32_t address,
|
||||
uint32_t val, int len)
|
||||
static void nvme_sriov_post_write_config(PCIDevice *dev, uint16_t old_num_vfs)
|
||||
{
|
||||
NvmeCtrl *n = NVME(dev);
|
||||
NvmeSecCtrlEntry *sctrl;
|
||||
uint16_t sriov_cap = dev->exp.sriov_cap;
|
||||
uint32_t off = address - sriov_cap;
|
||||
int i, num_vfs;
|
||||
int i;
|
||||
|
||||
if (!sriov_cap) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (range_covers_byte(off, len, PCI_SRIOV_CTRL)) {
|
||||
if (!(val & PCI_SRIOV_CTRL_VFE)) {
|
||||
num_vfs = pci_get_word(dev->config + sriov_cap + PCI_SRIOV_NUM_VF);
|
||||
for (i = 0; i < num_vfs; i++) {
|
||||
sctrl = &n->sec_ctrl_list.sec[i];
|
||||
nvme_virt_set_state(n, le16_to_cpu(sctrl->scid), false);
|
||||
}
|
||||
}
|
||||
for (i = pcie_sriov_num_vfs(dev); i < old_num_vfs; i++) {
|
||||
sctrl = &n->sec_ctrl_list.sec[i];
|
||||
nvme_virt_set_state(n, le16_to_cpu(sctrl->scid), false);
|
||||
}
|
||||
}
|
||||
|
||||
static void nvme_pci_write_config(PCIDevice *dev, uint32_t address,
|
||||
uint32_t val, int len)
|
||||
{
|
||||
nvme_sriov_pre_write_ctrl(dev, address, val, len);
|
||||
uint16_t old_num_vfs = pcie_sriov_num_vfs(dev);
|
||||
|
||||
pci_default_write_config(dev, address, val, len);
|
||||
pcie_cap_flr_write_config(dev, address, val, len);
|
||||
nvme_sriov_post_write_config(dev, old_num_vfs);
|
||||
}
|
||||
|
||||
static const VMStateDescription nvme_vmstate = {
|
||||
|
||||
@@ -522,6 +522,7 @@ typedef struct NvmeParams {
|
||||
uint16_t sriov_vi_flexible;
|
||||
uint8_t sriov_max_vq_per_vf;
|
||||
uint8_t sriov_max_vi_per_vf;
|
||||
bool msix_exclusive_bar;
|
||||
} NvmeParams;
|
||||
|
||||
typedef struct NvmeCtrl {
|
||||
|
||||
@@ -176,6 +176,9 @@ static void register_vfs(PCIDevice *dev)
|
||||
|
||||
assert(sriov_cap > 0);
|
||||
num_vfs = pci_get_word(dev->config + sriov_cap + PCI_SRIOV_NUM_VF);
|
||||
if (num_vfs > pci_get_word(dev->config + sriov_cap + PCI_SRIOV_TOTAL_VF)) {
|
||||
return;
|
||||
}
|
||||
|
||||
dev->exp.sriov_pf.vf = g_new(PCIDevice *, num_vfs);
|
||||
|
||||
|
||||
@@ -53,7 +53,7 @@ OBJECT_DECLARE_SIMPLE_TYPE(PPC440PCIXState, PPC440_PCIX_HOST)
|
||||
struct PPC440PCIXState {
|
||||
PCIHostState parent_obj;
|
||||
|
||||
PCIDevice *dev;
|
||||
uint8_t config[PCI_CONFIG_SPACE_SIZE];
|
||||
struct PLBOutMap pom[PPC440_PCIX_NR_POMS];
|
||||
struct PLBInMap pim[PPC440_PCIX_NR_PIMS];
|
||||
uint32_t sts;
|
||||
@@ -172,7 +172,7 @@ static void ppc440_pcix_reg_write4(void *opaque, hwaddr addr,
|
||||
trace_ppc440_pcix_reg_write(addr, val, size);
|
||||
switch (addr) {
|
||||
case PCI_VENDOR_ID ... PCI_MAX_LAT:
|
||||
stl_le_p(s->dev->config + addr, val);
|
||||
stl_le_p(s->config + addr, val);
|
||||
break;
|
||||
|
||||
case PCIX0_POM0LAL:
|
||||
@@ -303,7 +303,7 @@ static uint64_t ppc440_pcix_reg_read4(void *opaque, hwaddr addr,
|
||||
|
||||
switch (addr) {
|
||||
case PCI_VENDOR_ID ... PCI_MAX_LAT:
|
||||
val = ldl_le_p(s->dev->config + addr);
|
||||
val = ldl_le_p(s->config + addr);
|
||||
break;
|
||||
|
||||
case PCIX0_POM0LAL:
|
||||
@@ -499,10 +499,7 @@ static void ppc440_pcix_realize(DeviceState *dev, Error **errp)
|
||||
memory_region_init(&s->iomem, OBJECT(dev), "pci-io", 64 * KiB);
|
||||
h->bus = pci_register_root_bus(dev, NULL, ppc440_pcix_set_irq,
|
||||
ppc440_pcix_map_irq, &s->irq, &s->busmem, &s->iomem,
|
||||
PCI_DEVFN(0, 0), 1, TYPE_PCI_BUS);
|
||||
|
||||
s->dev = pci_create_simple(h->bus, PCI_DEVFN(0, 0),
|
||||
TYPE_PPC4xx_HOST_BRIDGE);
|
||||
PCI_DEVFN(1, 0), 1, TYPE_PCI_BUS);
|
||||
|
||||
memory_region_init(&s->bm, OBJECT(s), "bm-ppc440-pcix", UINT64_MAX);
|
||||
memory_region_add_subregion(&s->bm, 0x0, &s->busmem);
|
||||
|
||||
+3
-6
@@ -4647,13 +4647,10 @@ static void spapr_machine_class_init(ObjectClass *oc, void *data)
|
||||
mc->block_default_type = IF_SCSI;
|
||||
|
||||
/*
|
||||
* Setting max_cpus to INT32_MAX. Both KVM and TCG max_cpus values
|
||||
* should be limited by the host capability instead of hardcoded.
|
||||
* max_cpus for KVM guests will be checked in kvm_init(), and TCG
|
||||
* guests are welcome to have as many CPUs as the host are capable
|
||||
* of emulate.
|
||||
* While KVM determines max cpus in kvm_init() using kvm_max_vcpus(),
|
||||
* In TCG the limit is restricted by the range of CPU IPIs available.
|
||||
*/
|
||||
mc->max_cpus = INT32_MAX;
|
||||
mc->max_cpus = SPAPR_IRQ_NR_IPIS;
|
||||
|
||||
mc->no_parallel = 1;
|
||||
mc->default_boot_order = "";
|
||||
|
||||
+4
-2
@@ -23,6 +23,8 @@
|
||||
|
||||
#include "trace.h"
|
||||
|
||||
QEMU_BUILD_BUG_ON(SPAPR_IRQ_NR_IPIS > SPAPR_XIRQ_BASE);
|
||||
|
||||
static const TypeInfo spapr_intc_info = {
|
||||
.name = TYPE_SPAPR_INTC,
|
||||
.parent = TYPE_INTERFACE,
|
||||
@@ -329,7 +331,7 @@ void spapr_irq_init(SpaprMachineState *spapr, Error **errp)
|
||||
int i;
|
||||
|
||||
dev = qdev_new(TYPE_SPAPR_XIVE);
|
||||
qdev_prop_set_uint32(dev, "nr-irqs", smc->nr_xirqs + SPAPR_XIRQ_BASE);
|
||||
qdev_prop_set_uint32(dev, "nr-irqs", smc->nr_xirqs + SPAPR_IRQ_NR_IPIS);
|
||||
/*
|
||||
* 8 XIVE END structures per CPU. One for each available
|
||||
* priority
|
||||
@@ -356,7 +358,7 @@ void spapr_irq_init(SpaprMachineState *spapr, Error **errp)
|
||||
}
|
||||
|
||||
spapr->qirqs = qemu_allocate_irqs(spapr_set_irq, spapr,
|
||||
smc->nr_xirqs + SPAPR_XIRQ_BASE);
|
||||
smc->nr_xirqs + SPAPR_IRQ_NR_IPIS);
|
||||
|
||||
/*
|
||||
* Mostly we don't actually need this until reset, except that not
|
||||
|
||||
@@ -743,6 +743,8 @@ static void create_fdt_sockets(RISCVVirtState *s, const MemMapEntry *memmap,
|
||||
|
||||
qemu_fdt_add_subnode(ms->fdt, "/cpus");
|
||||
qemu_fdt_setprop_cell(ms->fdt, "/cpus", "timebase-frequency",
|
||||
kvm_enabled() ?
|
||||
kvm_riscv_get_timebase_frequency(first_cpu) :
|
||||
RISCV_ACLINT_DEFAULT_TIMEBASE_FREQ);
|
||||
qemu_fdt_setprop_cell(ms->fdt, "/cpus", "#size-cells", 0x0);
|
||||
qemu_fdt_setprop_cell(ms->fdt, "/cpus", "#address-cells", 0x1);
|
||||
|
||||
+1
-1
@@ -5,7 +5,7 @@
|
||||
*
|
||||
* Copyright (c) 2016 Artyom Tarasenko
|
||||
*
|
||||
* This code is licensed under the GNU GPL v3 or (at your option) any later
|
||||
* This code is licensed under the GNU GPL v2 or (at your option) any later
|
||||
* version.
|
||||
*/
|
||||
|
||||
|
||||
+45
-14
@@ -188,7 +188,7 @@ static const char *names[] = {
|
||||
#define LSI_TAG_VALID (1 << 16)
|
||||
|
||||
/* Maximum instructions to process. */
|
||||
#define LSI_MAX_INSN 10000
|
||||
#define LSI_MAX_INSN 100
|
||||
|
||||
typedef struct lsi_request {
|
||||
SCSIRequest *req;
|
||||
@@ -205,6 +205,7 @@ enum {
|
||||
LSI_WAIT_RESELECT, /* Wait Reselect instruction has been issued */
|
||||
LSI_DMA_SCRIPTS, /* processing DMA from lsi_execute_script */
|
||||
LSI_DMA_IN_PROGRESS, /* DMA operation is in progress */
|
||||
LSI_WAIT_SCRIPTS, /* SCRIPTS stopped because of instruction count limit */
|
||||
};
|
||||
|
||||
enum {
|
||||
@@ -224,6 +225,7 @@ struct LSIState {
|
||||
MemoryRegion ram_io;
|
||||
MemoryRegion io_io;
|
||||
AddressSpace pci_io_as;
|
||||
QEMUTimer *scripts_timer;
|
||||
|
||||
int carry; /* ??? Should this be an a visible register somewhere? */
|
||||
int status;
|
||||
@@ -415,6 +417,7 @@ static void lsi_soft_reset(LSIState *s)
|
||||
s->sbr = 0;
|
||||
assert(QTAILQ_EMPTY(&s->queue));
|
||||
assert(!s->current);
|
||||
timer_del(s->scripts_timer);
|
||||
}
|
||||
|
||||
static int lsi_dma_40bit(LSIState *s)
|
||||
@@ -570,8 +573,9 @@ static inline void lsi_set_phase(LSIState *s, int phase)
|
||||
s->sstat1 = (s->sstat1 & ~PHASE_MASK) | phase;
|
||||
}
|
||||
|
||||
static void lsi_bad_phase(LSIState *s, int out, int new_phase)
|
||||
static int lsi_bad_phase(LSIState *s, int out, int new_phase)
|
||||
{
|
||||
int ret = 0;
|
||||
/* Trigger a phase mismatch. */
|
||||
if (s->ccntl0 & LSI_CCNTL0_ENPMJ) {
|
||||
if ((s->ccntl0 & LSI_CCNTL0_PMJCTL)) {
|
||||
@@ -584,8 +588,10 @@ static void lsi_bad_phase(LSIState *s, int out, int new_phase)
|
||||
trace_lsi_bad_phase_interrupt();
|
||||
lsi_script_scsi_interrupt(s, LSI_SIST0_MA, 0);
|
||||
lsi_stop_script(s);
|
||||
ret = 1;
|
||||
}
|
||||
lsi_set_phase(s, new_phase);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
@@ -789,7 +795,7 @@ static int lsi_queue_req(LSIState *s, SCSIRequest *req, uint32_t len)
|
||||
static void lsi_command_complete(SCSIRequest *req, size_t resid)
|
||||
{
|
||||
LSIState *s = LSI53C895A(req->bus->qbus.parent);
|
||||
int out;
|
||||
int out, stop = 0;
|
||||
|
||||
out = (s->sstat1 & PHASE_MASK) == PHASE_DO;
|
||||
trace_lsi_command_complete(req->status);
|
||||
@@ -797,7 +803,10 @@ static void lsi_command_complete(SCSIRequest *req, size_t resid)
|
||||
s->command_complete = 2;
|
||||
if (s->waiting && s->dbc != 0) {
|
||||
/* Raise phase mismatch for short transfers. */
|
||||
lsi_bad_phase(s, out, PHASE_ST);
|
||||
stop = lsi_bad_phase(s, out, PHASE_ST);
|
||||
if (stop) {
|
||||
s->waiting = 0;
|
||||
}
|
||||
} else {
|
||||
lsi_set_phase(s, PHASE_ST);
|
||||
}
|
||||
@@ -807,7 +816,9 @@ static void lsi_command_complete(SCSIRequest *req, size_t resid)
|
||||
lsi_request_free(s, s->current);
|
||||
scsi_req_unref(req);
|
||||
}
|
||||
lsi_resume_script(s);
|
||||
if (!stop) {
|
||||
lsi_resume_script(s);
|
||||
}
|
||||
}
|
||||
|
||||
/* Callback to indicate that the SCSI layer has completed a transfer. */
|
||||
@@ -1127,6 +1138,12 @@ static void lsi_wait_reselect(LSIState *s)
|
||||
}
|
||||
}
|
||||
|
||||
static void lsi_scripts_timer_start(LSIState *s)
|
||||
{
|
||||
trace_lsi_scripts_timer_start();
|
||||
timer_mod(s->scripts_timer, qemu_clock_get_us(QEMU_CLOCK_VIRTUAL) + 500);
|
||||
}
|
||||
|
||||
static void lsi_execute_script(LSIState *s)
|
||||
{
|
||||
PCIDevice *pci_dev = PCI_DEVICE(s);
|
||||
@@ -1136,6 +1153,11 @@ static void lsi_execute_script(LSIState *s)
|
||||
int insn_processed = 0;
|
||||
static int reentrancy_level;
|
||||
|
||||
if (s->waiting == LSI_WAIT_SCRIPTS) {
|
||||
timer_del(s->scripts_timer);
|
||||
s->waiting = LSI_NOWAIT;
|
||||
}
|
||||
|
||||
reentrancy_level++;
|
||||
|
||||
s->istat1 |= LSI_ISTAT1_SRUN;
|
||||
@@ -1143,8 +1165,8 @@ again:
|
||||
/*
|
||||
* Some windows drivers make the device spin waiting for a memory location
|
||||
* to change. If we have executed more than LSI_MAX_INSN instructions then
|
||||
* assume this is the case and force an unexpected device disconnect. This
|
||||
* is apparently sufficient to beat the drivers into submission.
|
||||
* assume this is the case and start a timer. Until the timer fires, the
|
||||
* host CPU has a chance to run and change the memory location.
|
||||
*
|
||||
* Another issue (CVE-2023-0330) can occur if the script is programmed to
|
||||
* trigger itself again and again. Avoid this problem by stopping after
|
||||
@@ -1152,13 +1174,8 @@ again:
|
||||
* which should be enough for all valid use cases).
|
||||
*/
|
||||
if (++insn_processed > LSI_MAX_INSN || reentrancy_level > 8) {
|
||||
if (!(s->sien0 & LSI_SIST0_UDC)) {
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"lsi_scsi: inf. loop with UDC masked");
|
||||
}
|
||||
lsi_script_scsi_interrupt(s, LSI_SIST0_UDC, 0);
|
||||
lsi_disconnect(s);
|
||||
trace_lsi_execute_script_stop();
|
||||
s->waiting = LSI_WAIT_SCRIPTS;
|
||||
lsi_scripts_timer_start(s);
|
||||
reentrancy_level--;
|
||||
return;
|
||||
}
|
||||
@@ -2197,6 +2214,9 @@ static int lsi_post_load(void *opaque, int version_id)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (s->waiting == LSI_WAIT_SCRIPTS) {
|
||||
lsi_scripts_timer_start(s);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -2294,6 +2314,15 @@ static const struct SCSIBusInfo lsi_scsi_info = {
|
||||
.cancel = lsi_request_cancelled
|
||||
};
|
||||
|
||||
static void scripts_timer_cb(void *opaque)
|
||||
{
|
||||
LSIState *s = opaque;
|
||||
|
||||
trace_lsi_scripts_timer_triggered();
|
||||
s->waiting = LSI_NOWAIT;
|
||||
lsi_execute_script(s);
|
||||
}
|
||||
|
||||
static void lsi_scsi_realize(PCIDevice *dev, Error **errp)
|
||||
{
|
||||
LSIState *s = LSI53C895A(dev);
|
||||
@@ -2313,6 +2342,7 @@ static void lsi_scsi_realize(PCIDevice *dev, Error **errp)
|
||||
"lsi-ram", 0x2000);
|
||||
memory_region_init_io(&s->io_io, OBJECT(s), &lsi_io_ops, s,
|
||||
"lsi-io", 256);
|
||||
s->scripts_timer = timer_new_us(QEMU_CLOCK_VIRTUAL, scripts_timer_cb, s);
|
||||
|
||||
/*
|
||||
* Since we use the address-space API to interact with ram_io, disable the
|
||||
@@ -2337,6 +2367,7 @@ static void lsi_scsi_exit(PCIDevice *dev)
|
||||
LSIState *s = LSI53C895A(dev);
|
||||
|
||||
address_space_destroy(&s->pci_io_as);
|
||||
timer_del(s->scripts_timer);
|
||||
}
|
||||
|
||||
static void lsi_class_init(ObjectClass *klass, void *data)
|
||||
|
||||
@@ -766,7 +766,6 @@ static void scsi_generic_realize(SCSIDevice *s, Error **errp)
|
||||
|
||||
/* Only used by scsi-block, but initialize it nevertheless to be clean. */
|
||||
s->default_scsi_version = -1;
|
||||
s->io_timeout = DEFAULT_IO_TIMEOUT;
|
||||
scsi_generic_read_device_inquiry(s);
|
||||
}
|
||||
|
||||
|
||||
@@ -301,6 +301,8 @@ lsi_execute_script_stop(void) "SCRIPTS execution stopped"
|
||||
lsi_awoken(void) "Woken by SIGP"
|
||||
lsi_reg_read(const char *name, int offset, uint8_t ret) "Read reg %s 0x%x = 0x%02x"
|
||||
lsi_reg_write(const char *name, int offset, uint8_t val) "Write reg %s 0x%x = 0x%02x"
|
||||
lsi_scripts_timer_triggered(void) "SCRIPTS timer triggered"
|
||||
lsi_scripts_timer_start(void) "SCRIPTS timer started"
|
||||
|
||||
# virtio-scsi.c
|
||||
virtio_scsi_cmd_req(int lun, uint32_t tag, uint8_t cmd) "virtio_scsi_cmd_req lun=%u tag=0x%x cmd=0x%x"
|
||||
|
||||
@@ -473,6 +473,7 @@ static uint32_t sdhci_read_dataport(SDHCIState *s, unsigned size)
|
||||
}
|
||||
|
||||
for (i = 0; i < size; i++) {
|
||||
assert(s->data_count < s->buf_maxsz);
|
||||
value |= s->fifo_buffer[s->data_count] << i * 8;
|
||||
s->data_count++;
|
||||
/* check if we've read all valid data (blksize bytes) from buffer */
|
||||
@@ -561,6 +562,7 @@ static void sdhci_write_dataport(SDHCIState *s, uint32_t value, unsigned size)
|
||||
}
|
||||
|
||||
for (i = 0; i < size; i++) {
|
||||
assert(s->data_count < s->buf_maxsz);
|
||||
s->fifo_buffer[s->data_count] = value & 0xFF;
|
||||
s->data_count++;
|
||||
value >>= 8;
|
||||
@@ -1208,6 +1210,12 @@ sdhci_write(void *opaque, hwaddr offset, uint64_t val, unsigned size)
|
||||
if (!(s->capareg & R_SDHC_CAPAB_SDMA_MASK)) {
|
||||
value &= ~SDHC_TRNS_DMA;
|
||||
}
|
||||
|
||||
/* TRNMOD writes are inhibited while Command Inhibit (DAT) is true */
|
||||
if (s->prnsts & SDHC_DATA_INHIBIT) {
|
||||
mask |= 0xffff;
|
||||
}
|
||||
|
||||
MASKED_WRITE(s->trnmod, mask, value & SDHC_TRNMOD_MASK);
|
||||
MASKED_WRITE(s->cmdreg, mask >> 16, value >> 16);
|
||||
|
||||
|
||||
@@ -126,6 +126,10 @@ static MemTxResult ufs_dma_read_req_upiu(UfsRequest *req)
|
||||
copy_size = sizeof(UtpUpiuHeader) + UFS_TRANSACTION_SPECIFIC_FIELD_SIZE +
|
||||
data_segment_length;
|
||||
|
||||
if (copy_size > sizeof(req->req_upiu)) {
|
||||
copy_size = sizeof(req->req_upiu);
|
||||
}
|
||||
|
||||
ret = ufs_addr_read(u, req_upiu_base_addr, &req->req_upiu, copy_size);
|
||||
if (ret) {
|
||||
trace_ufs_err_dma_read_req_upiu(req->slot, req_upiu_base_addr);
|
||||
@@ -225,6 +229,10 @@ static MemTxResult ufs_dma_write_rsp_upiu(UfsRequest *req)
|
||||
copy_size = rsp_upiu_byte_len;
|
||||
}
|
||||
|
||||
if (copy_size > sizeof(req->rsp_upiu)) {
|
||||
copy_size = sizeof(req->rsp_upiu);
|
||||
}
|
||||
|
||||
ret = ufs_addr_write(u, rsp_upiu_base_addr, &req->rsp_upiu, copy_size);
|
||||
if (ret) {
|
||||
trace_ufs_err_dma_write_rsp_upiu(req->slot, rsp_upiu_base_addr);
|
||||
|
||||
@@ -48,7 +48,7 @@ vhost_vdpa_set_features(void *dev, uint64_t features) "dev: %p features: 0x%"PRI
|
||||
vhost_vdpa_get_device_id(void *dev, uint32_t device_id) "dev: %p device_id %"PRIu32
|
||||
vhost_vdpa_reset_device(void *dev) "dev: %p"
|
||||
vhost_vdpa_get_vq_index(void *dev, int idx, int vq_idx) "dev: %p idx: %d vq idx: %d"
|
||||
vhost_vdpa_set_vring_ready(void *dev, unsigned i, int r) "dev: %p, idx: %u, r: %d"
|
||||
vhost_vdpa_set_vring_enable_one(void *dev, unsigned i, int enable, int r) "dev: %p, idx: %u, enable: %u, r: %d"
|
||||
vhost_vdpa_dump_config(void *dev, const char *line) "dev: %p %s"
|
||||
vhost_vdpa_set_config(void *dev, uint32_t offset, uint32_t size, uint32_t flags) "dev: %p offset: %"PRIu32" size: %"PRIu32" flags: 0x%"PRIx32
|
||||
vhost_vdpa_get_config(void *dev, void *config, uint32_t config_len) "dev: %p config: %p config_len: %"PRIu32
|
||||
|
||||
@@ -192,7 +192,14 @@ static void
|
||||
vhost_vdpa_device_get_config(VirtIODevice *vdev, uint8_t *config)
|
||||
{
|
||||
VhostVdpaDevice *s = VHOST_VDPA_DEVICE(vdev);
|
||||
int ret;
|
||||
|
||||
ret = vhost_dev_get_config(&s->dev, s->config, s->config_size,
|
||||
NULL);
|
||||
if (ret < 0) {
|
||||
error_report("get device config space failed");
|
||||
return;
|
||||
}
|
||||
memcpy(config, s->config, s->config_size);
|
||||
}
|
||||
|
||||
@@ -250,14 +257,11 @@ static int vhost_vdpa_device_start(VirtIODevice *vdev, Error **errp)
|
||||
|
||||
s->dev.acked_features = vdev->guest_features;
|
||||
|
||||
ret = vhost_dev_start(&s->dev, vdev, false);
|
||||
ret = vhost_dev_start(&s->dev, vdev, true);
|
||||
if (ret < 0) {
|
||||
error_setg_errno(errp, -ret, "Error starting vhost");
|
||||
goto err_guest_notifiers;
|
||||
}
|
||||
for (i = 0; i < s->dev.nvqs; ++i) {
|
||||
vhost_vdpa_set_vring_ready(&s->vdpa, i);
|
||||
}
|
||||
s->started = true;
|
||||
|
||||
/*
|
||||
|
||||
+26
-3
@@ -882,19 +882,41 @@ static int vhost_vdpa_get_vq_index(struct vhost_dev *dev, int idx)
|
||||
return idx;
|
||||
}
|
||||
|
||||
int vhost_vdpa_set_vring_ready(struct vhost_vdpa *v, unsigned idx)
|
||||
static int vhost_vdpa_set_vring_enable_one(struct vhost_vdpa *v, unsigned idx,
|
||||
int enable)
|
||||
{
|
||||
struct vhost_dev *dev = v->dev;
|
||||
struct vhost_vring_state state = {
|
||||
.index = idx,
|
||||
.num = 1,
|
||||
.num = enable,
|
||||
};
|
||||
int r = vhost_vdpa_call(dev, VHOST_VDPA_SET_VRING_ENABLE, &state);
|
||||
|
||||
trace_vhost_vdpa_set_vring_ready(dev, idx, r);
|
||||
trace_vhost_vdpa_set_vring_enable_one(dev, idx, enable, r);
|
||||
return r;
|
||||
}
|
||||
|
||||
static int vhost_vdpa_set_vring_enable(struct vhost_dev *dev, int enable)
|
||||
{
|
||||
struct vhost_vdpa *v = dev->opaque;
|
||||
unsigned int i;
|
||||
int ret;
|
||||
|
||||
for (i = 0; i < dev->nvqs; ++i) {
|
||||
ret = vhost_vdpa_set_vring_enable_one(v, i, enable);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int vhost_vdpa_set_vring_ready(struct vhost_vdpa *v, unsigned idx)
|
||||
{
|
||||
return vhost_vdpa_set_vring_enable_one(v, idx, 1);
|
||||
}
|
||||
|
||||
static int vhost_vdpa_set_config_call(struct vhost_dev *dev,
|
||||
int fd)
|
||||
{
|
||||
@@ -1508,6 +1530,7 @@ const VhostOps vdpa_ops = {
|
||||
.vhost_set_features = vhost_vdpa_set_features,
|
||||
.vhost_reset_device = vhost_vdpa_reset_device,
|
||||
.vhost_get_vq_index = vhost_vdpa_get_vq_index,
|
||||
.vhost_set_vring_enable = vhost_vdpa_set_vring_enable,
|
||||
.vhost_get_config = vhost_vdpa_get_config,
|
||||
.vhost_set_config = vhost_vdpa_set_config,
|
||||
.vhost_requires_shm_log = NULL,
|
||||
|
||||
+7
-1
@@ -1984,7 +1984,13 @@ static int vhost_dev_set_vring_enable(struct vhost_dev *hdev, int enable)
|
||||
return hdev->vhost_ops->vhost_set_vring_enable(hdev, enable);
|
||||
}
|
||||
|
||||
/* Host notifiers must be enabled at this point. */
|
||||
/*
|
||||
* Host notifiers must be enabled at this point.
|
||||
*
|
||||
* If @vrings is true, this function will enable all vrings before starting the
|
||||
* device. If it is false, the vring initialization is left to be done by the
|
||||
* caller.
|
||||
*/
|
||||
int vhost_dev_start(struct vhost_dev *hdev, VirtIODevice *vdev, bool vrings)
|
||||
{
|
||||
int i, r;
|
||||
|
||||
@@ -1080,8 +1080,8 @@ static void virtio_crypto_device_realize(DeviceState *dev, Error **errp)
|
||||
vcrypto->vqs[i].dataq =
|
||||
virtio_add_queue(vdev, 1024, virtio_crypto_handle_dataq_bh);
|
||||
vcrypto->vqs[i].dataq_bh =
|
||||
qemu_bh_new_guarded(virtio_crypto_dataq_bh, &vcrypto->vqs[i],
|
||||
&dev->mem_reentrancy_guard);
|
||||
virtio_bh_new_guarded(dev, virtio_crypto_dataq_bh,
|
||||
&vcrypto->vqs[i]);
|
||||
vcrypto->vqs[i].vcrypto = vcrypto;
|
||||
}
|
||||
|
||||
|
||||
+35
-2
@@ -1424,6 +1424,38 @@ static int virtio_pci_add_mem_cap(VirtIOPCIProxy *proxy,
|
||||
return offset;
|
||||
}
|
||||
|
||||
static void virtio_pci_set_vector(VirtIODevice *vdev,
|
||||
VirtIOPCIProxy *proxy,
|
||||
int queue_no, uint16_t old_vector,
|
||||
uint16_t new_vector)
|
||||
{
|
||||
bool kvm_irqfd = (vdev->status & VIRTIO_CONFIG_S_DRIVER_OK) &&
|
||||
msix_enabled(&proxy->pci_dev) && kvm_msi_via_irqfd_enabled();
|
||||
|
||||
if (new_vector == old_vector) {
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* If the device uses irqfd and the vector changes after DRIVER_OK is
|
||||
* set, we need to release the old vector and set up the new one.
|
||||
* Otherwise just need to set the new vector on the device.
|
||||
*/
|
||||
if (kvm_irqfd && old_vector != VIRTIO_NO_VECTOR) {
|
||||
kvm_virtio_pci_vector_release_one(proxy, queue_no);
|
||||
}
|
||||
/* Set the new vector on the device. */
|
||||
if (queue_no == VIRTIO_CONFIG_IRQ_IDX) {
|
||||
vdev->config_vector = new_vector;
|
||||
} else {
|
||||
virtio_queue_set_vector(vdev, queue_no, new_vector);
|
||||
}
|
||||
/* If the new vector changed need to set it up. */
|
||||
if (kvm_irqfd && new_vector != VIRTIO_NO_VECTOR) {
|
||||
kvm_virtio_pci_vector_use_one(proxy, queue_no);
|
||||
}
|
||||
}
|
||||
|
||||
int virtio_pci_add_shm_cap(VirtIOPCIProxy *proxy,
|
||||
uint8_t bar, uint64_t offset, uint64_t length,
|
||||
uint8_t id)
|
||||
@@ -1570,7 +1602,8 @@ static void virtio_pci_common_write(void *opaque, hwaddr addr,
|
||||
} else {
|
||||
val = VIRTIO_NO_VECTOR;
|
||||
}
|
||||
vdev->config_vector = val;
|
||||
virtio_pci_set_vector(vdev, proxy, VIRTIO_CONFIG_IRQ_IDX,
|
||||
vdev->config_vector, val);
|
||||
break;
|
||||
case VIRTIO_PCI_COMMON_STATUS:
|
||||
if (!(val & VIRTIO_CONFIG_S_DRIVER_OK)) {
|
||||
@@ -1610,7 +1643,7 @@ static void virtio_pci_common_write(void *opaque, hwaddr addr,
|
||||
} else {
|
||||
val = VIRTIO_NO_VECTOR;
|
||||
}
|
||||
virtio_queue_set_vector(vdev, vdev->queue_sel, val);
|
||||
virtio_pci_set_vector(vdev, proxy, vdev->queue_sel, vector, val);
|
||||
break;
|
||||
case VIRTIO_PCI_COMMON_Q_ENABLE:
|
||||
if (val == 1) {
|
||||
|
||||
+20
-2
@@ -957,12 +957,20 @@ static void virtqueue_packed_flush(VirtQueue *vq, unsigned int count)
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* For indirect element's 'ndescs' is 1.
|
||||
* For all other elemment's 'ndescs' is the
|
||||
* number of descriptors chained by NEXT (as set in virtqueue_packed_pop).
|
||||
* So When the 'elem' be filled into the descriptor ring,
|
||||
* The 'idx' of this 'elem' shall be
|
||||
* the value of 'vq->used_idx' plus the 'ndescs'.
|
||||
*/
|
||||
ndescs += vq->used_elems[0].ndescs;
|
||||
for (i = 1; i < count; i++) {
|
||||
virtqueue_packed_fill_desc(vq, &vq->used_elems[i], i, false);
|
||||
virtqueue_packed_fill_desc(vq, &vq->used_elems[i], ndescs, false);
|
||||
ndescs += vq->used_elems[i].ndescs;
|
||||
}
|
||||
virtqueue_packed_fill_desc(vq, &vq->used_elems[0], 0, true);
|
||||
ndescs += vq->used_elems[0].ndescs;
|
||||
|
||||
vq->inuse -= ndescs;
|
||||
vq->used_idx += ndescs;
|
||||
@@ -4137,3 +4145,13 @@ static void virtio_register_types(void)
|
||||
}
|
||||
|
||||
type_init(virtio_register_types)
|
||||
|
||||
QEMUBH *virtio_bh_new_guarded_full(DeviceState *dev,
|
||||
QEMUBHFunc *cb, void *opaque,
|
||||
const char *name)
|
||||
{
|
||||
DeviceState *transport = qdev_get_parent_bus(dev)->parent;
|
||||
|
||||
return qemu_bh_new_full(cb, opaque, name,
|
||||
&transport->mem_reentrancy_guard);
|
||||
}
|
||||
|
||||
+28
-2
@@ -481,11 +481,37 @@ static void xen_invalidate_map_cache_entry_unlocked(uint8_t *buffer)
|
||||
g_free(entry);
|
||||
}
|
||||
|
||||
void xen_invalidate_map_cache_entry(uint8_t *buffer)
|
||||
typedef struct XenMapCacheData {
|
||||
Coroutine *co;
|
||||
uint8_t *buffer;
|
||||
} XenMapCacheData;
|
||||
|
||||
static void xen_invalidate_map_cache_entry_bh(void *opaque)
|
||||
{
|
||||
XenMapCacheData *data = opaque;
|
||||
|
||||
mapcache_lock();
|
||||
xen_invalidate_map_cache_entry_unlocked(buffer);
|
||||
xen_invalidate_map_cache_entry_unlocked(data->buffer);
|
||||
mapcache_unlock();
|
||||
|
||||
aio_co_wake(data->co);
|
||||
}
|
||||
|
||||
void coroutine_mixed_fn xen_invalidate_map_cache_entry(uint8_t *buffer)
|
||||
{
|
||||
if (qemu_in_coroutine()) {
|
||||
XenMapCacheData data = {
|
||||
.co = qemu_coroutine_self(),
|
||||
.buffer = buffer,
|
||||
};
|
||||
aio_bh_schedule_oneshot(qemu_get_current_aio_context(),
|
||||
xen_invalidate_map_cache_entry_bh, &data);
|
||||
qemu_coroutine_yield();
|
||||
} else {
|
||||
mapcache_lock();
|
||||
xen_invalidate_map_cache_entry_unlocked(buffer);
|
||||
mapcache_unlock();
|
||||
}
|
||||
}
|
||||
|
||||
void xen_invalidate_map_cache(void)
|
||||
|
||||
@@ -151,7 +151,6 @@ struct VirtIOSoundPCMStream {
|
||||
QemuMutex queue_mutex;
|
||||
bool active;
|
||||
QSIMPLEQ_HEAD(, VirtIOSoundPCMBuffer) queue;
|
||||
QSIMPLEQ_HEAD(, VirtIOSoundPCMBuffer) invalid;
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -223,6 +222,21 @@ struct VirtIOSound {
|
||||
QemuMutex cmdq_mutex;
|
||||
QTAILQ_HEAD(, virtio_snd_ctrl_command) cmdq;
|
||||
bool processing_cmdq;
|
||||
/*
|
||||
* Convenience queue to keep track of invalid tx/rx queue messages inside
|
||||
* the tx/rx callbacks.
|
||||
*
|
||||
* In the callbacks as a first step we are emptying the virtqueue to handle
|
||||
* each message and we cannot add an invalid message back to the queue: we
|
||||
* would re-process it in subsequent loop iterations.
|
||||
*
|
||||
* Instead, we add them to this queue and after finishing examining every
|
||||
* virtqueue element, we inform the guest for each invalid message.
|
||||
*
|
||||
* This queue must be empty at all times except for inside the tx/rx
|
||||
* callbacks.
|
||||
*/
|
||||
QSIMPLEQ_HEAD(, VirtIOSoundPCMBuffer) invalid;
|
||||
};
|
||||
|
||||
struct virtio_snd_ctrl_command {
|
||||
@@ -230,6 +244,7 @@ struct virtio_snd_ctrl_command {
|
||||
VirtQueue *vq;
|
||||
virtio_snd_hdr ctrl;
|
||||
virtio_snd_hdr resp;
|
||||
size_t payload_size;
|
||||
QTAILQ_ENTRY(virtio_snd_ctrl_command) next;
|
||||
};
|
||||
#endif
|
||||
|
||||
@@ -14,9 +14,21 @@
|
||||
#include "qom/object.h"
|
||||
|
||||
/*
|
||||
* IRQ range offsets per device type
|
||||
* The XIVE IRQ backend uses the same layout as the XICS backend but
|
||||
* covers the full range of the IRQ number space. The IRQ numbers for
|
||||
* the CPU IPIs are allocated at the bottom of this space, below 4K,
|
||||
* to preserve compatibility with XICS which does not use that range.
|
||||
*/
|
||||
|
||||
/*
|
||||
* CPU IPI range (XIVE only)
|
||||
*/
|
||||
#define SPAPR_IRQ_IPI 0x0
|
||||
#define SPAPR_IRQ_NR_IPIS 0x1000
|
||||
|
||||
/*
|
||||
* IRQ range offsets per device type
|
||||
*/
|
||||
|
||||
#define SPAPR_XIRQ_BASE XICS_IRQ_BASE /* 0x1000 */
|
||||
#define SPAPR_IRQ_EPOW (SPAPR_XIRQ_BASE + 0x0000)
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
*
|
||||
* Copyright (c) 2016 Artyom Tarasenko
|
||||
*
|
||||
* This code is licensed under the GNU GPL v3 or (at your option) any later
|
||||
* This code is licensed under the GNU GPL v2 or (at your option) any later
|
||||
* version.
|
||||
*/
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include "standard-headers/linux/virtio_config.h"
|
||||
#include "standard-headers/linux/virtio_ring.h"
|
||||
#include "qom/object.h"
|
||||
#include "block/aio.h"
|
||||
|
||||
/*
|
||||
* A guest should never accept this. It implies negotiation is broken
|
||||
@@ -508,4 +509,10 @@ static inline bool virtio_device_disabled(VirtIODevice *vdev)
|
||||
bool virtio_legacy_allowed(VirtIODevice *vdev);
|
||||
bool virtio_legacy_check_disabled(VirtIODevice *vdev);
|
||||
|
||||
QEMUBH *virtio_bh_new_guarded_full(DeviceState *dev,
|
||||
QEMUBHFunc *cb, void *opaque,
|
||||
const char *name);
|
||||
#define virtio_bh_new_guarded(dev, cb, opaque) \
|
||||
virtio_bh_new_guarded_full((dev), (cb), (opaque), (stringify(cb)))
|
||||
|
||||
#endif
|
||||
|
||||
+1
-1
@@ -503,7 +503,7 @@ void job_enter(Job *job);
|
||||
*
|
||||
* Called with job_mutex *not* held.
|
||||
*/
|
||||
void coroutine_fn job_pause_point(Job *job);
|
||||
void coroutine_fn GRAPH_UNLOCKED job_pause_point(Job *job);
|
||||
|
||||
/**
|
||||
* @job: The job that calls the function.
|
||||
|
||||
@@ -3016,8 +3016,6 @@ static void pgb_dynamic(const char *image_name, uintptr_t guest_loaddr,
|
||||
uintptr_t brk, ret;
|
||||
PGBAddrs ga;
|
||||
|
||||
assert(QEMU_IS_ALIGNED(guest_loaddr, align));
|
||||
|
||||
/* Try the identity map first. */
|
||||
if (pgb_addr_set(&ga, guest_loaddr, guest_hiaddr, true)) {
|
||||
brk = (uintptr_t)sbrk(0);
|
||||
|
||||
+34
-13
@@ -2277,18 +2277,13 @@ static abi_long do_setsockopt(int sockfd, int level, int optname,
|
||||
switch (optname) {
|
||||
case ALG_SET_KEY:
|
||||
{
|
||||
char *alg_key = g_malloc(optlen);
|
||||
|
||||
char *alg_key = lock_user(VERIFY_READ, optval_addr, optlen, 1);
|
||||
if (!alg_key) {
|
||||
return -TARGET_ENOMEM;
|
||||
}
|
||||
if (copy_from_user(alg_key, optval_addr, optlen)) {
|
||||
g_free(alg_key);
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
ret = get_errno(setsockopt(sockfd, level, optname,
|
||||
alg_key, optlen));
|
||||
g_free(alg_key);
|
||||
unlock_user(alg_key, optval_addr, optlen);
|
||||
break;
|
||||
}
|
||||
case ALG_SET_AEAD_AUTHSIZE:
|
||||
@@ -7994,6 +7989,10 @@ static void open_self_maps_4(const struct open_self_maps_data *d,
|
||||
path = "[heap]";
|
||||
} else if (start == info->vdso) {
|
||||
path = "[vdso]";
|
||||
#ifdef TARGET_X86_64
|
||||
} else if (start == TARGET_VSYSCALL_PAGE) {
|
||||
path = "[vsyscall]";
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Except null device (MAP_ANON), adjust offset for this fragment. */
|
||||
@@ -8082,6 +8081,18 @@ static int open_self_maps_2(void *opaque, target_ulong guest_start,
|
||||
uintptr_t host_start = (uintptr_t)g2h_untagged(guest_start);
|
||||
uintptr_t host_last = (uintptr_t)g2h_untagged(guest_end - 1);
|
||||
|
||||
#ifdef TARGET_X86_64
|
||||
/*
|
||||
* Because of the extremely high position of the page within the guest
|
||||
* virtual address space, this is not backed by host memory at all.
|
||||
* Therefore the loop below would fail. This is the only instance
|
||||
* of not having host backing memory.
|
||||
*/
|
||||
if (guest_start == TARGET_VSYSCALL_PAGE) {
|
||||
return open_self_maps_3(opaque, guest_start, guest_end, flags);
|
||||
}
|
||||
#endif
|
||||
|
||||
while (1) {
|
||||
IntervalTreeNode *n =
|
||||
interval_tree_iter_first(d->host_maps, host_start, host_start);
|
||||
@@ -9154,14 +9165,24 @@ static abi_long do_syscall1(CPUArchState *cpu_env, int num, abi_long arg1,
|
||||
#ifdef TARGET_NR_waitid
|
||||
case TARGET_NR_waitid:
|
||||
{
|
||||
struct rusage ru;
|
||||
siginfo_t info;
|
||||
info.si_pid = 0;
|
||||
ret = get_errno(safe_waitid(arg1, arg2, &info, arg4, NULL));
|
||||
if (!is_error(ret) && arg3 && info.si_pid != 0) {
|
||||
if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_siginfo_t), 0)))
|
||||
|
||||
ret = get_errno(safe_waitid(arg1, arg2, (arg3 ? &info : NULL),
|
||||
arg4, (arg5 ? &ru : NULL)));
|
||||
if (!is_error(ret)) {
|
||||
if (arg3) {
|
||||
p = lock_user(VERIFY_WRITE, arg3,
|
||||
sizeof(target_siginfo_t), 0);
|
||||
if (!p) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
host_to_target_siginfo(p, &info);
|
||||
unlock_user(p, arg3, sizeof(target_siginfo_t));
|
||||
}
|
||||
if (arg5 && host_to_target_rusage(arg5, &ru)) {
|
||||
return -TARGET_EFAULT;
|
||||
host_to_target_siginfo(p, &info);
|
||||
unlock_user(p, arg3, sizeof(target_siginfo_t));
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
|
||||
+4
-1
@@ -409,7 +409,10 @@ static int init_blk_migration(QEMUFile *f)
|
||||
}
|
||||
|
||||
sectors = bdrv_nb_sectors(bs);
|
||||
if (sectors <= 0) {
|
||||
if (sectors == 0) {
|
||||
continue;
|
||||
}
|
||||
if (sectors < 0) {
|
||||
ret = sectors;
|
||||
bdrv_next_cleanup(&it);
|
||||
goto out;
|
||||
|
||||
+10
-8
@@ -830,6 +830,16 @@ static void *colo_process_incoming_thread(void *opaque)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Make sure all file formats throw away their mutable metadata */
|
||||
qemu_mutex_lock_iothread();
|
||||
bdrv_activate_all(&local_err);
|
||||
if (local_err) {
|
||||
qemu_mutex_unlock_iothread();
|
||||
error_report_err(local_err);
|
||||
return NULL;
|
||||
}
|
||||
qemu_mutex_unlock_iothread();
|
||||
|
||||
failover_init_state();
|
||||
|
||||
mis->to_src_file = qemu_file_get_return_path(mis->from_src_file);
|
||||
@@ -917,7 +927,6 @@ out:
|
||||
int coroutine_fn colo_incoming_co(void)
|
||||
{
|
||||
MigrationIncomingState *mis = migration_incoming_get_current();
|
||||
Error *local_err = NULL;
|
||||
QemuThread th;
|
||||
|
||||
assert(qemu_mutex_iothread_locked());
|
||||
@@ -926,13 +935,6 @@ int coroutine_fn colo_incoming_co(void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Make sure all file formats throw away their mutable metadata */
|
||||
bdrv_activate_all(&local_err);
|
||||
if (local_err) {
|
||||
error_report_err(local_err);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
qemu_thread_create(&th, "COLO incoming", colo_process_incoming_thread,
|
||||
mis, QEMU_THREAD_JOINABLE);
|
||||
|
||||
|
||||
@@ -2408,6 +2408,8 @@ static int postcopy_start(MigrationState *ms, Error **errp)
|
||||
migration_wait_main_channel(ms);
|
||||
if (postcopy_preempt_establish_channel(ms)) {
|
||||
migrate_set_state(&ms->state, ms->state, MIGRATION_STATUS_FAILED);
|
||||
error_setg(errp, "%s: Failed to establish preempt channel",
|
||||
__func__);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
@@ -2427,17 +2429,22 @@ static int postcopy_start(MigrationState *ms, Error **errp)
|
||||
global_state_store();
|
||||
ret = migration_stop_vm(RUN_STATE_FINISH_MIGRATE);
|
||||
if (ret < 0) {
|
||||
error_setg_errno(errp, -ret, "%s: Failed to stop the VM", __func__);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ret = migration_maybe_pause(ms, &cur_state,
|
||||
MIGRATION_STATUS_POSTCOPY_ACTIVE);
|
||||
if (ret < 0) {
|
||||
error_setg_errno(errp, -ret, "%s: Failed in migration_maybe_pause()",
|
||||
__func__);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ret = bdrv_inactivate_all();
|
||||
if (ret < 0) {
|
||||
error_setg_errno(errp, -ret, "%s: Failed in bdrv_inactivate_all()",
|
||||
__func__);
|
||||
goto fail;
|
||||
}
|
||||
restart_block = true;
|
||||
@@ -2514,6 +2521,7 @@ static int postcopy_start(MigrationState *ms, Error **errp)
|
||||
|
||||
/* Now send that blob */
|
||||
if (qemu_savevm_send_packaged(ms->to_dst_file, bioc->data, bioc->usage)) {
|
||||
error_setg(errp, "%s: Failed to send packaged data", __func__);
|
||||
goto fail_closefb;
|
||||
}
|
||||
qemu_fclose(fb);
|
||||
|
||||
+1
-1
@@ -3357,7 +3357,7 @@ static int qemu_rdma_accept(RDMAContext *rdma)
|
||||
goto err_rdma_dest_wait;
|
||||
}
|
||||
|
||||
isock->host = rdma->host;
|
||||
isock->host = g_strdup(rdma->host);
|
||||
isock->port = g_strdup_printf("%d", rdma->port);
|
||||
|
||||
/*
|
||||
|
||||
@@ -2343,6 +2343,27 @@ static int loadvm_handle_cmd_packaged(MigrationIncomingState *mis)
|
||||
|
||||
QEMUFile *packf = qemu_file_new_input(QIO_CHANNEL(bioc));
|
||||
|
||||
/*
|
||||
* Before loading the guest states, ensure that the preempt channel has
|
||||
* been ready to use, as some of the states (e.g. via virtio_load) might
|
||||
* trigger page faults that will be handled through the preempt channel.
|
||||
* So yield to the main thread in the case that the channel create event
|
||||
* hasn't been dispatched.
|
||||
*
|
||||
* TODO: if we can move migration loadvm out of main thread, then we
|
||||
* won't block main thread from polling the accept() fds. We can drop
|
||||
* this as a whole when that is done.
|
||||
*/
|
||||
do {
|
||||
if (!migrate_postcopy_preempt() || !qemu_in_coroutine() ||
|
||||
mis->postcopy_qemufile_dst) {
|
||||
break;
|
||||
}
|
||||
|
||||
aio_co_schedule(qemu_get_current_aio_context(), qemu_coroutine_self());
|
||||
qemu_coroutine_yield();
|
||||
} while (1);
|
||||
|
||||
ret = qemu_loadvm_state_main(packf, mis);
|
||||
trace_loadvm_handle_cmd_packaged_main(ret);
|
||||
qemu_fclose(packf);
|
||||
|
||||
@@ -260,7 +260,7 @@ void *gpa2hva(MemoryRegion **p_mr, hwaddr addr, uint64_t size, Error **errp)
|
||||
}
|
||||
|
||||
if (!memory_region_is_ram(mrs.mr) && !memory_region_is_romd(mrs.mr)) {
|
||||
error_setg(errp, "Memory at address 0x%" HWADDR_PRIx "is not RAM", addr);
|
||||
error_setg(errp, "Memory at address 0x%" HWADDR_PRIx " is not RAM", addr);
|
||||
memory_region_unref(mrs.mr);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
+24
-4
@@ -596,13 +596,31 @@ static int nbd_request_simple_option(QIOChannel *ioc, int opt, bool strict,
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Callback to learn when QIO TLS upgrade is complete */
|
||||
struct NBDTLSClientHandshakeData {
|
||||
bool complete;
|
||||
Error *error;
|
||||
GMainLoop *loop;
|
||||
};
|
||||
|
||||
static void nbd_client_tls_handshake(QIOTask *task, void *opaque)
|
||||
{
|
||||
struct NBDTLSClientHandshakeData *data = opaque;
|
||||
|
||||
qio_task_propagate_error(task, &data->error);
|
||||
data->complete = true;
|
||||
if (data->loop) {
|
||||
g_main_loop_quit(data->loop);
|
||||
}
|
||||
}
|
||||
|
||||
static QIOChannel *nbd_receive_starttls(QIOChannel *ioc,
|
||||
QCryptoTLSCreds *tlscreds,
|
||||
const char *hostname, Error **errp)
|
||||
{
|
||||
int ret;
|
||||
QIOChannelTLS *tioc;
|
||||
struct NBDTLSHandshakeData data = { 0 };
|
||||
struct NBDTLSClientHandshakeData data = { 0 };
|
||||
|
||||
ret = nbd_request_simple_option(ioc, NBD_OPT_STARTTLS, true, errp);
|
||||
if (ret <= 0) {
|
||||
@@ -619,18 +637,20 @@ static QIOChannel *nbd_receive_starttls(QIOChannel *ioc,
|
||||
return NULL;
|
||||
}
|
||||
qio_channel_set_name(QIO_CHANNEL(tioc), "nbd-client-tls");
|
||||
data.loop = g_main_loop_new(g_main_context_default(), FALSE);
|
||||
trace_nbd_receive_starttls_tls_handshake();
|
||||
qio_channel_tls_handshake(tioc,
|
||||
nbd_tls_handshake,
|
||||
nbd_client_tls_handshake,
|
||||
&data,
|
||||
NULL,
|
||||
NULL);
|
||||
|
||||
if (!data.complete) {
|
||||
data.loop = g_main_loop_new(g_main_context_default(), FALSE);
|
||||
g_main_loop_run(data.loop);
|
||||
assert(data.complete);
|
||||
g_main_loop_unref(data.loop);
|
||||
}
|
||||
g_main_loop_unref(data.loop);
|
||||
|
||||
if (data.error) {
|
||||
error_propagate(errp, data.error);
|
||||
object_unref(OBJECT(tioc));
|
||||
|
||||
@@ -47,17 +47,6 @@ int nbd_drop(QIOChannel *ioc, size_t size, Error **errp)
|
||||
}
|
||||
|
||||
|
||||
void nbd_tls_handshake(QIOTask *task,
|
||||
void *opaque)
|
||||
{
|
||||
struct NBDTLSHandshakeData *data = opaque;
|
||||
|
||||
qio_task_propagate_error(task, &data->error);
|
||||
data->complete = true;
|
||||
g_main_loop_quit(data->loop);
|
||||
}
|
||||
|
||||
|
||||
const char *nbd_opt_lookup(uint32_t opt)
|
||||
{
|
||||
switch (opt) {
|
||||
|
||||
@@ -72,16 +72,6 @@ static inline int nbd_write(QIOChannel *ioc, const void *buffer, size_t size,
|
||||
return qio_channel_write_all(ioc, buffer, size, errp) < 0 ? -EIO : 0;
|
||||
}
|
||||
|
||||
struct NBDTLSHandshakeData {
|
||||
GMainLoop *loop;
|
||||
bool complete;
|
||||
Error *error;
|
||||
};
|
||||
|
||||
|
||||
void nbd_tls_handshake(QIOTask *task,
|
||||
void *opaque);
|
||||
|
||||
int nbd_drop(QIOChannel *ioc, size_t size, Error **errp);
|
||||
|
||||
#endif
|
||||
|
||||
+245
-93
@@ -122,26 +122,28 @@ struct NBDMetaContexts {
|
||||
};
|
||||
|
||||
struct NBDClient {
|
||||
int refcount;
|
||||
int refcount; /* atomic */
|
||||
void (*close_fn)(NBDClient *client, bool negotiated);
|
||||
|
||||
QemuMutex lock;
|
||||
|
||||
NBDExport *exp;
|
||||
QCryptoTLSCreds *tlscreds;
|
||||
char *tlsauthz;
|
||||
QIOChannelSocket *sioc; /* The underlying data channel */
|
||||
QIOChannel *ioc; /* The current I/O channel which may differ (eg TLS) */
|
||||
|
||||
Coroutine *recv_coroutine;
|
||||
Coroutine *recv_coroutine; /* protected by lock */
|
||||
|
||||
CoMutex send_lock;
|
||||
Coroutine *send_coroutine;
|
||||
|
||||
bool read_yielding;
|
||||
bool quiescing;
|
||||
bool read_yielding; /* protected by lock */
|
||||
bool quiescing; /* protected by lock */
|
||||
|
||||
QTAILQ_ENTRY(NBDClient) next;
|
||||
int nb_requests;
|
||||
bool closing;
|
||||
int nb_requests; /* protected by lock */
|
||||
bool closing; /* protected by lock */
|
||||
|
||||
uint32_t check_align; /* If non-zero, check for aligned client requests */
|
||||
|
||||
@@ -193,8 +195,9 @@ static inline void set_be_option_rep(NBDOptionReply *rep, uint32_t option,
|
||||
|
||||
/* Send a reply header, including length, but no payload.
|
||||
* Return -errno on error, 0 on success. */
|
||||
static int nbd_negotiate_send_rep_len(NBDClient *client, uint32_t type,
|
||||
uint32_t len, Error **errp)
|
||||
static coroutine_fn int
|
||||
nbd_negotiate_send_rep_len(NBDClient *client, uint32_t type,
|
||||
uint32_t len, Error **errp)
|
||||
{
|
||||
NBDOptionReply rep;
|
||||
|
||||
@@ -209,15 +212,15 @@ static int nbd_negotiate_send_rep_len(NBDClient *client, uint32_t type,
|
||||
|
||||
/* Send a reply header with default 0 length.
|
||||
* Return -errno on error, 0 on success. */
|
||||
static int nbd_negotiate_send_rep(NBDClient *client, uint32_t type,
|
||||
Error **errp)
|
||||
static coroutine_fn int
|
||||
nbd_negotiate_send_rep(NBDClient *client, uint32_t type, Error **errp)
|
||||
{
|
||||
return nbd_negotiate_send_rep_len(client, type, 0, errp);
|
||||
}
|
||||
|
||||
/* Send an error reply.
|
||||
* Return -errno on error, 0 on success. */
|
||||
static int G_GNUC_PRINTF(4, 0)
|
||||
static coroutine_fn int G_GNUC_PRINTF(4, 0)
|
||||
nbd_negotiate_send_rep_verr(NBDClient *client, uint32_t type,
|
||||
Error **errp, const char *fmt, va_list va)
|
||||
{
|
||||
@@ -257,7 +260,7 @@ nbd_sanitize_name(const char *name)
|
||||
|
||||
/* Send an error reply.
|
||||
* Return -errno on error, 0 on success. */
|
||||
static int G_GNUC_PRINTF(4, 5)
|
||||
static coroutine_fn int G_GNUC_PRINTF(4, 5)
|
||||
nbd_negotiate_send_rep_err(NBDClient *client, uint32_t type,
|
||||
Error **errp, const char *fmt, ...)
|
||||
{
|
||||
@@ -273,7 +276,7 @@ nbd_negotiate_send_rep_err(NBDClient *client, uint32_t type,
|
||||
/* Drop remainder of the current option, and send a reply with the
|
||||
* given error type and message. Return -errno on read or write
|
||||
* failure; or 0 if connection is still live. */
|
||||
static int G_GNUC_PRINTF(4, 0)
|
||||
static coroutine_fn int G_GNUC_PRINTF(4, 0)
|
||||
nbd_opt_vdrop(NBDClient *client, uint32_t type, Error **errp,
|
||||
const char *fmt, va_list va)
|
||||
{
|
||||
@@ -286,7 +289,7 @@ nbd_opt_vdrop(NBDClient *client, uint32_t type, Error **errp,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int G_GNUC_PRINTF(4, 5)
|
||||
static coroutine_fn int G_GNUC_PRINTF(4, 5)
|
||||
nbd_opt_drop(NBDClient *client, uint32_t type, Error **errp,
|
||||
const char *fmt, ...)
|
||||
{
|
||||
@@ -300,7 +303,7 @@ nbd_opt_drop(NBDClient *client, uint32_t type, Error **errp,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int G_GNUC_PRINTF(3, 4)
|
||||
static coroutine_fn int G_GNUC_PRINTF(3, 4)
|
||||
nbd_opt_invalid(NBDClient *client, Error **errp, const char *fmt, ...)
|
||||
{
|
||||
int ret;
|
||||
@@ -317,8 +320,9 @@ nbd_opt_invalid(NBDClient *client, Error **errp, const char *fmt, ...)
|
||||
* If @check_nul, require that no NUL bytes appear in buffer.
|
||||
* Return -errno on I/O error, 0 if option was completely handled by
|
||||
* sending a reply about inconsistent lengths, or 1 on success. */
|
||||
static int nbd_opt_read(NBDClient *client, void *buffer, size_t size,
|
||||
bool check_nul, Error **errp)
|
||||
static coroutine_fn int
|
||||
nbd_opt_read(NBDClient *client, void *buffer, size_t size,
|
||||
bool check_nul, Error **errp)
|
||||
{
|
||||
if (size > client->optlen) {
|
||||
return nbd_opt_invalid(client, errp,
|
||||
@@ -341,7 +345,8 @@ static int nbd_opt_read(NBDClient *client, void *buffer, size_t size,
|
||||
/* Drop size bytes from the unparsed payload of the current option.
|
||||
* Return -errno on I/O error, 0 if option was completely handled by
|
||||
* sending a reply about inconsistent lengths, or 1 on success. */
|
||||
static int nbd_opt_skip(NBDClient *client, size_t size, Error **errp)
|
||||
static coroutine_fn int
|
||||
nbd_opt_skip(NBDClient *client, size_t size, Error **errp)
|
||||
{
|
||||
if (size > client->optlen) {
|
||||
return nbd_opt_invalid(client, errp,
|
||||
@@ -364,8 +369,9 @@ static int nbd_opt_skip(NBDClient *client, size_t size, Error **errp)
|
||||
* Return -errno on I/O error, 0 if option was completely handled by
|
||||
* sending a reply about inconsistent lengths, or 1 on success.
|
||||
*/
|
||||
static int nbd_opt_read_name(NBDClient *client, char **name, uint32_t *length,
|
||||
Error **errp)
|
||||
static coroutine_fn int
|
||||
nbd_opt_read_name(NBDClient *client, char **name, uint32_t *length,
|
||||
Error **errp)
|
||||
{
|
||||
int ret;
|
||||
uint32_t len;
|
||||
@@ -400,8 +406,8 @@ static int nbd_opt_read_name(NBDClient *client, char **name, uint32_t *length,
|
||||
|
||||
/* Send a single NBD_REP_SERVER reply to NBD_OPT_LIST, including payload.
|
||||
* Return -errno on error, 0 on success. */
|
||||
static int nbd_negotiate_send_rep_list(NBDClient *client, NBDExport *exp,
|
||||
Error **errp)
|
||||
static coroutine_fn int
|
||||
nbd_negotiate_send_rep_list(NBDClient *client, NBDExport *exp, Error **errp)
|
||||
{
|
||||
ERRP_GUARD();
|
||||
size_t name_len, desc_len;
|
||||
@@ -442,7 +448,8 @@ static int nbd_negotiate_send_rep_list(NBDClient *client, NBDExport *exp,
|
||||
|
||||
/* Process the NBD_OPT_LIST command, with a potential series of replies.
|
||||
* Return -errno on error, 0 on success. */
|
||||
static int nbd_negotiate_handle_list(NBDClient *client, Error **errp)
|
||||
static coroutine_fn int
|
||||
nbd_negotiate_handle_list(NBDClient *client, Error **errp)
|
||||
{
|
||||
NBDExport *exp;
|
||||
assert(client->opt == NBD_OPT_LIST);
|
||||
@@ -457,7 +464,8 @@ static int nbd_negotiate_handle_list(NBDClient *client, Error **errp)
|
||||
return nbd_negotiate_send_rep(client, NBD_REP_ACK, errp);
|
||||
}
|
||||
|
||||
static void nbd_check_meta_export(NBDClient *client, NBDExport *exp)
|
||||
static coroutine_fn void
|
||||
nbd_check_meta_export(NBDClient *client, NBDExport *exp)
|
||||
{
|
||||
if (exp != client->contexts.exp) {
|
||||
client->contexts.count = 0;
|
||||
@@ -466,8 +474,9 @@ static void nbd_check_meta_export(NBDClient *client, NBDExport *exp)
|
||||
|
||||
/* Send a reply to NBD_OPT_EXPORT_NAME.
|
||||
* Return -errno on error, 0 on success. */
|
||||
static int nbd_negotiate_handle_export_name(NBDClient *client, bool no_zeroes,
|
||||
Error **errp)
|
||||
static coroutine_fn int
|
||||
nbd_negotiate_handle_export_name(NBDClient *client, bool no_zeroes,
|
||||
Error **errp)
|
||||
{
|
||||
ERRP_GUARD();
|
||||
g_autofree char *name = NULL;
|
||||
@@ -534,9 +543,9 @@ static int nbd_negotiate_handle_export_name(NBDClient *client, bool no_zeroes,
|
||||
/* Send a single NBD_REP_INFO, with a buffer @buf of @length bytes.
|
||||
* The buffer does NOT include the info type prefix.
|
||||
* Return -errno on error, 0 if ready to send more. */
|
||||
static int nbd_negotiate_send_info(NBDClient *client,
|
||||
uint16_t info, uint32_t length, void *buf,
|
||||
Error **errp)
|
||||
static coroutine_fn int
|
||||
nbd_negotiate_send_info(NBDClient *client, uint16_t info, uint32_t length,
|
||||
void *buf, Error **errp)
|
||||
{
|
||||
int rc;
|
||||
|
||||
@@ -563,7 +572,8 @@ static int nbd_negotiate_send_info(NBDClient *client,
|
||||
* -errno transmission error occurred or @fatal was requested, errp is set
|
||||
* 0 error message successfully sent to client, errp is not set
|
||||
*/
|
||||
static int nbd_reject_length(NBDClient *client, bool fatal, Error **errp)
|
||||
static coroutine_fn int
|
||||
nbd_reject_length(NBDClient *client, bool fatal, Error **errp)
|
||||
{
|
||||
int ret;
|
||||
|
||||
@@ -581,7 +591,8 @@ static int nbd_reject_length(NBDClient *client, bool fatal, Error **errp)
|
||||
/* Handle NBD_OPT_INFO and NBD_OPT_GO.
|
||||
* Return -errno on error, 0 if ready for next option, and 1 to move
|
||||
* into transmission phase. */
|
||||
static int nbd_negotiate_handle_info(NBDClient *client, Error **errp)
|
||||
static coroutine_fn int
|
||||
nbd_negotiate_handle_info(NBDClient *client, Error **errp)
|
||||
{
|
||||
int rc;
|
||||
g_autofree char *name = NULL;
|
||||
@@ -746,15 +757,33 @@ static int nbd_negotiate_handle_info(NBDClient *client, Error **errp)
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Callback to learn when QIO TLS upgrade is complete */
|
||||
struct NBDTLSServerHandshakeData {
|
||||
bool complete;
|
||||
Error *error;
|
||||
Coroutine *co;
|
||||
};
|
||||
|
||||
static void
|
||||
nbd_server_tls_handshake(QIOTask *task, void *opaque)
|
||||
{
|
||||
struct NBDTLSServerHandshakeData *data = opaque;
|
||||
|
||||
qio_task_propagate_error(task, &data->error);
|
||||
data->complete = true;
|
||||
if (!qemu_coroutine_entered(data->co)) {
|
||||
aio_co_wake(data->co);
|
||||
}
|
||||
}
|
||||
|
||||
/* Handle NBD_OPT_STARTTLS. Return NULL to drop connection, or else the
|
||||
* new channel for all further (now-encrypted) communication. */
|
||||
static QIOChannel *nbd_negotiate_handle_starttls(NBDClient *client,
|
||||
Error **errp)
|
||||
static coroutine_fn QIOChannel *
|
||||
nbd_negotiate_handle_starttls(NBDClient *client, Error **errp)
|
||||
{
|
||||
QIOChannel *ioc;
|
||||
QIOChannelTLS *tioc;
|
||||
struct NBDTLSHandshakeData data = { 0 };
|
||||
struct NBDTLSServerHandshakeData data = { 0 };
|
||||
|
||||
assert(client->opt == NBD_OPT_STARTTLS);
|
||||
|
||||
@@ -775,17 +804,18 @@ static QIOChannel *nbd_negotiate_handle_starttls(NBDClient *client,
|
||||
|
||||
qio_channel_set_name(QIO_CHANNEL(tioc), "nbd-server-tls");
|
||||
trace_nbd_negotiate_handle_starttls_handshake();
|
||||
data.loop = g_main_loop_new(g_main_context_default(), FALSE);
|
||||
data.co = qemu_coroutine_self();
|
||||
qio_channel_tls_handshake(tioc,
|
||||
nbd_tls_handshake,
|
||||
nbd_server_tls_handshake,
|
||||
&data,
|
||||
NULL,
|
||||
NULL);
|
||||
|
||||
if (!data.complete) {
|
||||
g_main_loop_run(data.loop);
|
||||
qemu_coroutine_yield();
|
||||
assert(data.complete);
|
||||
}
|
||||
g_main_loop_unref(data.loop);
|
||||
|
||||
if (data.error) {
|
||||
object_unref(OBJECT(tioc));
|
||||
error_propagate(errp, data.error);
|
||||
@@ -801,10 +831,9 @@ static QIOChannel *nbd_negotiate_handle_starttls(NBDClient *client,
|
||||
*
|
||||
* For NBD_OPT_LIST_META_CONTEXT @context_id is ignored, 0 is used instead.
|
||||
*/
|
||||
static int nbd_negotiate_send_meta_context(NBDClient *client,
|
||||
const char *context,
|
||||
uint32_t context_id,
|
||||
Error **errp)
|
||||
static coroutine_fn int
|
||||
nbd_negotiate_send_meta_context(NBDClient *client, const char *context,
|
||||
uint32_t context_id, Error **errp)
|
||||
{
|
||||
NBDOptionReplyMetaContext opt;
|
||||
struct iovec iov[] = {
|
||||
@@ -829,8 +858,9 @@ static int nbd_negotiate_send_meta_context(NBDClient *client,
|
||||
* Return true if @query matches @pattern, or if @query is empty when
|
||||
* the @client is performing _LIST_.
|
||||
*/
|
||||
static bool nbd_meta_empty_or_pattern(NBDClient *client, const char *pattern,
|
||||
const char *query)
|
||||
static coroutine_fn bool
|
||||
nbd_meta_empty_or_pattern(NBDClient *client, const char *pattern,
|
||||
const char *query)
|
||||
{
|
||||
if (!*query) {
|
||||
trace_nbd_negotiate_meta_query_parse("empty");
|
||||
@@ -847,7 +877,8 @@ static bool nbd_meta_empty_or_pattern(NBDClient *client, const char *pattern,
|
||||
/*
|
||||
* Return true and adjust @str in place if it begins with @prefix.
|
||||
*/
|
||||
static bool nbd_strshift(const char **str, const char *prefix)
|
||||
static coroutine_fn bool
|
||||
nbd_strshift(const char **str, const char *prefix)
|
||||
{
|
||||
size_t len = strlen(prefix);
|
||||
|
||||
@@ -863,8 +894,9 @@ static bool nbd_strshift(const char **str, const char *prefix)
|
||||
* Handle queries to 'base' namespace. For now, only the base:allocation
|
||||
* context is available. Return true if @query has been handled.
|
||||
*/
|
||||
static bool nbd_meta_base_query(NBDClient *client, NBDMetaContexts *meta,
|
||||
const char *query)
|
||||
static coroutine_fn bool
|
||||
nbd_meta_base_query(NBDClient *client, NBDMetaContexts *meta,
|
||||
const char *query)
|
||||
{
|
||||
if (!nbd_strshift(&query, "base:")) {
|
||||
return false;
|
||||
@@ -883,8 +915,9 @@ static bool nbd_meta_base_query(NBDClient *client, NBDMetaContexts *meta,
|
||||
* and qemu:allocation-depth contexts are available. Return true if @query
|
||||
* has been handled.
|
||||
*/
|
||||
static bool nbd_meta_qemu_query(NBDClient *client, NBDMetaContexts *meta,
|
||||
const char *query)
|
||||
static coroutine_fn bool
|
||||
nbd_meta_qemu_query(NBDClient *client, NBDMetaContexts *meta,
|
||||
const char *query)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
@@ -948,8 +981,9 @@ static bool nbd_meta_qemu_query(NBDClient *client, NBDMetaContexts *meta,
|
||||
*
|
||||
* Return -errno on I/O error, 0 if option was completely handled by
|
||||
* sending a reply about inconsistent lengths, or 1 on success. */
|
||||
static int nbd_negotiate_meta_query(NBDClient *client,
|
||||
NBDMetaContexts *meta, Error **errp)
|
||||
static coroutine_fn int
|
||||
nbd_negotiate_meta_query(NBDClient *client,
|
||||
NBDMetaContexts *meta, Error **errp)
|
||||
{
|
||||
int ret;
|
||||
g_autofree char *query = NULL;
|
||||
@@ -988,7 +1022,8 @@ static int nbd_negotiate_meta_query(NBDClient *client,
|
||||
* Handle NBD_OPT_LIST_META_CONTEXT and NBD_OPT_SET_META_CONTEXT
|
||||
*
|
||||
* Return -errno on I/O error, or 0 if option was completely handled. */
|
||||
static int nbd_negotiate_meta_queries(NBDClient *client, Error **errp)
|
||||
static coroutine_fn int
|
||||
nbd_negotiate_meta_queries(NBDClient *client, Error **errp)
|
||||
{
|
||||
int ret;
|
||||
g_autofree char *export_name = NULL;
|
||||
@@ -1116,7 +1151,8 @@ static int nbd_negotiate_meta_queries(NBDClient *client, Error **errp)
|
||||
* 1 if client sent NBD_OPT_ABORT, i.e. on valid disconnect,
|
||||
* errp is not set
|
||||
*/
|
||||
static int nbd_negotiate_options(NBDClient *client, Error **errp)
|
||||
static coroutine_fn int
|
||||
nbd_negotiate_options(NBDClient *client, Error **errp)
|
||||
{
|
||||
uint32_t flags;
|
||||
bool fixedNewstyle = false;
|
||||
@@ -1415,11 +1451,18 @@ nbd_read_eof(NBDClient *client, void *buffer, size_t size, Error **errp)
|
||||
|
||||
len = qio_channel_readv(client->ioc, &iov, 1, errp);
|
||||
if (len == QIO_CHANNEL_ERR_BLOCK) {
|
||||
client->read_yielding = true;
|
||||
WITH_QEMU_LOCK_GUARD(&client->lock) {
|
||||
client->read_yielding = true;
|
||||
|
||||
/* Prompt main loop thread to re-run nbd_drained_poll() */
|
||||
aio_wait_kick();
|
||||
}
|
||||
qio_channel_yield(client->ioc, G_IO_IN);
|
||||
client->read_yielding = false;
|
||||
if (client->quiescing) {
|
||||
return -EAGAIN;
|
||||
WITH_QEMU_LOCK_GUARD(&client->lock) {
|
||||
client->read_yielding = false;
|
||||
if (client->quiescing) {
|
||||
return -EAGAIN;
|
||||
}
|
||||
}
|
||||
continue;
|
||||
} else if (len < 0) {
|
||||
@@ -1501,14 +1544,17 @@ static int coroutine_fn nbd_receive_request(NBDClient *client, NBDRequest *reque
|
||||
|
||||
#define MAX_NBD_REQUESTS 16
|
||||
|
||||
/* Runs in export AioContext and main loop thread */
|
||||
void nbd_client_get(NBDClient *client)
|
||||
{
|
||||
client->refcount++;
|
||||
qatomic_inc(&client->refcount);
|
||||
}
|
||||
|
||||
void nbd_client_put(NBDClient *client)
|
||||
{
|
||||
if (--client->refcount == 0) {
|
||||
assert(qemu_in_main_thread());
|
||||
|
||||
if (qatomic_fetch_dec(&client->refcount) == 1) {
|
||||
/* The last reference should be dropped by client->close,
|
||||
* which is called by client_close.
|
||||
*/
|
||||
@@ -1525,17 +1571,47 @@ void nbd_client_put(NBDClient *client)
|
||||
blk_exp_unref(&client->exp->common);
|
||||
}
|
||||
g_free(client->contexts.bitmaps);
|
||||
qemu_mutex_destroy(&client->lock);
|
||||
g_free(client);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Tries to release the reference to @client, but only if other references
|
||||
* remain. This is an optimization for the common case where we want to avoid
|
||||
* the expense of scheduling nbd_client_put() in the main loop thread.
|
||||
*
|
||||
* Returns true upon success or false if the reference was not released because
|
||||
* it is the last reference.
|
||||
*/
|
||||
static bool nbd_client_put_nonzero(NBDClient *client)
|
||||
{
|
||||
int old = qatomic_read(&client->refcount);
|
||||
int expected;
|
||||
|
||||
do {
|
||||
if (old == 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
expected = old;
|
||||
old = qatomic_cmpxchg(&client->refcount, expected, expected - 1);
|
||||
} while (old != expected);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void client_close(NBDClient *client, bool negotiated)
|
||||
{
|
||||
if (client->closing) {
|
||||
return;
|
||||
}
|
||||
assert(qemu_in_main_thread());
|
||||
|
||||
client->closing = true;
|
||||
WITH_QEMU_LOCK_GUARD(&client->lock) {
|
||||
if (client->closing) {
|
||||
return;
|
||||
}
|
||||
|
||||
client->closing = true;
|
||||
}
|
||||
|
||||
/* Force requests to finish. They will drop their own references,
|
||||
* then we'll close the socket and free the NBDClient.
|
||||
@@ -1549,6 +1625,7 @@ static void client_close(NBDClient *client, bool negotiated)
|
||||
}
|
||||
}
|
||||
|
||||
/* Runs in export AioContext with client->lock held */
|
||||
static NBDRequestData *nbd_request_get(NBDClient *client)
|
||||
{
|
||||
NBDRequestData *req;
|
||||
@@ -1562,6 +1639,7 @@ static NBDRequestData *nbd_request_get(NBDClient *client)
|
||||
return req;
|
||||
}
|
||||
|
||||
/* Runs in export AioContext with client->lock held */
|
||||
static void nbd_request_put(NBDRequestData *req)
|
||||
{
|
||||
NBDClient *client = req->client;
|
||||
@@ -1587,14 +1665,18 @@ static void blk_aio_attached(AioContext *ctx, void *opaque)
|
||||
NBDExport *exp = opaque;
|
||||
NBDClient *client;
|
||||
|
||||
assert(qemu_in_main_thread());
|
||||
|
||||
trace_nbd_blk_aio_attached(exp->name, ctx);
|
||||
|
||||
exp->common.ctx = ctx;
|
||||
|
||||
QTAILQ_FOREACH(client, &exp->clients, next) {
|
||||
assert(client->nb_requests == 0);
|
||||
assert(client->recv_coroutine == NULL);
|
||||
assert(client->send_coroutine == NULL);
|
||||
WITH_QEMU_LOCK_GUARD(&client->lock) {
|
||||
assert(client->nb_requests == 0);
|
||||
assert(client->recv_coroutine == NULL);
|
||||
assert(client->send_coroutine == NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1602,6 +1684,8 @@ static void blk_aio_detach(void *opaque)
|
||||
{
|
||||
NBDExport *exp = opaque;
|
||||
|
||||
assert(qemu_in_main_thread());
|
||||
|
||||
trace_nbd_blk_aio_detach(exp->name, exp->common.ctx);
|
||||
|
||||
exp->common.ctx = NULL;
|
||||
@@ -1612,8 +1696,12 @@ static void nbd_drained_begin(void *opaque)
|
||||
NBDExport *exp = opaque;
|
||||
NBDClient *client;
|
||||
|
||||
assert(qemu_in_main_thread());
|
||||
|
||||
QTAILQ_FOREACH(client, &exp->clients, next) {
|
||||
client->quiescing = true;
|
||||
WITH_QEMU_LOCK_GUARD(&client->lock) {
|
||||
client->quiescing = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1622,28 +1710,48 @@ static void nbd_drained_end(void *opaque)
|
||||
NBDExport *exp = opaque;
|
||||
NBDClient *client;
|
||||
|
||||
assert(qemu_in_main_thread());
|
||||
|
||||
QTAILQ_FOREACH(client, &exp->clients, next) {
|
||||
client->quiescing = false;
|
||||
nbd_client_receive_next_request(client);
|
||||
WITH_QEMU_LOCK_GUARD(&client->lock) {
|
||||
client->quiescing = false;
|
||||
nbd_client_receive_next_request(client);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Runs in export AioContext */
|
||||
static void nbd_wake_read_bh(void *opaque)
|
||||
{
|
||||
NBDClient *client = opaque;
|
||||
qio_channel_wake_read(client->ioc);
|
||||
}
|
||||
|
||||
static bool nbd_drained_poll(void *opaque)
|
||||
{
|
||||
NBDExport *exp = opaque;
|
||||
NBDClient *client;
|
||||
|
||||
QTAILQ_FOREACH(client, &exp->clients, next) {
|
||||
if (client->nb_requests != 0) {
|
||||
/*
|
||||
* If there's a coroutine waiting for a request on nbd_read_eof()
|
||||
* enter it here so we don't depend on the client to wake it up.
|
||||
*/
|
||||
if (client->recv_coroutine != NULL && client->read_yielding) {
|
||||
qio_channel_wake_read(client->ioc);
|
||||
}
|
||||
assert(qemu_in_main_thread());
|
||||
|
||||
return true;
|
||||
QTAILQ_FOREACH(client, &exp->clients, next) {
|
||||
WITH_QEMU_LOCK_GUARD(&client->lock) {
|
||||
if (client->nb_requests != 0) {
|
||||
/*
|
||||
* If there's a coroutine waiting for a request on nbd_read_eof()
|
||||
* enter it here so we don't depend on the client to wake it up.
|
||||
*
|
||||
* Schedule a BH in the export AioContext to avoid missing the
|
||||
* wake up due to the race between qio_channel_wake_read() and
|
||||
* qio_channel_yield().
|
||||
*/
|
||||
if (client->recv_coroutine != NULL && client->read_yielding) {
|
||||
aio_bh_schedule_oneshot(nbd_export_aio_context(client->exp),
|
||||
nbd_wake_read_bh, client);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1654,6 +1762,8 @@ static void nbd_eject_notifier(Notifier *n, void *data)
|
||||
{
|
||||
NBDExport *exp = container_of(n, NBDExport, eject_notifier);
|
||||
|
||||
assert(qemu_in_main_thread());
|
||||
|
||||
blk_exp_request_shutdown(&exp->common);
|
||||
}
|
||||
|
||||
@@ -2539,7 +2649,6 @@ static int coroutine_fn nbd_co_receive_request(NBDRequestData *req,
|
||||
int ret;
|
||||
|
||||
g_assert(qemu_in_coroutine());
|
||||
assert(client->recv_coroutine == qemu_coroutine_self());
|
||||
ret = nbd_receive_request(client, request, errp);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
@@ -2935,16 +3044,24 @@ static coroutine_fn int nbd_handle_request(NBDClient *client,
|
||||
/* Owns a reference to the NBDClient passed as opaque. */
|
||||
static coroutine_fn void nbd_trip(void *opaque)
|
||||
{
|
||||
NBDClient *client = opaque;
|
||||
NBDRequestData *req;
|
||||
NBDRequestData *req = opaque;
|
||||
NBDClient *client = req->client;
|
||||
NBDRequest request = { 0 }; /* GCC thinks it can be used uninitialized */
|
||||
int ret;
|
||||
Error *local_err = NULL;
|
||||
|
||||
/*
|
||||
* Note that nbd_client_put() and client_close() must be called from the
|
||||
* main loop thread. Use aio_co_reschedule_self() to switch AioContext
|
||||
* before calling these functions.
|
||||
*/
|
||||
|
||||
trace_nbd_trip();
|
||||
|
||||
qemu_mutex_lock(&client->lock);
|
||||
|
||||
if (client->closing) {
|
||||
nbd_client_put(client);
|
||||
return;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (client->quiescing) {
|
||||
@@ -2952,14 +3069,25 @@ static coroutine_fn void nbd_trip(void *opaque)
|
||||
* We're switching between AIO contexts. Don't attempt to receive a new
|
||||
* request and kick the main context which may be waiting for us.
|
||||
*/
|
||||
nbd_client_put(client);
|
||||
client->recv_coroutine = NULL;
|
||||
aio_wait_kick();
|
||||
return;
|
||||
goto done;
|
||||
}
|
||||
|
||||
req = nbd_request_get(client);
|
||||
ret = nbd_co_receive_request(req, &request, &local_err);
|
||||
/*
|
||||
* nbd_co_receive_request() returns -EAGAIN when nbd_drained_begin() has
|
||||
* set client->quiescing but by the time we get back nbd_drained_end() may
|
||||
* have already cleared client->quiescing. In that case we try again
|
||||
* because nothing else will spawn an nbd_trip() coroutine until we set
|
||||
* client->recv_coroutine = NULL further down.
|
||||
*/
|
||||
do {
|
||||
assert(client->recv_coroutine == qemu_coroutine_self());
|
||||
qemu_mutex_unlock(&client->lock);
|
||||
ret = nbd_co_receive_request(req, &request, &local_err);
|
||||
qemu_mutex_lock(&client->lock);
|
||||
} while (ret == -EAGAIN && !client->quiescing);
|
||||
|
||||
client->recv_coroutine = NULL;
|
||||
|
||||
if (client->closing) {
|
||||
@@ -2971,15 +3099,16 @@ static coroutine_fn void nbd_trip(void *opaque)
|
||||
}
|
||||
|
||||
if (ret == -EAGAIN) {
|
||||
assert(client->quiescing);
|
||||
goto done;
|
||||
}
|
||||
|
||||
nbd_client_receive_next_request(client);
|
||||
|
||||
if (ret == -EIO) {
|
||||
goto disconnect;
|
||||
}
|
||||
|
||||
qemu_mutex_unlock(&client->lock);
|
||||
qio_channel_set_cork(client->ioc, true);
|
||||
|
||||
if (ret < 0) {
|
||||
@@ -2999,6 +3128,10 @@ static coroutine_fn void nbd_trip(void *opaque)
|
||||
g_free(request.contexts->bitmaps);
|
||||
g_free(request.contexts);
|
||||
}
|
||||
|
||||
qio_channel_set_cork(client->ioc, false);
|
||||
qemu_mutex_lock(&client->lock);
|
||||
|
||||
if (ret < 0) {
|
||||
error_prepend(&local_err, "Failed to send reply: ");
|
||||
goto disconnect;
|
||||
@@ -3013,27 +3146,43 @@ static coroutine_fn void nbd_trip(void *opaque)
|
||||
goto disconnect;
|
||||
}
|
||||
|
||||
qio_channel_set_cork(client->ioc, false);
|
||||
done:
|
||||
nbd_request_put(req);
|
||||
nbd_client_put(client);
|
||||
|
||||
qemu_mutex_unlock(&client->lock);
|
||||
|
||||
if (!nbd_client_put_nonzero(client)) {
|
||||
aio_co_reschedule_self(qemu_get_aio_context());
|
||||
nbd_client_put(client);
|
||||
}
|
||||
return;
|
||||
|
||||
disconnect:
|
||||
if (local_err) {
|
||||
error_reportf_err(local_err, "Disconnect client, due to: ");
|
||||
}
|
||||
|
||||
nbd_request_put(req);
|
||||
qemu_mutex_unlock(&client->lock);
|
||||
|
||||
aio_co_reschedule_self(qemu_get_aio_context());
|
||||
client_close(client, true);
|
||||
nbd_client_put(client);
|
||||
}
|
||||
|
||||
/*
|
||||
* Runs in export AioContext and main loop thread. Caller must hold
|
||||
* client->lock.
|
||||
*/
|
||||
static void nbd_client_receive_next_request(NBDClient *client)
|
||||
{
|
||||
NBDRequestData *req;
|
||||
|
||||
if (!client->recv_coroutine && client->nb_requests < MAX_NBD_REQUESTS &&
|
||||
!client->quiescing) {
|
||||
nbd_client_get(client);
|
||||
client->recv_coroutine = qemu_coroutine_create(nbd_trip, client);
|
||||
req = nbd_request_get(client);
|
||||
client->recv_coroutine = qemu_coroutine_create(nbd_trip, req);
|
||||
aio_co_schedule(client->exp->common.ctx, client->recv_coroutine);
|
||||
}
|
||||
}
|
||||
@@ -3053,7 +3202,9 @@ static coroutine_fn void nbd_co_client_start(void *opaque)
|
||||
return;
|
||||
}
|
||||
|
||||
nbd_client_receive_next_request(client);
|
||||
WITH_QEMU_LOCK_GUARD(&client->lock) {
|
||||
nbd_client_receive_next_request(client);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -3070,6 +3221,7 @@ void nbd_client_new(QIOChannelSocket *sioc,
|
||||
Coroutine *co;
|
||||
|
||||
client = g_new0(NBDClient, 1);
|
||||
qemu_mutex_init(&client->lock);
|
||||
client->refcount = 1;
|
||||
client->tlscreds = tlscreds;
|
||||
if (tlscreds) {
|
||||
|
||||
+3
-3
@@ -149,14 +149,14 @@ SRST
|
||||
platform and configuration dependent.
|
||||
|
||||
``interleave-granularity=granularity`` sets the granularity of
|
||||
interleave. Default 256KiB. Only 256KiB, 512KiB, 1024KiB, 2048KiB
|
||||
4096KiB, 8192KiB and 16384KiB granularities supported.
|
||||
interleave. Default 256 (bytes). Only 256, 512, 1k, 2k,
|
||||
4k, 8k and 16k granularities supported.
|
||||
|
||||
Example:
|
||||
|
||||
::
|
||||
|
||||
-machine cxl-fmw.0.targets.0=cxl.0,cxl-fmw.0.targets.1=cxl.1,cxl-fmw.0.size=128G,cxl-fmw.0.interleave-granularity=512k
|
||||
-machine cxl-fmw.0.targets.0=cxl.0,cxl-fmw.0.targets.1=cxl.1,cxl-fmw.0.size=128G,cxl-fmw.0.interleave-granularity=512
|
||||
ERST
|
||||
|
||||
DEF("M", HAS_ARG, QEMU_OPTION_M,
|
||||
|
||||
@@ -47,5 +47,5 @@ meson subprojects download $SUBPROJECTS
|
||||
CryptoPkg/Library/OpensslLib/openssl \
|
||||
MdeModulePkg/Library/BrotliCustomDecompressLib/brotli)
|
||||
popd
|
||||
tar --exclude=.git -cjf ${destination}.tar.bz2 ${destination}
|
||||
tar --exclude=.git -cJf ${destination}.tar.xz ${destination}
|
||||
rm -rf ${destination}
|
||||
|
||||
+11
-12
@@ -858,19 +858,18 @@ void qmp_device_add(QDict *qdict, QObject **ret_data, Error **errp)
|
||||
return;
|
||||
}
|
||||
dev = qdev_device_add(opts, errp);
|
||||
|
||||
/*
|
||||
* Drain all pending RCU callbacks. This is done because
|
||||
* some bus related operations can delay a device removal
|
||||
* (in this case this can happen if device is added and then
|
||||
* removed due to a configuration error)
|
||||
* to a RCU callback, but user might expect that this interface
|
||||
* will finish its job completely once qmp command returns result
|
||||
* to the user
|
||||
*/
|
||||
drain_call_rcu();
|
||||
|
||||
if (!dev) {
|
||||
/*
|
||||
* Drain all pending RCU callbacks. This is done because
|
||||
* some bus related operations can delay a device removal
|
||||
* (in this case this can happen if device is added and then
|
||||
* removed due to a configuration error)
|
||||
* to a RCU callback, but user might expect that this interface
|
||||
* will finish its job completely once qmp command returns result
|
||||
* to the user
|
||||
*/
|
||||
drain_call_rcu();
|
||||
|
||||
qemu_opts_del(opts);
|
||||
return;
|
||||
}
|
||||
|
||||
+5
-2
@@ -3703,6 +3703,8 @@ static void ats_write64(CPUARMState *env, const ARMCPRegInfo *ri,
|
||||
ARMMMUIdx mmu_idx;
|
||||
uint64_t hcr_el2 = arm_hcr_el2_eff(env);
|
||||
bool regime_e20 = (hcr_el2 & (HCR_E2H | HCR_TGE)) == (HCR_E2H | HCR_TGE);
|
||||
bool for_el3 = false;
|
||||
ARMSecuritySpace ss;
|
||||
|
||||
switch (ri->opc2 & 6) {
|
||||
case 0:
|
||||
@@ -3720,6 +3722,7 @@ static void ats_write64(CPUARMState *env, const ARMCPRegInfo *ri,
|
||||
break;
|
||||
case 6: /* AT S1E3R, AT S1E3W */
|
||||
mmu_idx = ARMMMUIdx_E3;
|
||||
for_el3 = true;
|
||||
break;
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
@@ -3738,8 +3741,8 @@ static void ats_write64(CPUARMState *env, const ARMCPRegInfo *ri,
|
||||
g_assert_not_reached();
|
||||
}
|
||||
|
||||
env->cp15.par_el[1] = do_ats_write(env, value, access_type,
|
||||
mmu_idx, arm_security_space(env));
|
||||
ss = for_el3 ? arm_security_space(env) : arm_security_space_below_el3(env);
|
||||
env->cp15.par_el[1] = do_ats_write(env, value, access_type, mmu_idx, ss);
|
||||
#else
|
||||
/* Handled by hardware accelerator. */
|
||||
g_assert_not_reached();
|
||||
|
||||
+45
-32
@@ -1083,11 +1083,32 @@ void HELPER(sme_bfmopa)(void *vza, void *vzn, void *vzm, void *vpn,
|
||||
}
|
||||
}
|
||||
|
||||
typedef uint64_t IMOPFn(uint64_t, uint64_t, uint64_t, uint8_t, bool);
|
||||
typedef uint32_t IMOPFn32(uint32_t, uint32_t, uint32_t, uint8_t, bool);
|
||||
static inline void do_imopa_s(uint32_t *za, uint32_t *zn, uint32_t *zm,
|
||||
uint8_t *pn, uint8_t *pm,
|
||||
uint32_t desc, IMOPFn32 *fn)
|
||||
{
|
||||
intptr_t row, col, oprsz = simd_oprsz(desc) / 4;
|
||||
bool neg = simd_data(desc);
|
||||
|
||||
static inline void do_imopa(uint64_t *za, uint64_t *zn, uint64_t *zm,
|
||||
uint8_t *pn, uint8_t *pm,
|
||||
uint32_t desc, IMOPFn *fn)
|
||||
for (row = 0; row < oprsz; ++row) {
|
||||
uint8_t pa = (pn[H1(row >> 1)] >> ((row & 1) * 4)) & 0xf;
|
||||
uint32_t *za_row = &za[tile_vslice_index(row)];
|
||||
uint32_t n = zn[H4(row)];
|
||||
|
||||
for (col = 0; col < oprsz; ++col) {
|
||||
uint8_t pb = pm[H1(col >> 1)] >> ((col & 1) * 4);
|
||||
uint32_t *a = &za_row[H4(col)];
|
||||
|
||||
*a = fn(n, zm[H4(col)], *a, pa & pb, neg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
typedef uint64_t IMOPFn64(uint64_t, uint64_t, uint64_t, uint8_t, bool);
|
||||
static inline void do_imopa_d(uint64_t *za, uint64_t *zn, uint64_t *zm,
|
||||
uint8_t *pn, uint8_t *pm,
|
||||
uint32_t desc, IMOPFn64 *fn)
|
||||
{
|
||||
intptr_t row, col, oprsz = simd_oprsz(desc) / 8;
|
||||
bool neg = simd_data(desc);
|
||||
@@ -1107,25 +1128,16 @@ static inline void do_imopa(uint64_t *za, uint64_t *zn, uint64_t *zm,
|
||||
}
|
||||
|
||||
#define DEF_IMOP_32(NAME, NTYPE, MTYPE) \
|
||||
static uint64_t NAME(uint64_t n, uint64_t m, uint64_t a, uint8_t p, bool neg) \
|
||||
static uint32_t NAME(uint32_t n, uint32_t m, uint32_t a, uint8_t p, bool neg) \
|
||||
{ \
|
||||
uint32_t sum0 = 0, sum1 = 0; \
|
||||
uint32_t sum = 0; \
|
||||
/* Apply P to N as a mask, making the inactive elements 0. */ \
|
||||
n &= expand_pred_b(p); \
|
||||
sum0 += (NTYPE)(n >> 0) * (MTYPE)(m >> 0); \
|
||||
sum0 += (NTYPE)(n >> 8) * (MTYPE)(m >> 8); \
|
||||
sum0 += (NTYPE)(n >> 16) * (MTYPE)(m >> 16); \
|
||||
sum0 += (NTYPE)(n >> 24) * (MTYPE)(m >> 24); \
|
||||
sum1 += (NTYPE)(n >> 32) * (MTYPE)(m >> 32); \
|
||||
sum1 += (NTYPE)(n >> 40) * (MTYPE)(m >> 40); \
|
||||
sum1 += (NTYPE)(n >> 48) * (MTYPE)(m >> 48); \
|
||||
sum1 += (NTYPE)(n >> 56) * (MTYPE)(m >> 56); \
|
||||
if (neg) { \
|
||||
sum0 = (uint32_t)a - sum0, sum1 = (uint32_t)(a >> 32) - sum1; \
|
||||
} else { \
|
||||
sum0 = (uint32_t)a + sum0, sum1 = (uint32_t)(a >> 32) + sum1; \
|
||||
} \
|
||||
return ((uint64_t)sum1 << 32) | sum0; \
|
||||
sum += (NTYPE)(n >> 0) * (MTYPE)(m >> 0); \
|
||||
sum += (NTYPE)(n >> 8) * (MTYPE)(m >> 8); \
|
||||
sum += (NTYPE)(n >> 16) * (MTYPE)(m >> 16); \
|
||||
sum += (NTYPE)(n >> 24) * (MTYPE)(m >> 24); \
|
||||
return neg ? a - sum : a + sum; \
|
||||
}
|
||||
|
||||
#define DEF_IMOP_64(NAME, NTYPE, MTYPE) \
|
||||
@@ -1151,16 +1163,17 @@ DEF_IMOP_64(umopa_d, uint16_t, uint16_t)
|
||||
DEF_IMOP_64(sumopa_d, int16_t, uint16_t)
|
||||
DEF_IMOP_64(usmopa_d, uint16_t, int16_t)
|
||||
|
||||
#define DEF_IMOPH(NAME) \
|
||||
void HELPER(sme_##NAME)(void *vza, void *vzn, void *vzm, void *vpn, \
|
||||
void *vpm, uint32_t desc) \
|
||||
{ do_imopa(vza, vzn, vzm, vpn, vpm, desc, NAME); }
|
||||
#define DEF_IMOPH(NAME, S) \
|
||||
void HELPER(sme_##NAME##_##S)(void *vza, void *vzn, void *vzm, \
|
||||
void *vpn, void *vpm, uint32_t desc) \
|
||||
{ do_imopa_##S(vza, vzn, vzm, vpn, vpm, desc, NAME##_##S); }
|
||||
|
||||
DEF_IMOPH(smopa_s)
|
||||
DEF_IMOPH(umopa_s)
|
||||
DEF_IMOPH(sumopa_s)
|
||||
DEF_IMOPH(usmopa_s)
|
||||
DEF_IMOPH(smopa_d)
|
||||
DEF_IMOPH(umopa_d)
|
||||
DEF_IMOPH(sumopa_d)
|
||||
DEF_IMOPH(usmopa_d)
|
||||
DEF_IMOPH(smopa, s)
|
||||
DEF_IMOPH(umopa, s)
|
||||
DEF_IMOPH(sumopa, s)
|
||||
DEF_IMOPH(usmopa, s)
|
||||
|
||||
DEF_IMOPH(smopa, d)
|
||||
DEF_IMOPH(umopa, d)
|
||||
DEF_IMOPH(sumopa, d)
|
||||
DEF_IMOPH(usmopa, d)
|
||||
|
||||
@@ -4584,7 +4584,7 @@ static void do_coproc_insn(DisasContext *s, int cpnum, int is64,
|
||||
tcg_gen_andi_i32(t, t, 1u << maskbit);
|
||||
tcg_gen_brcondi_i32(TCG_COND_EQ, t, 0, over.label);
|
||||
|
||||
gen_exception_insn(s, 0, EXCP_UDEF, syndrome);
|
||||
gen_exception_insn_el(s, 0, EXCP_UDEF, syndrome, 2);
|
||||
/*
|
||||
* gen_exception_insn() will set is_jmp to DISAS_NORETURN,
|
||||
* but since we're conditionally branching over it, we want
|
||||
|
||||
+32
-23
@@ -24,16 +24,17 @@
|
||||
%assemble_sr3 13:1 14:2
|
||||
%assemble_sr3x 13:1 14:2 !function=expand_sr3x
|
||||
|
||||
%assemble_11a 0:s1 4:10 !function=expand_shl3
|
||||
%assemble_11a 4:12 0:1 !function=expand_11a
|
||||
%assemble_12 0:s1 2:1 3:10 !function=expand_shl2
|
||||
%assemble_12a 0:s1 3:11 !function=expand_shl2
|
||||
%assemble_12a 3:13 0:1 !function=expand_12a
|
||||
%assemble_16 0:16 !function=expand_16
|
||||
%assemble_17 0:s1 16:5 2:1 3:10 !function=expand_shl2
|
||||
%assemble_22 0:s1 16:10 2:1 3:10 !function=expand_shl2
|
||||
%assemble_sp 14:2 !function=sp0_if_wide
|
||||
|
||||
%assemble_21 0:s1 1:11 14:2 16:5 12:2 !function=expand_shl11
|
||||
|
||||
%lowsign_11 0:s1 1:10
|
||||
%lowsign_14 0:s1 1:13
|
||||
|
||||
%sm_imm 16:10 !function=expand_sm_imm
|
||||
|
||||
@@ -143,9 +144,9 @@ getshadowregs 1111 1111 1111 1101 1110 1010 1101 0010
|
||||
nop 000001 ----- ----- -- 11001010 0 ----- # fdc, disp
|
||||
nop_addrx 000001 ..... ..... -- 01001010 . ----- @addrx # fdc, index
|
||||
nop_addrx 000001 ..... ..... -- 01001011 . ----- @addrx # fdce
|
||||
nop_addrx 000001 ..... ..... --- 0001010 . ----- @addrx # fic 0x0a
|
||||
nop_addrx 000001 ..... ..... -- 01001111 . 00000 @addrx # fic 0x4f
|
||||
nop_addrx 000001 ..... ..... --- 0001011 . ----- @addrx # fice
|
||||
fic 000001 ..... ..... --- 0001010 . ----- @addrx # fic 0x0a
|
||||
fic 000001 ..... ..... -- 01001111 . 00000 @addrx # fic 0x4f
|
||||
fic 000001 ..... ..... --- 0001011 . ----- @addrx # fice
|
||||
nop_addrx 000001 ..... ..... -- 01001110 . 00000 @addrx # pdc
|
||||
|
||||
probe 000001 b:5 ri:5 sp:2 imm:1 100011 write:1 0 t:5
|
||||
@@ -221,7 +222,7 @@ sub_b_tsv 000010 ..... ..... .... 110100 . ..... @rrr_cf_d
|
||||
|
||||
ldil 001000 t:5 ..................... i=%assemble_21
|
||||
addil 001010 r:5 ..................... i=%assemble_21
|
||||
ldo 001101 b:5 t:5 -- .............. i=%lowsign_14
|
||||
ldo 001101 b:5 t:5 ................ i=%assemble_16
|
||||
|
||||
addi 101101 ..... ..... .... 0 ........... @rri_cf
|
||||
addi_tsv 101101 ..... ..... .... 1 ........... @rri_cf
|
||||
@@ -304,14 +305,18 @@ fstd 001011 ..... ..... .. . 1 -- 100 0 . ..... @fldstdi
|
||||
# Offset Mem
|
||||
####
|
||||
|
||||
@ldstim11 ...... b:5 t:5 sp:2 .............. \
|
||||
&ldst disp=%assemble_11a m=%ma2_to_m x=0 scale=0 size=3
|
||||
@ldstim14 ...... b:5 t:5 sp:2 .............. \
|
||||
&ldst disp=%lowsign_14 x=0 scale=0 m=0
|
||||
@ldstim14m ...... b:5 t:5 sp:2 .............. \
|
||||
&ldst disp=%lowsign_14 x=0 scale=0 m=%neg_to_m
|
||||
@ldstim12m ...... b:5 t:5 sp:2 .............. \
|
||||
&ldst disp=%assemble_12a x=0 scale=0 m=%pos_to_m
|
||||
@ldstim11 ...... b:5 t:5 ................ \
|
||||
&ldst sp=%assemble_sp disp=%assemble_11a \
|
||||
m=%ma2_to_m x=0 scale=0 size=3
|
||||
@ldstim14 ...... b:5 t:5 ................ \
|
||||
&ldst sp=%assemble_sp disp=%assemble_16 \
|
||||
x=0 scale=0 m=0
|
||||
@ldstim14m ...... b:5 t:5 ................ \
|
||||
&ldst sp=%assemble_sp disp=%assemble_16 \
|
||||
x=0 scale=0 m=%neg_to_m
|
||||
@ldstim12m ...... b:5 t:5 ................ \
|
||||
&ldst sp=%assemble_sp disp=%assemble_12a \
|
||||
x=0 scale=0 m=%pos_to_m
|
||||
|
||||
# LDB, LDH, LDW, LDWM
|
||||
ld 010000 ..... ..... .. .............. @ldstim14 size=0
|
||||
@@ -327,15 +332,19 @@ st 011010 ..... ..... .. .............. @ldstim14 size=2
|
||||
st 011011 ..... ..... .. .............. @ldstim14m size=2
|
||||
st 011111 ..... ..... .. ...........10. @ldstim12m size=2
|
||||
|
||||
fldw 010110 b:5 ..... sp:2 .............. \
|
||||
&ldst disp=%assemble_12a t=%rm64 m=%a_to_m x=0 scale=0 size=2
|
||||
fldw 010111 b:5 ..... sp:2 ...........0.. \
|
||||
&ldst disp=%assemble_12a t=%rm64 m=0 x=0 scale=0 size=2
|
||||
fldw 010110 b:5 ..... ................ \
|
||||
&ldst disp=%assemble_12a sp=%assemble_sp \
|
||||
t=%rm64 m=%a_to_m x=0 scale=0 size=2
|
||||
fldw 010111 b:5 ..... .............0.. \
|
||||
&ldst disp=%assemble_12a sp=%assemble_sp \
|
||||
t=%rm64 m=0 x=0 scale=0 size=2
|
||||
|
||||
fstw 011110 b:5 ..... sp:2 .............. \
|
||||
&ldst disp=%assemble_12a t=%rm64 m=%a_to_m x=0 scale=0 size=2
|
||||
fstw 011111 b:5 ..... sp:2 ...........0.. \
|
||||
&ldst disp=%assemble_12a t=%rm64 m=0 x=0 scale=0 size=2
|
||||
fstw 011110 b:5 ..... ................ \
|
||||
&ldst disp=%assemble_12a sp=%assemble_sp \
|
||||
t=%rm64 m=%a_to_m x=0 scale=0 size=2
|
||||
fstw 011111 b:5 ..... .............0.. \
|
||||
&ldst disp=%assemble_12a sp=%assemble_sp \
|
||||
t=%rm64 m=0 x=0 scale=0 size=2
|
||||
|
||||
ld 010100 ..... ..... .. ............0. @ldstim11
|
||||
fldd 010100 ..... ..... .. ............1. @ldstim11
|
||||
|
||||
+62
-18
@@ -152,6 +152,49 @@ static HPPATLBEntry *hppa_alloc_tlb_ent(CPUHPPAState *env)
|
||||
return ent;
|
||||
}
|
||||
|
||||
#define ACCESS_ID_MASK 0xffff
|
||||
|
||||
/* Return the set of protections allowed by a PID match. */
|
||||
static int match_prot_id_1(uint32_t access_id, uint32_t prot_id)
|
||||
{
|
||||
if (((access_id ^ (prot_id >> 1)) & ACCESS_ID_MASK) == 0) {
|
||||
return (prot_id & 1
|
||||
? PAGE_EXEC | PAGE_READ
|
||||
: PAGE_EXEC | PAGE_READ | PAGE_WRITE);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int match_prot_id32(CPUHPPAState *env, uint32_t access_id)
|
||||
{
|
||||
int r, i;
|
||||
|
||||
for (i = CR_PID1; i <= CR_PID4; ++i) {
|
||||
r = match_prot_id_1(access_id, env->cr[i]);
|
||||
if (r) {
|
||||
return r;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int match_prot_id64(CPUHPPAState *env, uint32_t access_id)
|
||||
{
|
||||
int r, i;
|
||||
|
||||
for (i = CR_PID1; i <= CR_PID4; ++i) {
|
||||
r = match_prot_id_1(access_id, env->cr[i]);
|
||||
if (r) {
|
||||
return r;
|
||||
}
|
||||
r = match_prot_id_1(access_id, env->cr[i] >> 32);
|
||||
if (r) {
|
||||
return r;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int hppa_get_physical_address(CPUHPPAState *env, vaddr addr, int mmu_idx,
|
||||
int type, hwaddr *pphys, int *pprot,
|
||||
HPPATLBEntry **tlb_entry)
|
||||
@@ -224,29 +267,30 @@ int hppa_get_physical_address(CPUHPPAState *env, vaddr addr, int mmu_idx,
|
||||
break;
|
||||
}
|
||||
|
||||
/* access_id == 0 means public page and no check is performed */
|
||||
if (ent->access_id && MMU_IDX_TO_P(mmu_idx)) {
|
||||
/* If bits [31:1] match, and bit 0 is set, suppress write. */
|
||||
int match = ent->access_id * 2 + 1;
|
||||
|
||||
if (match == env->cr[CR_PID1] || match == env->cr[CR_PID2] ||
|
||||
match == env->cr[CR_PID3] || match == env->cr[CR_PID4]) {
|
||||
prot &= PAGE_READ | PAGE_EXEC;
|
||||
if (type == PAGE_WRITE) {
|
||||
ret = EXCP_DMPI;
|
||||
goto egress;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* No guest access type indicates a non-architectural access from
|
||||
within QEMU. Bypass checks for access, D, B and T bits. */
|
||||
/*
|
||||
* No guest access type indicates a non-architectural access from
|
||||
* within QEMU. Bypass checks for access, D, B, P and T bits.
|
||||
*/
|
||||
if (type == 0) {
|
||||
goto egress;
|
||||
}
|
||||
|
||||
/* access_id == 0 means public page and no check is performed */
|
||||
if (ent->access_id && MMU_IDX_TO_P(mmu_idx)) {
|
||||
int access_prot = (hppa_is_pa20(env)
|
||||
? match_prot_id64(env, ent->access_id)
|
||||
: match_prot_id32(env, ent->access_id));
|
||||
if (unlikely(!(type & access_prot))) {
|
||||
/* Not allowed -- Inst/Data Memory Protection Id Fault. */
|
||||
ret = type & PAGE_EXEC ? EXCP_IMP : EXCP_DMPI;
|
||||
goto egress;
|
||||
}
|
||||
/* Otherwise exclude permissions not allowed (i.e WD). */
|
||||
prot &= access_prot;
|
||||
}
|
||||
|
||||
if (unlikely(!(prot & type))) {
|
||||
/* The access isn't allowed -- Inst/Data Memory Protection Fault. */
|
||||
/* Not allowed -- Inst/Data Memory Access Rights Fault. */
|
||||
ret = (type & PAGE_EXEC) ? EXCP_IMP : EXCP_DMAR;
|
||||
goto egress;
|
||||
}
|
||||
|
||||
@@ -281,17 +281,17 @@ static void do_stdby_e(CPUHPPAState *env, target_ulong addr, uint64_t val,
|
||||
case 3:
|
||||
/* The 3 byte store must appear atomic. */
|
||||
if (parallel) {
|
||||
atomic_store_mask32(env, addr - 3, val, 0xffffff00u, ra);
|
||||
atomic_store_mask32(env, addr - 3, val >> 32, 0xffffff00u, ra);
|
||||
} else {
|
||||
cpu_stw_data_ra(env, addr - 3, val >> 16, ra);
|
||||
cpu_stb_data_ra(env, addr - 1, val >> 8, ra);
|
||||
cpu_stw_data_ra(env, addr - 3, val >> 48, ra);
|
||||
cpu_stb_data_ra(env, addr - 1, val >> 40, ra);
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
cpu_stw_data_ra(env, addr - 2, val >> 16, ra);
|
||||
cpu_stw_data_ra(env, addr - 2, val >> 48, ra);
|
||||
break;
|
||||
case 1:
|
||||
cpu_stb_data_ra(env, addr - 1, val >> 24, ra);
|
||||
cpu_stb_data_ra(env, addr - 1, val >> 56, ra);
|
||||
break;
|
||||
default:
|
||||
/* Nothing is stored, but protection is checked and the
|
||||
|
||||
+68
-10
@@ -121,12 +121,6 @@ static int expand_shl2(DisasContext *ctx, int val)
|
||||
return val << 2;
|
||||
}
|
||||
|
||||
/* Used for fp memory ops. */
|
||||
static int expand_shl3(DisasContext *ctx, int val)
|
||||
{
|
||||
return val << 3;
|
||||
}
|
||||
|
||||
/* Used for assemble_21. */
|
||||
static int expand_shl11(DisasContext *ctx, int val)
|
||||
{
|
||||
@@ -144,6 +138,62 @@ static int assemble_6(DisasContext *ctx, int val)
|
||||
return (val ^ 31) + 1;
|
||||
}
|
||||
|
||||
/* Expander for assemble_16a(s,cat(im10a,0),i). */
|
||||
static int expand_11a(DisasContext *ctx, int val)
|
||||
{
|
||||
/*
|
||||
* @val is bit 0 and bits [4:15].
|
||||
* Swizzle thing around depending on PSW.W.
|
||||
*/
|
||||
int im10a = extract32(val, 1, 10);
|
||||
int s = extract32(val, 11, 2);
|
||||
int i = (-(val & 1) << 13) | (im10a << 3);
|
||||
|
||||
if (ctx->tb_flags & PSW_W) {
|
||||
i ^= s << 13;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
/* Expander for assemble_16a(s,im11a,i). */
|
||||
static int expand_12a(DisasContext *ctx, int val)
|
||||
{
|
||||
/*
|
||||
* @val is bit 0 and bits [3:15].
|
||||
* Swizzle thing around depending on PSW.W.
|
||||
*/
|
||||
int im11a = extract32(val, 1, 11);
|
||||
int s = extract32(val, 12, 2);
|
||||
int i = (-(val & 1) << 13) | (im11a << 2);
|
||||
|
||||
if (ctx->tb_flags & PSW_W) {
|
||||
i ^= s << 13;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
/* Expander for assemble_16(s,im14). */
|
||||
static int expand_16(DisasContext *ctx, int val)
|
||||
{
|
||||
/*
|
||||
* @val is bits [0:15], containing both im14 and s.
|
||||
* Swizzle thing around depending on PSW.W.
|
||||
*/
|
||||
int s = extract32(val, 14, 2);
|
||||
int i = (-(val & 1) << 13) | extract32(val, 1, 13);
|
||||
|
||||
if (ctx->tb_flags & PSW_W) {
|
||||
i ^= s << 13;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
/* The sp field is only present with !PSW_W. */
|
||||
static int sp0_if_wide(DisasContext *ctx, int sp)
|
||||
{
|
||||
return ctx->tb_flags & PSW_W ? 0 : sp;
|
||||
}
|
||||
|
||||
/* Translate CMPI doubleword conditions to standard. */
|
||||
static int cmpbid_c(DisasContext *ctx, int val)
|
||||
{
|
||||
@@ -1961,7 +2011,7 @@ static bool trans_mfia(DisasContext *ctx, arg_mfia *a)
|
||||
{
|
||||
unsigned rt = a->t;
|
||||
TCGv_i64 tmp = dest_gpr(ctx, rt);
|
||||
tcg_gen_movi_i64(tmp, ctx->iaoq_f);
|
||||
tcg_gen_movi_i64(tmp, ctx->iaoq_f & ~3ULL);
|
||||
save_gpr(ctx, rt, tmp);
|
||||
|
||||
cond_free(&ctx->null_cond);
|
||||
@@ -2287,6 +2337,13 @@ static bool trans_nop_addrx(DisasContext *ctx, arg_ldst *a)
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_fic(DisasContext *ctx, arg_ldst *a)
|
||||
{
|
||||
/* End TB for flush instruction cache, so we pick up new insns. */
|
||||
ctx->base.is_jmp = DISAS_IAQ_N_STALE;
|
||||
return trans_nop_addrx(ctx, a);
|
||||
}
|
||||
|
||||
static bool trans_probe(DisasContext *ctx, arg_probe *a)
|
||||
{
|
||||
TCGv_i64 dest, ofs;
|
||||
@@ -3079,7 +3136,7 @@ static bool trans_ldc(DisasContext *ctx, arg_ldst *a)
|
||||
dest = dest_gpr(ctx, a->t);
|
||||
}
|
||||
|
||||
form_gva(ctx, &addr, &ofs, a->b, a->x, a->scale ? a->size : 0,
|
||||
form_gva(ctx, &addr, &ofs, a->b, a->x, a->scale ? 3 : 0,
|
||||
a->disp, a->sp, a->m, MMU_DISABLED(ctx));
|
||||
|
||||
/*
|
||||
@@ -3456,7 +3513,7 @@ static bool trans_shrp_sar(DisasContext *ctx, arg_shrp_sar *a)
|
||||
/* Install the new nullification. */
|
||||
cond_free(&ctx->null_cond);
|
||||
if (a->c) {
|
||||
ctx->null_cond = do_sed_cond(ctx, a->c, false, dest);
|
||||
ctx->null_cond = do_sed_cond(ctx, a->c, a->d, dest);
|
||||
}
|
||||
return nullify_end(ctx);
|
||||
}
|
||||
@@ -3499,7 +3556,7 @@ static bool trans_shrp_imm(DisasContext *ctx, arg_shrp_imm *a)
|
||||
/* Install the new nullification. */
|
||||
cond_free(&ctx->null_cond);
|
||||
if (a->c) {
|
||||
ctx->null_cond = do_sed_cond(ctx, a->c, false, dest);
|
||||
ctx->null_cond = do_sed_cond(ctx, a->c, a->d, dest);
|
||||
}
|
||||
return nullify_end(ctx);
|
||||
}
|
||||
@@ -3762,6 +3819,7 @@ static bool trans_be(DisasContext *ctx, arg_be *a)
|
||||
copy_iaoq_entry(ctx, cpu_iaoq_b, -1, tmp);
|
||||
tcg_gen_mov_i64(cpu_iasq_f, new_spc);
|
||||
tcg_gen_mov_i64(cpu_iasq_b, cpu_iasq_f);
|
||||
nullify_set(ctx, 0);
|
||||
} else {
|
||||
copy_iaoq_entry(ctx, cpu_iaoq_f, ctx->iaoq_b, cpu_iaoq_b);
|
||||
if (ctx->iaoq_b == -1) {
|
||||
|
||||
+39
-11
@@ -2289,17 +2289,42 @@ uint64_t cpu_get_tsc(CPUX86State *env);
|
||||
#define cpu_list x86_cpu_list
|
||||
|
||||
/* MMU modes definitions */
|
||||
#define MMU_KSMAP_IDX 0
|
||||
#define MMU_USER_IDX 1
|
||||
#define MMU_KNOSMAP_IDX 2
|
||||
#define MMU_NESTED_IDX 3
|
||||
#define MMU_PHYS_IDX 4
|
||||
#define MMU_KSMAP64_IDX 0
|
||||
#define MMU_KSMAP32_IDX 1
|
||||
#define MMU_USER64_IDX 2
|
||||
#define MMU_USER32_IDX 3
|
||||
#define MMU_KNOSMAP64_IDX 4
|
||||
#define MMU_KNOSMAP32_IDX 5
|
||||
#define MMU_PHYS_IDX 6
|
||||
#define MMU_NESTED_IDX 7
|
||||
|
||||
#ifdef CONFIG_USER_ONLY
|
||||
#ifdef TARGET_X86_64
|
||||
#define MMU_USER_IDX MMU_USER64_IDX
|
||||
#else
|
||||
#define MMU_USER_IDX MMU_USER32_IDX
|
||||
#endif
|
||||
#endif
|
||||
|
||||
static inline int cpu_mmu_index(CPUX86State *env, bool ifetch)
|
||||
{
|
||||
return (env->hflags & HF_CPL_MASK) == 3 ? MMU_USER_IDX :
|
||||
(!(env->hflags & HF_SMAP_MASK) || (env->eflags & AC_MASK))
|
||||
? MMU_KNOSMAP_IDX : MMU_KSMAP_IDX;
|
||||
int mmu_index_32 = (env->hflags & HF_CS64_MASK) ? 0 : 1;
|
||||
int mmu_index_base =
|
||||
(env->hflags & HF_CPL_MASK) == 3 ? MMU_USER64_IDX :
|
||||
!(env->hflags & HF_SMAP_MASK) ? MMU_KNOSMAP64_IDX :
|
||||
(env->eflags & AC_MASK) ? MMU_KNOSMAP64_IDX : MMU_KSMAP64_IDX;
|
||||
|
||||
return mmu_index_base + mmu_index_32;
|
||||
}
|
||||
|
||||
static inline bool is_mmu_index_smap(int mmu_index)
|
||||
{
|
||||
return (mmu_index & ~1) == MMU_KSMAP64_IDX;
|
||||
}
|
||||
|
||||
static inline bool is_mmu_index_user(int mmu_index)
|
||||
{
|
||||
return (mmu_index & ~1) == MMU_USER64_IDX;
|
||||
}
|
||||
|
||||
static inline bool is_mmu_index_32(int mmu_index)
|
||||
@@ -2310,9 +2335,12 @@ static inline bool is_mmu_index_32(int mmu_index)
|
||||
|
||||
static inline int cpu_mmu_index_kernel(CPUX86State *env)
|
||||
{
|
||||
return !(env->hflags & HF_SMAP_MASK) ? MMU_KNOSMAP_IDX :
|
||||
((env->hflags & HF_CPL_MASK) < 3 && (env->eflags & AC_MASK))
|
||||
? MMU_KNOSMAP_IDX : MMU_KSMAP_IDX;
|
||||
int mmu_index_32 = (env->hflags & HF_LMA_MASK) ? 0 : 1;
|
||||
int mmu_index_base =
|
||||
!(env->hflags & HF_SMAP_MASK) ? MMU_KNOSMAP64_IDX :
|
||||
((env->hflags & HF_CPL_MASK) < 3 && (env->eflags & AC_MASK)) ? MMU_KNOSMAP64_IDX : MMU_KSMAP64_IDX;
|
||||
|
||||
return mmu_index_base + mmu_index_32;
|
||||
}
|
||||
|
||||
#define CC_DST (env->cc_dst)
|
||||
|
||||
@@ -430,7 +430,7 @@ static void do_inject_x86_mce(CPUState *cs, run_on_cpu_data data)
|
||||
if (need_reset) {
|
||||
emit_guest_memory_failure(MEMORY_FAILURE_ACTION_RESET, ar,
|
||||
recursive);
|
||||
monitor_puts(params->mon, msg);
|
||||
monitor_printf(params->mon, "%s", msg);
|
||||
qemu_log_mask(CPU_LOG_RESET, "%s\n", msg);
|
||||
qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET);
|
||||
return;
|
||||
|
||||
@@ -59,14 +59,14 @@ typedef struct PTETranslate {
|
||||
hwaddr gaddr;
|
||||
} PTETranslate;
|
||||
|
||||
static bool ptw_translate(PTETranslate *inout, hwaddr addr)
|
||||
static bool ptw_translate(PTETranslate *inout, hwaddr addr, uint64_t ra)
|
||||
{
|
||||
CPUTLBEntryFull *full;
|
||||
int flags;
|
||||
|
||||
inout->gaddr = addr;
|
||||
flags = probe_access_full(inout->env, addr, 0, MMU_DATA_STORE,
|
||||
inout->ptw_idx, true, &inout->haddr, &full, 0);
|
||||
inout->ptw_idx, true, &inout->haddr, &full, ra);
|
||||
|
||||
if (unlikely(flags & TLB_INVALID_MASK)) {
|
||||
TranslateFault *err = inout->err;
|
||||
@@ -82,20 +82,20 @@ static bool ptw_translate(PTETranslate *inout, hwaddr addr)
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline uint32_t ptw_ldl(const PTETranslate *in)
|
||||
static inline uint32_t ptw_ldl(const PTETranslate *in, uint64_t ra)
|
||||
{
|
||||
if (likely(in->haddr)) {
|
||||
return ldl_p(in->haddr);
|
||||
}
|
||||
return cpu_ldl_mmuidx_ra(in->env, in->gaddr, in->ptw_idx, 0);
|
||||
return cpu_ldl_mmuidx_ra(in->env, in->gaddr, in->ptw_idx, ra);
|
||||
}
|
||||
|
||||
static inline uint64_t ptw_ldq(const PTETranslate *in)
|
||||
static inline uint64_t ptw_ldq(const PTETranslate *in, uint64_t ra)
|
||||
{
|
||||
if (likely(in->haddr)) {
|
||||
return ldq_p(in->haddr);
|
||||
}
|
||||
return cpu_ldq_mmuidx_ra(in->env, in->gaddr, in->ptw_idx, 0);
|
||||
return cpu_ldq_mmuidx_ra(in->env, in->gaddr, in->ptw_idx, ra);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -132,11 +132,12 @@ static inline bool ptw_setl(const PTETranslate *in, uint32_t old, uint32_t set)
|
||||
}
|
||||
|
||||
static bool mmu_translate(CPUX86State *env, const TranslateParams *in,
|
||||
TranslateResult *out, TranslateFault *err)
|
||||
TranslateResult *out, TranslateFault *err,
|
||||
uint64_t ra)
|
||||
{
|
||||
const target_ulong addr = in->addr;
|
||||
const int pg_mode = in->pg_mode;
|
||||
const bool is_user = (in->mmu_idx == MMU_USER_IDX);
|
||||
const bool is_user = is_mmu_index_user(in->mmu_idx);
|
||||
const MMUAccessType access_type = in->access_type;
|
||||
uint64_t ptep, pte, rsvd_mask;
|
||||
PTETranslate pte_trans = {
|
||||
@@ -164,11 +165,11 @@ static bool mmu_translate(CPUX86State *env, const TranslateParams *in,
|
||||
* Page table level 5
|
||||
*/
|
||||
pte_addr = (in->cr3 & ~0xfff) + (((addr >> 48) & 0x1ff) << 3);
|
||||
if (!ptw_translate(&pte_trans, pte_addr)) {
|
||||
if (!ptw_translate(&pte_trans, pte_addr, ra)) {
|
||||
return false;
|
||||
}
|
||||
restart_5:
|
||||
pte = ptw_ldq(&pte_trans);
|
||||
pte = ptw_ldq(&pte_trans, ra);
|
||||
if (!(pte & PG_PRESENT_MASK)) {
|
||||
goto do_fault;
|
||||
}
|
||||
@@ -188,11 +189,11 @@ static bool mmu_translate(CPUX86State *env, const TranslateParams *in,
|
||||
* Page table level 4
|
||||
*/
|
||||
pte_addr = (pte & PG_ADDRESS_MASK) + (((addr >> 39) & 0x1ff) << 3);
|
||||
if (!ptw_translate(&pte_trans, pte_addr)) {
|
||||
if (!ptw_translate(&pte_trans, pte_addr, ra)) {
|
||||
return false;
|
||||
}
|
||||
restart_4:
|
||||
pte = ptw_ldq(&pte_trans);
|
||||
pte = ptw_ldq(&pte_trans, ra);
|
||||
if (!(pte & PG_PRESENT_MASK)) {
|
||||
goto do_fault;
|
||||
}
|
||||
@@ -208,11 +209,11 @@ static bool mmu_translate(CPUX86State *env, const TranslateParams *in,
|
||||
* Page table level 3
|
||||
*/
|
||||
pte_addr = (pte & PG_ADDRESS_MASK) + (((addr >> 30) & 0x1ff) << 3);
|
||||
if (!ptw_translate(&pte_trans, pte_addr)) {
|
||||
if (!ptw_translate(&pte_trans, pte_addr, ra)) {
|
||||
return false;
|
||||
}
|
||||
restart_3_lma:
|
||||
pte = ptw_ldq(&pte_trans);
|
||||
pte = ptw_ldq(&pte_trans, ra);
|
||||
if (!(pte & PG_PRESENT_MASK)) {
|
||||
goto do_fault;
|
||||
}
|
||||
@@ -235,12 +236,12 @@ static bool mmu_translate(CPUX86State *env, const TranslateParams *in,
|
||||
* Page table level 3
|
||||
*/
|
||||
pte_addr = (in->cr3 & 0xffffffe0ULL) + ((addr >> 27) & 0x18);
|
||||
if (!ptw_translate(&pte_trans, pte_addr)) {
|
||||
if (!ptw_translate(&pte_trans, pte_addr, ra)) {
|
||||
return false;
|
||||
}
|
||||
rsvd_mask |= PG_HI_USER_MASK;
|
||||
restart_3_nolma:
|
||||
pte = ptw_ldq(&pte_trans);
|
||||
pte = ptw_ldq(&pte_trans, ra);
|
||||
if (!(pte & PG_PRESENT_MASK)) {
|
||||
goto do_fault;
|
||||
}
|
||||
@@ -257,11 +258,11 @@ static bool mmu_translate(CPUX86State *env, const TranslateParams *in,
|
||||
* Page table level 2
|
||||
*/
|
||||
pte_addr = (pte & PG_ADDRESS_MASK) + (((addr >> 21) & 0x1ff) << 3);
|
||||
if (!ptw_translate(&pte_trans, pte_addr)) {
|
||||
if (!ptw_translate(&pte_trans, pte_addr, ra)) {
|
||||
return false;
|
||||
}
|
||||
restart_2_pae:
|
||||
pte = ptw_ldq(&pte_trans);
|
||||
pte = ptw_ldq(&pte_trans, ra);
|
||||
if (!(pte & PG_PRESENT_MASK)) {
|
||||
goto do_fault;
|
||||
}
|
||||
@@ -283,10 +284,10 @@ static bool mmu_translate(CPUX86State *env, const TranslateParams *in,
|
||||
* Page table level 1
|
||||
*/
|
||||
pte_addr = (pte & PG_ADDRESS_MASK) + (((addr >> 12) & 0x1ff) << 3);
|
||||
if (!ptw_translate(&pte_trans, pte_addr)) {
|
||||
if (!ptw_translate(&pte_trans, pte_addr, ra)) {
|
||||
return false;
|
||||
}
|
||||
pte = ptw_ldq(&pte_trans);
|
||||
pte = ptw_ldq(&pte_trans, ra);
|
||||
if (!(pte & PG_PRESENT_MASK)) {
|
||||
goto do_fault;
|
||||
}
|
||||
@@ -301,11 +302,11 @@ static bool mmu_translate(CPUX86State *env, const TranslateParams *in,
|
||||
* Page table level 2
|
||||
*/
|
||||
pte_addr = (in->cr3 & 0xfffff000ULL) + ((addr >> 20) & 0xffc);
|
||||
if (!ptw_translate(&pte_trans, pte_addr)) {
|
||||
if (!ptw_translate(&pte_trans, pte_addr, ra)) {
|
||||
return false;
|
||||
}
|
||||
restart_2_nopae:
|
||||
pte = ptw_ldl(&pte_trans);
|
||||
pte = ptw_ldl(&pte_trans, ra);
|
||||
if (!(pte & PG_PRESENT_MASK)) {
|
||||
goto do_fault;
|
||||
}
|
||||
@@ -330,10 +331,10 @@ static bool mmu_translate(CPUX86State *env, const TranslateParams *in,
|
||||
* Page table level 1
|
||||
*/
|
||||
pte_addr = (pte & ~0xfffu) + ((addr >> 10) & 0xffc);
|
||||
if (!ptw_translate(&pte_trans, pte_addr)) {
|
||||
if (!ptw_translate(&pte_trans, pte_addr, ra)) {
|
||||
return false;
|
||||
}
|
||||
pte = ptw_ldl(&pte_trans);
|
||||
pte = ptw_ldl(&pte_trans, ra);
|
||||
if (!(pte & PG_PRESENT_MASK)) {
|
||||
goto do_fault;
|
||||
}
|
||||
@@ -357,7 +358,7 @@ do_check_protect_pse36:
|
||||
}
|
||||
|
||||
int prot = 0;
|
||||
if (in->mmu_idx != MMU_KSMAP_IDX || !(ptep & PG_USER_MASK)) {
|
||||
if (!is_mmu_index_smap(in->mmu_idx) || !(ptep & PG_USER_MASK)) {
|
||||
prot |= PAGE_READ;
|
||||
if ((ptep & PG_RW_MASK) || !(is_user || (pg_mode & PG_MODE_WP))) {
|
||||
prot |= PAGE_WRITE;
|
||||
@@ -526,7 +527,8 @@ static G_NORETURN void raise_stage2(CPUX86State *env, TranslateFault *err,
|
||||
|
||||
static bool get_physical_address(CPUX86State *env, vaddr addr,
|
||||
MMUAccessType access_type, int mmu_idx,
|
||||
TranslateResult *out, TranslateFault *err)
|
||||
TranslateResult *out, TranslateFault *err,
|
||||
uint64_t ra)
|
||||
{
|
||||
TranslateParams in;
|
||||
bool use_stage2 = env->hflags2 & HF2_NPT_MASK;
|
||||
@@ -542,10 +544,11 @@ static bool get_physical_address(CPUX86State *env, vaddr addr,
|
||||
if (likely(use_stage2)) {
|
||||
in.cr3 = env->nested_cr3;
|
||||
in.pg_mode = env->nested_pg_mode;
|
||||
in.mmu_idx = MMU_USER_IDX;
|
||||
in.mmu_idx =
|
||||
env->nested_pg_mode & PG_MODE_LMA ? MMU_USER64_IDX : MMU_USER32_IDX;
|
||||
in.ptw_idx = MMU_PHYS_IDX;
|
||||
|
||||
if (!mmu_translate(env, &in, out, err)) {
|
||||
if (!mmu_translate(env, &in, out, err, ra)) {
|
||||
err->stage2 = S2_GPA;
|
||||
return false;
|
||||
}
|
||||
@@ -576,7 +579,7 @@ static bool get_physical_address(CPUX86State *env, vaddr addr,
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return mmu_translate(env, &in, out, err);
|
||||
return mmu_translate(env, &in, out, err, ra);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -596,7 +599,8 @@ bool x86_cpu_tlb_fill(CPUState *cs, vaddr addr, int size,
|
||||
TranslateResult out;
|
||||
TranslateFault err;
|
||||
|
||||
if (get_physical_address(env, addr, access_type, mmu_idx, &out, &err)) {
|
||||
if (get_physical_address(env, addr, access_type, mmu_idx, &out, &err,
|
||||
retaddr)) {
|
||||
/*
|
||||
* Even if 4MB pages, we map only one 4KB page in the cache to
|
||||
* avoid filling it too fast.
|
||||
|
||||
+40
-34
@@ -35,33 +35,45 @@ const char * const fregnames[32] = {
|
||||
"f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31",
|
||||
};
|
||||
|
||||
static const char * const excp_names[] = {
|
||||
[EXCCODE_INT] = "Interrupt",
|
||||
[EXCCODE_PIL] = "Page invalid exception for load",
|
||||
[EXCCODE_PIS] = "Page invalid exception for store",
|
||||
[EXCCODE_PIF] = "Page invalid exception for fetch",
|
||||
[EXCCODE_PME] = "Page modified exception",
|
||||
[EXCCODE_PNR] = "Page Not Readable exception",
|
||||
[EXCCODE_PNX] = "Page Not Executable exception",
|
||||
[EXCCODE_PPI] = "Page Privilege error",
|
||||
[EXCCODE_ADEF] = "Address error for instruction fetch",
|
||||
[EXCCODE_ADEM] = "Address error for Memory access",
|
||||
[EXCCODE_SYS] = "Syscall",
|
||||
[EXCCODE_BRK] = "Break",
|
||||
[EXCCODE_INE] = "Instruction Non-Existent",
|
||||
[EXCCODE_IPE] = "Instruction privilege error",
|
||||
[EXCCODE_FPD] = "Floating Point Disabled",
|
||||
[EXCCODE_FPE] = "Floating Point Exception",
|
||||
[EXCCODE_DBP] = "Debug breakpoint",
|
||||
[EXCCODE_BCE] = "Bound Check Exception",
|
||||
[EXCCODE_SXD] = "128 bit vector instructions Disable exception",
|
||||
[EXCCODE_ASXD] = "256 bit vector instructions Disable exception",
|
||||
struct TypeExcp {
|
||||
int32_t exccode;
|
||||
const char * const name;
|
||||
};
|
||||
|
||||
static const struct TypeExcp excp_names[] = {
|
||||
{EXCCODE_INT, "Interrupt"},
|
||||
{EXCCODE_PIL, "Page invalid exception for load"},
|
||||
{EXCCODE_PIS, "Page invalid exception for store"},
|
||||
{EXCCODE_PIF, "Page invalid exception for fetch"},
|
||||
{EXCCODE_PME, "Page modified exception"},
|
||||
{EXCCODE_PNR, "Page Not Readable exception"},
|
||||
{EXCCODE_PNX, "Page Not Executable exception"},
|
||||
{EXCCODE_PPI, "Page Privilege error"},
|
||||
{EXCCODE_ADEF, "Address error for instruction fetch"},
|
||||
{EXCCODE_ADEM, "Address error for Memory access"},
|
||||
{EXCCODE_SYS, "Syscall"},
|
||||
{EXCCODE_BRK, "Break"},
|
||||
{EXCCODE_INE, "Instruction Non-Existent"},
|
||||
{EXCCODE_IPE, "Instruction privilege error"},
|
||||
{EXCCODE_FPD, "Floating Point Disabled"},
|
||||
{EXCCODE_FPE, "Floating Point Exception"},
|
||||
{EXCCODE_DBP, "Debug breakpoint"},
|
||||
{EXCCODE_BCE, "Bound Check Exception"},
|
||||
{EXCCODE_SXD, "128 bit vector instructions Disable exception"},
|
||||
{EXCCODE_ASXD, "256 bit vector instructions Disable exception"},
|
||||
{EXCP_HLT, "EXCP_HLT"},
|
||||
};
|
||||
|
||||
const char *loongarch_exception_name(int32_t exception)
|
||||
{
|
||||
assert(excp_names[exception]);
|
||||
return excp_names[exception];
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(excp_names); i++) {
|
||||
if (excp_names[i].exccode == exception) {
|
||||
return excp_names[i].name;
|
||||
}
|
||||
}
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
void G_NORETURN do_raise_exception(CPULoongArchState *env,
|
||||
@@ -70,7 +82,7 @@ void G_NORETURN do_raise_exception(CPULoongArchState *env,
|
||||
{
|
||||
CPUState *cs = env_cpu(env);
|
||||
|
||||
qemu_log_mask(CPU_LOG_INT, "%s: %d (%s)\n",
|
||||
qemu_log_mask(CPU_LOG_INT, "%s: exception: %d (%s)\n",
|
||||
__func__,
|
||||
exception,
|
||||
loongarch_exception_name(exception));
|
||||
@@ -145,22 +157,16 @@ static void loongarch_cpu_do_interrupt(CPUState *cs)
|
||||
CPULoongArchState *env = &cpu->env;
|
||||
bool update_badinstr = 1;
|
||||
int cause = -1;
|
||||
const char *name;
|
||||
bool tlbfill = FIELD_EX64(env->CSR_TLBRERA, CSR_TLBRERA, ISTLBR);
|
||||
uint32_t vec_size = FIELD_EX64(env->CSR_ECFG, CSR_ECFG, VS);
|
||||
|
||||
if (cs->exception_index != EXCCODE_INT) {
|
||||
if (cs->exception_index < 0 ||
|
||||
cs->exception_index >= ARRAY_SIZE(excp_names)) {
|
||||
name = "unknown";
|
||||
} else {
|
||||
name = excp_names[cs->exception_index];
|
||||
}
|
||||
|
||||
qemu_log_mask(CPU_LOG_INT,
|
||||
"%s enter: pc " TARGET_FMT_lx " ERA " TARGET_FMT_lx
|
||||
" TLBRERA " TARGET_FMT_lx " %s exception\n", __func__,
|
||||
env->pc, env->CSR_ERA, env->CSR_TLBRERA, name);
|
||||
" TLBRERA " TARGET_FMT_lx " exception: %d (%s)\n",
|
||||
__func__, env->pc, env->CSR_ERA, env->CSR_TLBRERA,
|
||||
cs->exception_index,
|
||||
loongarch_exception_name(cs->exception_index));
|
||||
}
|
||||
|
||||
switch (cs->exception_index) {
|
||||
|
||||
@@ -5,14 +5,14 @@
|
||||
|
||||
static bool gen_ll(DisasContext *ctx, arg_rr_i *a, MemOp mop)
|
||||
{
|
||||
TCGv dest = gpr_dst(ctx, a->rd, EXT_NONE);
|
||||
TCGv t1 = tcg_temp_new();
|
||||
TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE);
|
||||
TCGv t0 = make_address_i(ctx, src1, a->imm);
|
||||
|
||||
tcg_gen_qemu_ld_i64(dest, t0, ctx->mem_idx, mop);
|
||||
tcg_gen_qemu_ld_i64(t1, t0, ctx->mem_idx, mop);
|
||||
tcg_gen_st_tl(t0, tcg_env, offsetof(CPULoongArchState, lladdr));
|
||||
tcg_gen_st_tl(dest, tcg_env, offsetof(CPULoongArchState, llval));
|
||||
gen_set_gpr(a->rd, dest, EXT_NONE);
|
||||
tcg_gen_st_tl(t1, tcg_env, offsetof(CPULoongArchState, llval));
|
||||
gen_set_gpr(a->rd, t1, EXT_NONE);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
+10
-2
@@ -396,12 +396,19 @@ static const VMStateDescription vmstate_freg = {
|
||||
}
|
||||
};
|
||||
|
||||
static int fpu_pre_save(void *opaque)
|
||||
{
|
||||
M68kCPU *s = opaque;
|
||||
|
||||
s->env.fpsr = cpu_m68k_get_fpsr(&s->env);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fpu_post_load(void *opaque, int version)
|
||||
{
|
||||
M68kCPU *s = opaque;
|
||||
|
||||
cpu_m68k_restore_fp_status(&s->env);
|
||||
|
||||
cpu_m68k_set_fpsr(&s->env, s->env.fpsr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -410,6 +417,7 @@ const VMStateDescription vmmstate_fpu = {
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.needed = fpu_needed,
|
||||
.pre_save = fpu_pre_save,
|
||||
.post_load = fpu_post_load,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT32(env.fpcr, M68kCPU),
|
||||
|
||||
+2
-1
@@ -199,7 +199,8 @@ void cpu_m68k_set_ccr(CPUM68KState *env, uint32_t);
|
||||
void cpu_m68k_set_sr(CPUM68KState *env, uint32_t);
|
||||
void cpu_m68k_restore_fp_status(CPUM68KState *env);
|
||||
void cpu_m68k_set_fpcr(CPUM68KState *env, uint32_t val);
|
||||
|
||||
uint32_t cpu_m68k_get_fpsr(CPUM68KState *env);
|
||||
void cpu_m68k_set_fpsr(CPUM68KState *env, uint32_t val);
|
||||
|
||||
/*
|
||||
* Instead of computing the condition codes after each m68k instruction,
|
||||
|
||||
@@ -164,6 +164,78 @@ void HELPER(set_fpcr)(CPUM68KState *env, uint32_t val)
|
||||
cpu_m68k_set_fpcr(env, val);
|
||||
}
|
||||
|
||||
/* Convert host exception flags to cpu_m68k form. */
|
||||
static int cpu_m68k_exceptbits_from_host(int host_bits)
|
||||
{
|
||||
int target_bits = 0;
|
||||
|
||||
if (host_bits & float_flag_invalid) {
|
||||
target_bits |= 0x80;
|
||||
}
|
||||
if (host_bits & float_flag_overflow) {
|
||||
target_bits |= 0x40;
|
||||
}
|
||||
if (host_bits & (float_flag_underflow | float_flag_output_denormal)) {
|
||||
target_bits |= 0x20;
|
||||
}
|
||||
if (host_bits & float_flag_divbyzero) {
|
||||
target_bits |= 0x10;
|
||||
}
|
||||
if (host_bits & float_flag_inexact) {
|
||||
target_bits |= 0x08;
|
||||
}
|
||||
return target_bits;
|
||||
}
|
||||
|
||||
/* Convert cpu_m68k exception flags to target form. */
|
||||
static int cpu_m68k_exceptbits_to_host(int target_bits)
|
||||
{
|
||||
int host_bits = 0;
|
||||
|
||||
if (target_bits & 0x80) {
|
||||
host_bits |= float_flag_invalid;
|
||||
}
|
||||
if (target_bits & 0x40) {
|
||||
host_bits |= float_flag_overflow;
|
||||
}
|
||||
if (target_bits & 0x20) {
|
||||
host_bits |= float_flag_underflow;
|
||||
}
|
||||
if (target_bits & 0x10) {
|
||||
host_bits |= float_flag_divbyzero;
|
||||
}
|
||||
if (target_bits & 0x08) {
|
||||
host_bits |= float_flag_inexact;
|
||||
}
|
||||
return host_bits;
|
||||
}
|
||||
|
||||
uint32_t cpu_m68k_get_fpsr(CPUM68KState *env)
|
||||
{
|
||||
int host_flags = get_float_exception_flags(&env->fp_status);
|
||||
int target_flags = cpu_m68k_exceptbits_from_host(host_flags);
|
||||
int except = (env->fpsr & ~(0xf8)) | target_flags;
|
||||
return except;
|
||||
}
|
||||
|
||||
uint32_t HELPER(get_fpsr)(CPUM68KState *env)
|
||||
{
|
||||
return cpu_m68k_get_fpsr(env);
|
||||
}
|
||||
|
||||
void cpu_m68k_set_fpsr(CPUM68KState *env, uint32_t val)
|
||||
{
|
||||
env->fpsr = val;
|
||||
|
||||
int host_flags = cpu_m68k_exceptbits_to_host((int) env->fpsr);
|
||||
set_float_exception_flags(host_flags, &env->fp_status);
|
||||
}
|
||||
|
||||
void HELPER(set_fpsr)(CPUM68KState *env, uint32_t val)
|
||||
{
|
||||
cpu_m68k_set_fpsr(env, val);
|
||||
}
|
||||
|
||||
#define PREC_BEGIN(prec) \
|
||||
do { \
|
||||
FloatX80RoundPrec old = \
|
||||
|
||||
@@ -118,7 +118,7 @@ static int m68k_fpu_gdb_get_reg(CPUM68KState *env, GByteArray *mem_buf, int n)
|
||||
case 8: /* fpcontrol */
|
||||
return gdb_get_reg32(mem_buf, env->fpcr);
|
||||
case 9: /* fpstatus */
|
||||
return gdb_get_reg32(mem_buf, env->fpsr);
|
||||
return gdb_get_reg32(mem_buf, cpu_m68k_get_fpsr(env));
|
||||
case 10: /* fpiar, not implemented */
|
||||
return gdb_get_reg32(mem_buf, 0);
|
||||
}
|
||||
@@ -137,7 +137,7 @@ static int m68k_fpu_gdb_set_reg(CPUM68KState *env, uint8_t *mem_buf, int n)
|
||||
cpu_m68k_set_fpcr(env, ldl_p(mem_buf));
|
||||
return 4;
|
||||
case 9: /* fpstatus */
|
||||
env->fpsr = ldl_p(mem_buf);
|
||||
cpu_m68k_set_fpsr(env, ldl_p(mem_buf));
|
||||
return 4;
|
||||
case 10: /* fpiar, not implemented */
|
||||
return 4;
|
||||
|
||||
@@ -54,6 +54,8 @@ DEF_HELPER_4(fsdiv, void, env, fp, fp, fp)
|
||||
DEF_HELPER_4(fddiv, void, env, fp, fp, fp)
|
||||
DEF_HELPER_4(fsgldiv, void, env, fp, fp, fp)
|
||||
DEF_HELPER_FLAGS_3(fcmp, TCG_CALL_NO_RWG, void, env, fp, fp)
|
||||
DEF_HELPER_2(set_fpsr, void, env, i32)
|
||||
DEF_HELPER_1(get_fpsr, i32, env)
|
||||
DEF_HELPER_FLAGS_2(set_fpcr, TCG_CALL_NO_RWG, void, env, i32)
|
||||
DEF_HELPER_FLAGS_2(ftst, TCG_CALL_NO_RWG, void, env, fp)
|
||||
DEF_HELPER_3(fconst, void, env, fp, i32)
|
||||
|
||||
@@ -4686,7 +4686,7 @@ static void gen_load_fcr(DisasContext *s, TCGv res, int reg)
|
||||
tcg_gen_movi_i32(res, 0);
|
||||
break;
|
||||
case M68K_FPSR:
|
||||
tcg_gen_ld_i32(res, tcg_env, offsetof(CPUM68KState, fpsr));
|
||||
gen_helper_get_fpsr(res, tcg_env);
|
||||
break;
|
||||
case M68K_FPCR:
|
||||
tcg_gen_ld_i32(res, tcg_env, offsetof(CPUM68KState, fpcr));
|
||||
@@ -4700,7 +4700,7 @@ static void gen_store_fcr(DisasContext *s, TCGv val, int reg)
|
||||
case M68K_FPIAR:
|
||||
break;
|
||||
case M68K_FPSR:
|
||||
tcg_gen_st_i32(val, tcg_env, offsetof(CPUM68KState, fpsr));
|
||||
gen_helper_set_fpsr(tcg_env, val);
|
||||
break;
|
||||
case M68K_FPCR:
|
||||
gen_helper_set_fpcr(tcg_env, val);
|
||||
|
||||
@@ -1301,7 +1301,7 @@ bool riscv_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
|
||||
bool two_stage_lookup = mmuidx_2stage(mmu_idx);
|
||||
bool two_stage_indirect_error = false;
|
||||
int ret = TRANSLATE_FAIL;
|
||||
int mode = mmu_idx;
|
||||
int mode = mmuidx_priv(mmu_idx);
|
||||
/* default TLB page size */
|
||||
target_ulong tlb_size = TARGET_PAGE_SIZE;
|
||||
|
||||
|
||||
@@ -3360,6 +3360,8 @@ static bool trans_vmv_x_s(DisasContext *s, arg_vmv_x_s *a)
|
||||
vec_element_loadi(s, t1, a->rs2, 0, true);
|
||||
tcg_gen_trunc_i64_tl(dest, t1);
|
||||
gen_set_gpr(s, a->rd, dest);
|
||||
tcg_gen_movi_tl(cpu_vstart, 0);
|
||||
mark_vs_dirty(s);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -3386,8 +3388,9 @@ static bool trans_vmv_s_x(DisasContext *s, arg_vmv_s_x *a)
|
||||
s1 = get_gpr(s, a->rs1, EXT_NONE);
|
||||
tcg_gen_ext_tl_i64(t1, s1);
|
||||
vec_element_storei(s, a->rd, 0, t1);
|
||||
mark_vs_dirty(s);
|
||||
gen_set_label(over);
|
||||
tcg_gen_movi_tl(cpu_vstart, 0);
|
||||
mark_vs_dirty(s);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -3414,6 +3417,8 @@ static bool trans_vfmv_f_s(DisasContext *s, arg_vfmv_f_s *a)
|
||||
}
|
||||
|
||||
mark_fs_dirty(s);
|
||||
tcg_gen_movi_tl(cpu_vstart, 0);
|
||||
mark_vs_dirty(s);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -3439,8 +3444,9 @@ static bool trans_vfmv_s_f(DisasContext *s, arg_vfmv_s_f *a)
|
||||
do_nanbox(s, t1, cpu_fpr[a->rs1]);
|
||||
|
||||
vec_element_storei(s, a->rd, 0, t1);
|
||||
mark_vs_dirty(s);
|
||||
gen_set_label(over);
|
||||
tcg_gen_movi_tl(cpu_vstart, 0);
|
||||
mark_vs_dirty(s);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -3647,12 +3653,9 @@ static bool trans_##NAME(DisasContext *s, arg_##NAME * a) \
|
||||
vreg_ofs(s, a->rs2), maxsz, maxsz); \
|
||||
mark_vs_dirty(s); \
|
||||
} else { \
|
||||
TCGLabel *over = gen_new_label(); \
|
||||
tcg_gen_brcondi_tl(TCG_COND_GEU, cpu_vstart, maxsz, over); \
|
||||
tcg_gen_gvec_2_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, a->rs2), \
|
||||
tcg_env, maxsz, maxsz, 0, gen_helper_vmvr_v); \
|
||||
mark_vs_dirty(s); \
|
||||
gen_set_label(over); \
|
||||
} \
|
||||
return true; \
|
||||
} \
|
||||
|
||||
+38
-19
@@ -72,18 +72,28 @@ static uint64_t kvm_riscv_reg_id(CPURISCVState *env, uint64_t type,
|
||||
return id;
|
||||
}
|
||||
|
||||
static uint64_t kvm_riscv_reg_id_u32(uint64_t type, uint64_t idx)
|
||||
{
|
||||
return KVM_REG_RISCV | KVM_REG_SIZE_U32 | type | idx;
|
||||
}
|
||||
|
||||
static uint64_t kvm_riscv_reg_id_u64(uint64_t type, uint64_t idx)
|
||||
{
|
||||
return KVM_REG_RISCV | KVM_REG_SIZE_U64 | type | idx;
|
||||
}
|
||||
|
||||
#define RISCV_CORE_REG(env, name) kvm_riscv_reg_id(env, KVM_REG_RISCV_CORE, \
|
||||
KVM_REG_RISCV_CORE_REG(name))
|
||||
|
||||
#define RISCV_CSR_REG(env, name) kvm_riscv_reg_id(env, KVM_REG_RISCV_CSR, \
|
||||
KVM_REG_RISCV_CSR_REG(name))
|
||||
|
||||
#define RISCV_TIMER_REG(env, name) kvm_riscv_reg_id(env, KVM_REG_RISCV_TIMER, \
|
||||
#define RISCV_TIMER_REG(name) kvm_riscv_reg_id_u64(KVM_REG_RISCV_TIMER, \
|
||||
KVM_REG_RISCV_TIMER_REG(name))
|
||||
|
||||
#define RISCV_FP_F_REG(env, idx) kvm_riscv_reg_id(env, KVM_REG_RISCV_FP_F, idx)
|
||||
#define RISCV_FP_F_REG(idx) kvm_riscv_reg_id_u32(KVM_REG_RISCV_FP_F, idx)
|
||||
|
||||
#define RISCV_FP_D_REG(env, idx) kvm_riscv_reg_id(env, KVM_REG_RISCV_FP_D, idx)
|
||||
#define RISCV_FP_D_REG(idx) kvm_riscv_reg_id_u64(KVM_REG_RISCV_FP_D, idx)
|
||||
|
||||
#define KVM_RISCV_GET_CSR(cs, env, csr, reg) \
|
||||
do { \
|
||||
@@ -101,17 +111,17 @@ static uint64_t kvm_riscv_reg_id(CPURISCVState *env, uint64_t type,
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define KVM_RISCV_GET_TIMER(cs, env, name, reg) \
|
||||
#define KVM_RISCV_GET_TIMER(cs, name, reg) \
|
||||
do { \
|
||||
int ret = kvm_get_one_reg(cs, RISCV_TIMER_REG(env, name), ®); \
|
||||
int ret = kvm_get_one_reg(cs, RISCV_TIMER_REG(name), ®); \
|
||||
if (ret) { \
|
||||
abort(); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define KVM_RISCV_SET_TIMER(cs, env, name, reg) \
|
||||
#define KVM_RISCV_SET_TIMER(cs, name, reg) \
|
||||
do { \
|
||||
int ret = kvm_set_one_reg(cs, RISCV_TIMER_REG(env, name), ®); \
|
||||
int ret = kvm_set_one_reg(cs, RISCV_TIMER_REG(name), ®); \
|
||||
if (ret) { \
|
||||
abort(); \
|
||||
} \
|
||||
@@ -574,7 +584,7 @@ static int kvm_riscv_get_regs_fp(CPUState *cs)
|
||||
if (riscv_has_ext(env, RVD)) {
|
||||
uint64_t reg;
|
||||
for (i = 0; i < 32; i++) {
|
||||
ret = kvm_get_one_reg(cs, RISCV_FP_D_REG(env, i), ®);
|
||||
ret = kvm_get_one_reg(cs, RISCV_FP_D_REG(i), ®);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
@@ -586,7 +596,7 @@ static int kvm_riscv_get_regs_fp(CPUState *cs)
|
||||
if (riscv_has_ext(env, RVF)) {
|
||||
uint32_t reg;
|
||||
for (i = 0; i < 32; i++) {
|
||||
ret = kvm_get_one_reg(cs, RISCV_FP_F_REG(env, i), ®);
|
||||
ret = kvm_get_one_reg(cs, RISCV_FP_F_REG(i), ®);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
@@ -608,7 +618,7 @@ static int kvm_riscv_put_regs_fp(CPUState *cs)
|
||||
uint64_t reg;
|
||||
for (i = 0; i < 32; i++) {
|
||||
reg = env->fpr[i];
|
||||
ret = kvm_set_one_reg(cs, RISCV_FP_D_REG(env, i), ®);
|
||||
ret = kvm_set_one_reg(cs, RISCV_FP_D_REG(i), ®);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
@@ -620,7 +630,7 @@ static int kvm_riscv_put_regs_fp(CPUState *cs)
|
||||
uint32_t reg;
|
||||
for (i = 0; i < 32; i++) {
|
||||
reg = env->fpr[i];
|
||||
ret = kvm_set_one_reg(cs, RISCV_FP_F_REG(env, i), ®);
|
||||
ret = kvm_set_one_reg(cs, RISCV_FP_F_REG(i), ®);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
@@ -639,10 +649,10 @@ static void kvm_riscv_get_regs_timer(CPUState *cs)
|
||||
return;
|
||||
}
|
||||
|
||||
KVM_RISCV_GET_TIMER(cs, env, time, env->kvm_timer_time);
|
||||
KVM_RISCV_GET_TIMER(cs, env, compare, env->kvm_timer_compare);
|
||||
KVM_RISCV_GET_TIMER(cs, env, state, env->kvm_timer_state);
|
||||
KVM_RISCV_GET_TIMER(cs, env, frequency, env->kvm_timer_frequency);
|
||||
KVM_RISCV_GET_TIMER(cs, time, env->kvm_timer_time);
|
||||
KVM_RISCV_GET_TIMER(cs, compare, env->kvm_timer_compare);
|
||||
KVM_RISCV_GET_TIMER(cs, state, env->kvm_timer_state);
|
||||
KVM_RISCV_GET_TIMER(cs, frequency, env->kvm_timer_frequency);
|
||||
|
||||
env->kvm_timer_dirty = true;
|
||||
}
|
||||
@@ -656,8 +666,8 @@ static void kvm_riscv_put_regs_timer(CPUState *cs)
|
||||
return;
|
||||
}
|
||||
|
||||
KVM_RISCV_SET_TIMER(cs, env, time, env->kvm_timer_time);
|
||||
KVM_RISCV_SET_TIMER(cs, env, compare, env->kvm_timer_compare);
|
||||
KVM_RISCV_SET_TIMER(cs, time, env->kvm_timer_time);
|
||||
KVM_RISCV_SET_TIMER(cs, compare, env->kvm_timer_compare);
|
||||
|
||||
/*
|
||||
* To set register of RISCV_TIMER_REG(state) will occur a error from KVM
|
||||
@@ -666,7 +676,7 @@ static void kvm_riscv_put_regs_timer(CPUState *cs)
|
||||
* TODO If KVM changes, adapt here.
|
||||
*/
|
||||
if (env->kvm_timer_state) {
|
||||
KVM_RISCV_SET_TIMER(cs, env, state, env->kvm_timer_state);
|
||||
KVM_RISCV_SET_TIMER(cs, state, env->kvm_timer_state);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -675,7 +685,7 @@ static void kvm_riscv_put_regs_timer(CPUState *cs)
|
||||
* during the migration.
|
||||
*/
|
||||
if (migration_is_running(migrate_get_current()->state)) {
|
||||
KVM_RISCV_GET_TIMER(cs, env, frequency, reg);
|
||||
KVM_RISCV_GET_TIMER(cs, frequency, reg);
|
||||
if (reg != env->kvm_timer_frequency) {
|
||||
error_report("Dst Hosts timer frequency != Src Hosts");
|
||||
}
|
||||
@@ -684,6 +694,15 @@ static void kvm_riscv_put_regs_timer(CPUState *cs)
|
||||
env->kvm_timer_dirty = false;
|
||||
}
|
||||
|
||||
uint64_t kvm_riscv_get_timebase_frequency(CPUState *cs)
|
||||
{
|
||||
uint64_t reg;
|
||||
|
||||
KVM_RISCV_GET_TIMER(cs, frequency, reg);
|
||||
|
||||
return reg;
|
||||
}
|
||||
|
||||
typedef struct KVMScratchCPU {
|
||||
int kvmfd;
|
||||
int vmfd;
|
||||
|
||||
@@ -27,5 +27,6 @@ void kvm_riscv_aia_create(MachineState *machine, uint64_t group_shift,
|
||||
uint64_t guest_num);
|
||||
void riscv_kvm_aplic_request(void *opaque, int irq, int level);
|
||||
int kvm_riscv_sync_mpstate_to_kvm(RISCVCPU *cpu, int state);
|
||||
uint64_t kvm_riscv_get_timebase_frequency(CPUState *cs);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -417,11 +417,6 @@ void riscv_cpu_validate_set_extensions(RISCVCPU *cpu, Error **errp)
|
||||
return;
|
||||
}
|
||||
|
||||
if (cpu->cfg.ext_zvfbfmin && !cpu->cfg.ext_zfbfmin) {
|
||||
error_setg(errp, "Zvfbfmin extension depends on Zfbfmin extension");
|
||||
return;
|
||||
}
|
||||
|
||||
if (cpu->cfg.ext_zvfbfmin && !cpu->cfg.ext_zve32f) {
|
||||
error_setg(errp, "Zvfbfmin extension depends on Zve32f extension");
|
||||
return;
|
||||
|
||||
@@ -222,6 +222,8 @@ static inline void xor_round_key(AESState *round_state, AESState *round_key)
|
||||
uint32_t total_elems = vext_get_total_elems(env, desc, 4); \
|
||||
uint32_t vta = vext_vta(desc); \
|
||||
\
|
||||
VSTART_CHECK_EARLY_EXIT(env); \
|
||||
\
|
||||
for (uint32_t i = env->vstart / 4; i < env->vl / 4; i++) { \
|
||||
AESState round_key; \
|
||||
round_key.d[0] = *((uint64_t *)vs2 + H8(i * 2 + 0)); \
|
||||
@@ -246,6 +248,8 @@ static inline void xor_round_key(AESState *round_state, AESState *round_key)
|
||||
uint32_t total_elems = vext_get_total_elems(env, desc, 4); \
|
||||
uint32_t vta = vext_vta(desc); \
|
||||
\
|
||||
VSTART_CHECK_EARLY_EXIT(env); \
|
||||
\
|
||||
for (uint32_t i = env->vstart / 4; i < env->vl / 4; i++) { \
|
||||
AESState round_key; \
|
||||
round_key.d[0] = *((uint64_t *)vs2 + H8(0)); \
|
||||
@@ -305,6 +309,8 @@ void HELPER(vaeskf1_vi)(void *vd_vptr, void *vs2_vptr, uint32_t uimm,
|
||||
uint32_t total_elems = vext_get_total_elems(env, desc, 4);
|
||||
uint32_t vta = vext_vta(desc);
|
||||
|
||||
VSTART_CHECK_EARLY_EXIT(env);
|
||||
|
||||
uimm &= 0b1111;
|
||||
if (uimm > 10 || uimm == 0) {
|
||||
uimm ^= 0b1000;
|
||||
@@ -351,6 +357,8 @@ void HELPER(vaeskf2_vi)(void *vd_vptr, void *vs2_vptr, uint32_t uimm,
|
||||
uint32_t total_elems = vext_get_total_elems(env, desc, 4);
|
||||
uint32_t vta = vext_vta(desc);
|
||||
|
||||
VSTART_CHECK_EARLY_EXIT(env);
|
||||
|
||||
uimm &= 0b1111;
|
||||
if (uimm > 14 || uimm < 2) {
|
||||
uimm ^= 0b1000;
|
||||
@@ -457,6 +465,8 @@ void HELPER(vsha2ms_vv)(void *vd, void *vs1, void *vs2, CPURISCVState *env,
|
||||
uint32_t total_elems;
|
||||
uint32_t vta = vext_vta(desc);
|
||||
|
||||
VSTART_CHECK_EARLY_EXIT(env);
|
||||
|
||||
for (uint32_t i = env->vstart / 4; i < env->vl / 4; i++) {
|
||||
if (sew == MO_32) {
|
||||
vsha2ms_e32(((uint32_t *)vd) + i * 4, ((uint32_t *)vs1) + i * 4,
|
||||
@@ -572,6 +582,8 @@ void HELPER(vsha2ch32_vv)(void *vd, void *vs1, void *vs2, CPURISCVState *env,
|
||||
uint32_t total_elems;
|
||||
uint32_t vta = vext_vta(desc);
|
||||
|
||||
VSTART_CHECK_EARLY_EXIT(env);
|
||||
|
||||
for (uint32_t i = env->vstart / 4; i < env->vl / 4; i++) {
|
||||
vsha2c_32(((uint32_t *)vs2) + 4 * i, ((uint32_t *)vd) + 4 * i,
|
||||
((uint32_t *)vs1) + 4 * i + 2);
|
||||
@@ -590,6 +602,8 @@ void HELPER(vsha2ch64_vv)(void *vd, void *vs1, void *vs2, CPURISCVState *env,
|
||||
uint32_t total_elems;
|
||||
uint32_t vta = vext_vta(desc);
|
||||
|
||||
VSTART_CHECK_EARLY_EXIT(env);
|
||||
|
||||
for (uint32_t i = env->vstart / 4; i < env->vl / 4; i++) {
|
||||
vsha2c_64(((uint64_t *)vs2) + 4 * i, ((uint64_t *)vd) + 4 * i,
|
||||
((uint64_t *)vs1) + 4 * i + 2);
|
||||
@@ -608,6 +622,8 @@ void HELPER(vsha2cl32_vv)(void *vd, void *vs1, void *vs2, CPURISCVState *env,
|
||||
uint32_t total_elems;
|
||||
uint32_t vta = vext_vta(desc);
|
||||
|
||||
VSTART_CHECK_EARLY_EXIT(env);
|
||||
|
||||
for (uint32_t i = env->vstart / 4; i < env->vl / 4; i++) {
|
||||
vsha2c_32(((uint32_t *)vs2) + 4 * i, ((uint32_t *)vd) + 4 * i,
|
||||
(((uint32_t *)vs1) + 4 * i));
|
||||
@@ -626,6 +642,8 @@ void HELPER(vsha2cl64_vv)(void *vd, void *vs1, void *vs2, CPURISCVState *env,
|
||||
uint32_t total_elems;
|
||||
uint32_t vta = vext_vta(desc);
|
||||
|
||||
VSTART_CHECK_EARLY_EXIT(env);
|
||||
|
||||
for (uint32_t i = env->vstart / 4; i < env->vl / 4; i++) {
|
||||
vsha2c_64(((uint64_t *)vs2) + 4 * i, ((uint64_t *)vd) + 4 * i,
|
||||
(((uint64_t *)vs1) + 4 * i));
|
||||
@@ -658,6 +676,8 @@ void HELPER(vsm3me_vv)(void *vd_vptr, void *vs1_vptr, void *vs2_vptr,
|
||||
uint32_t *vs1 = vs1_vptr;
|
||||
uint32_t *vs2 = vs2_vptr;
|
||||
|
||||
VSTART_CHECK_EARLY_EXIT(env);
|
||||
|
||||
for (int i = env->vstart / 8; i < env->vl / 8; i++) {
|
||||
uint32_t w[24];
|
||||
for (int j = 0; j < 8; j++) {
|
||||
@@ -757,6 +777,8 @@ void HELPER(vsm3c_vi)(void *vd_vptr, void *vs2_vptr, uint32_t uimm,
|
||||
uint32_t *vs2 = vs2_vptr;
|
||||
uint32_t v1[8], v2[8], v3[8];
|
||||
|
||||
VSTART_CHECK_EARLY_EXIT(env);
|
||||
|
||||
for (int i = env->vstart / 8; i < env->vl / 8; i++) {
|
||||
for (int k = 0; k < 8; k++) {
|
||||
v2[k] = bswap32(vd[H4(i * 8 + k)]);
|
||||
@@ -780,6 +802,8 @@ void HELPER(vghsh_vv)(void *vd_vptr, void *vs1_vptr, void *vs2_vptr,
|
||||
uint32_t vta = vext_vta(desc);
|
||||
uint32_t total_elems = vext_get_total_elems(env, desc, 4);
|
||||
|
||||
VSTART_CHECK_EARLY_EXIT(env);
|
||||
|
||||
for (uint32_t i = env->vstart / 4; i < env->vl / 4; i++) {
|
||||
uint64_t Y[2] = {vd[i * 2 + 0], vd[i * 2 + 1]};
|
||||
uint64_t H[2] = {brev8(vs2[i * 2 + 0]), brev8(vs2[i * 2 + 1])};
|
||||
@@ -817,6 +841,8 @@ void HELPER(vgmul_vv)(void *vd_vptr, void *vs2_vptr, CPURISCVState *env,
|
||||
uint32_t vta = vext_vta(desc);
|
||||
uint32_t total_elems = vext_get_total_elems(env, desc, 4);
|
||||
|
||||
VSTART_CHECK_EARLY_EXIT(env);
|
||||
|
||||
for (uint32_t i = env->vstart / 4; i < env->vl / 4; i++) {
|
||||
uint64_t Y[2] = {brev8(vd[i * 2 + 0]), brev8(vd[i * 2 + 1])};
|
||||
uint64_t H[2] = {brev8(vs2[i * 2 + 0]), brev8(vs2[i * 2 + 1])};
|
||||
@@ -853,6 +879,8 @@ void HELPER(vsm4k_vi)(void *vd, void *vs2, uint32_t uimm5, CPURISCVState *env,
|
||||
uint32_t esz = sizeof(uint32_t);
|
||||
uint32_t total_elems = vext_get_total_elems(env, desc, esz);
|
||||
|
||||
VSTART_CHECK_EARLY_EXIT(env);
|
||||
|
||||
for (uint32_t i = group_start; i < group_end; ++i) {
|
||||
uint32_t vstart = i * egs;
|
||||
uint32_t vend = (i + 1) * egs;
|
||||
@@ -909,6 +937,8 @@ void HELPER(vsm4r_vv)(void *vd, void *vs2, CPURISCVState *env, uint32_t desc)
|
||||
uint32_t esz = sizeof(uint32_t);
|
||||
uint32_t total_elems = vext_get_total_elems(env, desc, esz);
|
||||
|
||||
VSTART_CHECK_EARLY_EXIT(env);
|
||||
|
||||
for (uint32_t i = group_start; i < group_end; ++i) {
|
||||
uint32_t vstart = i * egs;
|
||||
uint32_t vend = (i + 1) * egs;
|
||||
@@ -943,6 +973,8 @@ void HELPER(vsm4r_vs)(void *vd, void *vs2, CPURISCVState *env, uint32_t desc)
|
||||
uint32_t esz = sizeof(uint32_t);
|
||||
uint32_t total_elems = vext_get_total_elems(env, desc, esz);
|
||||
|
||||
VSTART_CHECK_EARLY_EXIT(env);
|
||||
|
||||
for (uint32_t i = group_start; i < group_end; ++i) {
|
||||
uint32_t vstart = i * egs;
|
||||
uint32_t vend = (i + 1) * egs;
|
||||
|
||||
@@ -196,7 +196,9 @@ vext_ldst_stride(void *vd, void *v0, target_ulong base,
|
||||
uint32_t esz = 1 << log2_esz;
|
||||
uint32_t vma = vext_vma(desc);
|
||||
|
||||
for (i = env->vstart; i < env->vl; i++, env->vstart++) {
|
||||
VSTART_CHECK_EARLY_EXIT(env);
|
||||
|
||||
for (i = env->vstart; i < env->vl; env->vstart = ++i) {
|
||||
k = 0;
|
||||
while (k < nf) {
|
||||
if (!vm && !vext_elem_mask(v0, i)) {
|
||||
@@ -261,8 +263,10 @@ vext_ldst_us(void *vd, target_ulong base, CPURISCVState *env, uint32_t desc,
|
||||
uint32_t max_elems = vext_max_elems(desc, log2_esz);
|
||||
uint32_t esz = 1 << log2_esz;
|
||||
|
||||
VSTART_CHECK_EARLY_EXIT(env);
|
||||
|
||||
/* load bytes from guest memory */
|
||||
for (i = env->vstart; i < evl; i++, env->vstart++) {
|
||||
for (i = env->vstart; i < evl; env->vstart = ++i) {
|
||||
k = 0;
|
||||
while (k < nf) {
|
||||
target_ulong addr = base + ((i * nf + k) << log2_esz);
|
||||
@@ -375,8 +379,10 @@ vext_ldst_index(void *vd, void *v0, target_ulong base,
|
||||
uint32_t esz = 1 << log2_esz;
|
||||
uint32_t vma = vext_vma(desc);
|
||||
|
||||
VSTART_CHECK_EARLY_EXIT(env);
|
||||
|
||||
/* load bytes from guest memory */
|
||||
for (i = env->vstart; i < env->vl; i++, env->vstart++) {
|
||||
for (i = env->vstart; i < env->vl; env->vstart = ++i) {
|
||||
k = 0;
|
||||
while (k < nf) {
|
||||
if (!vm && !vext_elem_mask(v0, i)) {
|
||||
@@ -465,6 +471,8 @@ vext_ldff(void *vd, void *v0, target_ulong base,
|
||||
uint32_t vma = vext_vma(desc);
|
||||
target_ulong addr, offset, remain;
|
||||
|
||||
VSTART_CHECK_EARLY_EXIT(env);
|
||||
|
||||
/* probe every access */
|
||||
for (i = env->vstart; i < env->vl; i++) {
|
||||
if (!vm && !vext_elem_mask(v0, i)) {
|
||||
@@ -866,6 +874,8 @@ void HELPER(NAME)(void *vd, void *v0, void *vs1, void *vs2, \
|
||||
uint32_t vta = vext_vta(desc); \
|
||||
uint32_t i; \
|
||||
\
|
||||
VSTART_CHECK_EARLY_EXIT(env); \
|
||||
\
|
||||
for (i = env->vstart; i < vl; i++) { \
|
||||
ETYPE s1 = *((ETYPE *)vs1 + H(i)); \
|
||||
ETYPE s2 = *((ETYPE *)vs2 + H(i)); \
|
||||
@@ -898,6 +908,8 @@ void HELPER(NAME)(void *vd, void *v0, target_ulong s1, void *vs2, \
|
||||
uint32_t vta = vext_vta(desc); \
|
||||
uint32_t i; \
|
||||
\
|
||||
VSTART_CHECK_EARLY_EXIT(env); \
|
||||
\
|
||||
for (i = env->vstart; i < vl; i++) { \
|
||||
ETYPE s2 = *((ETYPE *)vs2 + H(i)); \
|
||||
ETYPE carry = vext_elem_mask(v0, i); \
|
||||
@@ -933,6 +945,8 @@ void HELPER(NAME)(void *vd, void *v0, void *vs1, void *vs2, \
|
||||
uint32_t vta_all_1s = vext_vta_all_1s(desc); \
|
||||
uint32_t i; \
|
||||
\
|
||||
VSTART_CHECK_EARLY_EXIT(env); \
|
||||
\
|
||||
for (i = env->vstart; i < vl; i++) { \
|
||||
ETYPE s1 = *((ETYPE *)vs1 + H(i)); \
|
||||
ETYPE s2 = *((ETYPE *)vs2 + H(i)); \
|
||||
@@ -971,6 +985,8 @@ void HELPER(NAME)(void *vd, void *v0, target_ulong s1, \
|
||||
uint32_t vta_all_1s = vext_vta_all_1s(desc); \
|
||||
uint32_t i; \
|
||||
\
|
||||
VSTART_CHECK_EARLY_EXIT(env); \
|
||||
\
|
||||
for (i = env->vstart; i < vl; i++) { \
|
||||
ETYPE s2 = *((ETYPE *)vs2 + H(i)); \
|
||||
ETYPE carry = !vm && vext_elem_mask(v0, i); \
|
||||
@@ -1067,6 +1083,8 @@ void HELPER(NAME)(void *vd, void *v0, void *vs1, \
|
||||
uint32_t vma = vext_vma(desc); \
|
||||
uint32_t i; \
|
||||
\
|
||||
VSTART_CHECK_EARLY_EXIT(env); \
|
||||
\
|
||||
for (i = env->vstart; i < vl; i++) { \
|
||||
if (!vm && !vext_elem_mask(v0, i)) { \
|
||||
/* set masked-off elements to 1s */ \
|
||||
@@ -1114,6 +1132,8 @@ void HELPER(NAME)(void *vd, void *v0, target_ulong s1, \
|
||||
uint32_t vma = vext_vma(desc); \
|
||||
uint32_t i; \
|
||||
\
|
||||
VSTART_CHECK_EARLY_EXIT(env); \
|
||||
\
|
||||
for (i = env->vstart; i < vl; i++) { \
|
||||
if (!vm && !vext_elem_mask(v0, i)) { \
|
||||
/* set masked-off elements to 1s */ \
|
||||
@@ -1176,6 +1196,8 @@ void HELPER(NAME)(void *vd, void *v0, void *vs1, void *vs2, \
|
||||
uint32_t vma = vext_vma(desc); \
|
||||
uint32_t i; \
|
||||
\
|
||||
VSTART_CHECK_EARLY_EXIT(env); \
|
||||
\
|
||||
for (i = env->vstart; i < vl; i++) { \
|
||||
ETYPE s1 = *((ETYPE *)vs1 + H(i)); \
|
||||
ETYPE s2 = *((ETYPE *)vs2 + H(i)); \
|
||||
@@ -1241,6 +1263,8 @@ void HELPER(NAME)(void *vd, void *v0, target_ulong s1, void *vs2, \
|
||||
uint32_t vma = vext_vma(desc); \
|
||||
uint32_t i; \
|
||||
\
|
||||
VSTART_CHECK_EARLY_EXIT(env); \
|
||||
\
|
||||
for (i = env->vstart; i < vl; i++) { \
|
||||
ETYPE s2 = *((ETYPE *)vs2 + H(i)); \
|
||||
if (!vm && !vext_elem_mask(v0, i)) { \
|
||||
@@ -1788,6 +1812,8 @@ void HELPER(NAME)(void *vd, void *vs1, CPURISCVState *env, \
|
||||
uint32_t vta = vext_vta(desc); \
|
||||
uint32_t i; \
|
||||
\
|
||||
VSTART_CHECK_EARLY_EXIT(env); \
|
||||
\
|
||||
for (i = env->vstart; i < vl; i++) { \
|
||||
ETYPE s1 = *((ETYPE *)vs1 + H(i)); \
|
||||
*((ETYPE *)vd + H(i)) = s1; \
|
||||
@@ -1812,6 +1838,8 @@ void HELPER(NAME)(void *vd, uint64_t s1, CPURISCVState *env, \
|
||||
uint32_t vta = vext_vta(desc); \
|
||||
uint32_t i; \
|
||||
\
|
||||
VSTART_CHECK_EARLY_EXIT(env); \
|
||||
\
|
||||
for (i = env->vstart; i < vl; i++) { \
|
||||
*((ETYPE *)vd + H(i)) = (ETYPE)s1; \
|
||||
} \
|
||||
@@ -1835,6 +1863,8 @@ void HELPER(NAME)(void *vd, void *v0, void *vs1, void *vs2, \
|
||||
uint32_t vta = vext_vta(desc); \
|
||||
uint32_t i; \
|
||||
\
|
||||
VSTART_CHECK_EARLY_EXIT(env); \
|
||||
\
|
||||
for (i = env->vstart; i < vl; i++) { \
|
||||
ETYPE *vt = (!vext_elem_mask(v0, i) ? vs2 : vs1); \
|
||||
*((ETYPE *)vd + H(i)) = *(vt + H(i)); \
|
||||
@@ -1859,6 +1889,8 @@ void HELPER(NAME)(void *vd, void *v0, target_ulong s1, \
|
||||
uint32_t vta = vext_vta(desc); \
|
||||
uint32_t i; \
|
||||
\
|
||||
VSTART_CHECK_EARLY_EXIT(env); \
|
||||
\
|
||||
for (i = env->vstart; i < vl; i++) { \
|
||||
ETYPE s2 = *((ETYPE *)vs2 + H(i)); \
|
||||
ETYPE d = (!vext_elem_mask(v0, i) ? s2 : \
|
||||
@@ -1904,6 +1936,8 @@ vext_vv_rm_1(void *vd, void *v0, void *vs1, void *vs2,
|
||||
uint32_t vl, uint32_t vm, int vxrm,
|
||||
opivv2_rm_fn *fn, uint32_t vma, uint32_t esz)
|
||||
{
|
||||
VSTART_CHECK_EARLY_EXIT(env);
|
||||
|
||||
for (uint32_t i = env->vstart; i < vl; i++) {
|
||||
if (!vm && !vext_elem_mask(v0, i)) {
|
||||
/* set masked-off elements to 1s */
|
||||
@@ -2029,6 +2063,8 @@ vext_vx_rm_1(void *vd, void *v0, target_long s1, void *vs2,
|
||||
uint32_t vl, uint32_t vm, int vxrm,
|
||||
opivx2_rm_fn *fn, uint32_t vma, uint32_t esz)
|
||||
{
|
||||
VSTART_CHECK_EARLY_EXIT(env);
|
||||
|
||||
for (uint32_t i = env->vstart; i < vl; i++) {
|
||||
if (!vm && !vext_elem_mask(v0, i)) {
|
||||
/* set masked-off elements to 1s */
|
||||
@@ -2826,6 +2862,8 @@ void HELPER(NAME)(void *vd, void *v0, void *vs1, \
|
||||
uint32_t vma = vext_vma(desc); \
|
||||
uint32_t i; \
|
||||
\
|
||||
VSTART_CHECK_EARLY_EXIT(env); \
|
||||
\
|
||||
for (i = env->vstart; i < vl; i++) { \
|
||||
if (!vm && !vext_elem_mask(v0, i)) { \
|
||||
/* set masked-off elements to 1s */ \
|
||||
@@ -2869,6 +2907,8 @@ void HELPER(NAME)(void *vd, void *v0, uint64_t s1, \
|
||||
uint32_t vma = vext_vma(desc); \
|
||||
uint32_t i; \
|
||||
\
|
||||
VSTART_CHECK_EARLY_EXIT(env); \
|
||||
\
|
||||
for (i = env->vstart; i < vl; i++) { \
|
||||
if (!vm && !vext_elem_mask(v0, i)) { \
|
||||
/* set masked-off elements to 1s */ \
|
||||
@@ -3455,6 +3495,8 @@ void HELPER(NAME)(void *vd, void *v0, void *vs2, \
|
||||
uint32_t vma = vext_vma(desc); \
|
||||
uint32_t i; \
|
||||
\
|
||||
VSTART_CHECK_EARLY_EXIT(env); \
|
||||
\
|
||||
if (vl == 0) { \
|
||||
return; \
|
||||
} \
|
||||
@@ -3976,6 +4018,8 @@ void HELPER(NAME)(void *vd, void *v0, void *vs1, void *vs2, \
|
||||
uint32_t vma = vext_vma(desc); \
|
||||
uint32_t i; \
|
||||
\
|
||||
VSTART_CHECK_EARLY_EXIT(env); \
|
||||
\
|
||||
for (i = env->vstart; i < vl; i++) { \
|
||||
ETYPE s1 = *((ETYPE *)vs1 + H(i)); \
|
||||
ETYPE s2 = *((ETYPE *)vs2 + H(i)); \
|
||||
@@ -4016,6 +4060,8 @@ void HELPER(NAME)(void *vd, void *v0, uint64_t s1, void *vs2, \
|
||||
uint32_t vma = vext_vma(desc); \
|
||||
uint32_t i; \
|
||||
\
|
||||
VSTART_CHECK_EARLY_EXIT(env); \
|
||||
\
|
||||
for (i = env->vstart; i < vl; i++) { \
|
||||
ETYPE s2 = *((ETYPE *)vs2 + H(i)); \
|
||||
if (!vm && !vext_elem_mask(v0, i)) { \
|
||||
@@ -4209,6 +4255,8 @@ void HELPER(NAME)(void *vd, void *v0, uint64_t s1, void *vs2, \
|
||||
uint32_t vta = vext_vta(desc); \
|
||||
uint32_t i; \
|
||||
\
|
||||
VSTART_CHECK_EARLY_EXIT(env); \
|
||||
\
|
||||
for (i = env->vstart; i < vl; i++) { \
|
||||
ETYPE s2 = *((ETYPE *)vs2 + H(i)); \
|
||||
*((ETYPE *)vd + H(i)) = \
|
||||
@@ -4533,6 +4581,8 @@ void HELPER(NAME)(void *vd, void *v0, void *vs1, \
|
||||
uint32_t i; \
|
||||
int a, b; \
|
||||
\
|
||||
VSTART_CHECK_EARLY_EXIT(env); \
|
||||
\
|
||||
for (i = env->vstart; i < vl; i++) { \
|
||||
a = vext_elem_mask(vs1, i); \
|
||||
b = vext_elem_mask(vs2, i); \
|
||||
@@ -4726,6 +4776,8 @@ void HELPER(NAME)(void *vd, void *v0, CPURISCVState *env, uint32_t desc) \
|
||||
uint32_t vma = vext_vma(desc); \
|
||||
int i; \
|
||||
\
|
||||
VSTART_CHECK_EARLY_EXIT(env); \
|
||||
\
|
||||
for (i = env->vstart; i < vl; i++) { \
|
||||
if (!vm && !vext_elem_mask(v0, i)) { \
|
||||
/* set masked-off elements to 1s */ \
|
||||
@@ -4761,6 +4813,8 @@ void HELPER(NAME)(void *vd, void *v0, target_ulong s1, void *vs2, \
|
||||
uint32_t vma = vext_vma(desc); \
|
||||
target_ulong offset = s1, i_min, i; \
|
||||
\
|
||||
VSTART_CHECK_EARLY_EXIT(env); \
|
||||
\
|
||||
i_min = MAX(env->vstart, offset); \
|
||||
for (i = i_min; i < vl; i++) { \
|
||||
if (!vm && !vext_elem_mask(v0, i)) { \
|
||||
@@ -4770,6 +4824,7 @@ void HELPER(NAME)(void *vd, void *v0, target_ulong s1, void *vs2, \
|
||||
} \
|
||||
*((ETYPE *)vd + H(i)) = *((ETYPE *)vs2 + H(i - offset)); \
|
||||
} \
|
||||
env->vstart = 0; \
|
||||
/* set tail elements to 1s */ \
|
||||
vext_set_elems_1s(vd, vta, vl * esz, total_elems * esz); \
|
||||
}
|
||||
@@ -4793,6 +4848,8 @@ void HELPER(NAME)(void *vd, void *v0, target_ulong s1, void *vs2, \
|
||||
uint32_t vma = vext_vma(desc); \
|
||||
target_ulong i_max, i_min, i; \
|
||||
\
|
||||
VSTART_CHECK_EARLY_EXIT(env); \
|
||||
\
|
||||
i_min = MIN(s1 < vlmax ? vlmax - s1 : 0, vl); \
|
||||
i_max = MAX(i_min, env->vstart); \
|
||||
for (i = env->vstart; i < i_max; ++i) { \
|
||||
@@ -4835,6 +4892,8 @@ static void vslide1up_##BITWIDTH(void *vd, void *v0, uint64_t s1, \
|
||||
uint32_t vma = vext_vma(desc); \
|
||||
uint32_t i; \
|
||||
\
|
||||
VSTART_CHECK_EARLY_EXIT(env); \
|
||||
\
|
||||
for (i = env->vstart; i < vl; i++) { \
|
||||
if (!vm && !vext_elem_mask(v0, i)) { \
|
||||
/* set masked-off elements to 1s */ \
|
||||
@@ -4884,6 +4943,8 @@ static void vslide1down_##BITWIDTH(void *vd, void *v0, uint64_t s1, \
|
||||
uint32_t vma = vext_vma(desc); \
|
||||
uint32_t i; \
|
||||
\
|
||||
VSTART_CHECK_EARLY_EXIT(env); \
|
||||
\
|
||||
for (i = env->vstart; i < vl; i++) { \
|
||||
if (!vm && !vext_elem_mask(v0, i)) { \
|
||||
/* set masked-off elements to 1s */ \
|
||||
@@ -4959,6 +5020,8 @@ void HELPER(NAME)(void *vd, void *v0, void *vs1, void *vs2, \
|
||||
uint64_t index; \
|
||||
uint32_t i; \
|
||||
\
|
||||
VSTART_CHECK_EARLY_EXIT(env); \
|
||||
\
|
||||
for (i = env->vstart; i < vl; i++) { \
|
||||
if (!vm && !vext_elem_mask(v0, i)) { \
|
||||
/* set masked-off elements to 1s */ \
|
||||
@@ -5002,6 +5065,8 @@ void HELPER(NAME)(void *vd, void *v0, target_ulong s1, void *vs2, \
|
||||
uint64_t index = s1; \
|
||||
uint32_t i; \
|
||||
\
|
||||
VSTART_CHECK_EARLY_EXIT(env); \
|
||||
\
|
||||
for (i = env->vstart; i < vl; i++) { \
|
||||
if (!vm && !vext_elem_mask(v0, i)) { \
|
||||
/* set masked-off elements to 1s */ \
|
||||
@@ -5063,9 +5128,22 @@ void HELPER(vmvr_v)(void *vd, void *vs2, CPURISCVState *env, uint32_t desc)
|
||||
uint32_t startb = env->vstart * sewb;
|
||||
uint32_t i = startb;
|
||||
|
||||
if (startb >= maxsz) {
|
||||
env->vstart = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if (HOST_BIG_ENDIAN && i % 8 != 0) {
|
||||
uint32_t j = ROUND_UP(i, 8);
|
||||
memcpy((uint8_t *)vd + H1(j - 1),
|
||||
(uint8_t *)vs2 + H1(j - 1),
|
||||
j - i);
|
||||
i = j;
|
||||
}
|
||||
|
||||
memcpy((uint8_t *)vd + H1(i),
|
||||
(uint8_t *)vs2 + H1(i),
|
||||
maxsz - startb);
|
||||
maxsz - i);
|
||||
|
||||
env->vstart = 0;
|
||||
}
|
||||
@@ -5083,6 +5161,8 @@ void HELPER(NAME)(void *vd, void *v0, void *vs2, \
|
||||
uint32_t vma = vext_vma(desc); \
|
||||
uint32_t i; \
|
||||
\
|
||||
VSTART_CHECK_EARLY_EXIT(env); \
|
||||
\
|
||||
for (i = env->vstart; i < vl; i++) { \
|
||||
if (!vm && !vext_elem_mask(v0, i)) { \
|
||||
/* set masked-off elements to 1s */ \
|
||||
|
||||
@@ -43,6 +43,8 @@ void do_vext_vv(void *vd, void *v0, void *vs1, void *vs2,
|
||||
uint32_t vma = vext_vma(desc);
|
||||
uint32_t i;
|
||||
|
||||
VSTART_CHECK_EARLY_EXIT(env);
|
||||
|
||||
for (i = env->vstart; i < vl; i++) {
|
||||
if (!vm && !vext_elem_mask(v0, i)) {
|
||||
/* set masked-off elements to 1s */
|
||||
@@ -67,6 +69,8 @@ void do_vext_vx(void *vd, void *v0, target_long s1, void *vs2,
|
||||
uint32_t vma = vext_vma(desc);
|
||||
uint32_t i;
|
||||
|
||||
VSTART_CHECK_EARLY_EXIT(env);
|
||||
|
||||
for (i = env->vstart; i < vl; i++) {
|
||||
if (!vm && !vext_elem_mask(v0, i)) {
|
||||
/* set masked-off elements to 1s */
|
||||
|
||||
@@ -25,6 +25,13 @@
|
||||
#include "tcg/tcg-gvec-desc.h"
|
||||
#include "internals.h"
|
||||
|
||||
#define VSTART_CHECK_EARLY_EXIT(env) do { \
|
||||
if (env->vstart >= env->vl) { \
|
||||
env->vstart = 0; \
|
||||
return; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
static inline uint32_t vext_nf(uint32_t desc)
|
||||
{
|
||||
return FIELD_EX32(simd_data(desc), VDATA, NF);
|
||||
@@ -152,6 +159,8 @@ void HELPER(NAME)(void *vd, void *v0, void *vs2, \
|
||||
uint32_t vma = vext_vma(desc); \
|
||||
uint32_t i; \
|
||||
\
|
||||
VSTART_CHECK_EARLY_EXIT(env); \
|
||||
\
|
||||
for (i = env->vstart; i < vl; i++) { \
|
||||
if (!vm && !vext_elem_mask(v0, i)) { \
|
||||
/* set masked-off elements to 1s */ \
|
||||
|
||||
@@ -4783,9 +4783,10 @@ static DisasJumpType op_trXX(DisasContext *s, DisasOps *o)
|
||||
|
||||
static DisasJumpType op_ts(DisasContext *s, DisasOps *o)
|
||||
{
|
||||
TCGv_i32 t1 = tcg_constant_i32(0xff);
|
||||
TCGv_i32 ff = tcg_constant_i32(0xff);
|
||||
TCGv_i32 t1 = tcg_temp_new_i32();
|
||||
|
||||
tcg_gen_atomic_xchg_i32(t1, o->in2, t1, get_mem_index(s), MO_UB);
|
||||
tcg_gen_atomic_xchg_i32(t1, o->in2, ff, get_mem_index(s), MO_UB);
|
||||
tcg_gen_extract_i32(cc_op, t1, 7, 1);
|
||||
set_cc_static(s);
|
||||
return DISAS_NEXT;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user