Merge tag 'block-pull-request' of https://gitlab.com/stefanha/qemu into staging
Pull request
Please include these bug fixes in QEMU 8.1. Thanks!
# -----BEGIN PGP SIGNATURE-----
#
# iQEzBAABCAAdFiEEhpWov9P5fNqsNXdanKSrs4Grc8gFAmTCzPUACgkQnKSrs4Gr
# c8g1DAf/fPUQ4zRsCn079pHIyK9TFo4COm23p4kiusxj8otfjt8LH1Zsc9pGWC2+
# bl2RlnPID8JlyJFDRN7b/RCEhj45a83GtCmhDDmqVgy1eO5vwOKm2XyyWeD+pq/U
# Hf2QLPLZZ7tCD8Njpty+gB3Ux4zqthKGXSg8FpJ3w0tl4me2efLvjMa6jHMwtnHT
# aAbyQ3WMpT9w4XHLqRQDHzBqrTSY4od3nl9SrM/DQ2klLIcz8ECTEZVBY9B3pq6m
# QvAg24tfb0QvS14YnZv/PMCfOaVuE87M9G4f93pCynnMxMYze+XczL0sGhIAS9wp
# 03NgGlhGumOix6r2kHjlG6p3xywV8A==
# =jMf8
# -----END PGP SIGNATURE-----
# gpg: Signature made Thu 27 Jul 2023 01:00:53 PM PDT
# gpg: using RSA key 8695A8BFD3F97CDAAC35775A9CA4ABB381AB73C8
# gpg: Good signature from "Stefan Hajnoczi <stefanha@redhat.com>" [full]
# gpg: aka "Stefan Hajnoczi <stefanha@gmail.com>" [full]
* tag 'block-pull-request' of https://gitlab.com/stefanha/qemu:
block/blkio: use blkio_set_int("fd") to check fd support
block/blkio: fall back on using `path` when `fd` setting fails
block/blkio: retry blkio_connect() if it fails using `fd`
block/blkio: move blkio_connect() in the drivers functions
block: Fix pad_request's request restriction
block/file-posix: fix g_file_get_contents return path
block/blkio: do not use open flags in qemu_open()
block/blkio: enable the completion eventfd
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
diff --git a/VERSION b/VERSION
index 6f6578c..cbe9ed9 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-8.0.50
+8.0.91
diff --git a/accel/tcg/cpu-exec.c b/accel/tcg/cpu-exec.c
index fdd6d3e..e2c494e 100644
--- a/accel/tcg/cpu-exec.c
+++ b/accel/tcg/cpu-exec.c
@@ -298,7 +298,7 @@
if (qemu_log_in_addr_range(pc)) {
qemu_log_mask(CPU_LOG_EXEC,
"Trace %d: %p [%08" PRIx64
- "/%" VADDR_PRIx "/%08x/%08x] %s\n",
+ "/%016" VADDR_PRIx "/%08x/%08x] %s\n",
cpu->cpu_index, tb->tc.ptr, tb->cs_base, pc,
tb->flags, tb->cflags, lookup_symbol(pc));
@@ -487,7 +487,7 @@
if (qemu_loglevel_mask(CPU_LOG_EXEC)) {
vaddr pc = log_pc(cpu, last_tb);
if (qemu_log_in_addr_range(pc)) {
- qemu_log("Stopped execution of TB chain before %p [%"
+ qemu_log("Stopped execution of TB chain before %p [%016"
VADDR_PRIx "] %s\n",
last_tb->tc.ptr, pc, lookup_symbol(pc));
}
diff --git a/accel/tcg/cputlb.c b/accel/tcg/cputlb.c
index e0079c9..ba44501 100644
--- a/accel/tcg/cputlb.c
+++ b/accel/tcg/cputlb.c
@@ -497,8 +497,8 @@
/* Check if we need to flush due to large pages. */
if ((page & lp_mask) == lp_addr) {
- tlb_debug("forcing full flush midx %d (%"
- VADDR_PRIx "/%" VADDR_PRIx ")\n",
+ tlb_debug("forcing full flush midx %d (%016"
+ VADDR_PRIx "/%016" VADDR_PRIx ")\n",
midx, lp_addr, lp_mask);
tlb_flush_one_mmuidx_locked(env, midx, get_clock_realtime());
} else {
@@ -527,7 +527,7 @@
assert_cpu_is_self(cpu);
- tlb_debug("page addr: %" VADDR_PRIx " mmu_map:0x%x\n", addr, idxmap);
+ tlb_debug("page addr: %016" VADDR_PRIx " mmu_map:0x%x\n", addr, idxmap);
qemu_spin_lock(&env_tlb(env)->c.lock);
for (mmu_idx = 0; mmu_idx < NB_MMU_MODES; mmu_idx++) {
@@ -591,7 +591,7 @@
void tlb_flush_page_by_mmuidx(CPUState *cpu, vaddr addr, uint16_t idxmap)
{
- tlb_debug("addr: %" VADDR_PRIx " mmu_idx:%" PRIx16 "\n", addr, idxmap);
+ tlb_debug("addr: %016" VADDR_PRIx " mmu_idx:%" PRIx16 "\n", addr, idxmap);
/* This should already be page aligned */
addr &= TARGET_PAGE_MASK;
@@ -625,7 +625,7 @@
void tlb_flush_page_by_mmuidx_all_cpus(CPUState *src_cpu, vaddr addr,
uint16_t idxmap)
{
- tlb_debug("addr: %" VADDR_PRIx " mmu_idx:%"PRIx16"\n", addr, idxmap);
+ tlb_debug("addr: %016" VADDR_PRIx " mmu_idx:%"PRIx16"\n", addr, idxmap);
/* This should already be page aligned */
addr &= TARGET_PAGE_MASK;
@@ -666,7 +666,7 @@
vaddr addr,
uint16_t idxmap)
{
- tlb_debug("addr: %" VADDR_PRIx " mmu_idx:%"PRIx16"\n", addr, idxmap);
+ tlb_debug("addr: %016" VADDR_PRIx " mmu_idx:%"PRIx16"\n", addr, idxmap);
/* This should already be page aligned */
addr &= TARGET_PAGE_MASK;
@@ -728,7 +728,7 @@
*/
if (mask < f->mask || len > f->mask) {
tlb_debug("forcing full flush midx %d ("
- "%" VADDR_PRIx "/%" VADDR_PRIx "+%" VADDR_PRIx ")\n",
+ "%016" VADDR_PRIx "/%016" VADDR_PRIx "+%016" VADDR_PRIx ")\n",
midx, addr, mask, len);
tlb_flush_one_mmuidx_locked(env, midx, get_clock_realtime());
return;
@@ -741,7 +741,7 @@
*/
if (((addr + len - 1) & d->large_page_mask) == d->large_page_addr) {
tlb_debug("forcing full flush midx %d ("
- "%" VADDR_PRIx "/%" VADDR_PRIx ")\n",
+ "%016" VADDR_PRIx "/%016" VADDR_PRIx ")\n",
midx, d->large_page_addr, d->large_page_mask);
tlb_flush_one_mmuidx_locked(env, midx, get_clock_realtime());
return;
@@ -773,7 +773,7 @@
assert_cpu_is_self(cpu);
- tlb_debug("range: %" VADDR_PRIx "/%u+%" VADDR_PRIx " mmu_map:0x%x\n",
+ tlb_debug("range: %016" VADDR_PRIx "/%u+%016" VADDR_PRIx " mmu_map:0x%x\n",
d.addr, d.bits, d.len, d.idxmap);
qemu_spin_lock(&env_tlb(env)->c.lock);
@@ -1165,7 +1165,7 @@
&xlat, &sz, full->attrs, &prot);
assert(sz >= TARGET_PAGE_SIZE);
- tlb_debug("vaddr=%" VADDR_PRIx " paddr=0x" HWADDR_FMT_plx
+ tlb_debug("vaddr=%016" VADDR_PRIx " paddr=0x" HWADDR_FMT_plx
" prot=%x idx=%d\n",
addr, full->phys_addr, prot, mmu_idx);
diff --git a/accel/tcg/ldst_atomicity.c.inc b/accel/tcg/ldst_atomicity.c.inc
index 4de0a80..e5c590a 100644
--- a/accel/tcg/ldst_atomicity.c.inc
+++ b/accel/tcg/ldst_atomicity.c.inc
@@ -159,9 +159,11 @@
* another process, because the fallback start_exclusive solution
* provides no protection across processes.
*/
- if (page_check_range(h2g(pv), 8, PAGE_WRITE_ORG)) {
- uint64_t *p = __builtin_assume_aligned(pv, 8);
- return *p;
+ WITH_MMAP_LOCK_GUARD() {
+ if (!page_check_range(h2g(pv), 8, PAGE_WRITE_ORG)) {
+ uint64_t *p = __builtin_assume_aligned(pv, 8);
+ return *p;
+ }
}
#endif
@@ -186,25 +188,27 @@
return atomic16_read_ro(p);
}
-#ifdef CONFIG_USER_ONLY
/*
* We can only use cmpxchg to emulate a load if the page is writable.
* If the page is not writable, then assume the value is immutable
* and requires no locking. This ignores the case of MAP_SHARED with
* another process, because the fallback start_exclusive solution
* provides no protection across processes.
+ *
+ * In system mode all guest pages are writable. For user mode,
+ * we must take mmap_lock so that the query remains valid until
+ * the write is complete -- tests/tcg/multiarch/munmap-pthread.c
+ * is an example that can race.
*/
- if (page_check_range(h2g(p), 16, PAGE_WRITE_ORG)) {
- return *p;
- }
+ WITH_MMAP_LOCK_GUARD() {
+#ifdef CONFIG_USER_ONLY
+ if (!page_check_range(h2g(p), 16, PAGE_WRITE_ORG)) {
+ return *p;
+ }
#endif
-
- /*
- * In system mode all guest pages are writable, and for user-only
- * we have just checked writability. Try cmpxchg.
- */
- if (HAVE_ATOMIC128_RW) {
- return atomic16_read_rw(p);
+ if (HAVE_ATOMIC128_RW) {
+ return atomic16_read_rw(p);
+ }
}
/* Ultimate fallback: re-execute in serial context. */
diff --git a/accel/tcg/translate-all.c b/accel/tcg/translate-all.c
index 4c17474..a1782db 100644
--- a/accel/tcg/translate-all.c
+++ b/accel/tcg/translate-all.c
@@ -637,7 +637,7 @@
if (qemu_loglevel_mask(CPU_LOG_EXEC)) {
vaddr pc = log_pc(cpu, tb);
if (qemu_log_in_addr_range(pc)) {
- qemu_log("cpu_io_recompile: rewound execution of TB to %"
+ qemu_log("cpu_io_recompile: rewound execution of TB to %016"
VADDR_PRIx "\n", pc);
}
}
diff --git a/accel/tcg/user-exec.c b/accel/tcg/user-exec.c
index ac38c2b..ab48cb4 100644
--- a/accel/tcg/user-exec.c
+++ b/accel/tcg/user-exec.c
@@ -144,7 +144,7 @@
static IntervalTreeRoot pageflags_root;
-static PageFlagsNode *pageflags_find(target_ulong start, target_long last)
+static PageFlagsNode *pageflags_find(target_ulong start, target_ulong last)
{
IntervalTreeNode *n;
@@ -153,7 +153,7 @@
}
static PageFlagsNode *pageflags_next(PageFlagsNode *p, target_ulong start,
- target_long last)
+ target_ulong last)
{
IntervalTreeNode *n;
diff --git a/audio/pwaudio.c b/audio/pwaudio.c
index 1d108bd..b6a3873 100644
--- a/audio/pwaudio.c
+++ b/audio/pwaudio.c
@@ -1,5 +1,5 @@
/*
- * QEMU Pipewire audio driver
+ * QEMU PipeWire audio driver
*
* Copyright (c) 2023 Red Hat Inc.
*
@@ -66,6 +66,9 @@
PWVoice v;
} PWVoiceIn;
+#define PW_VOICE_IN(v) ((PWVoiceIn *)v)
+#define PW_VOICE_OUT(v) ((PWVoiceOut *)v)
+
static void
stream_destroy(void *data)
{
@@ -197,16 +200,6 @@
trace_pw_state_changed(pw_stream_get_node_id(v->stream),
pw_stream_state_as_string(state));
-
- switch (state) {
- case PW_STREAM_STATE_ERROR:
- case PW_STREAM_STATE_UNCONNECTED:
- break;
- case PW_STREAM_STATE_PAUSED:
- case PW_STREAM_STATE_CONNECTING:
- case PW_STREAM_STATE_STREAMING:
- break;
- }
}
static const struct pw_stream_events capture_stream_events = {
@@ -424,8 +417,8 @@
}
static int
-create_stream(pwaudio *c, PWVoice *v, const char *stream_name,
- const char *name, enum spa_direction dir)
+qpw_stream_new(pwaudio *c, PWVoice *v, const char *stream_name,
+ const char *name, enum spa_direction dir)
{
int res;
uint32_t n_params;
@@ -436,6 +429,10 @@
struct pw_properties *props;
props = pw_properties_new(NULL, NULL);
+ if (!props) {
+ error_report("Failed to create PW properties: %s", g_strerror(errno));
+ return -1;
+ }
/* 75% of the timer period for faster updates */
buf_samples = (uint64_t)v->g->dev->timer_period * v->info.rate
@@ -448,8 +445,8 @@
pw_properties_set(props, PW_KEY_TARGET_OBJECT, name);
}
v->stream = pw_stream_new(c->core, stream_name, props);
-
if (v->stream == NULL) {
+ error_report("Failed to create PW stream: %s", g_strerror(errno));
return -1;
}
@@ -477,6 +474,7 @@
PW_STREAM_FLAG_MAP_BUFFERS |
PW_STREAM_FLAG_RT_PROCESS, params, n_params);
if (res < 0) {
+ error_report("Failed to connect PW stream: %s", g_strerror(errno));
pw_stream_destroy(v->stream);
return -1;
}
@@ -484,71 +482,37 @@
return 0;
}
-static int
-qpw_stream_new(pwaudio *c, PWVoice *v, const char *stream_name,
- const char *name, enum spa_direction dir)
+static void
+qpw_set_position(uint32_t channels, uint32_t position[SPA_AUDIO_MAX_CHANNELS])
{
- int r;
-
- switch (v->info.channels) {
+ memcpy(position, (uint32_t[SPA_AUDIO_MAX_CHANNELS]) { SPA_AUDIO_CHANNEL_UNKNOWN, },
+ sizeof(uint32_t) * SPA_AUDIO_MAX_CHANNELS);
+ /*
+ * TODO: This currently expects the only frontend supporting more than 2
+ * channels is the usb-audio. We will need some means to set channel
+ * order when a new frontend gains multi-channel support.
+ */
+ switch (channels) {
case 8:
- v->info.position[0] = SPA_AUDIO_CHANNEL_FL;
- v->info.position[1] = SPA_AUDIO_CHANNEL_FR;
- v->info.position[2] = SPA_AUDIO_CHANNEL_FC;
- v->info.position[3] = SPA_AUDIO_CHANNEL_LFE;
- v->info.position[4] = SPA_AUDIO_CHANNEL_RL;
- v->info.position[5] = SPA_AUDIO_CHANNEL_RR;
- v->info.position[6] = SPA_AUDIO_CHANNEL_SL;
- v->info.position[7] = SPA_AUDIO_CHANNEL_SR;
- break;
+ position[6] = SPA_AUDIO_CHANNEL_SL;
+ position[7] = SPA_AUDIO_CHANNEL_SR;
+ /* fallthrough */
case 6:
- v->info.position[0] = SPA_AUDIO_CHANNEL_FL;
- v->info.position[1] = SPA_AUDIO_CHANNEL_FR;
- v->info.position[2] = SPA_AUDIO_CHANNEL_FC;
- v->info.position[3] = SPA_AUDIO_CHANNEL_LFE;
- v->info.position[4] = SPA_AUDIO_CHANNEL_RL;
- v->info.position[5] = SPA_AUDIO_CHANNEL_RR;
- break;
- case 5:
- v->info.position[0] = SPA_AUDIO_CHANNEL_FL;
- v->info.position[1] = SPA_AUDIO_CHANNEL_FR;
- v->info.position[2] = SPA_AUDIO_CHANNEL_FC;
- v->info.position[3] = SPA_AUDIO_CHANNEL_LFE;
- v->info.position[4] = SPA_AUDIO_CHANNEL_RC;
- break;
- case 4:
- v->info.position[0] = SPA_AUDIO_CHANNEL_FL;
- v->info.position[1] = SPA_AUDIO_CHANNEL_FR;
- v->info.position[2] = SPA_AUDIO_CHANNEL_FC;
- v->info.position[3] = SPA_AUDIO_CHANNEL_RC;
- break;
- case 3:
- v->info.position[0] = SPA_AUDIO_CHANNEL_FL;
- v->info.position[1] = SPA_AUDIO_CHANNEL_FR;
- v->info.position[2] = SPA_AUDIO_CHANNEL_LFE;
- break;
+ position[2] = SPA_AUDIO_CHANNEL_FC;
+ position[3] = SPA_AUDIO_CHANNEL_LFE;
+ position[4] = SPA_AUDIO_CHANNEL_RL;
+ position[5] = SPA_AUDIO_CHANNEL_RR;
+ /* fallthrough */
case 2:
- v->info.position[0] = SPA_AUDIO_CHANNEL_FL;
- v->info.position[1] = SPA_AUDIO_CHANNEL_FR;
+ position[0] = SPA_AUDIO_CHANNEL_FL;
+ position[1] = SPA_AUDIO_CHANNEL_FR;
break;
case 1:
- v->info.position[0] = SPA_AUDIO_CHANNEL_MONO;
+ position[0] = SPA_AUDIO_CHANNEL_MONO;
break;
default:
- for (size_t i = 0; i < v->info.channels; i++) {
- v->info.position[i] = SPA_AUDIO_CHANNEL_UNKNOWN;
- }
- break;
+ dolog("Internal error: unsupported channel count %d\n", channels);
}
-
- /* create a new unconnected pwstream */
- r = create_stream(c, v, stream_name, name, dir);
- if (r < 0) {
- AUD_log(AUDIO_CAP, "Failed to create stream.");
- return -1;
- }
-
- return r;
}
static int
@@ -566,6 +530,7 @@
v->info.format = audfmt_to_pw(as->fmt, as->endianness);
v->info.channels = as->nchannels;
+ qpw_set_position(as->nchannels, v->info.position);
v->info.rate = as->freq;
obt_as.fmt =
@@ -579,7 +544,6 @@
r = qpw_stream_new(c, v, ppdo->stream_name ? : c->dev->id,
ppdo->name, SPA_DIRECTION_OUTPUT);
if (r < 0) {
- error_report("qpw_stream_new for playback failed");
pw_thread_loop_unlock(c->thread_loop);
return -1;
}
@@ -613,6 +577,7 @@
v->info.format = audfmt_to_pw(as->fmt, as->endianness);
v->info.channels = as->nchannels;
+ qpw_set_position(as->nchannels, v->info.position);
v->info.rate = as->freq;
obt_as.fmt =
@@ -623,7 +588,6 @@
r = qpw_stream_new(c, v, ppdo->stream_name ? : c->dev->id,
ppdo->name, SPA_DIRECTION_INPUT);
if (r < 0) {
- error_report("qpw_stream_new for recording failed");
pw_thread_loop_unlock(c->thread_loop);
return -1;
}
@@ -640,40 +604,34 @@
}
static void
+qpw_voice_fini(PWVoice *v)
+{
+ pwaudio *c = v->g;
+
+ if (!v->stream) {
+ return;
+ }
+ pw_thread_loop_lock(c->thread_loop);
+ pw_stream_destroy(v->stream);
+ v->stream = NULL;
+ pw_thread_loop_unlock(c->thread_loop);
+}
+
+static void
qpw_fini_out(HWVoiceOut *hw)
{
- PWVoiceOut *pw = (PWVoiceOut *) hw;
- PWVoice *v = &pw->v;
-
- if (v->stream) {
- pwaudio *c = v->g;
- pw_thread_loop_lock(c->thread_loop);
- pw_stream_destroy(v->stream);
- v->stream = NULL;
- pw_thread_loop_unlock(c->thread_loop);
- }
+ qpw_voice_fini(&PW_VOICE_OUT(hw)->v);
}
static void
qpw_fini_in(HWVoiceIn *hw)
{
- PWVoiceIn *pw = (PWVoiceIn *) hw;
- PWVoice *v = &pw->v;
-
- if (v->stream) {
- pwaudio *c = v->g;
- pw_thread_loop_lock(c->thread_loop);
- pw_stream_destroy(v->stream);
- v->stream = NULL;
- pw_thread_loop_unlock(c->thread_loop);
- }
+ qpw_voice_fini(&PW_VOICE_IN(hw)->v);
}
static void
-qpw_enable_out(HWVoiceOut *hw, bool enable)
+qpw_voice_set_enabled(PWVoice *v, bool enable)
{
- PWVoiceOut *po = (PWVoiceOut *) hw;
- PWVoice *v = &po->v;
pwaudio *c = v->g;
pw_thread_loop_lock(c->thread_loop);
pw_stream_set_active(v->stream, enable);
@@ -681,64 +639,50 @@
}
static void
+qpw_enable_out(HWVoiceOut *hw, bool enable)
+{
+ qpw_voice_set_enabled(&PW_VOICE_OUT(hw)->v, enable);
+}
+
+static void
qpw_enable_in(HWVoiceIn *hw, bool enable)
{
- PWVoiceIn *pi = (PWVoiceIn *) hw;
- PWVoice *v = &pi->v;
+ qpw_voice_set_enabled(&PW_VOICE_IN(hw)->v, enable);
+}
+
+static void
+qpw_voice_set_volume(PWVoice *v, Volume *vol)
+{
pwaudio *c = v->g;
+ int i, ret;
+
pw_thread_loop_lock(c->thread_loop);
- pw_stream_set_active(v->stream, enable);
+ v->volume.channels = vol->channels;
+
+ for (i = 0; i < vol->channels; ++i) {
+ v->volume.values[i] = (float)vol->vol[i] / 255;
+ }
+
+ ret = pw_stream_set_control(v->stream,
+ SPA_PROP_channelVolumes, v->volume.channels, v->volume.values, 0);
+ trace_pw_vol(ret == 0 ? "success" : "failed");
+
+ v->muted = vol->mute;
+ float val = v->muted ? 1.f : 0.f;
+ ret = pw_stream_set_control(v->stream, SPA_PROP_mute, 1, &val, 0);
pw_thread_loop_unlock(c->thread_loop);
}
static void
qpw_volume_out(HWVoiceOut *hw, Volume *vol)
{
- PWVoiceOut *pw = (PWVoiceOut *) hw;
- PWVoice *v = &pw->v;
- pwaudio *c = v->g;
- int i, ret;
-
- pw_thread_loop_lock(c->thread_loop);
- v->volume.channels = vol->channels;
-
- for (i = 0; i < vol->channels; ++i) {
- v->volume.values[i] = (float)vol->vol[i] / 255;
- }
-
- ret = pw_stream_set_control(v->stream,
- SPA_PROP_channelVolumes, v->volume.channels, v->volume.values, 0);
- trace_pw_vol(ret == 0 ? "success" : "failed");
-
- v->muted = vol->mute;
- float val = v->muted ? 1.f : 0.f;
- ret = pw_stream_set_control(v->stream, SPA_PROP_mute, 1, &val, 0);
- pw_thread_loop_unlock(c->thread_loop);
+ qpw_voice_set_volume(&PW_VOICE_OUT(hw)->v, vol);
}
static void
qpw_volume_in(HWVoiceIn *hw, Volume *vol)
{
- PWVoiceIn *pw = (PWVoiceIn *) hw;
- PWVoice *v = &pw->v;
- pwaudio *c = v->g;
- int i, ret;
-
- pw_thread_loop_lock(c->thread_loop);
- v->volume.channels = vol->channels;
-
- for (i = 0; i < vol->channels; ++i) {
- v->volume.values[i] = (float)vol->vol[i] / 255;
- }
-
- ret = pw_stream_set_control(v->stream,
- SPA_PROP_channelVolumes, v->volume.channels, v->volume.values, 0);
- trace_pw_vol(ret == 0 ? "success" : "failed");
-
- v->muted = vol->mute;
- float val = v->muted ? 1.f : 0.f;
- ret = pw_stream_set_control(v->stream, SPA_PROP_mute, 1, &val, 0);
- pw_thread_loop_unlock(c->thread_loop);
+ qpw_voice_set_volume(&PW_VOICE_IN(hw)->v, vol);
}
static int wait_resync(pwaudio *pw)
@@ -760,6 +704,7 @@
}
return 0;
}
+
static void
on_core_error(void *data, uint32_t id, int seq, int res, const char *message)
{
@@ -794,27 +739,28 @@
qpw_audio_init(Audiodev *dev)
{
g_autofree pwaudio *pw = g_new0(pwaudio, 1);
+
+ assert(dev->driver == AUDIODEV_DRIVER_PIPEWIRE);
+ trace_pw_audio_init();
+
pw_init(NULL, NULL);
- trace_pw_audio_init();
- assert(dev->driver == AUDIODEV_DRIVER_PIPEWIRE);
-
pw->dev = dev;
- pw->thread_loop = pw_thread_loop_new("Pipewire thread loop", NULL);
+ pw->thread_loop = pw_thread_loop_new("PipeWire thread loop", NULL);
if (pw->thread_loop == NULL) {
- error_report("Could not create Pipewire loop");
+ error_report("Could not create PipeWire loop: %s", g_strerror(errno));
goto fail;
}
pw->context =
pw_context_new(pw_thread_loop_get_loop(pw->thread_loop), NULL, 0);
if (pw->context == NULL) {
- error_report("Could not create Pipewire context");
+ error_report("Could not create PipeWire context: %s", g_strerror(errno));
goto fail;
}
if (pw_thread_loop_start(pw->thread_loop) < 0) {
- error_report("Could not start Pipewire loop");
+ error_report("Could not start PipeWire loop: %s", g_strerror(errno));
goto fail;
}
@@ -844,12 +790,8 @@
if (pw->thread_loop) {
pw_thread_loop_stop(pw->thread_loop);
}
- if (pw->context) {
- g_clear_pointer(&pw->context, pw_context_destroy);
- }
- if (pw->thread_loop) {
- g_clear_pointer(&pw->thread_loop, pw_thread_loop_destroy);
- }
+ g_clear_pointer(&pw->context, pw_context_destroy);
+ g_clear_pointer(&pw->thread_loop, pw_thread_loop_destroy);
return NULL;
}
diff --git a/audio/trace-events b/audio/trace-events
index 85dbb50..ab04f02 100644
--- a/audio/trace-events
+++ b/audio/trace-events
@@ -24,7 +24,7 @@
pw_write(int32_t filled, int32_t avail, uint32_t index, size_t len) "filled=%d avail=%d index=%u len=%zu"
pw_vol(const char *ret) "set volume: %s"
pw_period(uint64_t quantum, uint32_t rate) "period =%" PRIu64 "/%u"
-pw_audio_init(void) "Initialize Pipewire context"
+pw_audio_init(void) "Initialize PipeWire context"
# audio.c
audio_timer_start(int interval) "interval %d ms"
diff --git a/block/nbd.c b/block/nbd.c
index 5aef5cb..5322e66 100644
--- a/block/nbd.c
+++ b/block/nbd.c
@@ -1,8 +1,8 @@
/*
- * QEMU Block driver for NBD
+ * QEMU Block driver for NBD
*
* Copyright (c) 2019 Virtuozzo International GmbH.
- * Copyright (C) 2016 Red Hat, Inc.
+ * Copyright Red Hat
* Copyright (C) 2008 Bull S.A.S.
* Author: Laurent Vivier <Laurent.Vivier@bull.net>
*
@@ -50,8 +50,8 @@
#define EN_OPTSTR ":exportname="
#define MAX_NBD_REQUESTS 16
-#define HANDLE_TO_INDEX(bs, handle) ((handle) ^ (uint64_t)(intptr_t)(bs))
-#define INDEX_TO_HANDLE(bs, index) ((index) ^ (uint64_t)(intptr_t)(bs))
+#define COOKIE_TO_INDEX(cookie) ((cookie) - 1)
+#define INDEX_TO_COOKIE(index) ((index) + 1)
typedef struct {
Coroutine *coroutine;
@@ -417,25 +417,25 @@
reconnect_delay_timer_del(s);
}
-static coroutine_fn int nbd_receive_replies(BDRVNBDState *s, uint64_t handle)
+static coroutine_fn int nbd_receive_replies(BDRVNBDState *s, uint64_t cookie)
{
int ret;
- uint64_t ind = HANDLE_TO_INDEX(s, handle), ind2;
+ uint64_t ind = COOKIE_TO_INDEX(cookie), ind2;
QEMU_LOCK_GUARD(&s->receive_mutex);
while (true) {
- if (s->reply.handle == handle) {
+ if (s->reply.cookie == cookie) {
/* We are done */
return 0;
}
- if (s->reply.handle != 0) {
+ if (s->reply.cookie != 0) {
/*
* Some other request is being handled now. It should already be
- * woken by whoever set s->reply.handle (or never wait in this
+ * woken by whoever set s->reply.cookie (or never wait in this
* yield). So, we should not wake it here.
*/
- ind2 = HANDLE_TO_INDEX(s, s->reply.handle);
+ ind2 = COOKIE_TO_INDEX(s->reply.cookie);
assert(!s->requests[ind2].receiving);
s->requests[ind].receiving = true;
@@ -445,9 +445,9 @@
/*
* We may be woken for 2 reasons:
* 1. From this function, executing in parallel coroutine, when our
- * handle is received.
+ * cookie is received.
* 2. From nbd_co_receive_one_chunk(), when previous request is
- * finished and s->reply.handle set to 0.
+ * finished and s->reply.cookie set to 0.
* Anyway, it's OK to lock the mutex and go to the next iteration.
*/
@@ -456,8 +456,8 @@
continue;
}
- /* We are under mutex and handle is 0. We have to do the dirty work. */
- assert(s->reply.handle == 0);
+ /* We are under mutex and cookie is 0. We have to do the dirty work. */
+ assert(s->reply.cookie == 0);
ret = nbd_receive_reply(s->bs, s->ioc, &s->reply, NULL);
if (ret <= 0) {
ret = ret ? ret : -EIO;
@@ -468,12 +468,12 @@
nbd_channel_error(s, -EINVAL);
return -EINVAL;
}
- ind2 = HANDLE_TO_INDEX(s, s->reply.handle);
+ ind2 = COOKIE_TO_INDEX(s->reply.cookie);
if (ind2 >= MAX_NBD_REQUESTS || !s->requests[ind2].coroutine) {
nbd_channel_error(s, -EINVAL);
return -EINVAL;
}
- if (s->reply.handle == handle) {
+ if (s->reply.cookie == cookie) {
/* We are done */
return 0;
}
@@ -519,7 +519,7 @@
qemu_mutex_unlock(&s->requests_lock);
qemu_co_mutex_lock(&s->send_mutex);
- request->handle = INDEX_TO_HANDLE(s, i);
+ request->cookie = INDEX_TO_COOKIE(i);
assert(s->ioc);
@@ -828,11 +828,11 @@
* corresponding to the server's error reply), and errp is unchanged.
*/
static coroutine_fn int nbd_co_do_receive_one_chunk(
- BDRVNBDState *s, uint64_t handle, bool only_structured,
+ BDRVNBDState *s, uint64_t cookie, bool only_structured,
int *request_ret, QEMUIOVector *qiov, void **payload, Error **errp)
{
int ret;
- int i = HANDLE_TO_INDEX(s, handle);
+ int i = COOKIE_TO_INDEX(cookie);
void *local_payload = NULL;
NBDStructuredReplyChunk *chunk;
@@ -841,14 +841,14 @@
}
*request_ret = 0;
- ret = nbd_receive_replies(s, handle);
+ ret = nbd_receive_replies(s, cookie);
if (ret < 0) {
error_setg(errp, "Connection closed");
return -EIO;
}
assert(s->ioc);
- assert(s->reply.handle == handle);
+ assert(s->reply.cookie == cookie);
if (nbd_reply_is_simple(&s->reply)) {
if (only_structured) {
@@ -918,11 +918,11 @@
* Return value is a fatal error code or normal nbd reply error code
*/
static coroutine_fn int nbd_co_receive_one_chunk(
- BDRVNBDState *s, uint64_t handle, bool only_structured,
+ BDRVNBDState *s, uint64_t cookie, bool only_structured,
int *request_ret, QEMUIOVector *qiov, NBDReply *reply, void **payload,
Error **errp)
{
- int ret = nbd_co_do_receive_one_chunk(s, handle, only_structured,
+ int ret = nbd_co_do_receive_one_chunk(s, cookie, only_structured,
request_ret, qiov, payload, errp);
if (ret < 0) {
@@ -932,7 +932,7 @@
/* For assert at loop start in nbd_connection_entry */
*reply = s->reply;
}
- s->reply.handle = 0;
+ s->reply.cookie = 0;
nbd_recv_coroutines_wake(s);
@@ -975,10 +975,10 @@
* NBD_FOREACH_REPLY_CHUNK
* The pointer stored in @payload requires g_free() to free it.
*/
-#define NBD_FOREACH_REPLY_CHUNK(s, iter, handle, structured, \
+#define NBD_FOREACH_REPLY_CHUNK(s, iter, cookie, structured, \
qiov, reply, payload) \
for (iter = (NBDReplyChunkIter) { .only_structured = structured }; \
- nbd_reply_chunk_iter_receive(s, &iter, handle, qiov, reply, payload);)
+ nbd_reply_chunk_iter_receive(s, &iter, cookie, qiov, reply, payload);)
/*
* nbd_reply_chunk_iter_receive
@@ -986,7 +986,7 @@
*/
static bool coroutine_fn nbd_reply_chunk_iter_receive(BDRVNBDState *s,
NBDReplyChunkIter *iter,
- uint64_t handle,
+ uint64_t cookie,
QEMUIOVector *qiov,
NBDReply *reply,
void **payload)
@@ -1005,7 +1005,7 @@
reply = &local_reply;
}
- ret = nbd_co_receive_one_chunk(s, handle, iter->only_structured,
+ ret = nbd_co_receive_one_chunk(s, cookie, iter->only_structured,
&request_ret, qiov, reply, payload,
&local_err);
if (ret < 0) {
@@ -1038,7 +1038,7 @@
break_loop:
qemu_mutex_lock(&s->requests_lock);
- s->requests[HANDLE_TO_INDEX(s, handle)].coroutine = NULL;
+ s->requests[COOKIE_TO_INDEX(cookie)].coroutine = NULL;
s->in_flight--;
qemu_co_queue_next(&s->free_sema);
qemu_mutex_unlock(&s->requests_lock);
@@ -1046,12 +1046,13 @@
return false;
}
-static int coroutine_fn nbd_co_receive_return_code(BDRVNBDState *s, uint64_t handle,
- int *request_ret, Error **errp)
+static int coroutine_fn
+nbd_co_receive_return_code(BDRVNBDState *s, uint64_t cookie,
+ int *request_ret, Error **errp)
{
NBDReplyChunkIter iter;
- NBD_FOREACH_REPLY_CHUNK(s, iter, handle, false, NULL, NULL, NULL) {
+ NBD_FOREACH_REPLY_CHUNK(s, iter, cookie, false, NULL, NULL, NULL) {
/* nbd_reply_chunk_iter_receive does all the work */
}
@@ -1060,16 +1061,17 @@
return iter.ret;
}
-static int coroutine_fn nbd_co_receive_cmdread_reply(BDRVNBDState *s, uint64_t handle,
- uint64_t offset, QEMUIOVector *qiov,
- int *request_ret, Error **errp)
+static int coroutine_fn
+nbd_co_receive_cmdread_reply(BDRVNBDState *s, uint64_t cookie,
+ uint64_t offset, QEMUIOVector *qiov,
+ int *request_ret, Error **errp)
{
NBDReplyChunkIter iter;
NBDReply reply;
void *payload = NULL;
Error *local_err = NULL;
- NBD_FOREACH_REPLY_CHUNK(s, iter, handle, s->info.structured_reply,
+ NBD_FOREACH_REPLY_CHUNK(s, iter, cookie, s->info.structured_reply,
qiov, &reply, &payload)
{
int ret;
@@ -1112,10 +1114,10 @@
return iter.ret;
}
-static int coroutine_fn nbd_co_receive_blockstatus_reply(BDRVNBDState *s,
- uint64_t handle, uint64_t length,
- NBDExtent *extent,
- int *request_ret, Error **errp)
+static int coroutine_fn
+nbd_co_receive_blockstatus_reply(BDRVNBDState *s, uint64_t cookie,
+ uint64_t length, NBDExtent *extent,
+ int *request_ret, Error **errp)
{
NBDReplyChunkIter iter;
NBDReply reply;
@@ -1124,7 +1126,7 @@
bool received = false;
assert(!extent->length);
- NBD_FOREACH_REPLY_CHUNK(s, iter, handle, false, NULL, &reply, &payload) {
+ NBD_FOREACH_REPLY_CHUNK(s, iter, cookie, false, NULL, &reply, &payload) {
int ret;
NBDStructuredReplyChunk *chunk = &reply.structured;
@@ -1194,11 +1196,11 @@
continue;
}
- ret = nbd_co_receive_return_code(s, request->handle,
+ ret = nbd_co_receive_return_code(s, request->cookie,
&request_ret, &local_err);
if (local_err) {
trace_nbd_co_request_fail(request->from, request->len,
- request->handle, request->flags,
+ request->cookie, request->flags,
request->type,
nbd_cmd_lookup(request->type),
ret, error_get_pretty(local_err));
@@ -1253,10 +1255,10 @@
continue;
}
- ret = nbd_co_receive_cmdread_reply(s, request.handle, offset, qiov,
+ ret = nbd_co_receive_cmdread_reply(s, request.cookie, offset, qiov,
&request_ret, &local_err);
if (local_err) {
- trace_nbd_co_request_fail(request.from, request.len, request.handle,
+ trace_nbd_co_request_fail(request.from, request.len, request.cookie,
request.flags, request.type,
nbd_cmd_lookup(request.type),
ret, error_get_pretty(local_err));
@@ -1411,11 +1413,11 @@
continue;
}
- ret = nbd_co_receive_blockstatus_reply(s, request.handle, bytes,
+ ret = nbd_co_receive_blockstatus_reply(s, request.cookie, bytes,
&extent, &request_ret,
&local_err);
if (local_err) {
- trace_nbd_co_request_fail(request.from, request.len, request.handle,
+ trace_nbd_co_request_fail(request.from, request.len, request.cookie,
request.flags, request.type,
nbd_cmd_lookup(request.type),
ret, error_get_pretty(local_err));
diff --git a/bsd-user/mmap.c b/bsd-user/mmap.c
index aca8764..74ed00b 100644
--- a/bsd-user/mmap.c
+++ b/bsd-user/mmap.c
@@ -32,6 +32,7 @@
void mmap_unlock(void)
{
+ assert(mmap_lock_count > 0);
if (--mmap_lock_count == 0) {
pthread_mutex_unlock(&mmap_mutex);
}
diff --git a/crypto/block-luks.c b/crypto/block-luks.c
index 5688783..2f59c3a 100644
--- a/crypto/block-luks.c
+++ b/crypto/block-luks.c
@@ -706,14 +706,14 @@
assert(slot_idx < QCRYPTO_BLOCK_LUKS_NUM_KEY_SLOTS);
slot = &luks->header.key_slots[slot_idx];
+ splitkeylen = luks->header.master_key_len * slot->stripes;
+
if (qcrypto_random_bytes(slot->salt,
QCRYPTO_BLOCK_LUKS_SALT_LEN,
errp) < 0) {
goto cleanup;
}
- splitkeylen = luks->header.master_key_len * slot->stripes;
-
/*
* Determine how many iterations are required to
* hash the user password while consuming 1 second of compute
diff --git a/disas/riscv.c b/disas/riscv.c
index cd7b6e8..3873a69 100644
--- a/disas/riscv.c
+++ b/disas/riscv.c
@@ -1135,8 +1135,8 @@
const rv_opcode_data rvi_opcode_data[] = {
{ "illegal", rv_codec_illegal, rv_fmt_none, NULL, 0, 0, 0 },
- { "lui", rv_codec_u, rv_fmt_rd_imm, NULL, 0, 0, 0 },
- { "auipc", rv_codec_u, rv_fmt_rd_offset, NULL, 0, 0, 0 },
+ { "lui", rv_codec_u, rv_fmt_rd_uimm, NULL, 0, 0, 0 },
+ { "auipc", rv_codec_u, rv_fmt_rd_uoffset, NULL, 0, 0, 0 },
{ "jal", rv_codec_uj, rv_fmt_rd_offset, rvcp_jal, 0, 0, 0 },
{ "jalr", rv_codec_i, rv_fmt_rd_rs1_offset, rvcp_jalr, 0, 0, 0 },
{ "beq", rv_codec_sb, rv_fmt_rs1_rs2_offset, rvcp_beq, 0, 0, 0 },
@@ -1382,7 +1382,7 @@
rv_op_addi },
{ "c.addi16sp", rv_codec_ci_16sp, rv_fmt_rd_rs1_imm, NULL, rv_op_addi,
rv_op_addi, rv_op_addi, rvcd_imm_nz },
- { "c.lui", rv_codec_ci_lui, rv_fmt_rd_imm, NULL, rv_op_lui, rv_op_lui,
+ { "c.lui", rv_codec_ci_lui, rv_fmt_rd_uimm, NULL, rv_op_lui, rv_op_lui,
rv_op_lui, rvcd_imm_nz },
{ "c.srli", rv_codec_cb_sh6, rv_fmt_rd_rs1_imm, NULL, rv_op_srli,
rv_op_srli, rv_op_srli, rvcd_imm_nz },
@@ -4694,6 +4694,19 @@
dec->pc + dec->imm);
append(buf, tmp, buflen);
break;
+ case 'U':
+ fmt++;
+ snprintf(tmp, sizeof(tmp), "%d", dec->imm >> 12);
+ append(buf, tmp, buflen);
+ if (*fmt == 'o') {
+ while (strlen(buf) < tab * 2) {
+ append(buf, " ", buflen);
+ }
+ snprintf(tmp, sizeof(tmp), "# 0x%" PRIx64,
+ dec->pc + dec->imm);
+ append(buf, tmp, buflen);
+ }
+ break;
case 'c': {
const char *name = csr_name(dec->imm & 0xfff);
if (name) {
diff --git a/disas/riscv.h b/disas/riscv.h
index 9cf901f..8abb578 100644
--- a/disas/riscv.h
+++ b/disas/riscv.h
@@ -227,7 +227,9 @@
#define rv_fmt_pred_succ "O\tp,s"
#define rv_fmt_rs1_rs2 "O\t1,2"
#define rv_fmt_rd_imm "O\t0,i"
+#define rv_fmt_rd_uimm "O\t0,Ui"
#define rv_fmt_rd_offset "O\t0,o"
+#define rv_fmt_rd_uoffset "O\t0,Uo"
#define rv_fmt_rd_rs1_rs2 "O\t0,1,2"
#define rv_fmt_frd_rs1 "O\t3,1"
#define rv_fmt_frd_rs1_rs2 "O\t3,1,2"
diff --git a/docs/about/deprecated.rst b/docs/about/deprecated.rst
index 02ea5a8..1c35f55 100644
--- a/docs/about/deprecated.rst
+++ b/docs/about/deprecated.rst
@@ -451,3 +451,13 @@
The ``blacklist`` config file option has been renamed to ``block-rpcs``
(to be in sync with the renaming of the corresponding command line
option).
+
+Migration
+---------
+
+``skipped`` MigrationStats field (since 8.1)
+''''''''''''''''''''''''''''''''''''''''''''
+
+``skipped`` field in Migration stats has been deprecated. It hasn't
+been used for more than 10 years.
+
diff --git a/docs/devel/migration.rst b/docs/devel/migration.rst
index 6f65c23..c3e1400 100644
--- a/docs/devel/migration.rst
+++ b/docs/devel/migration.rst
@@ -594,8 +594,7 @@
'Postcopy' migration is a way to deal with migrations that refuse to converge
(or take too long to converge) its plus side is that there is an upper bound on
the amount of migration traffic and time it takes, the down side is that during
-the postcopy phase, a failure of *either* side or the network connection causes
-the guest to be lost.
+the postcopy phase, a failure of *either* side causes the guest to be lost.
In postcopy the destination CPUs are started before all the memory has been
transferred, and accesses to pages that are yet to be transferred cause
@@ -721,6 +720,42 @@
is no longer used by migration, while the listen thread carries on servicing
page data until the end of migration.
+Postcopy Recovery
+-----------------
+
+Comparing to precopy, postcopy is special on error handlings. When any
+error happens (in this case, mostly network errors), QEMU cannot easily
+fail a migration because VM data resides in both source and destination
+QEMU instances. On the other hand, when issue happens QEMU on both sides
+will go into a paused state. It'll need a recovery phase to continue a
+paused postcopy migration.
+
+The recovery phase normally contains a few steps:
+
+ - When network issue occurs, both QEMU will go into PAUSED state
+
+ - When the network is recovered (or a new network is provided), the admin
+ can setup the new channel for migration using QMP command
+ 'migrate-recover' on destination node, preparing for a resume.
+
+ - On source host, the admin can continue the interrupted postcopy
+ migration using QMP command 'migrate' with resume=true flag set.
+
+ - After the connection is re-established, QEMU will continue the postcopy
+ migration on both sides.
+
+During a paused postcopy migration, the VM can logically still continue
+running, and it will not be impacted from any page access to pages that
+were already migrated to destination VM before the interruption happens.
+However, if any of the missing pages got accessed on destination VM, the VM
+thread will be halted waiting for the page to be migrated, it means it can
+be halted until the recovery is complete.
+
+The impact of accessing missing pages can be relevant to different
+configurations of the guest. For example, when with async page fault
+enabled, logically the guest can proactively schedule out the threads
+accessing missing pages.
+
Postcopy states
---------------
@@ -765,36 +800,31 @@
(although it can't do the cleanup it would do as it
finishes a normal migration).
+ - Paused
+
+ Postcopy can run into a paused state (normally on both sides when
+ happens), where all threads will be temporarily halted mostly due to
+ network errors. When reaching paused state, migration will make sure
+ the qemu binary on both sides maintain the data without corrupting
+ the VM. To continue the migration, the admin needs to fix the
+ migration channel using the QMP command 'migrate-recover' on the
+ destination node, then resume the migration using QMP command 'migrate'
+ again on source node, with resume=true flag set.
+
- End
The listen thread can now quit, and perform the cleanup of migration
state, the migration is now complete.
-Source side page maps
----------------------
+Source side page map
+--------------------
-The source side keeps two bitmaps during postcopy; 'the migration bitmap'
-and 'unsent map'. The 'migration bitmap' is basically the same as in
-the precopy case, and holds a bit to indicate that page is 'dirty' -
-i.e. needs sending. During the precopy phase this is updated as the CPU
-dirties pages, however during postcopy the CPUs are stopped and nothing
-should dirty anything any more.
-
-The 'unsent map' is used for the transition to postcopy. It is a bitmap that
-has a bit cleared whenever a page is sent to the destination, however during
-the transition to postcopy mode it is combined with the migration bitmap
-to form a set of pages that:
-
- a) Have been sent but then redirtied (which must be discarded)
- b) Have not yet been sent - which also must be discarded to cause any
- transparent huge pages built during precopy to be broken.
-
-Note that the contents of the unsentmap are sacrificed during the calculation
-of the discard set and thus aren't valid once in postcopy. The dirtymap
-is still valid and is used to ensure that no page is sent more than once. Any
-request for a page that has already been sent is ignored. Duplicate requests
-such as this can happen as a page is sent at about the same time the
-destination accesses it.
+The 'migration bitmap' in postcopy is basically the same as in the precopy,
+where each of the bit to indicate that page is 'dirty' - i.e. needs
+sending. During the precopy phase this is updated as the CPU dirties
+pages, however during postcopy the CPUs are stopped and nothing should
+dirty anything any more. Instead, dirty bits are cleared when the relevant
+pages are sent during postcopy.
Postcopy with hugepages
-----------------------
@@ -853,6 +883,16 @@
guest memory access is made while holding a lock then all other
threads waiting for that lock will also be blocked.
+Postcopy Preemption Mode
+------------------------
+
+Postcopy preempt is a new capability introduced in 8.0 QEMU release, it
+allows urgent pages (those got page fault requested from destination QEMU
+explicitly) to be sent in a separate preempt channel, rather than queued in
+the background migration channel. Anyone who cares about latencies of page
+faults during a postcopy migration should enable this feature. By default,
+it's not enabled.
+
Firmware
========
diff --git a/docs/devel/testing.rst b/docs/devel/testing.rst
index fb651ea..b6ad21b 100644
--- a/docs/devel/testing.rst
+++ b/docs/devel/testing.rst
@@ -1384,6 +1384,11 @@
def test(self):
do_something()
+QEMU_TEST_FLAKY_TESTS
+^^^^^^^^^^^^^^^^^^^^^
+Some tests are not working reliably and thus are disabled by default.
+Set this environment variable to enable them.
+
Uninstalling Avocado
~~~~~~~~~~~~~~~~~~~~
diff --git a/docs/system/target-riscv.rst b/docs/system/target-riscv.rst
index 89a866e..ba195f1 100644
--- a/docs/system/target-riscv.rst
+++ b/docs/system/target-riscv.rst
@@ -76,11 +76,19 @@
When using the ``sifive_u`` or ``virt`` machine there are three different
firmware boot options:
-1. ``-bios default`` - This is the default behaviour if no -bios option
-is included. This option will load the default OpenSBI firmware automatically.
-The firmware is included with the QEMU release and no user interaction is
-required. All a user needs to do is specify the kernel they want to boot
-with the -kernel option
-2. ``-bios none`` - QEMU will not automatically load any firmware. It is up
-to the user to load all the images they need.
-3. ``-bios <file>`` - Tells QEMU to load the specified file as the firmware.
+
+* ``-bios default``
+
+This is the default behaviour if no ``-bios`` option is included. This option
+will load the default OpenSBI firmware automatically. The firmware is included
+with the QEMU release and no user interaction is required. All a user needs to
+do is specify the kernel they want to boot with the ``-kernel`` option
+
+* ``-bios none``
+
+QEMU will not automatically load any firmware. It is up to the user to load all
+the images they need.
+
+* ``-bios <file>``
+
+Tells QEMU to load the specified file as the firmware.
diff --git a/host/include/aarch64/host/cpuinfo.h b/host/include/aarch64/host/cpuinfo.h
index 05feeb4..769626b 100644
--- a/host/include/aarch64/host/cpuinfo.h
+++ b/host/include/aarch64/host/cpuinfo.h
@@ -1,6 +1,6 @@
/*
* SPDX-License-Identifier: GPL-2.0-or-later
- * Host specific cpu indentification for AArch64.
+ * Host specific cpu identification for AArch64.
*/
#ifndef HOST_CPUINFO_H
diff --git a/host/include/generic/host/cpuinfo.h b/host/include/generic/host/cpuinfo.h
index eca6720..67ad410 100644
--- a/host/include/generic/host/cpuinfo.h
+++ b/host/include/generic/host/cpuinfo.h
@@ -1,4 +1,4 @@
/*
- * No host specific cpu indentification.
+ * No host specific cpu identification.
* SPDX-License-Identifier: GPL-2.0-or-later
*/
diff --git a/hw/9pfs/9p-local.c b/hw/9pfs/9p-local.c
index 9d07620..1b1f3b9 100644
--- a/hw/9pfs/9p-local.c
+++ b/hw/9pfs/9p-local.c
@@ -624,7 +624,7 @@
/*
* Initiate a writeback. This is not a data integrity sync.
* We want to ensure that we don't leave dirty pages in the cache
- * after write when writeout=immediate is sepcified.
+ * after write when writeout=immediate is specified.
*/
sync_file_range(fs->fd, offset, ret,
SYNC_FILE_RANGE_WAIT_BEFORE | SYNC_FILE_RANGE_WRITE);
@@ -843,7 +843,7 @@
}
credp->fc_mode = credp->fc_mode | S_IFREG;
if (fs_ctx->export_flags & V9FS_SM_MAPPED) {
- /* Set cleint credentials in xattr */
+ /* Set client credentials in xattr */
err = local_set_xattrat(dirfd, name, credp);
} else {
err = local_set_mapped_file_attrat(dirfd, name, credp);
@@ -912,7 +912,7 @@
if (write_size != oldpath_size) {
goto err_end;
}
- /* Set cleint credentials in symlink's xattr */
+ /* Set client credentials in symlink's xattr */
credp->fc_mode = credp->fc_mode | S_IFLNK;
if (fs_ctx->export_flags & V9FS_SM_MAPPED) {
@@ -1418,7 +1418,7 @@
struct statfs stbuf;
/*
- * use ioc_getversion only if the ioctl is definied
+ * use ioc_getversion only if the ioctl is defined
*/
if (fstatfs(data->mountfd, &stbuf) < 0) {
error_setg_errno(errp, errno,
diff --git a/hw/9pfs/9p-proxy.c b/hw/9pfs/9p-proxy.c
index 905cae6..7aac49a 100644
--- a/hw/9pfs/9p-proxy.c
+++ b/hw/9pfs/9p-proxy.c
@@ -767,7 +767,7 @@
/*
* Initiate a writeback. This is not a data integrity sync.
* We want to ensure that we don't leave dirty pages in the cache
- * after write when writeout=immediate is sepcified.
+ * after write when writeout=immediate is specified.
*/
sync_file_range(fs->fd, offset, ret,
SYNC_FILE_RANGE_WAIT_BEFORE | SYNC_FILE_RANGE_WRITE);
diff --git a/hw/9pfs/9p-synth.c b/hw/9pfs/9p-synth.c
index f62c40b..0ac79a5 100644
--- a/hw/9pfs/9p-synth.c
+++ b/hw/9pfs/9p-synth.c
@@ -493,7 +493,7 @@
node = dir_node;
goto out;
}
- /* search for the name in the childern */
+ /* search for the name in the children */
rcu_read_lock();
QLIST_FOREACH(node, &dir_node->child, sibling) {
if (!strcmp(node->name, name)) {
diff --git a/hw/9pfs/9p-util.h b/hw/9pfs/9p-util.h
index df1b583..51c94b0 100644
--- a/hw/9pfs/9p-util.h
+++ b/hw/9pfs/9p-util.h
@@ -48,7 +48,7 @@
/*
* Converts given device number from host's device number format to Linux
* device number format. As both the size of type dev_t and encoding of
- * dev_t is system dependant, we have to convert them for Linux guests if
+ * dev_t is system dependent, we have to convert them for Linux guests if
* host is not running Linux.
*/
static inline uint64_t host_dev_to_dotl_dev(dev_t dev)
diff --git a/hw/9pfs/9p.c b/hw/9pfs/9p.c
index 991645a..323f042 100644
--- a/hw/9pfs/9p.c
+++ b/hw/9pfs/9p.c
@@ -644,7 +644,7 @@
}
/*
- * Parameter k for the Exponential Golomb algorihm to be used.
+ * Parameter k for the Exponential Golomb algorithm to be used.
*
* The smaller this value, the smaller the minimum bit count for the Exp.
* Golomb generated affixes will be (at lowest index) however for the
@@ -1039,7 +1039,7 @@
* Sending a reply would confuse clients because they would
* assume that any EINTR is the actual result of the operation,
* rather than a consequence of the cancellation. However, if
- * the operation completed (succesfully or with an error other
+ * the operation completed (successfully or with an error other
* than caused be cancellation), we do send out that reply, both
* for efficiency and to avoid confusing the rest of the state machine
* that assumes passing a non-error here will mean a successful
diff --git a/hw/9pfs/9p.h b/hw/9pfs/9p.h
index 1b0d805..a6f59ab 100644
--- a/hw/9pfs/9p.h
+++ b/hw/9pfs/9p.h
@@ -304,7 +304,7 @@
AffixType_t type; /* Whether this affix is a suffix or a prefix. */
uint64_t value; /* Actual numerical value of this affix. */
/*
- * Lenght of the affix, that is how many (of the lowest) bits of ``value``
+ * Length of the affix, that is how many (of the lowest) bits of ``value``
* must be used for appending/prepending this affix to its final resulting,
* unique number.
*/
diff --git a/hw/arm/aspeed.c b/hw/arm/aspeed.c
index 6880998..263626a 100644
--- a/hw/arm/aspeed.c
+++ b/hw/arm/aspeed.c
@@ -1565,7 +1565,7 @@
{
AspeedSoCState *soc = &bmc->soc;
- /* U10 24C08 connects to SDA/SCL Groupt 1 by default */
+ /* U10 24C08 connects to SDA/SCL Group 1 by default */
uint8_t *eeprom_buf = g_malloc0(32 * 1024);
smbus_eeprom_init_one(aspeed_i2c_get_bus(&soc->i2c, 0), 0x50, eeprom_buf);
diff --git a/hw/arm/mps2-tz.c b/hw/arm/mps2-tz.c
index 07aecd9..5873107 100644
--- a/hw/arm/mps2-tz.c
+++ b/hw/arm/mps2-tz.c
@@ -1205,7 +1205,7 @@
{
/*
* The MPS2 TZ FPGA images have IDAUs in them which are connected to
- * the Master Security Controllers. Thes have the same logic as
+ * the Master Security Controllers. These have the same logic as
* is used by the IoTKit for the IDAU connected to the CPU, except
* that MSCs don't care about the NSC attribute.
*/
diff --git a/hw/arm/sbsa-ref.c b/hw/arm/sbsa-ref.c
index 64e1cbc..bc89eb4 100644
--- a/hw/arm/sbsa-ref.c
+++ b/hw/arm/sbsa-ref.c
@@ -611,6 +611,7 @@
hwaddr base = sbsa_ref_memmap[SBSA_XHCI].base;
int irq = sbsa_ref_irqmap[SBSA_XHCI];
DeviceState *dev = qdev_new(TYPE_XHCI_SYSBUS);
+ qdev_prop_set_uint32(dev, "slots", XHCI_MAXSLOTS);
sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base);
diff --git a/hw/arm/smmu-common.c b/hw/arm/smmu-common.c
index 5ab9d45..f35ae9a 100644
--- a/hw/arm/smmu-common.c
+++ b/hw/arm/smmu-common.c
@@ -216,8 +216,7 @@
dma_addr_t addr = baseaddr + index * sizeof(*pte);
/* TODO: guarantee 64-bit single-copy atomicity */
- ret = dma_memory_read(&address_space_memory, addr, pte, sizeof(*pte),
- MEMTXATTRS_UNSPECIFIED);
+ ret = ldq_le_dma(&address_space_memory, addr, pte, MEMTXATTRS_UNSPECIFIED);
if (ret != MEMTX_OK) {
info->type = SMMU_PTW_ERR_WALK_EABT;
diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c
index 932f009..1e9be8e 100644
--- a/hw/arm/smmuv3.c
+++ b/hw/arm/smmuv3.c
@@ -102,20 +102,34 @@
trace_smmuv3_write_gerrorn(toggled & pending, s->gerrorn);
}
-static inline MemTxResult queue_read(SMMUQueue *q, void *data)
+static inline MemTxResult queue_read(SMMUQueue *q, Cmd *cmd)
{
dma_addr_t addr = Q_CONS_ENTRY(q);
+ MemTxResult ret;
+ int i;
- return dma_memory_read(&address_space_memory, addr, data, q->entry_size,
- MEMTXATTRS_UNSPECIFIED);
+ ret = dma_memory_read(&address_space_memory, addr, cmd, sizeof(Cmd),
+ MEMTXATTRS_UNSPECIFIED);
+ if (ret != MEMTX_OK) {
+ return ret;
+ }
+ for (i = 0; i < ARRAY_SIZE(cmd->word); i++) {
+ le32_to_cpus(&cmd->word[i]);
+ }
+ return ret;
}
-static MemTxResult queue_write(SMMUQueue *q, void *data)
+static MemTxResult queue_write(SMMUQueue *q, Evt *evt_in)
{
dma_addr_t addr = Q_PROD_ENTRY(q);
MemTxResult ret;
+ Evt evt = *evt_in;
+ int i;
- ret = dma_memory_write(&address_space_memory, addr, data, q->entry_size,
+ for (i = 0; i < ARRAY_SIZE(evt.word); i++) {
+ cpu_to_le32s(&evt.word[i]);
+ }
+ ret = dma_memory_write(&address_space_memory, addr, &evt, sizeof(Evt),
MEMTXATTRS_UNSPECIFIED);
if (ret != MEMTX_OK) {
return ret;
@@ -298,7 +312,7 @@
static int smmu_get_ste(SMMUv3State *s, dma_addr_t addr, STE *buf,
SMMUEventInfo *event)
{
- int ret;
+ int ret, i;
trace_smmuv3_get_ste(addr);
/* TODO: guarantee 64-bit single-copy atomicity */
@@ -311,6 +325,9 @@
event->u.f_ste_fetch.addr = addr;
return -EINVAL;
}
+ for (i = 0; i < ARRAY_SIZE(buf->word); i++) {
+ le32_to_cpus(&buf->word[i]);
+ }
return 0;
}
@@ -320,7 +337,7 @@
CD *buf, SMMUEventInfo *event)
{
dma_addr_t addr = STE_CTXPTR(ste);
- int ret;
+ int ret, i;
trace_smmuv3_get_cd(addr);
/* TODO: guarantee 64-bit single-copy atomicity */
@@ -333,6 +350,9 @@
event->u.f_ste_fetch.addr = addr;
return -EINVAL;
}
+ for (i = 0; i < ARRAY_SIZE(buf->word); i++) {
+ le32_to_cpus(&buf->word[i]);
+ }
return 0;
}
@@ -569,7 +589,7 @@
return -EINVAL;
}
if (s->features & SMMU_FEATURE_2LVL_STE) {
- int l1_ste_offset, l2_ste_offset, max_l2_ste, span;
+ int l1_ste_offset, l2_ste_offset, max_l2_ste, span, i;
dma_addr_t l1ptr, l2ptr;
STEDesc l1std;
@@ -593,6 +613,9 @@
event->u.f_ste_fetch.addr = l1ptr;
return -EINVAL;
}
+ for (i = 0; i < ARRAY_SIZE(l1std.word); i++) {
+ le32_to_cpus(&l1std.word[i]);
+ }
span = L1STD_SPAN(&l1std);
diff --git a/hw/char/escc.c b/hw/char/escc.c
index 4f3872b..4be6605 100644
--- a/hw/char/escc.c
+++ b/hw/char/escc.c
@@ -653,7 +653,9 @@
escc_update_irq(s);
s->tx = val;
if (s->wregs[W_TXCTRL2] & TXCTRL2_TXEN) { /* tx enabled */
- if (qemu_chr_fe_backend_connected(&s->chr)) {
+ if (s->wregs[W_MISC2] & MISC2_LCL_LOOP) {
+ serial_receive_byte(s, s->tx);
+ } else if (qemu_chr_fe_backend_connected(&s->chr)) {
/*
* XXX this blocks entire thread. Rewrite to use
* qemu_chr_fe_write and background I/O callbacks
diff --git a/hw/display/virtio-gpu-udmabuf.c b/hw/display/virtio-gpu-udmabuf.c
index ef1a740..d51184d 100644
--- a/hw/display/virtio-gpu-udmabuf.c
+++ b/hw/display/virtio-gpu-udmabuf.c
@@ -181,13 +181,13 @@
}
dmabuf = g_new0(VGPUDMABuf, 1);
- dmabuf->buf.width = fb->width;
- dmabuf->buf.height = fb->height;
+ dmabuf->buf.width = r->width;
+ dmabuf->buf.height = r->height;
dmabuf->buf.stride = fb->stride;
dmabuf->buf.x = r->x;
dmabuf->buf.y = r->y;
- dmabuf->buf.scanout_width = r->width;
- dmabuf->buf.scanout_height = r->height;
+ dmabuf->buf.backing_width = fb->width;
+ dmabuf->buf.backing_height = fb->height;
dmabuf->buf.fourcc = qemu_pixman_to_drm_format(fb->format);
dmabuf->buf.fd = res->dmabuf_fd;
dmabuf->buf.allow_fences = true;
@@ -218,8 +218,8 @@
g->dmabuf.primary[scanout_id] = new_primary;
qemu_console_resize(scanout->con,
- new_primary->buf.scanout_width,
- new_primary->buf.scanout_height);
+ new_primary->buf.width,
+ new_primary->buf.height);
dpy_gl_scanout_dmabuf(scanout->con, &new_primary->buf);
if (old_primary) {
diff --git a/hw/display/virtio-gpu.c b/hw/display/virtio-gpu.c
index befa7d6..e8603d7 100644
--- a/hw/display/virtio-gpu.c
+++ b/hw/display/virtio-gpu.c
@@ -303,10 +303,11 @@
goto end;
}
#endif
- res->image = pixman_image_create_bits(pformat,
- c2d.width,
- c2d.height,
- bits, res->hostmem / c2d.height);
+ res->image = pixman_image_create_bits(
+ pformat,
+ c2d.width,
+ c2d.height,
+ bits, c2d.height ? res->hostmem / c2d.height : 0);
#ifdef WIN32
if (res->image) {
pixman_image_set_destroy_function(res->image, win32_pixman_image_destroy, res->handle);
@@ -1272,9 +1273,10 @@
return -EINVAL;
}
#endif
- res->image = pixman_image_create_bits(pformat,
- res->width, res->height,
- bits, res->hostmem / res->height);
+ res->image = pixman_image_create_bits(
+ pformat,
+ res->width, res->height,
+ bits, res->height ? res->hostmem / res->height : 0);
if (!res->image) {
g_free(res);
return -EINVAL;
@@ -1395,6 +1397,7 @@
VirtIOGPU *g = VIRTIO_GPU(vdev);
struct virtio_gpu_simple_resource *res, *tmp;
struct virtio_gpu_ctrl_command *cmd;
+ int i = 0;
QTAILQ_FOREACH_SAFE(res, &g->reslist, next, tmp) {
virtio_gpu_resource_destroy(g, res);
@@ -1413,6 +1416,10 @@
g_free(cmd);
}
+ for (i = 0; i < g->parent_obj.conf.max_outputs; i++) {
+ dpy_gfx_replace_surface(g->parent_obj.scanout[i].con, NULL);
+ }
+
virtio_gpu_base_reset(VIRTIO_GPU_BASE(vdev));
}
diff --git a/hw/intc/Kconfig b/hw/intc/Kconfig
index 21441d0..97d550b 100644
--- a/hw/intc/Kconfig
+++ b/hw/intc/Kconfig
@@ -49,7 +49,6 @@
config S390_FLIC_KVM
bool
- default y
depends on S390_FLIC && KVM
config OMPIC
diff --git a/hw/intc/arm_gic.c b/hw/intc/arm_gic.c
index 7a34bc0..074cf50 100644
--- a/hw/intc/arm_gic.c
+++ b/hw/intc/arm_gic.c
@@ -239,7 +239,7 @@
}
/* Return true if this LR should trigger an EOI maintenance interrupt, i.e. the
- * corrsponding bit in EISR is set.
+ * corresponding bit in EISR is set.
*/
static inline bool gic_lr_entry_is_eoi(uint32_t entry)
{
@@ -1333,7 +1333,7 @@
/* ??? This currently clears the pending bit for all CPUs, even
for per-CPU interrupts. It's unclear whether this is the
- corect behavior. */
+ correct behavior. */
if (value & (1 << i)) {
GIC_DIST_CLEAR_PENDING(irq + i, ALL_CPU_MASK);
}
diff --git a/hw/intc/arm_gicv3_redist.c b/hw/intc/arm_gicv3_redist.c
index 297f7f0..8153525 100644
--- a/hw/intc/arm_gicv3_redist.c
+++ b/hw/intc/arm_gicv3_redist.c
@@ -494,7 +494,7 @@
/* Only the ProcessorSleep bit is writable. When the guest sets
* it, it requests that we transition the channel between the
* redistributor and the cpu interface to quiescent, and that
- * we set the ChildrenAsleep bit once the inteface has reached the
+ * we set the ChildrenAsleep bit once the interface has reached the
* quiescent state.
* Setting the ProcessorSleep to 0 reverses the quiescing, and
* ChildrenAsleep is cleared once the transition is complete.
diff --git a/hw/intc/armv7m_nvic.c b/hw/intc/armv7m_nvic.c
index 63afe1f..03b6b8c 100644
--- a/hw/intc/armv7m_nvic.c
+++ b/hw/intc/armv7m_nvic.c
@@ -894,7 +894,7 @@
vec->active = 0;
if (vec->level) {
/* Re-pend the exception if it's still held high; only
- * happens for extenal IRQs
+ * happens for external IRQs
*/
assert(irq >= NVIC_FIRST_IRQ);
vec->pending = 1;
diff --git a/hw/intc/s390_flic_kvm.c b/hw/intc/s390_flic_kvm.c
index 4e86d2d..28364b2 100644
--- a/hw/intc/s390_flic_kvm.c
+++ b/hw/intc/s390_flic_kvm.c
@@ -380,7 +380,7 @@
* @size: ignored
*
* Note: Pass buf and len to kernel. Start with one page and
- * increase until buffer is sufficient or maxium size is
+ * increase until buffer is sufficient or maximum size is
* reached
*/
static int kvm_flic_save(QEMUFile *f, void *opaque, size_t size,
diff --git a/hw/m68k/next-cube.c b/hw/m68k/next-cube.c
index ce8ee50..5d244b3 100644
--- a/hw/m68k/next-cube.c
+++ b/hw/m68k/next-cube.c
@@ -734,7 +734,7 @@
M68kCPU *cpu = s->cpu;
int shift = 0;
- /* first switch sets interupt status */
+ /* first switch sets interrupt status */
/* DPRINTF("IRQ %i\n",number); */
switch (number) {
/* level 3 - floppy, kbd/mouse, power, ether rx/tx, scsi, clock */
diff --git a/hw/m68k/next-kbd.c b/hw/m68k/next-kbd.c
index 0544160..0c348c1 100644
--- a/hw/m68k/next-kbd.c
+++ b/hw/m68k/next-kbd.c
@@ -37,7 +37,7 @@
OBJECT_DECLARE_SIMPLE_TYPE(NextKBDState, NEXTKBD)
-/* following defintions from next68k netbsd */
+/* following definitions from next68k netbsd */
#define CSR_INT 0x00800000
#define CSR_DATA 0x00400000
diff --git a/hw/m68k/virt.c b/hw/m68k/virt.c
index 731205b..de91726 100644
--- a/hw/m68k/virt.c
+++ b/hw/m68k/virt.c
@@ -1,7 +1,7 @@
/*
* SPDX-License-Identifier: GPL-2.0-or-later
*
- * QEMU Vitual M68K Machine
+ * QEMU Virtual M68K Machine
*
* (c) 2020 Laurent Vivier <laurent@vivier.eu>
*
diff --git a/hw/microblaze/petalogix_ml605_mmu.c b/hw/microblaze/petalogix_ml605_mmu.c
index a24fadd..babb053 100644
--- a/hw/microblaze/petalogix_ml605_mmu.c
+++ b/hw/microblaze/petalogix_ml605_mmu.c
@@ -104,7 +104,7 @@
dinfo = drive_get(IF_PFLASH, 0, 0);
/* 5th parameter 2 means bank-width
- * 10th paremeter 0 means little-endian */
+ * 10th parameter 0 means little-endian */
pflash_cfi01_register(FLASH_BASEADDR, "petalogix_ml605.flash", FLASH_SIZE,
dinfo ? blk_by_legacy_dinfo(dinfo) : NULL,
64 * KiB, 2, 0x89, 0x18, 0x0000, 0x0, 0);
diff --git a/hw/mips/loongson3_virt.c b/hw/mips/loongson3_virt.c
index 4018b8c..3ad0a22 100644
--- a/hw/mips/loongson3_virt.c
+++ b/hw/mips/loongson3_virt.c
@@ -447,7 +447,7 @@
pci_vga_init(pci_bus);
- if (defaults_enabled()) {
+ if (defaults_enabled() && object_class_by_name("pci-ohci")) {
pci_create_simple(pci_bus, -1, "pci-ohci");
usb_create_simple(usb_bus_find(-1), "usb-kbd");
usb_create_simple(usb_bus_find(-1), "usb-tablet");
diff --git a/hw/misc/allwinner-r40-dramc.c b/hw/misc/allwinner-r40-dramc.c
index ea61247..6944f84 100644
--- a/hw/misc/allwinner-r40-dramc.c
+++ b/hw/misc/allwinner-r40-dramc.c
@@ -368,7 +368,7 @@
/*
* mctl_r40_detect_rank_count in u-boot will write the high 1G of DDR
- * to detect wether the board support dual_rank or not. Create a virtual memory
+ * to detect whether the board support dual_rank or not. Create a virtual memory
* if the board's ram_size less or equal than 1G, and set read time out flag of
* REG_DRAMCTL_PGSR when the user touch this high dram.
*/
diff --git a/hw/misc/exynos4210_rng.c b/hw/misc/exynos4210_rng.c
index 1b9e834..9214ec1 100644
--- a/hw/misc/exynos4210_rng.c
+++ b/hw/misc/exynos4210_rng.c
@@ -1,5 +1,5 @@
/*
- * Exynos4210 Pseudo Random Nubmer Generator Emulation
+ * Exynos4210 Pseudo Random Number Generator Emulation
*
* Copyright (c) 2017 Krzysztof Kozlowski <krzk@kernel.org>
*
diff --git a/hw/nvme/ctrl.c b/hw/nvme/ctrl.c
index 8e8e870..dadc2dc 100644
--- a/hw/nvme/ctrl.c
+++ b/hw/nvme/ctrl.c
@@ -6801,6 +6801,7 @@
PCIDevice *pci = PCI_DEVICE(n);
uint64_t dbs_addr = le64_to_cpu(req->cmd.dptr.prp1);
uint64_t eis_addr = le64_to_cpu(req->cmd.dptr.prp2);
+ uint32_t v;
int i;
/* Address should be page aligned */
@@ -6818,6 +6819,8 @@
NvmeCQueue *cq = n->cq[i];
if (sq) {
+ v = cpu_to_le32(sq->tail);
+
/*
* CAP.DSTRD is 0, so offset of ith sq db_addr is (i<<3)
* nvme_process_db() uses this hard-coded way to calculate
@@ -6825,7 +6828,7 @@
*/
sq->db_addr = dbs_addr + (i << 3);
sq->ei_addr = eis_addr + (i << 3);
- pci_dma_write(pci, sq->db_addr, &sq->tail, sizeof(sq->tail));
+ pci_dma_write(pci, sq->db_addr, &v, sizeof(sq->tail));
if (n->params.ioeventfd && sq->sqid != 0) {
if (!nvme_init_sq_ioeventfd(sq)) {
@@ -6835,10 +6838,12 @@
}
if (cq) {
+ v = cpu_to_le32(cq->head);
+
/* CAP.DSTRD is 0, so offset of ith cq db_addr is (i<<3)+(1<<2) */
cq->db_addr = dbs_addr + (i << 3) + (1 << 2);
cq->ei_addr = eis_addr + (i << 3) + (1 << 2);
- pci_dma_write(pci, cq->db_addr, &cq->head, sizeof(cq->head));
+ pci_dma_write(pci, cq->db_addr, &v, sizeof(cq->head));
if (n->params.ioeventfd && cq->cqid != 0) {
if (!nvme_init_cq_ioeventfd(cq)) {
@@ -7587,7 +7592,7 @@
static void nvme_process_db(NvmeCtrl *n, hwaddr addr, int val)
{
PCIDevice *pci = PCI_DEVICE(n);
- uint32_t qid;
+ uint32_t qid, v;
if (unlikely(addr & ((1 << 2) - 1))) {
NVME_GUEST_ERR(pci_nvme_ub_db_wr_misaligned,
@@ -7654,7 +7659,8 @@
start_sqs = nvme_cq_full(cq) ? 1 : 0;
cq->head = new_head;
if (!qid && n->dbbuf_enabled) {
- pci_dma_write(pci, cq->db_addr, &cq->head, sizeof(cq->head));
+ v = cpu_to_le32(cq->head);
+ pci_dma_write(pci, cq->db_addr, &v, sizeof(cq->head));
}
if (start_sqs) {
NvmeSQueue *sq;
@@ -7714,6 +7720,8 @@
sq->tail = new_tail;
if (!qid && n->dbbuf_enabled) {
+ v = cpu_to_le32(sq->tail);
+
/*
* The spec states "the host shall also update the controller's
* corresponding doorbell property to match the value of that entry
@@ -7727,7 +7735,7 @@
* including ones that run on Linux, are not updating Admin Queues,
* so we can't trust reading it for an appropriate sq tail.
*/
- pci_dma_write(pci, sq->db_addr, &sq->tail, sizeof(sq->tail));
+ pci_dma_write(pci, sq->db_addr, &v, sizeof(sq->tail));
}
qemu_bh_schedule(sq->bh);
diff --git a/hw/nvram/xlnx-efuse.c b/hw/nvram/xlnx-efuse.c
index fdfffaa..655c40b 100644
--- a/hw/nvram/xlnx-efuse.c
+++ b/hw/nvram/xlnx-efuse.c
@@ -143,6 +143,8 @@
bool xlnx_efuse_set_bit(XlnxEFuse *s, unsigned int bit)
{
+ uint32_t set, *row;
+
if (efuse_ro_bits_find(s, bit)) {
g_autofree char *path = object_get_canonical_path(OBJECT(s));
@@ -152,8 +154,13 @@
return false;
}
- s->fuse32[bit / 32] |= 1 << (bit % 32);
- efuse_bdrv_sync(s, bit);
+ /* Avoid back-end write unless there is a real update */
+ row = &s->fuse32[bit / 32];
+ set = 1 << (bit % 32);
+ if (!(set & *row)) {
+ *row |= set;
+ efuse_bdrv_sync(s, bit);
+ }
return true;
}
diff --git a/hw/pci/pci.c b/hw/pci/pci.c
index 784c02a..b8d22e2 100644
--- a/hw/pci/pci.c
+++ b/hw/pci/pci.c
@@ -1183,9 +1183,14 @@
PCI_SLOT(devfn), PCI_FUNC(devfn), name,
bus->devices[devfn]->name, bus->devices[devfn]->qdev.id);
return NULL;
- } else if (dev->hotplugged &&
- !pci_is_vf(pci_dev) &&
- pci_get_function_0(pci_dev)) {
+ } /*
+ * Populating function 0 triggers a scan from the guest that
+ * exposes other non-zero functions. Hence we need to ensure that
+ * function 0 wasn't added yet.
+ */
+ else if (dev->hotplugged &&
+ !pci_is_vf(pci_dev) &&
+ pci_get_function_0(pci_dev)) {
error_setg(errp, "PCI: slot %d function 0 already occupied by %s,"
" new func %s cannot be exposed to guest.",
PCI_SLOT(pci_get_function_0(pci_dev)->devfn),
diff --git a/hw/riscv/numa.c b/hw/riscv/numa.c
index e0414d5..d319aef 100644
--- a/hw/riscv/numa.c
+++ b/hw/riscv/numa.c
@@ -209,8 +209,8 @@
if (ms->numa_state->num_nodes > ms->smp.cpus) {
error_report("Number of NUMA nodes (%d)"
- " cannot exceed the number of available CPUs (%d).",
- ms->numa_state->num_nodes, ms->smp.max_cpus);
+ " cannot exceed the number of available CPUs (%u).",
+ ms->numa_state->num_nodes, ms->smp.cpus);
exit(EXIT_FAILURE);
}
if (ms->numa_state->num_nodes) {
diff --git a/hw/s390x/Kconfig b/hw/s390x/Kconfig
index e8d4d68..4c068d7 100644
--- a/hw/s390x/Kconfig
+++ b/hw/s390x/Kconfig
@@ -8,6 +8,7 @@
imply PCIE_DEVICES
select PCI_EXPRESS
select S390_FLIC
+ select S390_FLIC_KVM if KVM
select SCLPCONSOLE
select VIRTIO_CCW
select MSI_NONBROKEN
diff --git a/hw/sd/sdhci.c b/hw/sd/sdhci.c
index 6811f0f..362c2c8 100644
--- a/hw/sd/sdhci.c
+++ b/hw/sd/sdhci.c
@@ -1382,6 +1382,8 @@
s->insert_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, sdhci_raise_insertion_irq, s);
s->transfer_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, sdhci_data_transfer, s);
+
+ s->io_ops = &sdhci_mmio_le_ops;
}
void sdhci_uninitfn(SDHCIState *s)
@@ -1399,9 +1401,13 @@
switch (s->endianness) {
case DEVICE_LITTLE_ENDIAN:
- s->io_ops = &sdhci_mmio_le_ops;
+ /* s->io_ops is little endian by default */
break;
case DEVICE_BIG_ENDIAN:
+ if (s->io_ops != &sdhci_mmio_le_ops) {
+ error_setg(errp, "SD controller doesn't support big endianness");
+ return;
+ }
s->io_ops = &sdhci_mmio_be_ops;
break;
default:
diff --git a/hw/sparc/sun4m_iommu.c b/hw/sparc/sun4m_iommu.c
index 71f5465..eb40f93 100644
--- a/hw/sparc/sun4m_iommu.c
+++ b/hw/sparc/sun4m_iommu.c
@@ -96,10 +96,10 @@
#define IOMMU_AER_SBW 0x80000000 /* S-to-M asynchronous writes */
#define IOMMU_AER_MASK 0x801f000f
-#define IOMMU_SBCFG0 (0x1010 >> 2) /* SBUS configration per-slot */
-#define IOMMU_SBCFG1 (0x1014 >> 2) /* SBUS configration per-slot */
-#define IOMMU_SBCFG2 (0x1018 >> 2) /* SBUS configration per-slot */
-#define IOMMU_SBCFG3 (0x101c >> 2) /* SBUS configration per-slot */
+#define IOMMU_SBCFG0 (0x1010 >> 2) /* SBUS configuration per-slot */
+#define IOMMU_SBCFG1 (0x1014 >> 2) /* SBUS configuration per-slot */
+#define IOMMU_SBCFG2 (0x1018 >> 2) /* SBUS configuration per-slot */
+#define IOMMU_SBCFG3 (0x101c >> 2) /* SBUS configuration per-slot */
#define IOMMU_SBCFG_SAB30 0x00010000 /* Phys-address bit 30 when
bypass enabled */
#define IOMMU_SBCFG_BA16 0x00000004 /* Slave supports 16 byte bursts */
diff --git a/hw/usb/canokey.c b/hw/usb/canokey.c
index bbc5da0..b306eeb 100644
--- a/hw/usb/canokey.c
+++ b/hw/usb/canokey.c
@@ -4,7 +4,7 @@
* Copyright (c) 2021-2022 Canokeys.org <contact@canokeys.org>
* Written by Hongren (Zenithal) Zheng <i@zenithal.me>
*
- * This code is licensed under the Apache-2.0.
+ * This code is licensed under the GPL v2 or later.
*/
#include "qemu/osdep.h"
diff --git a/hw/usb/canokey.h b/hw/usb/canokey.h
index 24cf304..e528889 100644
--- a/hw/usb/canokey.h
+++ b/hw/usb/canokey.h
@@ -4,7 +4,7 @@
* Copyright (c) 2021-2022 Canokeys.org <contact@canokeys.org>
* Written by Hongren (Zenithal) Zheng <i@zenithal.me>
*
- * This code is licensed under the Apache-2.0.
+ * This code is licensed under the GPL v2 or later.
*/
#ifndef CANOKEY_H
diff --git a/include/block/nbd.h b/include/block/nbd.h
index a4c9816..4428bcf 100644
--- a/include/block/nbd.h
+++ b/include/block/nbd.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2016-2022 Red Hat, Inc.
+ * Copyright Red Hat
* Copyright (C) 2005 Anthony Liguori <anthony@codemonkey.ws>
*
* Network Block Device
@@ -26,24 +26,26 @@
#include "qapi/error.h"
#include "qemu/bswap.h"
+typedef struct NBDExport NBDExport;
+typedef struct NBDClient NBDClient;
+typedef struct NBDClientConnection NBDClientConnection;
+
extern const BlockExportDriver blk_exp_nbd;
/* Handshake phase structs - this struct is passed on the wire */
-struct NBDOption {
+typedef struct NBDOption {
uint64_t magic; /* NBD_OPTS_MAGIC */
uint32_t option; /* NBD_OPT_* */
uint32_t length;
-} QEMU_PACKED;
-typedef struct NBDOption NBDOption;
+} QEMU_PACKED NBDOption;
-struct NBDOptionReply {
+typedef struct NBDOptionReply {
uint64_t magic; /* NBD_REP_MAGIC */
uint32_t option; /* NBD_OPT_* */
uint32_t type; /* NBD_REP_* */
uint32_t length;
-} QEMU_PACKED;
-typedef struct NBDOptionReply NBDOptionReply;
+} QEMU_PACKED NBDOptionReply;
typedef struct NBDOptionReplyMetaContext {
NBDOptionReply h; /* h.type = NBD_REP_META_CONTEXT, h.length > 4 */
@@ -51,24 +53,33 @@
/* metadata context name follows */
} QEMU_PACKED NBDOptionReplyMetaContext;
+/* Track results of negotiation */
+typedef enum NBDMode {
+ /* Keep this list in a continuum of increasing features. */
+ NBD_MODE_OLDSTYLE, /* server lacks newstyle negotiation */
+ NBD_MODE_EXPORT_NAME, /* newstyle but only OPT_EXPORT_NAME safe */
+ NBD_MODE_SIMPLE, /* newstyle but only simple replies */
+ NBD_MODE_STRUCTURED, /* newstyle, structured replies enabled */
+ /* TODO add NBD_MODE_EXTENDED */
+} NBDMode;
+
/* Transmission phase structs
*
* Note: these are _NOT_ the same as the network representation of an NBD
* request and reply!
*/
-struct NBDRequest {
- uint64_t handle;
+typedef struct NBDRequest {
+ uint64_t cookie;
uint64_t from;
uint32_t len;
uint16_t flags; /* NBD_CMD_FLAG_* */
uint16_t type; /* NBD_CMD_* */
-};
-typedef struct NBDRequest NBDRequest;
+} NBDRequest;
typedef struct NBDSimpleReply {
uint32_t magic; /* NBD_SIMPLE_REPLY_MAGIC */
uint32_t error;
- uint64_t handle;
+ uint64_t cookie;
} QEMU_PACKED NBDSimpleReply;
/* Header of all structured replies */
@@ -76,7 +87,7 @@
uint32_t magic; /* NBD_STRUCTURED_REPLY_MAGIC */
uint16_t flags; /* combination of NBD_REPLY_FLAG_* */
uint16_t type; /* NBD_REPLY_TYPE_* */
- uint64_t handle; /* request handle */
+ uint64_t cookie; /* request handle */
uint32_t length; /* length of payload */
} QEMU_PACKED NBDStructuredReplyChunk;
@@ -84,40 +95,41 @@
NBDSimpleReply simple;
NBDStructuredReplyChunk structured;
struct {
- /* @magic and @handle fields have the same offset and size both in
+ /*
+ * @magic and @cookie fields have the same offset and size both in
* simple reply and structured reply chunk, so let them be accessible
* without ".simple." or ".structured." specification
*/
uint32_t magic;
uint32_t _skip;
- uint64_t handle;
+ uint64_t cookie;
} QEMU_PACKED;
} NBDReply;
/* Header of chunk for NBD_REPLY_TYPE_OFFSET_DATA */
typedef struct NBDStructuredReadData {
- NBDStructuredReplyChunk h; /* h.length >= 9 */
+ /* header's .length >= 9 */
uint64_t offset;
/* At least one byte of data payload follows, calculated from h.length */
} QEMU_PACKED NBDStructuredReadData;
/* Complete chunk for NBD_REPLY_TYPE_OFFSET_HOLE */
typedef struct NBDStructuredReadHole {
- NBDStructuredReplyChunk h; /* h.length == 12 */
+ /* header's length == 12 */
uint64_t offset;
uint32_t length;
} QEMU_PACKED NBDStructuredReadHole;
/* Header of all NBD_REPLY_TYPE_ERROR* errors */
typedef struct NBDStructuredError {
- NBDStructuredReplyChunk h; /* h.length >= 6 */
+ /* header's length >= 6 */
uint32_t error;
uint16_t message_length;
} QEMU_PACKED NBDStructuredError;
/* Header of NBD_REPLY_TYPE_BLOCK_STATUS */
typedef struct NBDStructuredMeta {
- NBDStructuredReplyChunk h; /* h.length >= 12 (at least one extent) */
+ /* header's length >= 12 (at least one extent) */
uint32_t context_id;
/* extents follows */
} QEMU_PACKED NBDStructuredMeta;
@@ -282,7 +294,7 @@
#define NBD_ESHUTDOWN 108
/* Details collected by NBD_OPT_EXPORT_NAME and NBD_OPT_GO */
-struct NBDExportInfo {
+typedef struct NBDExportInfo {
/* Set by client before nbd_receive_negotiate() */
bool request_sizes;
char *x_dirty_bitmap;
@@ -310,8 +322,7 @@
char *description;
int n_contexts;
char **contexts;
-};
-typedef struct NBDExportInfo NBDExportInfo;
+} NBDExportInfo;
int nbd_receive_negotiate(AioContext *aio_context, QIOChannel *ioc,
QCryptoTLSCreds *tlscreds,
@@ -330,9 +341,6 @@
int nbd_disconnect(int fd);
int nbd_errno_to_system_errno(int err);
-typedef struct NBDExport NBDExport;
-typedef struct NBDClient NBDClient;
-
void nbd_export_set_on_eject_blk(BlockExport *exp, BlockBackend *blk);
AioContext *nbd_export_aio_context(NBDExport *exp);
@@ -407,10 +415,9 @@
const char *nbd_info_lookup(uint16_t info);
const char *nbd_cmd_lookup(uint16_t info);
const char *nbd_err_lookup(int err);
+const char *nbd_mode_lookup(NBDMode mode);
/* nbd/client-connection.c */
-typedef struct NBDClientConnection NBDClientConnection;
-
void nbd_client_connection_enable_retry(NBDClientConnection *conn);
NBDClientConnection *nbd_client_connection_new(const SocketAddress *saddr,
diff --git a/include/elf.h b/include/elf.h
index 2f4d0e5..ec9755e 100644
--- a/include/elf.h
+++ b/include/elf.h
@@ -596,25 +596,53 @@
/* Bits present in AT_HWCAP for s390. */
-#define HWCAP_S390_ESAN3 1
-#define HWCAP_S390_ZARCH 2
-#define HWCAP_S390_STFLE 4
-#define HWCAP_S390_MSA 8
-#define HWCAP_S390_LDISP 16
-#define HWCAP_S390_EIMM 32
-#define HWCAP_S390_DFP 64
-#define HWCAP_S390_HPAGE 128
-#define HWCAP_S390_ETF3EH 256
-#define HWCAP_S390_HIGH_GPRS 512
-#define HWCAP_S390_TE 1024
-#define HWCAP_S390_VXRS 2048
-#define HWCAP_S390_VXRS_BCD 4096
-#define HWCAP_S390_VXRS_EXT 8192
-#define HWCAP_S390_GS 16384
-#define HWCAP_S390_VXRS_EXT2 32768
-#define HWCAP_S390_VXRS_PDE 65536
-#define HWCAP_S390_SORT 131072
-#define HWCAP_S390_DFLT 262144
+#define HWCAP_S390_NR_ESAN3 0
+#define HWCAP_S390_NR_ZARCH 1
+#define HWCAP_S390_NR_STFLE 2
+#define HWCAP_S390_NR_MSA 3
+#define HWCAP_S390_NR_LDISP 4
+#define HWCAP_S390_NR_EIMM 5
+#define HWCAP_S390_NR_DFP 6
+#define HWCAP_S390_NR_HPAGE 7
+#define HWCAP_S390_NR_ETF3EH 8
+#define HWCAP_S390_NR_HIGH_GPRS 9
+#define HWCAP_S390_NR_TE 10
+#define HWCAP_S390_NR_VXRS 11
+#define HWCAP_S390_NR_VXRS_BCD 12
+#define HWCAP_S390_NR_VXRS_EXT 13
+#define HWCAP_S390_NR_GS 14
+#define HWCAP_S390_NR_VXRS_EXT2 15
+#define HWCAP_S390_NR_VXRS_PDE 16
+#define HWCAP_S390_NR_SORT 17
+#define HWCAP_S390_NR_DFLT 18
+#define HWCAP_S390_NR_VXRS_PDE2 19
+#define HWCAP_S390_NR_NNPA 20
+#define HWCAP_S390_NR_PCI_MIO 21
+#define HWCAP_S390_NR_SIE 22
+
+#define HWCAP_S390_ESAN3 (1 << HWCAP_S390_NR_ESAN3)
+#define HWCAP_S390_ZARCH (1 << HWCAP_S390_NR_ZARCH)
+#define HWCAP_S390_STFLE (1 << HWCAP_S390_NR_STFLE)
+#define HWCAP_S390_MSA (1 << HWCAP_S390_NR_MSA)
+#define HWCAP_S390_LDISP (1 << HWCAP_S390_NR_LDISP)
+#define HWCAP_S390_EIMM (1 << HWCAP_S390_NR_EIMM)
+#define HWCAP_S390_DFP (1 << HWCAP_S390_NR_DFP)
+#define HWCAP_S390_HPAGE (1 << HWCAP_S390_NR_HPAGE)
+#define HWCAP_S390_ETF3EH (1 << HWCAP_S390_NR_ETF3EH)
+#define HWCAP_S390_HIGH_GPRS (1 << HWCAP_S390_NR_HIGH_GPRS)
+#define HWCAP_S390_TE (1 << HWCAP_S390_NR_TE)
+#define HWCAP_S390_VXRS (1 << HWCAP_S390_NR_VXRS)
+#define HWCAP_S390_VXRS_BCD (1 << HWCAP_S390_NR_VXRS_BCD)
+#define HWCAP_S390_VXRS_EXT (1 << HWCAP_S390_NR_VXRS_EXT)
+#define HWCAP_S390_GS (1 << HWCAP_S390_NR_GS)
+#define HWCAP_S390_VXRS_EXT2 (1 << HWCAP_S390_NR_VXRS_EXT2)
+#define HWCAP_S390_VXRS_PDE (1 << HWCAP_S390_NR_VXRS_PDE)
+#define HWCAP_S390_SORT (1 << HWCAP_S390_NR_SORT)
+#define HWCAP_S390_DFLT (1 << HWCAP_S390_NR_DFLT)
+#define HWCAP_S390_VXRS_PDE2 (1 << HWCAP_S390_NR_VXRS_PDE2)
+#define HWCAP_S390_NNPA (1 << HWCAP_S390_NR_NNPA)
+#define HWCAP_S390_PCI_MIO (1 << HWCAP_S390_NR_PCI_MIO)
+#define HWCAP_S390_SIE (1 << HWCAP_S390_NR_SIE)
/* M68K specific definitions. */
/* We use the top 24 bits to encode information about the
diff --git a/include/exec/exec-all.h b/include/exec/exec-all.h
index 5fa0687..d02517e 100644
--- a/include/exec/exec-all.h
+++ b/include/exec/exec-all.h
@@ -629,6 +629,15 @@
void TSA_NO_TSA mmap_unlock(void);
bool have_mmap_lock(void);
+static inline void mmap_unlock_guard(void *unused)
+{
+ mmap_unlock();
+}
+
+#define WITH_MMAP_LOCK_GUARD() \
+ for (int _mmap_lock_iter __attribute__((cleanup(mmap_unlock_guard))) \
+ = (mmap_lock(), 0); _mmap_lock_iter == 0; _mmap_lock_iter = 1)
+
/**
* adjust_signal_pc:
* @pc: raw pc from the host signal ucontext_t.
@@ -683,6 +692,7 @@
#else
static inline void mmap_lock(void) {}
static inline void mmap_unlock(void) {}
+#define WITH_MMAP_LOCK_GUARD()
void tlb_reset_dirty(CPUState *cpu, ram_addr_t start1, ram_addr_t length);
void tlb_set_dirty(CPUState *cpu, vaddr addr);
diff --git a/include/hw/arm/fsl-imx7.h b/include/hw/arm/fsl-imx7.h
index 54ea2f0..fcce642 100644
--- a/include/hw/arm/fsl-imx7.h
+++ b/include/hw/arm/fsl-imx7.h
@@ -165,7 +165,7 @@
* Some versions of the reference manual claim that UART2 is @
* 0x30870000, but experiments with HW + DT files in upstream
* Linux kernel show that not to be true and that block is
- * acutally located @ 0x30890000
+ * actually located @ 0x30890000
*/
FSL_IMX7_UART2_ADDR = 0x30890000,
FSL_IMX7_UART3_ADDR = 0x30880000,
diff --git a/include/hw/intc/armv7m_nvic.h b/include/hw/intc/armv7m_nvic.h
index 1ca262f..6b4ae56 100644
--- a/include/hw/intc/armv7m_nvic.h
+++ b/include/hw/intc/armv7m_nvic.h
@@ -74,7 +74,7 @@
*/
bool vectpending_is_s_banked;
int exception_prio; /* group prio of the highest prio active exception */
- int vectpending_prio; /* group prio of the exeception in vectpending */
+ int vectpending_prio; /* group prio of the exception in vectpending */
MemoryRegion sysregmem;
diff --git a/include/hw/s390x/s390-pci-bus.h b/include/hw/s390x/s390-pci-bus.h
index e0a9f93..b1bdbea 100644
--- a/include/hw/s390x/s390-pci-bus.h
+++ b/include/hw/s390x/s390-pci-bus.h
@@ -184,7 +184,7 @@
* The following states make up the "configured" meta-state:
* disabled: device is configured but not enabled; transition between this
* state and enabled via clp enable/disable
- * enbaled: device is ready for use; transition to disabled via clp disable;
+ * enabled: device is ready for use; transition to disabled via clp disable;
* may enter an error state
* blocked: ignore all DMA and interrupts; transition back to enabled or from
* error state via mpcifc
diff --git a/include/hw/s390x/sclp.h b/include/hw/s390x/sclp.h
index d3ade40..cf1f2ef 100644
--- a/include/hw/s390x/sclp.h
+++ b/include/hw/s390x/sclp.h
@@ -87,7 +87,7 @@
* - we work on a private copy of the SCCB, since there are several length
* fields, that would cause a security nightmare if we allow the guest to
* alter the structure while we parse it. We cannot use ldl_p and friends
- * either without doing pointer arithmetics
+ * either without doing pointer arithmetic
* So we have to double check that all users of sclp data structures use the
* right endianness wrappers.
*/
diff --git a/include/sysemu/dirtylimit.h b/include/sysemu/dirtylimit.h
index 8d2c1f3..d11ebbb 100644
--- a/include/sysemu/dirtylimit.h
+++ b/include/sysemu/dirtylimit.h
@@ -34,4 +34,6 @@
void dirtylimit_set_all(uint64_t quota,
bool enable);
void dirtylimit_vcpu_execute(CPUState *cpu);
+uint64_t dirtylimit_throttle_time_per_round(void);
+uint64_t dirtylimit_ring_full_time(void);
#endif
diff --git a/include/ui/console.h b/include/ui/console.h
index f27b2aa..3e8b22d 100644
--- a/include/ui/console.h
+++ b/include/ui/console.h
@@ -201,8 +201,8 @@
uint32_t texture;
uint32_t x;
uint32_t y;
- uint32_t scanout_width;
- uint32_t scanout_height;
+ uint32_t backing_width;
+ uint32_t backing_height;
bool y0_top;
void *sync;
int fence_fd;
diff --git a/linux-user/elfload.c b/linux-user/elfload.c
index a26200d..861ec07 100644
--- a/linux-user/elfload.c
+++ b/linux-user/elfload.c
@@ -1621,25 +1621,28 @@
const char *elf_hwcap_str(uint32_t bit)
{
static const char *hwcap_str[] = {
- [HWCAP_S390_ESAN3] = "esan3",
- [HWCAP_S390_ZARCH] = "zarch",
- [HWCAP_S390_STFLE] = "stfle",
- [HWCAP_S390_MSA] = "msa",
- [HWCAP_S390_LDISP] = "ldisp",
- [HWCAP_S390_EIMM] = "eimm",
- [HWCAP_S390_DFP] = "dfp",
- [HWCAP_S390_HPAGE] = "edat",
- [HWCAP_S390_ETF3EH] = "etf3eh",
- [HWCAP_S390_HIGH_GPRS] = "highgprs",
- [HWCAP_S390_TE] = "te",
- [HWCAP_S390_VXRS] = "vx",
- [HWCAP_S390_VXRS_BCD] = "vxd",
- [HWCAP_S390_VXRS_EXT] = "vxe",
- [HWCAP_S390_GS] = "gs",
- [HWCAP_S390_VXRS_EXT2] = "vxe2",
- [HWCAP_S390_VXRS_PDE] = "vxp",
- [HWCAP_S390_SORT] = "sort",
- [HWCAP_S390_DFLT] = "dflt",
+ [HWCAP_S390_NR_ESAN3] = "esan3",
+ [HWCAP_S390_NR_ZARCH] = "zarch",
+ [HWCAP_S390_NR_STFLE] = "stfle",
+ [HWCAP_S390_NR_MSA] = "msa",
+ [HWCAP_S390_NR_LDISP] = "ldisp",
+ [HWCAP_S390_NR_EIMM] = "eimm",
+ [HWCAP_S390_NR_DFP] = "dfp",
+ [HWCAP_S390_NR_HPAGE] = "edat",
+ [HWCAP_S390_NR_ETF3EH] = "etf3eh",
+ [HWCAP_S390_NR_HIGH_GPRS] = "highgprs",
+ [HWCAP_S390_NR_TE] = "te",
+ [HWCAP_S390_NR_VXRS] = "vx",
+ [HWCAP_S390_NR_VXRS_BCD] = "vxd",
+ [HWCAP_S390_NR_VXRS_EXT] = "vxe",
+ [HWCAP_S390_NR_GS] = "gs",
+ [HWCAP_S390_NR_VXRS_EXT2] = "vxe2",
+ [HWCAP_S390_NR_VXRS_PDE] = "vxp",
+ [HWCAP_S390_NR_SORT] = "sort",
+ [HWCAP_S390_NR_DFLT] = "dflt",
+ [HWCAP_S390_NR_NNPA] = "nnpa",
+ [HWCAP_S390_NR_PCI_MIO] = "pcimio",
+ [HWCAP_S390_NR_SIE] = "sie",
};
return bit < ARRAY_SIZE(hwcap_str) ? hwcap_str[bit] : NULL;
diff --git a/linux-user/mmap.c b/linux-user/mmap.c
index 44b53bd..a5dfb56 100644
--- a/linux-user/mmap.c
+++ b/linux-user/mmap.c
@@ -36,6 +36,7 @@
void mmap_unlock(void)
{
+ assert(mmap_lock_count > 0);
if (--mmap_lock_count == 0) {
pthread_mutex_unlock(&mmap_mutex);
}
diff --git a/linux-user/strace.c b/linux-user/strace.c
index bbd2914..e0ab804 100644
--- a/linux-user/strace.c
+++ b/linux-user/strace.c
@@ -3767,10 +3767,24 @@
#if defined(TARGET_NR_mmap) || defined(TARGET_NR_mmap2)
static void
-print_mmap(CPUArchState *cpu_env, const struct syscallname *name,
+print_mmap_both(CPUArchState *cpu_env, const struct syscallname *name,
abi_long arg0, abi_long arg1, abi_long arg2,
- abi_long arg3, abi_long arg4, abi_long arg5)
+ abi_long arg3, abi_long arg4, abi_long arg5,
+ bool is_old_mmap)
{
+ if (is_old_mmap) {
+ abi_ulong *v;
+ abi_ulong argp = arg0;
+ if (!(v = lock_user(VERIFY_READ, argp, 6 * sizeof(abi_ulong), 1)))
+ return;
+ arg0 = tswapal(v[0]);
+ arg1 = tswapal(v[1]);
+ arg2 = tswapal(v[2]);
+ arg3 = tswapal(v[3]);
+ arg4 = tswapal(v[4]);
+ arg5 = tswapal(v[5]);
+ unlock_user(v, argp, 0);
+ }
print_syscall_prologue(name);
print_pointer(arg0, 0);
print_raw_param("%d", arg1, 0);
@@ -3780,7 +3794,34 @@
print_raw_param("%#x", arg5, 1);
print_syscall_epilogue(name);
}
-#define print_mmap2 print_mmap
+#endif
+
+#if defined(TARGET_NR_mmap)
+static void
+print_mmap(CPUArchState *cpu_env, const struct syscallname *name,
+ abi_long arg0, abi_long arg1, abi_long arg2,
+ abi_long arg3, abi_long arg4, abi_long arg5)
+{
+ return print_mmap_both(cpu_env, name, arg0, arg1, arg2, arg3,
+ arg4, arg5,
+#if defined(TARGET_NR_mmap2)
+ true
+#else
+ false
+#endif
+ );
+}
+#endif
+
+#if defined(TARGET_NR_mmap2)
+static void
+print_mmap2(CPUArchState *cpu_env, const struct syscallname *name,
+ abi_long arg0, abi_long arg1, abi_long arg2,
+ abi_long arg3, abi_long arg4, abi_long arg5)
+{
+ return print_mmap_both(cpu_env, name, arg0, arg1, arg2, arg3,
+ arg4, arg5, false);
+}
#endif
#ifdef TARGET_NR_mprotect
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index 1464151..95727a8 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -801,12 +801,13 @@
return target_type;
}
-static abi_ulong target_brk;
+static abi_ulong target_brk, initial_target_brk;
static abi_ulong brk_page;
void target_set_brk(abi_ulong new_brk)
{
target_brk = TARGET_PAGE_ALIGN(new_brk);
+ initial_target_brk = target_brk;
brk_page = HOST_PAGE_ALIGN(target_brk);
}
@@ -824,15 +825,18 @@
return target_brk;
}
+ /* do not allow to shrink below initial brk value */
+ if (brk_val < initial_target_brk) {
+ brk_val = initial_target_brk;
+ }
+
new_brk = TARGET_PAGE_ALIGN(brk_val);
new_host_brk_page = HOST_PAGE_ALIGN(brk_val);
/* brk_val and old target_brk might be on the same page */
if (new_brk == TARGET_PAGE_ALIGN(target_brk)) {
- if (brk_val > target_brk) {
- /* empty remaining bytes in (possibly larger) host page */
- memset(g2h_untagged(target_brk), 0, new_host_brk_page - target_brk);
- }
+ /* empty remaining bytes in (possibly larger) host page */
+ memset(g2h_untagged(new_brk), 0, new_host_brk_page - new_brk);
target_brk = brk_val;
return target_brk;
}
@@ -840,7 +844,7 @@
/* Release heap if necesary */
if (new_brk < target_brk) {
/* empty remaining bytes in (possibly larger) host page */
- memset(g2h_untagged(brk_val), 0, new_host_brk_page - brk_val);
+ memset(g2h_untagged(new_brk), 0, new_host_brk_page - new_brk);
/* free unused host pages and set new brk_page */
target_munmap(new_host_brk_page, brk_page - new_host_brk_page);
@@ -856,12 +860,13 @@
* itself); instead we treat "mapped but at wrong address" as
* a failure and unmap again.
*/
- new_alloc_size = new_host_brk_page - brk_page;
- if (new_alloc_size) {
+ if (new_host_brk_page > brk_page) {
+ new_alloc_size = new_host_brk_page - brk_page;
mapped_addr = get_errno(target_mmap(brk_page, new_alloc_size,
PROT_READ|PROT_WRITE,
MAP_ANON|MAP_PRIVATE, 0, 0));
} else {
+ new_alloc_size = 0;
mapped_addr = brk_page;
}
@@ -873,7 +878,7 @@
* come from the remaining part of the previous page: it may
* contains garbage data due to a previous heap usage (grown
* then shrunken). */
- memset(g2h_untagged(target_brk), 0, brk_page - target_brk);
+ memset(g2h_untagged(brk_page), 0, HOST_PAGE_ALIGN(brk_page) - brk_page);
target_brk = brk_val;
brk_page = new_host_brk_page;
@@ -11190,16 +11195,14 @@
#if defined(TARGET_NR_clock_adjtime) && defined(CONFIG_CLOCK_ADJTIME)
case TARGET_NR_clock_adjtime:
{
- struct timex htx, *phtx = &htx;
+ struct timex htx;
- if (target_to_host_timex(phtx, arg2) != 0) {
+ if (target_to_host_timex(&htx, arg2) != 0) {
return -TARGET_EFAULT;
}
- ret = get_errno(clock_adjtime(arg1, phtx));
- if (!is_error(ret) && phtx) {
- if (host_to_target_timex(arg2, phtx) != 0) {
- return -TARGET_EFAULT;
- }
+ ret = get_errno(clock_adjtime(arg1, &htx));
+ if (!is_error(ret) && host_to_target_timex(arg2, &htx)) {
+ return -TARGET_EFAULT;
}
}
return ret;
diff --git a/meson.build b/meson.build
index 5fcdb37..98e68ef 100644
--- a/meson.build
+++ b/meson.build
@@ -4251,7 +4251,7 @@
summary_info += {'ALSA support': alsa}
summary_info += {'PulseAudio support': pulse}
endif
-summary_info += {'Pipewire support': pipewire}
+summary_info += {'PipeWire support': pipewire}
summary_info += {'JACK support': jack}
summary(summary_info, bool_yn: true, section: 'Audio backends')
diff --git a/meson_options.txt b/meson_options.txt
index bbb5c7e..aaea5dd 100644
--- a/meson_options.txt
+++ b/meson_options.txt
@@ -267,7 +267,7 @@
option('pa', type: 'feature', value: 'auto',
description: 'PulseAudio sound support')
option('pipewire', type: 'feature', value: 'auto',
- description: 'Pipewire sound support')
+ description: 'PipeWire sound support')
option('sndio', type: 'feature', value: 'auto',
description: 'sndio sound support')
diff --git a/migration/migration-hmp-cmds.c b/migration/migration-hmp-cmds.c
index 9885d7c..c115ef2 100644
--- a/migration/migration-hmp-cmds.c
+++ b/migration/migration-hmp-cmds.c
@@ -190,6 +190,16 @@
info->cpu_throttle_percentage);
}
+ if (info->has_dirty_limit_throttle_time_per_round) {
+ monitor_printf(mon, "dirty-limit throttle time: %" PRIu64 " us\n",
+ info->dirty_limit_throttle_time_per_round);
+ }
+
+ if (info->has_dirty_limit_ring_full_time) {
+ monitor_printf(mon, "dirty-limit ring full time: %" PRIu64 " us\n",
+ info->dirty_limit_ring_full_time);
+ }
+
if (info->has_postcopy_blocktime) {
monitor_printf(mon, "postcopy blocktime: %u\n",
info->postcopy_blocktime);
@@ -364,6 +374,14 @@
}
}
}
+
+ monitor_printf(mon, "%s: %" PRIu64 " ms\n",
+ MigrationParameter_str(MIGRATION_PARAMETER_X_VCPU_DIRTY_LIMIT_PERIOD),
+ params->x_vcpu_dirty_limit_period);
+
+ monitor_printf(mon, "%s: %" PRIu64 " MB/s\n",
+ MigrationParameter_str(MIGRATION_PARAMETER_VCPU_DIRTY_LIMIT),
+ params->vcpu_dirty_limit);
}
qapi_free_MigrationParameters(params);
@@ -620,6 +638,14 @@
error_setg(&err, "The block-bitmap-mapping parameter can only be set "
"through QMP");
break;
+ case MIGRATION_PARAMETER_X_VCPU_DIRTY_LIMIT_PERIOD:
+ p->has_x_vcpu_dirty_limit_period = true;
+ visit_type_size(v, param, &p->x_vcpu_dirty_limit_period, &err);
+ break;
+ case MIGRATION_PARAMETER_VCPU_DIRTY_LIMIT:
+ p->has_vcpu_dirty_limit = true;
+ visit_type_size(v, param, &p->vcpu_dirty_limit, &err);
+ break;
default:
assert(0);
}
diff --git a/migration/migration-stats.c b/migration/migration-stats.c
index f98c826..095d6d7 100644
--- a/migration/migration-stats.c
+++ b/migration/migration-stats.c
@@ -48,7 +48,7 @@
void migration_rate_set(uint64_t limit)
{
/*
- * 'limit' is per second. But we check it each BUFER_DELAY miliseconds.
+ * 'limit' is per second. But we check it each BUFFER_DELAY milliseconds.
*/
stat64_set(&mig_stats.rate_limit_max, limit / XFER_LIMIT_RATIO);
}
diff --git a/migration/migration.c b/migration/migration.c
index 91bba63..5528acb 100644
--- a/migration/migration.c
+++ b/migration/migration.c
@@ -64,6 +64,7 @@
#include "yank_functions.h"
#include "sysemu/qtest.h"
#include "options.h"
+#include "sysemu/dirtylimit.h"
static NotifierList migration_state_notifiers =
NOTIFIER_LIST_INITIALIZER(migration_state_notifiers);
@@ -166,6 +167,9 @@
if (error) {
migrate_set_error(current_migration, error);
}
+ if (migrate_dirty_limit()) {
+ qmp_cancel_vcpu_dirty_limit(false, -1, NULL);
+ }
migrate_fd_cancel(current_migration);
}
@@ -971,6 +975,15 @@
info->ram->dirty_pages_rate =
stat64_get(&mig_stats.dirty_pages_rate);
}
+
+ if (migrate_dirty_limit() && dirtylimit_in_service()) {
+ info->has_dirty_limit_throttle_time_per_round = true;
+ info->dirty_limit_throttle_time_per_round =
+ dirtylimit_throttle_time_per_round();
+
+ info->has_dirty_limit_ring_full_time = true;
+ info->dirty_limit_ring_full_time = dirtylimit_ring_full_time();
+ }
}
static void populate_disk_info(MigrationInfo *info)
@@ -1676,7 +1689,7 @@
if (!resume_requested) {
yank_unregister_instance(MIGRATION_YANK_INSTANCE);
}
- error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "uri",
+ error_setg(&local_err, QERR_INVALID_PARAMETER_VALUE, "uri",
"a valid migration protocol");
migrate_set_state(&s->state, MIGRATION_STATUS_SETUP,
MIGRATION_STATUS_FAILED);
@@ -2069,7 +2082,7 @@
* Switch from normal iteration to postcopy
* Returns non-0 on error
*/
-static int postcopy_start(MigrationState *ms)
+static int postcopy_start(MigrationState *ms, Error **errp)
{
int ret;
QIOChannelBuffer *bioc;
@@ -2179,7 +2192,7 @@
*/
ret = qemu_file_get_error(ms->to_dst_file);
if (ret) {
- error_report("postcopy_start: Migration stream errored (pre package)");
+ error_setg(errp, "postcopy_start: Migration stream errored (pre package)");
goto fail_closefb;
}
@@ -2216,7 +2229,7 @@
ret = qemu_file_get_error(ms->to_dst_file);
if (ret) {
- error_report("postcopy_start: Migration stream errored");
+ error_setg(errp, "postcopy_start: Migration stream errored");
migrate_set_state(&ms->state, MIGRATION_STATUS_POSTCOPY_ACTIVE,
MIGRATION_STATUS_FAILED);
}
@@ -2737,6 +2750,7 @@
static MigIterateState migration_iteration_run(MigrationState *s)
{
uint64_t must_precopy, can_postcopy;
+ Error *local_err = NULL;
bool in_postcopy = s->state == MIGRATION_STATUS_POSTCOPY_ACTIVE;
bool can_switchover = migration_can_switchover(s);
@@ -2760,8 +2774,9 @@
/* Still a significant amount to transfer */
if (!in_postcopy && must_precopy <= s->threshold_size && can_switchover &&
qatomic_read(&s->start_postcopy)) {
- if (postcopy_start(s)) {
- error_report("%s: postcopy failed to start", __func__);
+ if (postcopy_start(s, &local_err)) {
+ migrate_set_error(s, local_err);
+ error_report_err(local_err);
}
return MIG_ITERATE_SKIP;
}
@@ -2953,7 +2968,7 @@
MigThrError thr_error;
bool urgent = false;
- thread = MigrationThreadAdd("live_migration", qemu_get_thread_id());
+ thread = migration_threads_add("live_migration", qemu_get_thread_id());
rcu_register_thread();
@@ -3031,7 +3046,7 @@
migration_iteration_finish(s);
object_unref(OBJECT(s));
rcu_unregister_thread();
- MigrationThreadDel(thread);
+ migration_threads_remove(thread);
return NULL;
}
@@ -3252,8 +3267,10 @@
*/
if (migrate_postcopy_ram() || migrate_return_path()) {
if (open_return_path_on_source(s, !resume)) {
- error_report("Unable to open return-path for postcopy");
+ error_setg(&local_err, "Unable to open return-path for postcopy");
migrate_set_state(&s->state, s->state, MIGRATION_STATUS_FAILED);
+ migrate_set_error(s, local_err);
+ error_report_err(local_err);
migrate_fd_cleanup(s);
return;
}
@@ -3277,6 +3294,7 @@
}
if (multifd_save_setup(&local_err) != 0) {
+ migrate_set_error(s, local_err);
error_report_err(local_err);
migrate_set_state(&s->state, MIGRATION_STATUS_SETUP,
MIGRATION_STATUS_FAILED);
diff --git a/migration/migration.h b/migration/migration.h
index b7c8b67..6eea18d 100644
--- a/migration/migration.h
+++ b/migration/migration.h
@@ -134,7 +134,7 @@
/*
* Always set by the main vm load thread only, but can be read by the
* postcopy preempt thread. "volatile" makes sure all reads will be
- * uptodate across cores.
+ * up-to-date across cores.
*/
volatile PreemptThreadStatus preempt_thread_status;
/*
@@ -409,7 +409,7 @@
* channel itself.
*
* - postcopy preempt channel will be created at the switching phase
- * from precopy -> postcopy (to avoid race condtion of misordered
+ * from precopy -> postcopy (to avoid race condition of misordered
* creation of channels).
*
* NOTE: See message-id <ZBoShWArKDPpX/D7@work-vm> on qemu-devel
diff --git a/migration/multifd-zlib.c b/migration/multifd-zlib.c
index 8170125..37ce486 100644
--- a/migration/multifd-zlib.c
+++ b/migration/multifd-zlib.c
@@ -57,7 +57,7 @@
err_msg = "deflate init failed";
goto err_free_z;
}
- /* This is the maxium size of the compressed buffer */
+ /* This is the maximum size of the compressed buffer */
z->zbuff_len = compressBound(MULTIFD_PACKET_SIZE);
z->zbuff = g_try_malloc(z->zbuff_len);
if (!z->zbuff) {
diff --git a/migration/multifd-zstd.c b/migration/multifd-zstd.c
index d1d29e7..b471daa 100644
--- a/migration/multifd-zstd.c
+++ b/migration/multifd-zstd.c
@@ -68,7 +68,7 @@
p->id, ZSTD_getErrorName(res));
return -1;
}
- /* This is the maxium size of the compressed buffer */
+ /* This is the maximum size of the compressed buffer */
z->zbuff_len = ZSTD_compressBound(MULTIFD_PACKET_SIZE);
z->zbuff = g_try_malloc(z->zbuff_len);
if (!z->zbuff) {
diff --git a/migration/multifd.c b/migration/multifd.c
index 3387d82..0f6b203 100644
--- a/migration/multifd.c
+++ b/migration/multifd.c
@@ -651,7 +651,7 @@
int ret = 0;
bool use_zero_copy_send = migrate_zero_copy_send();
- thread = MigrationThreadAdd(p->name, qemu_get_thread_id());
+ thread = migration_threads_add(p->name, qemu_get_thread_id());
trace_multifd_send_thread_start(p->id);
rcu_register_thread();
@@ -767,7 +767,7 @@
qemu_mutex_unlock(&p->mutex);
rcu_unregister_thread();
- MigrationThreadDel(thread);
+ migration_threads_remove(thread);
trace_multifd_send_thread_end(p->id, p->num_packets, p->total_normal_pages);
return NULL;
@@ -878,7 +878,7 @@
qemu_sem_post(&p->sem_sync);
/*
* Although multifd_send_thread is not created, but main migration
- * thread neet to judge whether it is running, so we need to mark
+ * thread need to judge whether it is running, so we need to mark
* its status.
*/
p->quit = true;
diff --git a/migration/options.c b/migration/options.c
index 5a9505a..1d1e132 100644
--- a/migration/options.c
+++ b/migration/options.c
@@ -27,6 +27,7 @@
#include "qemu-file.h"
#include "ram.h"
#include "options.h"
+#include "sysemu/kvm.h"
/* Maximum migrate downtime set to 2000 seconds */
#define MAX_MIGRATE_DOWNTIME_SECONDS 2000
@@ -80,6 +81,9 @@
#define DEFINE_PROP_MIG_CAP(name, x) \
DEFINE_PROP_BOOL(name, MigrationState, capabilities[x], false)
+#define DEFAULT_MIGRATE_VCPU_DIRTY_LIMIT_PERIOD 1000 /* milliseconds */
+#define DEFAULT_MIGRATE_VCPU_DIRTY_LIMIT 1 /* MB/s */
+
Property migration_properties[] = {
DEFINE_PROP_BOOL("store-global-state", MigrationState,
store_global_state, true),
@@ -163,6 +167,12 @@
DEFINE_PROP_STRING("tls-creds", MigrationState, parameters.tls_creds),
DEFINE_PROP_STRING("tls-hostname", MigrationState, parameters.tls_hostname),
DEFINE_PROP_STRING("tls-authz", MigrationState, parameters.tls_authz),
+ DEFINE_PROP_UINT64("x-vcpu-dirty-limit-period", MigrationState,
+ parameters.x_vcpu_dirty_limit_period,
+ DEFAULT_MIGRATE_VCPU_DIRTY_LIMIT_PERIOD),
+ DEFINE_PROP_UINT64("vcpu-dirty-limit", MigrationState,
+ parameters.vcpu_dirty_limit,
+ DEFAULT_MIGRATE_VCPU_DIRTY_LIMIT),
/* Migration capabilities */
DEFINE_PROP_MIG_CAP("x-xbzrle", MIGRATION_CAPABILITY_XBZRLE),
@@ -187,7 +197,7 @@
#endif
DEFINE_PROP_MIG_CAP("x-switchover-ack",
MIGRATION_CAPABILITY_SWITCHOVER_ACK),
-
+ DEFINE_PROP_MIG_CAP("x-dirty-limit", MIGRATION_CAPABILITY_DIRTY_LIMIT),
DEFINE_PROP_END_OF_LIST(),
};
@@ -233,6 +243,13 @@
return s->capabilities[MIGRATION_CAPABILITY_DIRTY_BITMAPS];
}
+bool migrate_dirty_limit(void)
+{
+ MigrationState *s = migrate_get_current();
+
+ return s->capabilities[MIGRATION_CAPABILITY_DIRTY_LIMIT];
+}
+
bool migrate_events(void)
{
MigrationState *s = migrate_get_current();
@@ -424,6 +441,11 @@
MIGRATION_CAPABILITY_VALIDATE_UUID,
MIGRATION_CAPABILITY_ZERO_COPY_SEND);
+static bool migrate_incoming_started(void)
+{
+ return !!migration_incoming_get_current()->transport_data;
+}
+
/**
* @migration_caps_check - check capability compatibility
*
@@ -547,6 +569,12 @@
error_setg(errp, "Postcopy preempt not compatible with compress");
return false;
}
+
+ if (migrate_incoming_started()) {
+ error_setg(errp,
+ "Postcopy preempt must be set before incoming starts");
+ return false;
+ }
}
if (new_caps[MIGRATION_CAPABILITY_MULTIFD]) {
@@ -554,6 +582,10 @@
error_setg(errp, "Multifd is not compatible with compress");
return false;
}
+ if (migrate_incoming_started()) {
+ error_setg(errp, "Multifd must be set before incoming starts");
+ return false;
+ }
}
if (new_caps[MIGRATION_CAPABILITY_SWITCHOVER_ACK]) {
@@ -563,6 +595,19 @@
return false;
}
}
+ if (new_caps[MIGRATION_CAPABILITY_DIRTY_LIMIT]) {
+ if (new_caps[MIGRATION_CAPABILITY_AUTO_CONVERGE]) {
+ error_setg(errp, "dirty-limit conflicts with auto-converge"
+ " either of then available currently");
+ return false;
+ }
+
+ if (!kvm_enabled() || !kvm_dirty_ring_enabled()) {
+ error_setg(errp, "dirty-limit requires KVM with accelerator"
+ " property 'dirty-ring-size' set");
+ return false;
+ }
+ }
return true;
}
@@ -908,6 +953,11 @@
s->parameters.block_bitmap_mapping);
}
+ params->has_x_vcpu_dirty_limit_period = true;
+ params->x_vcpu_dirty_limit_period = s->parameters.x_vcpu_dirty_limit_period;
+ params->has_vcpu_dirty_limit = true;
+ params->vcpu_dirty_limit = s->parameters.vcpu_dirty_limit;
+
return params;
}
@@ -940,6 +990,8 @@
params->has_announce_max = true;
params->has_announce_rounds = true;
params->has_announce_step = true;
+ params->has_x_vcpu_dirty_limit_period = true;
+ params->has_vcpu_dirty_limit = true;
}
/*
@@ -1100,6 +1152,23 @@
}
#endif
+ if (params->has_x_vcpu_dirty_limit_period &&
+ (params->x_vcpu_dirty_limit_period < 1 ||
+ params->x_vcpu_dirty_limit_period > 1000)) {
+ error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
+ "x-vcpu-dirty-limit-period",
+ "a value between 1 and 1000");
+ return false;
+ }
+
+ if (params->has_vcpu_dirty_limit &&
+ (params->vcpu_dirty_limit < 1)) {
+ error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
+ "vcpu_dirty_limit",
+ "is invalid, it must greater then 1 MB/s");
+ return false;
+ }
+
return true;
}
@@ -1199,6 +1268,14 @@
dest->has_block_bitmap_mapping = true;
dest->block_bitmap_mapping = params->block_bitmap_mapping;
}
+
+ if (params->has_x_vcpu_dirty_limit_period) {
+ dest->x_vcpu_dirty_limit_period =
+ params->x_vcpu_dirty_limit_period;
+ }
+ if (params->has_vcpu_dirty_limit) {
+ dest->vcpu_dirty_limit = params->vcpu_dirty_limit;
+ }
}
static void migrate_params_apply(MigrateSetParameters *params, Error **errp)
@@ -1317,6 +1394,14 @@
QAPI_CLONE(BitmapMigrationNodeAliasList,
params->block_bitmap_mapping);
}
+
+ if (params->has_x_vcpu_dirty_limit_period) {
+ s->parameters.x_vcpu_dirty_limit_period =
+ params->x_vcpu_dirty_limit_period;
+ }
+ if (params->has_vcpu_dirty_limit) {
+ s->parameters.vcpu_dirty_limit = params->vcpu_dirty_limit;
+ }
}
void qmp_migrate_set_parameters(MigrateSetParameters *params, Error **errp)
diff --git a/migration/options.h b/migration/options.h
index 9aaf363..045e2a4 100644
--- a/migration/options.h
+++ b/migration/options.h
@@ -29,6 +29,7 @@
bool migrate_colo(void);
bool migrate_compress(void);
bool migrate_dirty_bitmaps(void);
+bool migrate_dirty_limit(void);
bool migrate_events(void);
bool migrate_ignore_shared(void);
bool migrate_late_block_activate(void);
diff --git a/migration/qemu-file.c b/migration/qemu-file.c
index acc2826..19c33c9 100644
--- a/migration/qemu-file.c
+++ b/migration/qemu-file.c
@@ -65,8 +65,6 @@
*/
int qemu_file_shutdown(QEMUFile *f)
{
- int ret = 0;
-
/*
* We must set qemufile error before the real shutdown(), otherwise
* there can be a race window where we thought IO all went though
@@ -96,22 +94,10 @@
}
if (qio_channel_shutdown(f->ioc, QIO_CHANNEL_SHUTDOWN_BOTH, NULL) < 0) {
- ret = -EIO;
+ return -EIO;
}
- return ret;
-}
-
-bool qemu_file_mode_is_not_valid(const char *mode)
-{
- if (mode == NULL ||
- (mode[0] != 'r' && mode[0] != 'w') ||
- mode[1] != 'b' || mode[2] != 0) {
- fprintf(stderr, "qemu_fopen: Argument validity check failed\n");
- return true;
- }
-
- return false;
+ return 0;
}
static QEMUFile *qemu_file_new_impl(QIOChannel *ioc, bool is_writable)
@@ -160,7 +146,7 @@
* is not 0.
*
*/
-int qemu_file_get_error_obj(QEMUFile *f, Error **errp)
+static int qemu_file_get_error_obj(QEMUFile *f, Error **errp)
{
if (errp) {
*errp = f->last_error_obj ? error_copy(f->last_error_obj) : NULL;
@@ -228,7 +214,7 @@
qemu_file_set_error_obj(f, ret, NULL);
}
-bool qemu_file_is_writable(QEMUFile *f)
+static bool qemu_file_is_writable(QEMUFile *f)
{
return f->is_writable;
}
@@ -694,7 +680,7 @@
return result;
}
-uint64_t qemu_file_transferred_fast(QEMUFile *f)
+uint64_t qemu_file_transferred_noflush(QEMUFile *f)
{
uint64_t ret = f->total_transferred;
int i;
diff --git a/migration/qemu-file.h b/migration/qemu-file.h
index e649718..47015f5 100644
--- a/migration/qemu-file.h
+++ b/migration/qemu-file.h
@@ -86,16 +86,15 @@
uint64_t qemu_file_transferred(QEMUFile *f);
/*
- * qemu_file_transferred_fast:
+ * qemu_file_transferred_noflush:
*
- * As qemu_file_transferred except for writable
- * files, where no flush is performed and the reported
- * amount will include the size of any queued buffers,
- * on top of the amount actually transferred.
+ * As qemu_file_transferred except for writable files, where no flush
+ * is performed and the reported amount will include the size of any
+ * queued buffers, on top of the amount actually transferred.
*
* Returns: the total bytes transferred and queued
*/
-uint64_t qemu_file_transferred_fast(QEMUFile *f);
+uint64_t qemu_file_transferred_noflush(QEMUFile *f);
/*
* put_buffer without copying the buffer.
@@ -103,8 +102,6 @@
*/
void qemu_put_buffer_async(QEMUFile *f, const uint8_t *buf, size_t size,
bool may_free);
-bool qemu_file_mode_is_not_valid(const char *mode);
-bool qemu_file_is_writable(QEMUFile *f);
#include "migration/qemu-file-types.h"
@@ -130,7 +127,6 @@
* accounting information tracks the total migration traffic.
*/
void qemu_file_credit_transfer(QEMUFile *f, size_t size);
-int qemu_file_get_error_obj(QEMUFile *f, Error **errp);
int qemu_file_get_error_obj_any(QEMUFile *f1, QEMUFile *f2, Error **errp);
void qemu_file_set_error_obj(QEMUFile *f, int ret, Error *err);
void qemu_file_set_error(QEMUFile *f, int ret);
diff --git a/migration/ram.c b/migration/ram.c
index 0ada647..9040d66 100644
--- a/migration/ram.c
+++ b/migration/ram.c
@@ -46,6 +46,7 @@
#include "qapi/error.h"
#include "qapi/qapi-types-migration.h"
#include "qapi/qapi-events-migration.h"
+#include "qapi/qapi-commands-migration.h"
#include "qapi/qmp/qerror.h"
#include "trace.h"
#include "exec/ram_addr.h"
@@ -59,6 +60,8 @@
#include "multifd.h"
#include "sysemu/runstate.h"
#include "options.h"
+#include "sysemu/dirtylimit.h"
+#include "sysemu/kvm.h"
#include "hw/boards.h" /* for machine_dump_guest_core() */
@@ -984,6 +987,37 @@
}
}
+/*
+ * Enable dirty-limit to throttle down the guest
+ */
+static void migration_dirty_limit_guest(void)
+{
+ /*
+ * dirty page rate quota for all vCPUs fetched from
+ * migration parameter 'vcpu_dirty_limit'
+ */
+ static int64_t quota_dirtyrate;
+ MigrationState *s = migrate_get_current();
+
+ /*
+ * If dirty limit already enabled and migration parameter
+ * vcpu-dirty-limit untouched.
+ */
+ if (dirtylimit_in_service() &&
+ quota_dirtyrate == s->parameters.vcpu_dirty_limit) {
+ return;
+ }
+
+ quota_dirtyrate = s->parameters.vcpu_dirty_limit;
+
+ /*
+ * Set all vCPU a quota dirtyrate, note that the second
+ * parameter will be ignored if setting all vCPU for the vm
+ */
+ qmp_set_vcpu_dirty_limit(false, -1, quota_dirtyrate, NULL);
+ trace_migration_dirty_limit_guest(quota_dirtyrate);
+}
+
static void migration_trigger_throttle(RAMState *rs)
{
uint64_t threshold = migrate_throttle_trigger_threshold();
@@ -995,19 +1029,26 @@
/* During block migration the auto-converge logic incorrectly detects
* that ram migration makes no progress. Avoid this by disabling the
* throttling logic during the bulk phase of block migration. */
- if (migrate_auto_converge() && !blk_mig_bulk_active()) {
- /* The following detection logic can be refined later. For now:
- Check to see if the ratio between dirtied bytes and the approx.
- amount of bytes that just got transferred since the last time
- we were in this routine reaches the threshold. If that happens
- twice, start or increase throttling. */
+ if (blk_mig_bulk_active()) {
+ return;
+ }
- if ((bytes_dirty_period > bytes_dirty_threshold) &&
- (++rs->dirty_rate_high_cnt >= 2)) {
+ /*
+ * The following detection logic can be refined later. For now:
+ * Check to see if the ratio between dirtied bytes and the approx.
+ * amount of bytes that just got transferred since the last time
+ * we were in this routine reaches the threshold. If that happens
+ * twice, start or increase throttling.
+ */
+ if ((bytes_dirty_period > bytes_dirty_threshold) &&
+ (++rs->dirty_rate_high_cnt >= 2)) {
+ rs->dirty_rate_high_cnt = 0;
+ if (migrate_auto_converge()) {
trace_migration_throttle();
- rs->dirty_rate_high_cnt = 0;
mig_throttle_guest_down(bytes_dirty_period,
bytes_dirty_threshold);
+ } else if (migrate_dirty_limit()) {
+ migration_dirty_limit_guest();
}
}
}
diff --git a/migration/rdma.c b/migration/rdma.c
index dd1c039..ca430d3 100644
--- a/migration/rdma.c
+++ b/migration/rdma.c
@@ -4053,27 +4053,26 @@
type_init(qio_channel_rdma_register_types);
-static QEMUFile *qemu_fopen_rdma(RDMAContext *rdma, const char *mode)
+static QEMUFile *rdma_new_input(RDMAContext *rdma)
{
- QIOChannelRDMA *rioc;
+ QIOChannelRDMA *rioc = QIO_CHANNEL_RDMA(object_new(TYPE_QIO_CHANNEL_RDMA));
- if (qemu_file_mode_is_not_valid(mode)) {
- return NULL;
- }
+ rioc->file = qemu_file_new_input(QIO_CHANNEL(rioc));
+ rioc->rdmain = rdma;
+ rioc->rdmaout = rdma->return_path;
+ qemu_file_set_hooks(rioc->file, &rdma_read_hooks);
- rioc = QIO_CHANNEL_RDMA(object_new(TYPE_QIO_CHANNEL_RDMA));
+ return rioc->file;
+}
- if (mode[0] == 'w') {
- rioc->file = qemu_file_new_output(QIO_CHANNEL(rioc));
- rioc->rdmaout = rdma;
- rioc->rdmain = rdma->return_path;
- qemu_file_set_hooks(rioc->file, &rdma_write_hooks);
- } else {
- rioc->file = qemu_file_new_input(QIO_CHANNEL(rioc));
- rioc->rdmain = rdma;
- rioc->rdmaout = rdma->return_path;
- qemu_file_set_hooks(rioc->file, &rdma_read_hooks);
- }
+static QEMUFile *rdma_new_output(RDMAContext *rdma)
+{
+ QIOChannelRDMA *rioc = QIO_CHANNEL_RDMA(object_new(TYPE_QIO_CHANNEL_RDMA));
+
+ rioc->file = qemu_file_new_output(QIO_CHANNEL(rioc));
+ rioc->rdmaout = rdma;
+ rioc->rdmain = rdma->return_path;
+ qemu_file_set_hooks(rioc->file, &rdma_write_hooks);
return rioc->file;
}
@@ -4099,9 +4098,9 @@
return;
}
- f = qemu_fopen_rdma(rdma, "rb");
+ f = rdma_new_input(rdma);
if (f == NULL) {
- fprintf(stderr, "RDMA ERROR: could not qemu_fopen_rdma\n");
+ fprintf(stderr, "RDMA ERROR: could not open RDMA for input\n");
qemu_rdma_cleanup(rdma);
return;
}
@@ -4224,7 +4223,7 @@
trace_rdma_start_outgoing_migration_after_rdma_connect();
- s->to_dst_file = qemu_fopen_rdma(rdma, "wb");
+ s->to_dst_file = rdma_new_output(rdma);
migrate_fd_connect(s, NULL);
return;
return_path_err:
diff --git a/migration/savevm.c b/migration/savevm.c
index 95c2abf4..a2cb885 100644
--- a/migration/savevm.c
+++ b/migration/savevm.c
@@ -117,7 +117,7 @@
* The format of arguments is depending on postcopy mode:
* - postcopy RAM only
* uint64_t host page size
- * uint64_t taget page size
+ * uint64_t target page size
*
* - postcopy RAM and postcopy dirty bitmaps
* format is the same as for postcopy RAM only
@@ -927,9 +927,9 @@
static void vmstate_save_old_style(QEMUFile *f, SaveStateEntry *se,
JSONWriter *vmdesc)
{
- uint64_t old_offset = qemu_file_transferred_fast(f);
+ uint64_t old_offset = qemu_file_transferred_noflush(f);
se->ops->save_state(f, se->opaque);
- uint64_t size = qemu_file_transferred_fast(f) - old_offset;
+ uint64_t size = qemu_file_transferred_noflush(f) - old_offset;
if (vmdesc) {
json_writer_int64(vmdesc, "size", size);
@@ -3007,7 +3007,7 @@
goto the_end;
}
ret = qemu_savevm_state(f, errp);
- vm_state_size = qemu_file_transferred(f);
+ vm_state_size = qemu_file_transferred_noflush(f);
ret2 = qemu_fclose(f);
if (ret < 0) {
goto the_end;
diff --git a/migration/threadinfo.c b/migration/threadinfo.c
index 1de8b31..262990d 100644
--- a/migration/threadinfo.c
+++ b/migration/threadinfo.c
@@ -10,23 +10,35 @@
* See the COPYING file in the top-level directory.
*/
+#include "qemu/osdep.h"
+#include "qemu/queue.h"
+#include "qemu/lockable.h"
#include "threadinfo.h"
+QemuMutex migration_threads_lock;
static QLIST_HEAD(, MigrationThread) migration_threads;
-MigrationThread *MigrationThreadAdd(const char *name, int thread_id)
+static void __attribute__((constructor)) migration_threads_init(void)
+{
+ qemu_mutex_init(&migration_threads_lock);
+}
+
+MigrationThread *migration_threads_add(const char *name, int thread_id)
{
MigrationThread *thread = g_new0(MigrationThread, 1);
thread->name = name;
thread->thread_id = thread_id;
- QLIST_INSERT_HEAD(&migration_threads, thread, node);
+ WITH_QEMU_LOCK_GUARD(&migration_threads_lock) {
+ QLIST_INSERT_HEAD(&migration_threads, thread, node);
+ }
return thread;
}
-void MigrationThreadDel(MigrationThread *thread)
+void migration_threads_remove(MigrationThread *thread)
{
+ QEMU_LOCK_GUARD(&migration_threads_lock);
if (thread) {
QLIST_REMOVE(thread, node);
g_free(thread);
@@ -39,6 +51,7 @@
MigrationThreadInfoList **tail = &head;
MigrationThread *thread = NULL;
+ QEMU_LOCK_GUARD(&migration_threads_lock);
QLIST_FOREACH(thread, &migration_threads, node) {
MigrationThreadInfo *info = g_new0(MigrationThreadInfo, 1);
info->name = g_strdup(thread->name);
diff --git a/migration/threadinfo.h b/migration/threadinfo.h
index 4d69423..2f356ff 100644
--- a/migration/threadinfo.h
+++ b/migration/threadinfo.h
@@ -10,8 +10,6 @@
* See the COPYING file in the top-level directory.
*/
-#include "qemu/queue.h"
-#include "qemu/osdep.h"
#include "qapi/error.h"
#include "qapi/qapi-commands-migration.h"
@@ -23,6 +21,5 @@
QLIST_ENTRY(MigrationThread) node;
};
-MigrationThread *MigrationThreadAdd(const char *name, int thread_id);
-
-void MigrationThreadDel(MigrationThread *info);
+MigrationThread *migration_threads_add(const char *name, int thread_id);
+void migration_threads_remove(MigrationThread *info);
diff --git a/migration/trace-events b/migration/trace-events
index 5259c10..4666f19 100644
--- a/migration/trace-events
+++ b/migration/trace-events
@@ -93,6 +93,7 @@
migration_bitmap_sync_end(uint64_t dirty_pages) "dirty_pages %" PRIu64
migration_bitmap_clear_dirty(char *str, uint64_t start, uint64_t size, unsigned long page) "rb %s start 0x%"PRIx64" size 0x%"PRIx64" page 0x%lx"
migration_throttle(void) ""
+migration_dirty_limit_guest(int64_t dirtyrate) "guest dirty page rate limit %" PRIi64 " MB/s"
ram_discard_range(const char *rbname, uint64_t start, size_t len) "%s: start: %" PRIx64 " %zx"
ram_load_loop(const char *rbname, uint64_t addr, int flags, void *host) "%s: addr: 0x%" PRIx64 " flags: 0x%x host: %p"
ram_load_postcopy_loop(int channel, uint64_t addr, int flags) "chan=%d addr=0x%" PRIx64 " flags=0x%x"
@@ -184,7 +185,7 @@
source_return_path_thread_resume_ack(uint32_t v) "%"PRIu32
source_return_path_thread_switchover_acked(void) ""
migration_thread_low_pending(uint64_t pending) "%" PRIu64
-migrate_transferred(uint64_t tranferred, uint64_t time_spent, uint64_t bandwidth, uint64_t size) "transferred %" PRIu64 " time_spent %" PRIu64 " bandwidth %" PRIu64 " max_size %" PRId64
+migrate_transferred(uint64_t transferred, uint64_t time_spent, uint64_t bandwidth, uint64_t size) "transferred %" PRIu64 " time_spent %" PRIu64 " bandwidth %" PRIu64 " max_size %" PRId64
process_incoming_migration_co_end(int ret, int ps) "ret=%d postcopy-state=%d"
process_incoming_migration_co_postcopy_end_main(void) ""
postcopy_preempt_enabled(bool value) "%d"
diff --git a/migration/vmstate.c b/migration/vmstate.c
index af01d54..31842c3 100644
--- a/migration/vmstate.c
+++ b/migration/vmstate.c
@@ -361,7 +361,7 @@
void *curr_elem = first_elem + size * i;
vmsd_desc_field_start(vmsd, vmdesc_loop, field, i, n_elems);
- old_offset = qemu_file_transferred_fast(f);
+ old_offset = qemu_file_transferred_noflush(f);
if (field->flags & VMS_ARRAY_OF_POINTER) {
assert(curr_elem);
curr_elem = *(void **)curr_elem;
@@ -391,7 +391,7 @@
return ret;
}
- written_bytes = qemu_file_transferred_fast(f) - old_offset;
+ written_bytes = qemu_file_transferred_noflush(f) - old_offset;
vmsd_desc_field_end(vmsd, vmdesc_loop, field, written_bytes, i);
/* Compressed arrays only care about the first element */
diff --git a/nbd/client.c b/nbd/client.c
index 30d5383..479208d 100644
--- a/nbd/client.c
+++ b/nbd/client.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2016-2019 Red Hat, Inc.
+ * Copyright Red Hat
* Copyright (C) 2005 Anthony Liguori <anthony@codemonkey.ws>
*
* Network Block Device Client Side
@@ -650,19 +650,20 @@
Error **errp)
{
int ret;
- uint32_t export_len = strlen(export);
+ uint32_t export_len;
uint32_t queries = !!query;
uint32_t query_len = 0;
uint32_t data_len;
char *data;
char *p;
+ assert(strnlen(export, NBD_MAX_STRING_SIZE + 1) <= NBD_MAX_STRING_SIZE);
+ export_len = strlen(export);
data_len = sizeof(export_len) + export_len + sizeof(queries);
- assert(export_len <= NBD_MAX_STRING_SIZE);
if (query) {
+ assert(strnlen(query, NBD_MAX_STRING_SIZE + 1) <= NBD_MAX_STRING_SIZE);
query_len = strlen(query);
data_len += sizeof(query_len) + query_len;
- assert(query_len <= NBD_MAX_STRING_SIZE);
} else {
assert(opt == NBD_OPT_LIST_META_CONTEXT);
}
@@ -874,10 +875,7 @@
* Start the handshake to the server. After a positive return, the server
* is ready to accept additional NBD_OPT requests.
* Returns: negative errno: failure talking to server
- * 0: server is oldstyle, must call nbd_negotiate_finish_oldstyle
- * 1: server is newstyle, but can only accept EXPORT_NAME
- * 2: server is newstyle, but lacks structured replies
- * 3: server is newstyle and set up for structured replies
+ * non-negative: enum NBDMode describing server abilities
*/
static int nbd_start_negotiate(AioContext *aio_context, QIOChannel *ioc,
QCryptoTLSCreds *tlscreds,
@@ -968,16 +966,16 @@
return -EINVAL;
}
}
- return 2 + result;
+ return result ? NBD_MODE_STRUCTURED : NBD_MODE_SIMPLE;
} else {
- return 1;
+ return NBD_MODE_EXPORT_NAME;
}
} else if (magic == NBD_CLIENT_MAGIC) {
if (tlscreds) {
error_setg(errp, "Server does not support STARTTLS");
return -EINVAL;
}
- return 0;
+ return NBD_MODE_OLDSTYLE;
} else {
error_setg(errp, "Bad server magic received: 0x%" PRIx64, magic);
return -EINVAL;
@@ -1031,6 +1029,9 @@
result = nbd_start_negotiate(aio_context, ioc, tlscreds, hostname, outioc,
info->structured_reply, &zeroes, errp);
+ if (result < 0) {
+ return result;
+ }
info->structured_reply = false;
info->base_allocation = false;
@@ -1038,8 +1039,8 @@
ioc = *outioc;
}
- switch (result) {
- case 3: /* newstyle, with structured replies */
+ switch ((NBDMode)result) {
+ case NBD_MODE_STRUCTURED:
info->structured_reply = true;
if (base_allocation) {
result = nbd_negotiate_simple_meta_context(ioc, info, errp);
@@ -1049,7 +1050,7 @@
info->base_allocation = result == 1;
}
/* fall through */
- case 2: /* newstyle, try OPT_GO */
+ case NBD_MODE_SIMPLE:
/* Try NBD_OPT_GO first - if it works, we are done (it
* also gives us a good message if the server requires
* TLS). If it is not available, fall back to
@@ -1072,7 +1073,7 @@
return -EINVAL;
}
/* fall through */
- case 1: /* newstyle, but limited to EXPORT_NAME */
+ case NBD_MODE_EXPORT_NAME:
/* write the export name request */
if (nbd_send_option_request(ioc, NBD_OPT_EXPORT_NAME, -1, info->name,
errp) < 0) {
@@ -1088,7 +1089,7 @@
return -EINVAL;
}
break;
- case 0: /* oldstyle, parse length and flags */
+ case NBD_MODE_OLDSTYLE:
if (*info->name) {
error_setg(errp, "Server does not support non-empty export names");
return -EINVAL;
@@ -1098,7 +1099,7 @@
}
break;
default:
- return result;
+ g_assert_not_reached();
}
trace_nbd_receive_negotiate_size_flags(info->size, info->flags);
@@ -1154,10 +1155,13 @@
if (tlscreds && sioc) {
ioc = sioc;
}
+ if (result < 0) {
+ goto out;
+ }
- switch (result) {
- case 2:
- case 3:
+ switch ((NBDMode)result) {
+ case NBD_MODE_SIMPLE:
+ case NBD_MODE_STRUCTURED:
/* newstyle - use NBD_OPT_LIST to populate array, then try
* NBD_OPT_INFO on each array member. If structured replies
* are enabled, also try NBD_OPT_LIST_META_CONTEXT. */
@@ -1178,7 +1182,7 @@
memset(&array[count - 1], 0, sizeof(*array));
array[count - 1].name = name;
array[count - 1].description = desc;
- array[count - 1].structured_reply = result == 3;
+ array[count - 1].structured_reply = result == NBD_MODE_STRUCTURED;
}
for (i = 0; i < count; i++) {
@@ -1194,7 +1198,7 @@
break;
}
- if (result == 3 &&
+ if (result == NBD_MODE_STRUCTURED &&
nbd_list_meta_contexts(ioc, &array[i], errp) < 0) {
goto out;
}
@@ -1203,11 +1207,12 @@
/* Send NBD_OPT_ABORT as a courtesy before hanging up */
nbd_send_opt_abort(ioc);
break;
- case 1: /* newstyle, but limited to EXPORT_NAME */
+ case NBD_MODE_EXPORT_NAME:
error_setg(errp, "Server does not support export lists");
/* We can't even send NBD_OPT_ABORT, so merely hang up */
goto out;
- case 0: /* oldstyle, parse length and flags */
+ case NBD_MODE_OLDSTYLE:
+ /* Lone export name is implied, but we can parse length and flags */
array = g_new0(NBDExportInfo, 1);
array->name = g_strdup("");
count = 1;
@@ -1225,7 +1230,7 @@
}
break;
default:
- goto out;
+ g_assert_not_reached();
}
*info = array;
@@ -1349,14 +1354,14 @@
{
uint8_t buf[NBD_REQUEST_SIZE];
- trace_nbd_send_request(request->from, request->len, request->handle,
+ trace_nbd_send_request(request->from, request->len, request->cookie,
request->flags, request->type,
nbd_cmd_lookup(request->type));
stl_be_p(buf, NBD_REQUEST_MAGIC);
stw_be_p(buf + 4, request->flags);
stw_be_p(buf + 6, request->type);
- stq_be_p(buf + 8, request->handle);
+ stq_be_p(buf + 8, request->cookie);
stq_be_p(buf + 16, request->from);
stl_be_p(buf + 24, request->len);
@@ -1382,7 +1387,7 @@
}
reply->error = be32_to_cpu(reply->error);
- reply->handle = be64_to_cpu(reply->handle);
+ reply->cookie = be64_to_cpu(reply->cookie);
return 0;
}
@@ -1409,9 +1414,21 @@
chunk->flags = be16_to_cpu(chunk->flags);
chunk->type = be16_to_cpu(chunk->type);
- chunk->handle = be64_to_cpu(chunk->handle);
+ chunk->cookie = be64_to_cpu(chunk->cookie);
chunk->length = be32_to_cpu(chunk->length);
+ /*
+ * Because we use BLOCK_STATUS with REQ_ONE, and cap READ requests
+ * at 32M, no valid server should send us payload larger than
+ * this. Even if we stopped using REQ_ONE, sane servers will cap
+ * the number of extents they return for block status.
+ */
+ if (chunk->length > NBD_MAX_BUFFER_SIZE + sizeof(NBDStructuredReadData)) {
+ error_setg(errp, "server chunk %" PRIu32 " (%s) payload is too long",
+ chunk->type, nbd_rep_lookup(chunk->type));
+ return -EINVAL;
+ }
+
return 0;
}
@@ -1486,7 +1503,7 @@
}
trace_nbd_receive_simple_reply(reply->simple.error,
nbd_err_lookup(reply->simple.error),
- reply->handle);
+ reply->cookie);
break;
case NBD_STRUCTURED_REPLY_MAGIC:
ret = nbd_receive_structured_reply_chunk(ioc, &reply->structured, errp);
@@ -1496,7 +1513,7 @@
type = nbd_reply_type_lookup(reply->structured.type);
trace_nbd_receive_structured_reply_chunk(reply->structured.flags,
reply->structured.type, type,
- reply->structured.handle,
+ reply->structured.cookie,
reply->structured.length);
break;
default:
diff --git a/nbd/common.c b/nbd/common.c
index ddfe7d1..989fbe5 100644
--- a/nbd/common.c
+++ b/nbd/common.c
@@ -248,3 +248,20 @@
}
return ret;
}
+
+
+const char *nbd_mode_lookup(NBDMode mode)
+{
+ switch (mode) {
+ case NBD_MODE_OLDSTYLE:
+ return "oldstyle";
+ case NBD_MODE_EXPORT_NAME:
+ return "export name only";
+ case NBD_MODE_SIMPLE:
+ return "simple headers";
+ case NBD_MODE_STRUCTURED:
+ return "structured replies";
+ default:
+ return "<unknown>";
+ }
+}
diff --git a/nbd/server.c b/nbd/server.c
index febe001..8486b64 100644
--- a/nbd/server.c
+++ b/nbd/server.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2016-2022 Red Hat, Inc.
+ * Copyright Red Hat
* Copyright (C) 2005 Anthony Liguori <anthony@codemonkey.ws>
*
* Network Block Device Server Side
@@ -1428,7 +1428,7 @@
[ 0 .. 3] magic (NBD_REQUEST_MAGIC)
[ 4 .. 5] flags (NBD_CMD_FLAG_FUA, ...)
[ 6 .. 7] type (NBD_CMD_READ, ...)
- [ 8 .. 15] handle
+ [ 8 .. 15] cookie
[16 .. 23] from
[24 .. 27] len
*/
@@ -1436,7 +1436,7 @@
magic = ldl_be_p(buf);
request->flags = lduw_be_p(buf + 4);
request->type = lduw_be_p(buf + 6);
- request->handle = ldq_be_p(buf + 8);
+ request->cookie = ldq_be_p(buf + 8);
request->from = ldq_be_p(buf + 16);
request->len = ldl_be_p(buf + 24);
@@ -1885,15 +1885,15 @@
}
static inline void set_be_simple_reply(NBDSimpleReply *reply, uint64_t error,
- uint64_t handle)
+ uint64_t cookie)
{
stl_be_p(&reply->magic, NBD_SIMPLE_REPLY_MAGIC);
stl_be_p(&reply->error, error);
- stq_be_p(&reply->handle, handle);
+ stq_be_p(&reply->cookie, cookie);
}
static int coroutine_fn nbd_co_send_simple_reply(NBDClient *client,
- uint64_t handle,
+ NBDRequest *request,
uint32_t error,
void *data,
size_t len,
@@ -1906,84 +1906,108 @@
{.iov_base = data, .iov_len = len}
};
- trace_nbd_co_send_simple_reply(handle, nbd_err, nbd_err_lookup(nbd_err),
- len);
- set_be_simple_reply(&reply, nbd_err, handle);
+ assert(!len || !nbd_err);
+ assert(!client->structured_reply || request->type != NBD_CMD_READ);
+ trace_nbd_co_send_simple_reply(request->cookie, nbd_err,
+ nbd_err_lookup(nbd_err), len);
+ set_be_simple_reply(&reply, nbd_err, request->cookie);
- return nbd_co_send_iov(client, iov, len ? 2 : 1, errp);
+ return nbd_co_send_iov(client, iov, 2, errp);
}
-static inline void set_be_chunk(NBDStructuredReplyChunk *chunk, uint16_t flags,
- uint16_t type, uint64_t handle, uint32_t length)
+/*
+ * Prepare the header of a reply chunk for network transmission.
+ *
+ * On input, @iov is partially initialized: iov[0].iov_base must point
+ * to an uninitialized NBDReply, while the remaining @niov elements
+ * (if any) must be ready for transmission. This function then
+ * populates iov[0] for transmission.
+ */
+static inline void set_be_chunk(NBDClient *client, struct iovec *iov,
+ size_t niov, uint16_t flags, uint16_t type,
+ NBDRequest *request)
{
+ /* TODO - handle structured vs. extended replies */
+ NBDStructuredReplyChunk *chunk = iov->iov_base;
+ size_t i, length = 0;
+
+ for (i = 1; i < niov; i++) {
+ length += iov[i].iov_len;
+ }
+ assert(length <= NBD_MAX_BUFFER_SIZE + sizeof(NBDStructuredReadData));
+
+ iov[0].iov_len = sizeof(*chunk);
stl_be_p(&chunk->magic, NBD_STRUCTURED_REPLY_MAGIC);
stw_be_p(&chunk->flags, flags);
stw_be_p(&chunk->type, type);
- stq_be_p(&chunk->handle, handle);
+ stq_be_p(&chunk->cookie, request->cookie);
stl_be_p(&chunk->length, length);
}
-static int coroutine_fn nbd_co_send_structured_done(NBDClient *client,
- uint64_t handle,
- Error **errp)
+static int coroutine_fn nbd_co_send_chunk_done(NBDClient *client,
+ NBDRequest *request,
+ Error **errp)
{
- NBDStructuredReplyChunk chunk;
+ NBDReply hdr;
struct iovec iov[] = {
- {.iov_base = &chunk, .iov_len = sizeof(chunk)},
+ {.iov_base = &hdr},
};
- trace_nbd_co_send_structured_done(handle);
- set_be_chunk(&chunk, NBD_REPLY_FLAG_DONE, NBD_REPLY_TYPE_NONE, handle, 0);
-
+ trace_nbd_co_send_chunk_done(request->cookie);
+ set_be_chunk(client, iov, 1, NBD_REPLY_FLAG_DONE,
+ NBD_REPLY_TYPE_NONE, request);
return nbd_co_send_iov(client, iov, 1, errp);
}
-static int coroutine_fn nbd_co_send_structured_read(NBDClient *client,
- uint64_t handle,
- uint64_t offset,
- void *data,
- size_t size,
- bool final,
- Error **errp)
+static int coroutine_fn nbd_co_send_chunk_read(NBDClient *client,
+ NBDRequest *request,
+ uint64_t offset,
+ void *data,
+ size_t size,
+ bool final,
+ Error **errp)
{
+ NBDReply hdr;
NBDStructuredReadData chunk;
struct iovec iov[] = {
+ {.iov_base = &hdr},
{.iov_base = &chunk, .iov_len = sizeof(chunk)},
{.iov_base = data, .iov_len = size}
};
assert(size);
- trace_nbd_co_send_structured_read(handle, offset, data, size);
- set_be_chunk(&chunk.h, final ? NBD_REPLY_FLAG_DONE : 0,
- NBD_REPLY_TYPE_OFFSET_DATA, handle,
- sizeof(chunk) - sizeof(chunk.h) + size);
+ trace_nbd_co_send_chunk_read(request->cookie, offset, data, size);
+ set_be_chunk(client, iov, 3, final ? NBD_REPLY_FLAG_DONE : 0,
+ NBD_REPLY_TYPE_OFFSET_DATA, request);
stq_be_p(&chunk.offset, offset);
- return nbd_co_send_iov(client, iov, 2, errp);
+ return nbd_co_send_iov(client, iov, 3, errp);
}
-
-static int coroutine_fn nbd_co_send_structured_error(NBDClient *client,
- uint64_t handle,
- uint32_t error,
- const char *msg,
- Error **errp)
+/*ebb*/
+static int coroutine_fn nbd_co_send_chunk_error(NBDClient *client,
+ NBDRequest *request,
+ uint32_t error,
+ const char *msg,
+ Error **errp)
{
+ NBDReply hdr;
NBDStructuredError chunk;
int nbd_err = system_errno_to_nbd_errno(error);
struct iovec iov[] = {
+ {.iov_base = &hdr},
{.iov_base = &chunk, .iov_len = sizeof(chunk)},
{.iov_base = (char *)msg, .iov_len = msg ? strlen(msg) : 0},
};
assert(nbd_err);
- trace_nbd_co_send_structured_error(handle, nbd_err,
- nbd_err_lookup(nbd_err), msg ? msg : "");
- set_be_chunk(&chunk.h, NBD_REPLY_FLAG_DONE, NBD_REPLY_TYPE_ERROR, handle,
- sizeof(chunk) - sizeof(chunk.h) + iov[1].iov_len);
+ trace_nbd_co_send_chunk_error(request->cookie, nbd_err,
+ nbd_err_lookup(nbd_err), msg ? msg : "");
+ set_be_chunk(client, iov, 3, NBD_REPLY_FLAG_DONE,
+ NBD_REPLY_TYPE_ERROR, request);
stl_be_p(&chunk.error, nbd_err);
- stw_be_p(&chunk.message_length, iov[1].iov_len);
+ stw_be_p(&chunk.message_length, iov[2].iov_len);
- return nbd_co_send_iov(client, iov, 1 + !!iov[1].iov_len, errp);
+ return nbd_co_send_iov(client, iov, 3, errp);
}
/* Do a sparse read and send the structured reply to the client.
@@ -1991,7 +2015,7 @@
* reported to the client, at which point this function succeeds.
*/
static int coroutine_fn nbd_co_send_sparse_read(NBDClient *client,
- uint64_t handle,
+ NBDRequest *request,
uint64_t offset,
uint8_t *data,
size_t size,
@@ -2013,27 +2037,28 @@
char *msg = g_strdup_printf("unable to check for holes: %s",
strerror(-status));
- ret = nbd_co_send_structured_error(client, handle, -status, msg,
- errp);
+ ret = nbd_co_send_chunk_error(client, request, -status, msg, errp);
g_free(msg);
return ret;
}
assert(pnum && pnum <= size - progress);
final = progress + pnum == size;
if (status & BDRV_BLOCK_ZERO) {
+ NBDReply hdr;
NBDStructuredReadHole chunk;
struct iovec iov[] = {
+ {.iov_base = &hdr},
{.iov_base = &chunk, .iov_len = sizeof(chunk)},
};
- trace_nbd_co_send_structured_read_hole(handle, offset + progress,
- pnum);
- set_be_chunk(&chunk.h, final ? NBD_REPLY_FLAG_DONE : 0,
- NBD_REPLY_TYPE_OFFSET_HOLE,
- handle, sizeof(chunk) - sizeof(chunk.h));
+ trace_nbd_co_send_chunk_read_hole(request->cookie,
+ offset + progress, pnum);
+ set_be_chunk(client, iov, 2,
+ final ? NBD_REPLY_FLAG_DONE : 0,
+ NBD_REPLY_TYPE_OFFSET_HOLE, request);
stq_be_p(&chunk.offset, offset + progress);
stl_be_p(&chunk.length, pnum);
- ret = nbd_co_send_iov(client, iov, 1, errp);
+ ret = nbd_co_send_iov(client, iov, 2, errp);
} else {
ret = blk_co_pread(exp->common.blk, offset + progress, pnum,
data + progress, 0);
@@ -2041,9 +2066,8 @@
error_setg_errno(errp, -ret, "reading from file failed");
break;
}
- ret = nbd_co_send_structured_read(client, handle, offset + progress,
- data + progress, pnum, final,
- errp);
+ ret = nbd_co_send_chunk_read(client, request, offset + progress,
+ data + progress, pnum, final, errp);
}
if (ret < 0) {
@@ -2196,30 +2220,31 @@
* @last controls whether NBD_REPLY_FLAG_DONE is sent.
*/
static int coroutine_fn
-nbd_co_send_extents(NBDClient *client, uint64_t handle, NBDExtentArray *ea,
+nbd_co_send_extents(NBDClient *client, NBDRequest *request, NBDExtentArray *ea,
bool last, uint32_t context_id, Error **errp)
{
+ NBDReply hdr;
NBDStructuredMeta chunk;
struct iovec iov[] = {
+ {.iov_base = &hdr},
{.iov_base = &chunk, .iov_len = sizeof(chunk)},
{.iov_base = ea->extents, .iov_len = ea->count * sizeof(ea->extents[0])}
};
nbd_extent_array_convert_to_be(ea);
- trace_nbd_co_send_extents(handle, ea->count, context_id, ea->total_length,
- last);
- set_be_chunk(&chunk.h, last ? NBD_REPLY_FLAG_DONE : 0,
- NBD_REPLY_TYPE_BLOCK_STATUS,
- handle, sizeof(chunk) - sizeof(chunk.h) + iov[1].iov_len);
+ trace_nbd_co_send_extents(request->cookie, ea->count, context_id,
+ ea->total_length, last);
+ set_be_chunk(client, iov, 3, last ? NBD_REPLY_FLAG_DONE : 0,
+ NBD_REPLY_TYPE_BLOCK_STATUS, request);
stl_be_p(&chunk.context_id, context_id);
- return nbd_co_send_iov(client, iov, 2, errp);
+ return nbd_co_send_iov(client, iov, 3, errp);
}
/* Get block status from the exported device and send it to the client */
static int
-coroutine_fn nbd_co_send_block_status(NBDClient *client, uint64_t handle,
+coroutine_fn nbd_co_send_block_status(NBDClient *client, NBDRequest *request,
BlockBackend *blk, uint64_t offset,
uint32_t length, bool dont_fragment,
bool last, uint32_t context_id,
@@ -2235,11 +2260,11 @@
ret = blockalloc_to_extents(blk, offset, length, ea);
}
if (ret < 0) {
- return nbd_co_send_structured_error(
- client, handle, -ret, "can't get block status", errp);
+ return nbd_co_send_chunk_error(client, request, -ret,
+ "can't get block status", errp);
}
- return nbd_co_send_extents(client, handle, ea, last, context_id, errp);
+ return nbd_co_send_extents(client, request, ea, last, context_id, errp);
}
/* Populate @ea from a dirty bitmap. */
@@ -2274,17 +2299,20 @@
bdrv_dirty_bitmap_unlock(bitmap);
}
-static int coroutine_fn nbd_co_send_bitmap(NBDClient *client, uint64_t handle,
- BdrvDirtyBitmap *bitmap, uint64_t offset,
- uint32_t length, bool dont_fragment, bool last,
- uint32_t context_id, Error **errp)
+static int coroutine_fn nbd_co_send_bitmap(NBDClient *client,
+ NBDRequest *request,
+ BdrvDirtyBitmap *bitmap,
+ uint64_t offset,
+ uint32_t length, bool dont_fragment,
+ bool last, uint32_t context_id,
+ Error **errp)
{
unsigned int nb_extents = dont_fragment ? 1 : NBD_MAX_BLOCK_STATUS_EXTENTS;
g_autoptr(NBDExtentArray) ea = nbd_extent_array_new(nb_extents);
bitmap_to_extents(bitmap, offset, length, ea);
- return nbd_co_send_extents(client, handle, ea, last, context_id, errp);
+ return nbd_co_send_extents(client, request, ea, last, context_id, errp);
}
/* nbd_co_receive_request
@@ -2308,7 +2336,7 @@
return ret;
}
- trace_nbd_co_receive_request_decode_type(request->handle, request->type,
+ trace_nbd_co_receive_request_decode_type(request->cookie, request->type,
nbd_cmd_lookup(request->type));
if (request->type != NBD_CMD_WRITE) {
@@ -2349,7 +2377,7 @@
}
req->complete = true;
- trace_nbd_co_receive_request_payload_received(request->handle,
+ trace_nbd_co_receive_request_payload_received(request->cookie,
request->len);
}
@@ -2402,16 +2430,15 @@
* Returns 0 if connection is still live, -errno on failure to talk to client
*/
static coroutine_fn int nbd_send_generic_reply(NBDClient *client,
- uint64_t handle,
+ NBDRequest *request,
int ret,
const char *error_msg,
Error **errp)
{
if (client->structured_reply && ret < 0) {
- return nbd_co_send_structured_error(client, handle, -ret, error_msg,
- errp);
+ return nbd_co_send_chunk_error(client, request, -ret, error_msg, errp);
} else {
- return nbd_co_send_simple_reply(client, handle, ret < 0 ? -ret : 0,
+ return nbd_co_send_simple_reply(client, request, ret < 0 ? -ret : 0,
NULL, 0, errp);
}
}
@@ -2431,7 +2458,7 @@
if (request->flags & NBD_CMD_FLAG_FUA) {
ret = blk_co_flush(exp->common.blk);
if (ret < 0) {
- return nbd_send_generic_reply(client, request->handle, ret,
+ return nbd_send_generic_reply(client, request, ret,
"flush failed", errp);
}
}
@@ -2439,26 +2466,25 @@
if (client->structured_reply && !(request->flags & NBD_CMD_FLAG_DF) &&
request->len)
{
- return nbd_co_send_sparse_read(client, request->handle, request->from,
+ return nbd_co_send_sparse_read(client, request, request->from,
data, request->len, errp);
}
ret = blk_co_pread(exp->common.blk, request->from, request->len, data, 0);
if (ret < 0) {
- return nbd_send_generic_reply(client, request->handle, ret,
+ return nbd_send_generic_reply(client, request, ret,
"reading from file failed", errp);
}
if (client->structured_reply) {
if (request->len) {
- return nbd_co_send_structured_read(client, request->handle,
- request->from, data,
- request->len, true, errp);
+ return nbd_co_send_chunk_read(client, request, request->from, data,
+ request->len, true, errp);
} else {
- return nbd_co_send_structured_done(client, request->handle, errp);
+ return nbd_co_send_chunk_done(client, request, errp);
}
} else {
- return nbd_co_send_simple_reply(client, request->handle, 0,
+ return nbd_co_send_simple_reply(client, request, 0,
data, request->len, errp);
}
}
@@ -2481,7 +2507,7 @@
ret = blk_co_preadv(exp->common.blk, request->from, request->len,
NULL, BDRV_REQ_COPY_ON_READ | BDRV_REQ_PREFETCH);
- return nbd_send_generic_reply(client, request->handle, ret,
+ return nbd_send_generic_reply(client, request, ret,
"caching data failed", errp);
}
@@ -2512,7 +2538,7 @@
}
ret = blk_co_pwrite(exp->common.blk, request->from, request->len, data,
flags);
- return nbd_send_generic_reply(client, request->handle, ret,
+ return nbd_send_generic_reply(client, request, ret,
"writing to file failed", errp);
case NBD_CMD_WRITE_ZEROES:
@@ -2528,7 +2554,7 @@
}
ret = blk_co_pwrite_zeroes(exp->common.blk, request->from, request->len,
flags);
- return nbd_send_generic_reply(client, request->handle, ret,
+ return nbd_send_generic_reply(client, request, ret,
"writing to file failed", errp);
case NBD_CMD_DISC:
@@ -2537,7 +2563,7 @@
case NBD_CMD_FLUSH:
ret = blk_co_flush(exp->common.blk);
- return nbd_send_generic_reply(client, request->handle, ret,
+ return nbd_send_generic_reply(client, request, ret,
"flush failed", errp);
case NBD_CMD_TRIM:
@@ -2545,12 +2571,12 @@
if (ret >= 0 && request->flags & NBD_CMD_FLAG_FUA) {
ret = blk_co_flush(exp->common.blk);
}
- return nbd_send_generic_reply(client, request->handle, ret,
+ return nbd_send_generic_reply(client, request, ret,
"discard failed", errp);
case NBD_CMD_BLOCK_STATUS:
if (!request->len) {
- return nbd_send_generic_reply(client, request->handle, -EINVAL,
+ return nbd_send_generic_reply(client, request, -EINVAL,
"need non-zero length", errp);
}
if (client->export_meta.count) {
@@ -2558,7 +2584,7 @@
int contexts_remaining = client->export_meta.count;
if (client->export_meta.base_allocation) {
- ret = nbd_co_send_block_status(client, request->handle,
+ ret = nbd_co_send_block_status(client, request,
exp->common.blk,
request->from,
request->len, dont_fragment,
@@ -2571,7 +2597,7 @@
}
if (client->export_meta.allocation_depth) {
- ret = nbd_co_send_block_status(client, request->handle,
+ ret = nbd_co_send_block_status(client, request,
exp->common.blk,
request->from, request->len,
dont_fragment,
@@ -2587,7 +2613,7 @@
if (!client->export_meta.bitmaps[i]) {
continue;
}
- ret = nbd_co_send_bitmap(client, request->handle,
+ ret = nbd_co_send_bitmap(client, request,
client->exp->export_bitmaps[i],
request->from, request->len,
dont_fragment, !--contexts_remaining,
@@ -2601,7 +2627,7 @@
return 0;
} else {
- return nbd_send_generic_reply(client, request->handle, -EINVAL,
+ return nbd_send_generic_reply(client, request, -EINVAL,
"CMD_BLOCK_STATUS not negotiated",
errp);
}
@@ -2609,7 +2635,7 @@
default:
msg = g_strdup_printf("invalid request type (%" PRIu32 ") received",
request->type);
- ret = nbd_send_generic_reply(client, request->handle, -EINVAL, msg,
+ ret = nbd_send_generic_reply(client, request, -EINVAL, msg,
errp);
g_free(msg);
return ret;
@@ -2672,7 +2698,7 @@
Error *export_err = local_err;
local_err = NULL;
- ret = nbd_send_generic_reply(client, request.handle, -EINVAL,
+ ret = nbd_send_generic_reply(client, &request, -EINVAL,
error_get_pretty(export_err), &local_err);
error_free(export_err);
} else {
diff --git a/nbd/trace-events b/nbd/trace-events
index b7032ca..f19a4d0 100644
--- a/nbd/trace-events
+++ b/nbd/trace-events
@@ -31,9 +31,9 @@
nbd_client_loop_ret(int ret, const char *error) "NBD loop returned %d: %s"
nbd_client_clear_queue(void) "Clearing NBD queue"
nbd_client_clear_socket(void) "Clearing NBD socket"
-nbd_send_request(uint64_t from, uint32_t len, uint64_t handle, uint16_t flags, uint16_t type, const char *name) "Sending request to server: { .from = %" PRIu64", .len = %" PRIu32 ", .handle = %" PRIu64 ", .flags = 0x%" PRIx16 ", .type = %" PRIu16 " (%s) }"
-nbd_receive_simple_reply(int32_t error, const char *errname, uint64_t handle) "Got simple reply: { .error = %" PRId32 " (%s), handle = %" PRIu64" }"
-nbd_receive_structured_reply_chunk(uint16_t flags, uint16_t type, const char *name, uint64_t handle, uint32_t length) "Got structured reply chunk: { flags = 0x%" PRIx16 ", type = %d (%s), handle = %" PRIu64 ", length = %" PRIu32 " }"
+nbd_send_request(uint64_t from, uint32_t len, uint64_t cookie, uint16_t flags, uint16_t type, const char *name) "Sending request to server: { .from = %" PRIu64", .len = %" PRIu32 ", .cookie = %" PRIu64 ", .flags = 0x%" PRIx16 ", .type = %" PRIu16 " (%s) }"
+nbd_receive_simple_reply(int32_t error, const char *errname, uint64_t cookie) "Got simple reply: { .error = %" PRId32 " (%s), cookie = %" PRIu64" }"
+nbd_receive_structured_reply_chunk(uint16_t flags, uint16_t type, const char *name, uint64_t cookie, uint32_t length) "Got structured reply chunk: { flags = 0x%" PRIx16 ", type = %d (%s), cookie = %" PRIu64 ", length = %" PRIu32 " }"
# common.c
nbd_unknown_error(int err) "Squashing unexpected error %d to EINVAL"
@@ -63,14 +63,14 @@
nbd_receive_request(uint32_t magic, uint16_t flags, uint16_t type, uint64_t from, uint32_t len) "Got request: { magic = 0x%" PRIx32 ", .flags = 0x%" PRIx16 ", .type = 0x%" PRIx16 ", from = %" PRIu64 ", len = %" PRIu32 " }"
nbd_blk_aio_attached(const char *name, void *ctx) "Export %s: Attaching clients to AIO context %p"
nbd_blk_aio_detach(const char *name, void *ctx) "Export %s: Detaching clients from AIO context %p"
-nbd_co_send_simple_reply(uint64_t handle, uint32_t error, const char *errname, int len) "Send simple reply: handle = %" PRIu64 ", error = %" PRIu32 " (%s), len = %d"
-nbd_co_send_structured_done(uint64_t handle) "Send structured reply done: handle = %" PRIu64
-nbd_co_send_structured_read(uint64_t handle, uint64_t offset, void *data, size_t size) "Send structured read data reply: handle = %" PRIu64 ", offset = %" PRIu64 ", data = %p, len = %zu"
-nbd_co_send_structured_read_hole(uint64_t handle, uint64_t offset, size_t size) "Send structured read hole reply: handle = %" PRIu64 ", offset = %" PRIu64 ", len = %zu"
-nbd_co_send_extents(uint64_t handle, unsigned int extents, uint32_t id, uint64_t length, int last) "Send block status reply: handle = %" PRIu64 ", extents = %u, context = %d (extents cover %" PRIu64 " bytes, last chunk = %d)"
-nbd_co_send_structured_error(uint64_t handle, int err, const char *errname, const char *msg) "Send structured error reply: handle = %" PRIu64 ", error = %d (%s), msg = '%s'"
-nbd_co_receive_request_decode_type(uint64_t handle, uint16_t type, const char *name) "Decoding type: handle = %" PRIu64 ", type = %" PRIu16 " (%s)"
-nbd_co_receive_request_payload_received(uint64_t handle, uint32_t len) "Payload received: handle = %" PRIu64 ", len = %" PRIu32
+nbd_co_send_simple_reply(uint64_t cookie, uint32_t error, const char *errname, int len) "Send simple reply: cookie = %" PRIu64 ", error = %" PRIu32 " (%s), len = %d"
+nbd_co_send_chunk_done(uint64_t cookie) "Send structured reply done: cookie = %" PRIu64
+nbd_co_send_chunk_read(uint64_t cookie, uint64_t offset, void *data, size_t size) "Send structured read data reply: cookie = %" PRIu64 ", offset = %" PRIu64 ", data = %p, len = %zu"
+nbd_co_send_chunk_read_hole(uint64_t cookie, uint64_t offset, size_t size) "Send structured read hole reply: cookie = %" PRIu64 ", offset = %" PRIu64 ", len = %zu"
+nbd_co_send_extents(uint64_t cookie, unsigned int extents, uint32_t id, uint64_t length, int last) "Send block status reply: cookie = %" PRIu64 ", extents = %u, context = %d (extents cover %" PRIu64 " bytes, last chunk = %d)"
+nbd_co_send_chunk_error(uint64_t cookie, int err, const char *errname, const char *msg) "Send structured error reply: cookie = %" PRIu64 ", error = %d (%s), msg = '%s'"
+nbd_co_receive_request_decode_type(uint64_t cookie, uint16_t type, const char *name) "Decoding type: cookie = %" PRIu64 ", type = %" PRIu16 " (%s)"
+nbd_co_receive_request_payload_received(uint64_t cookie, uint32_t len) "Payload received: cookie = %" PRIu64 ", len = %" PRIu32
nbd_co_receive_align_compliance(const char *op, uint64_t from, uint32_t len, uint32_t align) "client sent non-compliant unaligned %s request: from=0x%" PRIx64 ", len=0x%" PRIx32 ", align=0x%" PRIx32
nbd_trip(void) "Reading request"
diff --git a/pc-bios/opensbi-riscv32-generic-fw_dynamic.bin b/pc-bios/opensbi-riscv32-generic-fw_dynamic.bin
index 7b6c67e..9a2ba3f 100644
--- a/pc-bios/opensbi-riscv32-generic-fw_dynamic.bin
+++ b/pc-bios/opensbi-riscv32-generic-fw_dynamic.bin
Binary files differ
diff --git a/pc-bios/opensbi-riscv64-generic-fw_dynamic.bin b/pc-bios/opensbi-riscv64-generic-fw_dynamic.bin
index 1b831b4..5d4e812 100644
--- a/pc-bios/opensbi-riscv64-generic-fw_dynamic.bin
+++ b/pc-bios/opensbi-riscv64-generic-fw_dynamic.bin
Binary files differ
diff --git a/qapi/audio.json b/qapi/audio.json
index 534f10d..519697c 100644
--- a/qapi/audio.json
+++ b/qapi/audio.json
@@ -328,17 +328,17 @@
##
# @AudiodevPipewirePerDirectionOptions:
#
-# Options of the Pipewire backend that are used for both playback and
+# Options of the PipeWire backend that are used for both playback and
# recording.
#
# @name: name of the sink/source to use
#
-# @stream-name: name of the Pipewire stream created by qemu. Can be
-# used to identify the stream in Pipewire when you create multiple
-# Pipewire devices or run multiple qemu instances (default:
+# @stream-name: name of the PipeWire stream created by qemu. Can be
+# used to identify the stream in PipeWire when you create multiple
+# PipeWire devices or run multiple qemu instances (default:
# audiodev's id)
#
-# @latency: latency you want Pipewire to achieve in microseconds
+# @latency: latency you want PipeWire to achieve in microseconds
# (default 46000)
#
# Since: 8.1
@@ -353,7 +353,7 @@
##
# @AudiodevPipewireOptions:
#
-# Options of the Pipewire audio backend.
+# Options of the PipeWire audio backend.
#
# @in: options of the capture stream
#
diff --git a/qapi/block-core.json b/qapi/block-core.json
index 5dd5f7e..2b1d493 100644
--- a/qapi/block-core.json
+++ b/qapi/block-core.json
@@ -136,7 +136,7 @@
#
# @filename: Name of the extent file
#
-# @format: Extent type (e.g. FLAT or SPARSE)
+# @format: Extent type (e.g. FLAT or SPARSE)
#
# @virtual-size: Number of bytes covered by this extent
#
@@ -652,10 +652,9 @@
# 10), [10, 50), [50, 100), [100, +inf).
#
# @bins: list of io request counts corresponding to histogram
-# intervals.
-# len(@bins) = len(@boundaries) + 1
-# For the example above, @bins may be something like [3, 1, 5, 2],
-# and corresponding histogram looks like:
+# intervals, one more element than @boundaries has. For the
+# example above, @bins may be something like [3, 1, 5, 2], and
+# corresponding histogram looks like:
#
# ::
#
@@ -854,9 +853,8 @@
# @min_wr_latency_ns: Minimum latency of write operations in the
# defined interval, in nanoseconds.
#
-# @min_zone_append_latency_ns: Minimum latency of zone append operations
-# in the defined interval, in nanoseconds
-# (since 8.1)
+# @min_zone_append_latency_ns: Minimum latency of zone append
+# operations in the defined interval, in nanoseconds (since 8.1)
#
# @min_flush_latency_ns: Minimum latency of flush operations in the
# defined interval, in nanoseconds.
@@ -867,9 +865,8 @@
# @max_wr_latency_ns: Maximum latency of write operations in the
# defined interval, in nanoseconds.
#
-# @max_zone_append_latency_ns: Maximum latency of zone append operations
-# in the defined interval, in nanoseconds
-# (since 8.1)
+# @max_zone_append_latency_ns: Maximum latency of zone append
+# operations in the defined interval, in nanoseconds (since 8.1)
#
# @max_flush_latency_ns: Maximum latency of flush operations in the
# defined interval, in nanoseconds.
@@ -880,9 +877,8 @@
# @avg_wr_latency_ns: Average latency of write operations in the
# defined interval, in nanoseconds.
#
-# @avg_zone_append_latency_ns: Average latency of zone append operations
-# in the defined interval, in nanoseconds
-# (since 8.1)
+# @avg_zone_append_latency_ns: Average latency of zone append
+# operations in the defined interval, in nanoseconds (since 8.1)
#
# @avg_flush_latency_ns: Average latency of flush operations in the
# defined interval, in nanoseconds.
@@ -894,8 +890,7 @@
# the defined interval.
#
# @avg_zone_append_queue_depth: Average number of pending zone append
-# operations in the defined interval
-# (since 8.1).
+# operations in the defined interval (since 8.1).
#
# Since: 2.5
##
@@ -920,8 +915,8 @@
#
# @wr_bytes: The number of bytes written by the device.
#
-# @zone_append_bytes: The number of bytes appended by the zoned devices
-# (since 8.1)
+# @zone_append_bytes: The number of bytes appended by the zoned
+# devices (since 8.1)
#
# @unmap_bytes: The number of bytes unmapped by the device (Since 4.2)
#
@@ -931,8 +926,8 @@
# @wr_operations: The number of write operations performed by the
# device.
#
-# @zone_append_operations: The number of zone append operations performed
-# by the zoned devices (since 8.1)
+# @zone_append_operations: The number of zone append operations
+# performed by the zoned devices (since 8.1)
#
# @flush_operations: The number of cache flush operations performed by
# the device (since 0.15)
@@ -947,7 +942,7 @@
# 0.15).
#
# @zone_append_total_time_ns: Total time spent on zone append writes
-# in nanoseconds (since 8.1)
+# in nanoseconds (since 8.1)
#
# @flush_total_time_ns: Total time spent on cache flushes in
# nanoseconds (since 0.15).
@@ -966,8 +961,8 @@
# @wr_merged: Number of write requests that have been merged into
# another request (Since 2.3).
#
-# @zone_append_merged: Number of zone append requests that have been merged
-# into another request (since 8.1)
+# @zone_append_merged: Number of zone append requests that have been
+# merged into another request (since 8.1)
#
# @unmap_merged: Number of unmap requests that have been merged into
# another request (Since 4.2)
@@ -982,9 +977,8 @@
# @failed_wr_operations: The number of failed write operations
# performed by the device (Since 2.5)
#
-# @failed_zone_append_operations: The number of failed zone append write
-# operations performed by the zoned devices
-# (since 8.1)
+# @failed_zone_append_operations: The number of failed zone append
+# write operations performed by the zoned devices (since 8.1)
#
# @failed_flush_operations: The number of failed flush operations
# performed by the device (Since 2.5)
@@ -998,8 +992,8 @@
# @invalid_wr_operations: The number of invalid write operations
# performed by the device (Since 2.5)
#
-# @invalid_zone_append_operations: The number of invalid zone append operations
-# performed by the zoned device (since 8.1)
+# @invalid_zone_append_operations: The number of invalid zone append
+# operations performed by the zoned device (since 8.1)
#
# @invalid_flush_operations: The number of invalid flush operations
# performed by the device (Since 2.5)
@@ -1020,7 +1014,8 @@
#
# @wr_latency_histogram: @BlockLatencyHistogramInfo. (Since 4.0)
#
-# @zone_append_latency_histogram: @BlockLatencyHistogramInfo. (since 8.1)
+# @zone_append_latency_histogram: @BlockLatencyHistogramInfo.
+# (since 8.1)
#
# @flush_latency_histogram: @BlockLatencyHistogramInfo. (Since 4.0)
#
@@ -1127,7 +1122,7 @@
#
# @parent: This describes the file block device if it has one.
# Contains recursively the statistics of the underlying protocol
-# (e.g. the host file for a qcow2 image). If there is no
+# (e.g. the host file for a qcow2 image). If there is no
# underlying protocol, this field is omitted
#
# @backing: This describes the backing block device if it has one.
@@ -1487,7 +1482,7 @@
# @format: the format of the overlay image, default is 'qcow2'.
#
# @mode: whether and how QEMU should create a new image, default is
-# 'absolute-paths'.
+# 'absolute-paths'.
##
{ 'struct': 'BlockdevSnapshotSync',
'data': { '*device': 'str', '*node-name': 'str',
@@ -1551,7 +1546,7 @@
#
# @bitmap: The name of a dirty bitmap to use. Must be present if sync
# is "bitmap" or "incremental". Can be present if sync is "full"
-# or "top". Must not be present otherwise.
+# or "top". Must not be present otherwise.
# (Since 2.4 (drive-backup), 3.1 (blockdev-backup))
#
# @bitmap-mode: Specifies the type of data the bitmap should contain
@@ -3478,16 +3473,16 @@
# @pass-discard-other: whether discard requests for the data source
# should be issued on other occasions where a cluster gets freed
#
-# @discard-no-unref: when enabled, discards from the guest will not cause
-# cluster allocations to be relinquished. This prevents qcow2 fragmentation
-# that would be caused by such discards. Besides potential
-# performance degradation, such fragmentation can lead to increased
-# allocation of clusters past the end of the image file,
-# resulting in image files whose file length can grow much larger
-# than their guest disk size would suggest.
-# If image file length is of concern (e.g. when storing qcow2
-# images directly on block devices), you should consider enabling
-# this option. (since 8.1)
+# @discard-no-unref: when enabled, discards from the guest will not
+# cause cluster allocations to be relinquished. This prevents
+# qcow2 fragmentation that would be caused by such discards.
+# Besides potential performance degradation, such fragmentation
+# can lead to increased allocation of clusters past the end of the
+# image file, resulting in image files whose file length can grow
+# much larger than their guest disk size would suggest. If image
+# file length is of concern (e.g. when storing qcow2 images
+# directly on block devices), you should consider enabling this
+# option. (since 8.1)
#
# @overlap-check: which overlap checks to perform for writes to the
# image, defaults to 'cached' (since 2.2)
@@ -5241,9 +5236,9 @@
#
# @subformat: vhdx subformat (default: dynamic)
#
-# @block-state-zero: Force use of payload blocks of type
-# 'ZERO'. Non-standard, but default. Do not set to 'off' when
-# using 'qemu-img convert' with subformat=dynamic.
+# @block-state-zero: Force use of payload blocks of type 'ZERO'.
+# Non-standard, but default. Do not set to 'off' when using
+# 'qemu-img convert' with subformat=dynamic.
#
# Since: 2.12
##
diff --git a/qapi/block.json b/qapi/block.json
index 0f25ce3..998008c 100644
--- a/qapi/block.json
+++ b/qapi/block.json
@@ -534,8 +534,8 @@
# @boundaries-write: list of interval boundary values for write
# latency histogram.
#
-# @boundaries-zap: list of interval boundary values for zone append write
-# latency histogram.
+# @boundaries-zap: list of interval boundary values for zone append
+# write latency histogram.
#
# @boundaries-flush: list of interval boundary values for flush
# latency histogram.
@@ -547,7 +547,7 @@
#
# Example:
#
-# set new histograms for all io types with intervals [0, 10), [10,
+# Set new histograms for all io types with intervals [0, 10), [10,
# 50), [50, 100), [100, +inf):
#
# -> { "execute": "block-latency-histogram-set",
@@ -557,7 +557,7 @@
#
# Example:
#
-# set new histogram only for write, other histograms will remain not
+# Set new histogram only for write, other histograms will remain not
# changed (or not created):
#
# -> { "execute": "block-latency-histogram-set",
@@ -567,7 +567,7 @@
#
# Example:
#
-# set new histograms with the following intervals: read, flush: [0,
+# Set new histograms with the following intervals: read, flush: [0,
# 10), [10, 50), [50, 100), [100, +inf) write: [0, 1000), [1000,
# 5000), [5000, +inf)
#
@@ -579,7 +579,7 @@
#
# Example:
#
-# remove all latency histograms:
+# Remove all latency histograms:
#
# -> { "execute": "block-latency-histogram-set",
# "arguments": { "id": "drive0" } }
diff --git a/qapi/char.json b/qapi/char.json
index e413ac2..52aaff2 100644
--- a/qapi/char.json
+++ b/qapi/char.json
@@ -18,7 +18,7 @@
# @filename: the filename of the character device
#
# @frontend-open: shows whether the frontend device attached to this
-# backend (eg. with the chardev=... option) is in open or closed
+# backend (e.g. with the chardev=... option) is in open or closed
# state (since 2.1)
#
# Notes: @filename is encoded using the QEMU command line character
diff --git a/qapi/cxl.json b/qapi/cxl.json
index d5b5293..8cc4c72 100644
--- a/qapi/cxl.json
+++ b/qapi/cxl.json
@@ -172,8 +172,8 @@
#
# @temperature: Device temperature in degrees Celsius.
#
-# @dirty-shutdown-count: Number of times the device has been unable
-# to determine whether data loss may have occurred.
+# @dirty-shutdown-count: Number of times the device has been unable to
+# determine whether data loss may have occurred.
#
# @corrected-volatile-error-count: Total number of correctable errors
# in volatile memory.
diff --git a/qapi/machine-target.json b/qapi/machine-target.json
index 3362f8d..f0a6b72 100644
--- a/qapi/machine-target.json
+++ b/qapi/machine-target.json
@@ -61,7 +61,7 @@
# @CpuModelCompareResult:
#
# An enumeration of CPU model comparison results. The result is
-# usually calculated using e.g. CPU features or CPU generations.
+# usually calculated using e.g. CPU features or CPU generations.
#
# @incompatible: If model A is incompatible to model B, model A is not
# guaranteed to run where model B runs and the other way around.
diff --git a/qapi/migration.json b/qapi/migration.json
index 47dfef0..6b49593 100644
--- a/qapi/migration.json
+++ b/qapi/migration.json
@@ -23,7 +23,8 @@
#
# @duplicate: number of duplicate (zero) pages (since 1.2)
#
-# @skipped: number of skipped zero pages (since 1.5)
+# @skipped: number of skipped zero pages. Always zero, only provided for
+# compatibility (since 1.5)
#
# @normal: number of normal pages (since 1.2)
#
@@ -62,18 +63,25 @@
# between 0 and @dirty-sync-count * @multifd-channels. (since
# 7.1)
#
+# Features:
+#
+# @deprecated: Member @skipped is always zero since 1.5.3
+#
# Since: 0.14
+#
##
{ 'struct': 'MigrationStats',
'data': {'transferred': 'int', 'remaining': 'int', 'total': 'int' ,
- 'duplicate': 'int', 'skipped': 'int', 'normal': 'int',
- 'normal-bytes': 'int', 'dirty-pages-rate' : 'int',
- 'mbps' : 'number', 'dirty-sync-count' : 'int',
- 'postcopy-requests' : 'int', 'page-size' : 'int',
- 'multifd-bytes' : 'uint64', 'pages-per-second' : 'uint64',
- 'precopy-bytes' : 'uint64', 'downtime-bytes' : 'uint64',
- 'postcopy-bytes' : 'uint64',
- 'dirty-sync-missed-zero-copy' : 'uint64' } }
+ 'duplicate': 'int',
+ 'skipped': { 'type': 'int', 'features': ['deprecated'] },
+ 'normal': 'int',
+ 'normal-bytes': 'int', 'dirty-pages-rate': 'int',
+ 'mbps': 'number', 'dirty-sync-count': 'int',
+ 'postcopy-requests': 'int', 'page-size': 'int',
+ 'multifd-bytes': 'uint64', 'pages-per-second': 'uint64',
+ 'precopy-bytes': 'uint64', 'downtime-bytes': 'uint64',
+ 'postcopy-bytes': 'uint64',
+ 'dirty-sync-missed-zero-copy': 'uint64' } }
##
# @XBZRLECacheStats:
@@ -250,6 +258,18 @@
# blocked. Present and non-empty when migration is blocked.
# (since 6.0)
#
+# @dirty-limit-throttle-time-per-round: Maximum throttle time (in microseconds) of virtual
+# CPUs each dirty ring full round, which shows how
+# MigrationCapability dirty-limit affects the guest
+# during live migration. (since 8.1)
+#
+# @dirty-limit-ring-full-time: Estimated average dirty ring full time (in microseconds)
+# each dirty ring full round, note that the value equals
+# dirty ring memory size divided by average dirty page rate
+# of virtual CPU, which can be used to observe the average
+# memory load of virtual CPU indirectly. Note that zero
+# means guest doesn't dirty memory (since 8.1)
+#
# Since: 0.14
##
{ 'struct': 'MigrationInfo',
@@ -264,10 +284,12 @@
'*cpu-throttle-percentage': 'int',
'*error-desc': 'str',
'*blocked-reasons': ['str'],
- '*postcopy-blocktime' : 'uint32',
+ '*postcopy-blocktime': 'uint32',
'*postcopy-vcpu-blocktime': ['uint32'],
'*compression': 'CompressionStats',
- '*socket-address': ['SocketAddress'] } }
+ '*socket-address': ['SocketAddress'],
+ '*dirty-limit-throttle-time-per-round': 'uint64',
+ '*dirty-limit-ring-full-time': 'uint64'} }
##
# @query-migrate:
@@ -465,8 +487,8 @@
# block devices (and thus take locks) immediately at the end of
# migration. (since 3.0)
#
-# @x-ignore-shared: If enabled, QEMU will not migrate shared memory that is
-# accessible on the destination machine. (since 4.0)
+# @x-ignore-shared: If enabled, QEMU will not migrate shared memory
+# that is accessible on the destination machine. (since 4.0)
#
# @validate-uuid: Send the UUID of the source to allow the destination
# to ensure it is the same. (since 4.2)
@@ -490,13 +512,23 @@
# @switchover-ack: If enabled, migration will not stop the source VM
# and complete the migration until an ACK is received from the
# destination that it's OK to do so. Exactly when this ACK is
-# sent depends on the migrated devices that use this feature.
-# For example, a device can use it to make sure some of its data
-# is sent and loaded in the destination before doing switchover.
+# sent depends on the migrated devices that use this feature. For
+# example, a device can use it to make sure some of its data is
+# sent and loaded in the destination before doing switchover.
# This can reduce downtime if devices that support this capability
# are present. 'return-path' capability must be enabled to use
# it. (since 8.1)
#
+# @dirty-limit: If enabled, migration will use the dirty-limit algo to
+# throttle down guest instead of auto-converge algo.
+# Throttle algo only works when vCPU's dirtyrate greater
+# than 'vcpu-dirty-limit', read processes in guest os
+# aren't penalized any more, so this algo can improve
+# performance of vCPU during live migration. This is an
+# optional performance feature and should not affect the
+# correctness of the existing auto-converge algo.
+# (since 8.1)
+#
# Features:
#
# @unstable: Members @x-colo and @x-ignore-shared are experimental.
@@ -512,7 +544,8 @@
'dirty-bitmaps', 'postcopy-blocktime', 'late-block-activate',
{ 'name': 'x-ignore-shared', 'features': [ 'unstable' ] },
'validate-uuid', 'background-snapshot',
- 'zero-copy-send', 'postcopy-preempt', 'switchover-ack'] }
+ 'zero-copy-send', 'postcopy-preempt', 'switchover-ack',
+ 'dirty-limit'] }
##
# @MigrationCapabilityStatus:
@@ -526,7 +559,7 @@
# Since: 1.2
##
{ 'struct': 'MigrationCapabilityStatus',
- 'data': { 'capability' : 'MigrationCapability', 'state' : 'bool' } }
+ 'data': { 'capability': 'MigrationCapability', 'state': 'bool' } }
##
# @migrate-set-capabilities:
@@ -789,9 +822,17 @@
# Nodes are mapped to their block device name if there is one, and
# to their node name otherwise. (Since 5.2)
#
+# @x-vcpu-dirty-limit-period: Periodic time (in milliseconds) of dirty limit during
+# live migration. Should be in the range 1 to 1000ms,
+# defaults to 1000ms. (Since 8.1)
+#
+# @vcpu-dirty-limit: Dirtyrate limit (MB/s) during live migration.
+# Defaults to 1. (Since 8.1)
+#
# Features:
#
-# @unstable: Member @x-checkpoint-delay is experimental.
+# @unstable: Members @x-checkpoint-delay and @x-vcpu-dirty-limit-period
+# are experimental.
#
# Since: 2.4
##
@@ -809,8 +850,10 @@
'multifd-channels',
'xbzrle-cache-size', 'max-postcopy-bandwidth',
'max-cpu-throttle', 'multifd-compression',
- 'multifd-zlib-level' ,'multifd-zstd-level',
- 'block-bitmap-mapping' ] }
+ 'multifd-zlib-level', 'multifd-zstd-level',
+ 'block-bitmap-mapping',
+ { 'name': 'x-vcpu-dirty-limit-period', 'features': ['unstable'] },
+ 'vcpu-dirty-limit'] }
##
# @MigrateSetParameters:
@@ -945,9 +988,17 @@
# Nodes are mapped to their block device name if there is one, and
# to their node name otherwise. (Since 5.2)
#
+# @x-vcpu-dirty-limit-period: Periodic time (in milliseconds) of dirty limit during
+# live migration. Should be in the range 1 to 1000ms,
+# defaults to 1000ms. (Since 8.1)
+#
+# @vcpu-dirty-limit: Dirtyrate limit (MB/s) during live migration.
+# Defaults to 1. (Since 8.1)
+#
# Features:
#
-# @unstable: Member @x-checkpoint-delay is experimental.
+# @unstable: Members @x-checkpoint-delay and @x-vcpu-dirty-limit-period
+# are experimental.
#
# TODO: either fuse back into MigrationParameters, or make
# MigrationParameters members mandatory
@@ -982,7 +1033,10 @@
'*multifd-compression': 'MultiFDCompression',
'*multifd-zlib-level': 'uint8',
'*multifd-zstd-level': 'uint8',
- '*block-bitmap-mapping': [ 'BitmapMigrationNodeAlias' ] } }
+ '*block-bitmap-mapping': [ 'BitmapMigrationNodeAlias' ],
+ '*x-vcpu-dirty-limit-period': { 'type': 'uint64',
+ 'features': [ 'unstable' ] },
+ '*vcpu-dirty-limit': 'uint64'} }
##
# @migrate-set-parameters:
@@ -1137,9 +1191,17 @@
# Nodes are mapped to their block device name if there is one, and
# to their node name otherwise. (Since 5.2)
#
+# @x-vcpu-dirty-limit-period: Periodic time (in milliseconds) of dirty limit during
+# live migration. Should be in the range 1 to 1000ms,
+# defaults to 1000ms. (Since 8.1)
+#
+# @vcpu-dirty-limit: Dirtyrate limit (MB/s) during live migration.
+# Defaults to 1. (Since 8.1)
+#
# Features:
#
-# @unstable: Member @x-checkpoint-delay is experimental.
+# @unstable: Members @x-checkpoint-delay and @x-vcpu-dirty-limit-period
+# are experimental.
#
# Since: 2.4
##
@@ -1171,7 +1233,10 @@
'*multifd-compression': 'MultiFDCompression',
'*multifd-zlib-level': 'uint8',
'*multifd-zstd-level': 'uint8',
- '*block-bitmap-mapping': [ 'BitmapMigrationNodeAlias' ] } }
+ '*block-bitmap-mapping': [ 'BitmapMigrationNodeAlias' ],
+ '*x-vcpu-dirty-limit-period': { 'type': 'uint64',
+ 'features': [ 'unstable' ] },
+ '*vcpu-dirty-limit': 'uint64'} }
##
# @query-migrate-parameters:
@@ -1577,7 +1642,7 @@
# Since: 2.9
##
{ 'command': 'xen-set-replication',
- 'data': { 'enable': 'bool', 'primary': 'bool', '*failover' : 'bool' },
+ 'data': { 'enable': 'bool', 'primary': 'bool', '*failover': 'bool' },
'if': 'CONFIG_REPLICATION' }
##
@@ -1745,14 +1810,13 @@
##
# @DirtyRateStatus:
#
-# An enumeration of dirtyrate status.
+# Dirty page rate measurement status.
#
-# @unstarted: the dirtyrate thread has not been started.
+# @unstarted: measuring thread has not been started yet
#
-# @measuring: the dirtyrate thread is measuring.
+# @measuring: measuring thread is running
#
-# @measured: the dirtyrate thread has measured and results are
-# available.
+# @measured: dirty page rate is measured and the results are available
#
# Since: 5.2
##
@@ -1762,13 +1826,14 @@
##
# @DirtyRateMeasureMode:
#
-# An enumeration of mode of measuring dirtyrate.
+# Method used to measure dirty page rate. Differences between
+# available methods are explained in @calc-dirty-rate.
#
-# @page-sampling: calculate dirtyrate by sampling pages.
+# @page-sampling: use page sampling
#
-# @dirty-ring: calculate dirtyrate by dirty ring.
+# @dirty-ring: use dirty ring
#
-# @dirty-bitmap: calculate dirtyrate by dirty bitmap.
+# @dirty-bitmap: use dirty bitmap
#
# Since: 6.2
##
@@ -1778,25 +1843,24 @@
##
# @DirtyRateInfo:
#
-# Information about current dirty page rate of vm.
+# Information about measured dirty page rate.
#
# @dirty-rate: an estimate of the dirty page rate of the VM in units
-# of MB/s, present only when estimating the rate has completed.
+# of MiB/s. Value is present only when @status is 'measured'.
#
-# @status: status containing dirtyrate query status includes
-# 'unstarted' or 'measuring' or 'measured'
+# @status: current status of dirty page rate measurements
#
# @start-time: start time in units of second for calculation
#
-# @calc-time: time in units of second for sample dirty pages
+# @calc-time: time period for which dirty page rate was measured
+# (in seconds)
#
-# @sample-pages: page count per GB for sample dirty pages the default
-# value is 512 (since 6.1)
+# @sample-pages: number of sampled pages per GiB of guest memory.
+# Valid only in page-sampling mode (Since 6.1)
#
-# @mode: mode containing method of calculate dirtyrate includes
-# 'page-sampling' and 'dirty-ring' (Since 6.2)
+# @mode: mode that was used to measure dirty page rate (Since 6.2)
#
-# @vcpu-dirty-rate: dirtyrate for each vcpu if dirty-ring mode
+# @vcpu-dirty-rate: dirty rate for each vCPU if dirty-ring mode was
# specified (Since 6.2)
#
# Since: 5.2
@@ -1813,15 +1877,49 @@
##
# @calc-dirty-rate:
#
-# start calculating dirty page rate for vm
+# Start measuring dirty page rate of the VM. Results can be retrieved
+# with @query-dirty-rate after measurements are completed.
#
-# @calc-time: time in units of second for sample dirty pages
+# Dirty page rate is the number of pages changed in a given time
+# period expressed in MiB/s. The following methods of calculation are
+# available:
#
-# @sample-pages: page count per GB for sample dirty pages the default
-# value is 512 (since 6.1)
+# 1. In page sampling mode, a random subset of pages are selected and
+# hashed twice: once at the beginning of measurement time period,
+# and once again at the end. If two hashes for some page are
+# different, the page is counted as changed. Since this method
+# relies on sampling and hashing, calculated dirty page rate is
+# only an estimate of its true value. Increasing @sample-pages
+# improves estimation quality at the cost of higher computational
+# overhead.
#
-# @mode: mechanism of calculating dirtyrate includes 'page-sampling'
-# and 'dirty-ring' (Since 6.1)
+# 2. Dirty bitmap mode captures writes to memory (for example by
+# temporarily revoking write access to all pages) and counting page
+# faults. Information about modified pages is collected into a
+# bitmap, where each bit corresponds to one guest page. This mode
+# requires that KVM accelerator property "dirty-ring-size" is *not*
+# set.
+#
+# 3. Dirty ring mode is similar to dirty bitmap mode, but the
+# information about modified pages is collected into ring buffer.
+# This mode tracks page modification per each vCPU separately. It
+# requires that KVM accelerator property "dirty-ring-size" is set.
+#
+# @calc-time: time period in units of second for which dirty page rate
+# is calculated. Note that larger @calc-time values will
+# typically result in smaller dirty page rates because page
+# dirtying is a one-time event. Once some page is counted as
+# dirty during @calc-time period, further writes to this page will
+# not increase dirty page rate anymore.
+#
+# @sample-pages: number of sampled pages per each GiB of guest memory.
+# Default value is 512. For 4KiB guest pages this corresponds to
+# sampling ratio of 0.2%. This argument is used only in page
+# sampling mode. (Since 6.1)
+#
+# @mode: mechanism for tracking dirty pages. Default value is
+# 'page-sampling'. Others are 'dirty-bitmap' and 'dirty-ring'.
+# (Since 6.1)
#
# Since: 5.2
#
@@ -1838,9 +1936,21 @@
##
# @query-dirty-rate:
#
-# query dirty page rate in units of MB/s for vm
+# Query results of the most recent invocation of @calc-dirty-rate.
#
# Since: 5.2
+#
+# Examples:
+#
+# 1. Measurement is in progress:
+#
+# <- {"status": "measuring", "sample-pages": 512,
+# "mode": "page-sampling", "start-time": 3665220, "calc-time": 10}
+#
+# 2. Measurement has been completed:
+#
+# <- {"status": "measured", "sample-pages": 512, "dirty-rate": 108,
+# "mode": "page-sampling", "start-time": 3665220, "calc-time": 10}
##
{ 'command': 'query-dirty-rate', 'returns': 'DirtyRateInfo' }
diff --git a/qapi/misc.json b/qapi/misc.json
index ff070ec..cda2eff 100644
--- a/qapi/misc.json
+++ b/qapi/misc.json
@@ -18,7 +18,7 @@
# fail and the FD will be closed.
#
# @protocol: protocol name. Valid names are "vnc", "spice",
-# "@dbus-display" or the name of a character device (eg. from
+# "@dbus-display" or the name of a character device (e.g. from
# -chardev id=XXXX)
#
# @fdname: file descriptor name previously passed via 'getfd' command
diff --git a/qapi/net.json b/qapi/net.json
index db67501..313c8a6 100644
--- a/qapi/net.json
+++ b/qapi/net.json
@@ -663,7 +663,6 @@
# @type: Specify the driver used for interpreting remaining arguments.
#
# Since: 1.2
-#
##
{ 'union': 'Netdev',
'base': { 'id': 'str', 'type': 'NetClientDriver' },
diff --git a/qapi/qdev.json b/qapi/qdev.json
index 2d73b27..6bc5a73 100644
--- a/qapi/qdev.json
+++ b/qapi/qdev.json
@@ -53,12 +53,12 @@
#
# Notes:
#
-# Additional arguments depend on the type.
+# 1. Additional arguments depend on the type.
#
-# 1. For detailed information about this command, please refer to the
+# 2. For detailed information about this command, please refer to the
# 'docs/qdev-device-use.txt' file.
#
-# 2. It's possible to list device properties by running QEMU with the
+# 3. It's possible to list device properties by running QEMU with the
# "-device DEVICE,help" command-line argument, where DEVICE is the
# device's name
#
diff --git a/qapi/qom.json b/qapi/qom.json
index 7f92ea4..fa3e88c 100644
--- a/qapi/qom.json
+++ b/qapi/qom.json
@@ -647,9 +647,10 @@
# selects a default alignment (currently the page size).
# (default: 0)
#
-# @offset: the offset into the target file that the region starts at. You
-# can use this option to back multiple regions with a single file. Must
-# be a multiple of the page size. (default: 0) (since 8.1)
+# @offset: the offset into the target file that the region starts at.
+# You can use this option to back multiple regions with a single
+# file. Must be a multiple of the page size.
+# (default: 0) (since 8.1)
#
# @discard-data: if true, the file contents can be destroyed when QEMU
# exits, to avoid unnecessarily flushing data to the backing file.
@@ -662,7 +663,7 @@
#
# @pmem: specifies whether the backing file specified by @mem-path is
# in host persistent memory that can be accessed using the SNIA
-# NVM programming model (e.g. Intel NVDIMM).
+# NVM programming model (e.g. Intel NVDIMM).
#
# @readonly: if true, the backing file is opened read-only; if false,
# it is opened read-write. (default: false)
diff --git a/qapi/trace.json b/qapi/trace.json
index 39b752f..2077d7e 100644
--- a/qapi/trace.json
+++ b/qapi/trace.json
@@ -38,6 +38,7 @@
# @vcpu: Whether this is a per-vCPU event (since 2.7).
#
# Features:
+#
# @deprecated: Member @vcpu is deprecated, and always ignored.
#
# Since: 2.2
@@ -56,13 +57,11 @@
# @vcpu: The vCPU to query (since 2.7).
#
# Features:
+#
# @deprecated: Member @vcpu is deprecated, and always ignored.
#
# Returns: a list of @TraceEventInfo for the matching events
#
-# An event is returned if its name matches the @name pattern
-# (There are no longer any per-vCPU events).
-#
# Since: 2.2
#
# Example:
@@ -90,10 +89,8 @@
# @vcpu: The vCPU to act upon (all by default; since 2.7).
#
# Features:
-# @deprecated: Member @vcpu is deprecated, and always ignored.
#
-# An event is enabled if its name matches the @name pattern
-# (There are no longer any per-vCPU events).
+# @deprecated: Member @vcpu is deprecated, and always ignored.
#
# Since: 2.2
#
diff --git a/qapi/ui.json b/qapi/ui.json
index bb06fb6..006616a 100644
--- a/qapi/ui.json
+++ b/qapi/ui.json
@@ -1309,7 +1309,7 @@
# defaults to "off". (Since 3.1)
#
# @show-tabs: Display the tab bar for switching between the various
-# graphical interfaces (e.g. VGA and virtual console character
+# graphical interfaces (e.g. VGA and virtual console character
# devices) by default. (Since 7.1)
#
# @show-menubar: Display the main window menubar. Defaults to "on".
diff --git a/qemu-nbd.c b/qemu-nbd.c
index 4276163..5b27579 100644
--- a/qemu-nbd.c
+++ b/qemu-nbd.c
@@ -73,7 +73,6 @@
#define MBR_SIZE 512
-static int verbose;
static char *srcpath;
static SocketAddress *saddr;
static int persistent = 0;
@@ -272,9 +271,15 @@
return NULL;
}
+struct NbdClientOpts {
+ char *device;
+ bool fork_process;
+ bool verbose;
+};
+
static void *nbd_client_thread(void *arg)
{
- char *device = arg;
+ struct NbdClientOpts *opts = arg;
NBDExportInfo info = { .request_sizes = false, .name = g_strdup("") };
QIOChannelSocket *sioc;
int fd = -1;
@@ -298,10 +303,10 @@
goto out;
}
- fd = open(device, O_RDWR);
+ fd = open(opts->device, O_RDWR);
if (fd < 0) {
/* Linux-only, we can use %m in printf. */
- error_report("Failed to open %s: %m", device);
+ error_report("Failed to open %s: %m", opts->device);
goto out;
}
@@ -311,14 +316,18 @@
}
/* update partition table */
- pthread_create(&show_parts_thread, NULL, show_parts, device);
+ pthread_create(&show_parts_thread, NULL, show_parts, opts->device);
- if (verbose) {
+ if (opts->verbose && !opts->fork_process) {
fprintf(stderr, "NBD device %s is now connected to %s\n",
- device, srcpath);
+ opts->device, srcpath);
} else {
/* Close stderr so that the qemu-nbd process exits. */
- dup2(STDOUT_FILENO, STDERR_FILENO);
+ if (dup2(STDOUT_FILENO, STDERR_FILENO) < 0) {
+ error_report("Could not set stderr to /dev/null: %s",
+ strerror(errno));
+ exit(EXIT_FAILURE);
+ }
}
if (nbd_client(fd) < 0) {
@@ -573,9 +582,9 @@
const char *tlshostname = NULL;
bool imageOpts = false;
bool writethrough = false; /* Client will flush as needed. */
+ bool verbose = false;
bool fork_process = false;
bool list = false;
- int old_stderr = -1;
unsigned socket_activation;
const char *pid_file_name = NULL;
const char *selinux_label = NULL;
@@ -738,7 +747,7 @@
}
break;
case 'v':
- verbose = 1;
+ verbose = true;
break;
case 'V':
version(argv[0]);
@@ -928,19 +937,30 @@
error_report("Failed to fork: %s", strerror(errno));
exit(EXIT_FAILURE);
} else if (pid == 0) {
+ int saved_errno;
+
close(stderr_fd[0]);
- /* Remember parent's stderr if we will be restoring it. */
- if (fork_process) {
- old_stderr = dup(STDERR_FILENO);
- }
-
ret = qemu_daemon(1, 0);
+ saved_errno = errno; /* dup2 will overwrite error below */
/* Temporarily redirect stderr to the parent's pipe... */
- dup2(stderr_fd[1], STDERR_FILENO);
+ if (dup2(stderr_fd[1], STDERR_FILENO) < 0) {
+ char str[256];
+ snprintf(str, sizeof(str),
+ "%s: Failed to link stderr to the pipe: %s\n",
+ g_get_prgname(), strerror(errno));
+ /*
+ * We are unable to use error_report() here as we need to get
+ * stderr pointed to the parent's pipe. Write to that pipe
+ * manually.
+ */
+ ret = write(stderr_fd[1], str, strlen(str));
+ exit(EXIT_FAILURE);
+ }
+
if (ret < 0) {
- error_report("Failed to daemonize: %s", strerror(errno));
+ error_report("Failed to daemonize: %s", strerror(saved_errno));
exit(EXIT_FAILURE);
}
@@ -1125,8 +1145,13 @@
if (device) {
#if HAVE_NBD_DEVICE
int ret;
+ struct NbdClientOpts opts = {
+ .device = device,
+ .fork_process = fork_process,
+ .verbose = verbose,
+ };
- ret = pthread_create(&client_thread, NULL, nbd_client_thread, device);
+ ret = pthread_create(&client_thread, NULL, nbd_client_thread, &opts);
if (ret != 0) {
error_report("Failed to create client thread: %s", strerror(ret));
exit(EXIT_FAILURE);
@@ -1152,8 +1177,11 @@
}
if (fork_process) {
- dup2(old_stderr, STDERR_FILENO);
- close(old_stderr);
+ if (dup2(STDOUT_FILENO, STDERR_FILENO) < 0) {
+ error_report("Could not set stderr to /dev/null: %s",
+ strerror(errno));
+ exit(EXIT_FAILURE);
+ }
}
state = RUNNING;
diff --git a/qemu-options.hx b/qemu-options.hx
index f8f384e..29b98c3 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -963,10 +963,10 @@
to honor this value but actual latencies may be lower or higher.
``-audiodev pipewire,id=id[,prop[=value][,...]]``
- Creates a backend using Pipewire. This backend is available on
+ Creates a backend using PipeWire. This backend is available on
most systems.
- Pipewire specific options are:
+ PipeWire specific options are:
``in|out.latency=usecs``
Desired latency in microseconds.
diff --git a/roms/opensbi b/roms/opensbi
index 2552799..057eb10 160000
--- a/roms/opensbi
+++ b/roms/opensbi
@@ -1 +1 @@
-Subproject commit 2552799a1df30a3dcd2321a8b75d61d06f5fb9fc
+Subproject commit 057eb10b6d523540012e6947d5c9f63e95244e94
diff --git a/scripts/decodetree.py b/scripts/decodetree.py
index a8a6cb6..e8b72da 100644
--- a/scripts/decodetree.py
+++ b/scripts/decodetree.py
@@ -134,6 +134,10 @@ def error_with_file(file, lineno, *args):
global output_file
global output_fd
+ # For the test suite expected-errors case, don't print the
+ # string "error: ", so they don't turn up as false positives
+ # if you grep the meson logs for strings like that.
+ end = 'error: ' if not testforerror else 'detected: '
prefix = ''
if file:
prefix += f'{file}:'
@@ -141,7 +145,7 @@ def error_with_file(file, lineno, *args):
prefix += f'{lineno}:'
if prefix:
prefix += ' '
- print(prefix, end='error: ', file=sys.stderr)
+ print(prefix, end=end, file=sys.stderr)
print(*args, file=sys.stderr)
if output_file and output_fd:
diff --git a/scripts/git-submodule.sh b/scripts/git-submodule.sh
index 335f7f5..bb1222c 100755
--- a/scripts/git-submodule.sh
+++ b/scripts/git-submodule.sh
@@ -103,7 +103,7 @@
check_updated $module || echo Updated "$module"
done
- (while read -r; do
+ (while read -r REPLY; do
for module in $modules; do
case $REPLY in
*" $module "*) continue 2 ;;
diff --git a/scripts/meson-buildoptions.sh b/scripts/meson-buildoptions.sh
index 7dd5709..9da3fe2 100644
--- a/scripts/meson-buildoptions.sh
+++ b/scripts/meson-buildoptions.sh
@@ -145,7 +145,7 @@
printf "%s\n" ' oss OSS sound support'
printf "%s\n" ' pa PulseAudio sound support'
printf "%s\n" ' parallels parallels image format support'
- printf "%s\n" ' pipewire Pipewire sound support'
+ printf "%s\n" ' pipewire PipeWire sound support'
printf "%s\n" ' png PNG support with libpng'
printf "%s\n" ' pvrdma Enable PVRDMA support'
printf "%s\n" ' qcow1 qcow1 image format support'
diff --git a/softmmu/dirtylimit.c b/softmmu/dirtylimit.c
index 015a903..3c275ee 100644
--- a/softmmu/dirtylimit.c
+++ b/softmmu/dirtylimit.c
@@ -24,6 +24,9 @@
#include "hw/boards.h"
#include "sysemu/kvm.h"
#include "trace.h"
+#include "migration/misc.h"
+#include "migration/migration.h"
+#include "migration/options.h"
/*
* Dirtylimit stop working if dirty page rate error
@@ -75,14 +78,21 @@
static void vcpu_dirty_rate_stat_collect(void)
{
+ MigrationState *s = migrate_get_current();
VcpuStat stat;
int i = 0;
+ int64_t period = DIRTYLIMIT_CALC_TIME_MS;
+
+ if (migrate_dirty_limit() &&
+ migration_is_active(s)) {
+ period = s->parameters.x_vcpu_dirty_limit_period;
+ }
/* calculate vcpu dirtyrate */
- vcpu_calculate_dirtyrate(DIRTYLIMIT_CALC_TIME_MS,
- &stat,
- GLOBAL_DIRTY_LIMIT,
- false);
+ vcpu_calculate_dirtyrate(period,
+ &stat,
+ GLOBAL_DIRTY_LIMIT,
+ false);
for (i = 0; i < stat.nvcpu; i++) {
vcpu_dirty_rate_stat->stat.rates[i].id = i;
@@ -426,6 +436,23 @@
dirtylimit_state_finalize();
}
+/*
+ * dirty page rate limit is not allowed to set if migration
+ * is running with dirty-limit capability enabled.
+ */
+static bool dirtylimit_is_allowed(void)
+{
+ MigrationState *ms = migrate_get_current();
+
+ if (migration_is_running(ms->state) &&
+ (!qemu_thread_is_self(&ms->thread)) &&
+ migrate_dirty_limit() &&
+ dirtylimit_in_service()) {
+ return false;
+ }
+ return true;
+}
+
void qmp_cancel_vcpu_dirty_limit(bool has_cpu_index,
int64_t cpu_index,
Error **errp)
@@ -439,6 +466,12 @@
return;
}
+ if (!dirtylimit_is_allowed()) {
+ error_setg(errp, "can't cancel dirty page rate limit while"
+ " migration is running");
+ return;
+ }
+
if (!dirtylimit_in_service()) {
return;
}
@@ -489,6 +522,12 @@
return;
}
+ if (!dirtylimit_is_allowed()) {
+ error_setg(errp, "can't set dirty page rate limit while"
+ " migration is running");
+ return;
+ }
+
if (!dirty_rate) {
qmp_cancel_vcpu_dirty_limit(has_cpu_index, cpu_index, errp);
return;
@@ -515,14 +554,54 @@
int64_t cpu_index = qdict_get_try_int(qdict, "cpu_index", -1);
Error *err = NULL;
- qmp_set_vcpu_dirty_limit(!!(cpu_index != -1), cpu_index, dirty_rate, &err);
- if (err) {
- hmp_handle_error(mon, err);
- return;
+ if (dirty_rate < 0) {
+ error_setg(&err, "invalid dirty page limit %" PRId64, dirty_rate);
+ goto out;
}
- monitor_printf(mon, "[Please use 'info vcpu_dirty_limit' to query "
- "dirty limit for virtual CPU]\n");
+ qmp_set_vcpu_dirty_limit(!!(cpu_index != -1), cpu_index, dirty_rate, &err);
+
+out:
+ hmp_handle_error(mon, err);
+}
+
+/* Return the max throttle time of each virtual CPU */
+uint64_t dirtylimit_throttle_time_per_round(void)
+{
+ CPUState *cpu;
+ int64_t max = 0;
+
+ CPU_FOREACH(cpu) {
+ if (cpu->throttle_us_per_full > max) {
+ max = cpu->throttle_us_per_full;
+ }
+ }
+
+ return max;
+}
+
+/*
+ * Estimate average dirty ring full time of each virtaul CPU.
+ * Return 0 if guest doesn't dirty memory.
+ */
+uint64_t dirtylimit_ring_full_time(void)
+{
+ CPUState *cpu;
+ uint64_t curr_rate = 0;
+ int nvcpus = 0;
+
+ CPU_FOREACH(cpu) {
+ if (cpu->running) {
+ nvcpus++;
+ curr_rate += vcpu_dirty_rate_get(cpu->cpu_index);
+ }
+ }
+
+ if (!curr_rate || !nvcpus) {
+ return 0;
+ }
+
+ return dirtylimit_dirty_ring_full_time(curr_rate / nvcpus);
}
static struct DirtyLimitInfo *dirtylimit_query_vcpu(int cpu_index)
diff --git a/target/alpha/cpu.h b/target/alpha/cpu.h
index fcd20bf..1330666 100644
--- a/target/alpha/cpu.h
+++ b/target/alpha/cpu.h
@@ -191,7 +191,7 @@
That said, we're only emulating Unix PALcode, and not attempting VMS,
so we don't need to implement Executive and Supervisor. QEMU's own
- PALcode cheats and usees the KSEG mapping for its code+data rather than
+ PALcode cheats and uses the KSEG mapping for its code+data rather than
physical addresses. */
#define MMU_KERNEL_IDX 0
@@ -362,7 +362,7 @@
The Unix PALcode only uses bit 4. */
#define PS_USER_MODE 8u
-/* CPUAlphaState->flags constants. These are layed out so that we
+/* CPUAlphaState->flags constants. These are laid out so that we
can set or reset the pieces individually by assigning to the byte,
or manipulated as a whole. */
diff --git a/target/alpha/translate.c b/target/alpha/translate.c
index 1f7dd07..846f3d8 100644
--- a/target/alpha/translate.c
+++ b/target/alpha/translate.c
@@ -2893,7 +2893,7 @@
the first fp insn of the TB. Alternately we could define a proper
default for every TB (e.g. QUAL_RM_N or QUAL_RM_D) and make sure
to reset the FP_STATUS to that default at the end of any TB that
- changes the default. We could even (gasp) dynamiclly figure out
+ changes the default. We could even (gasp) dynamically figure out
what default would be most efficient given the running program. */
ctx->tb_rm = -1;
/* Similarly for flush-to-zero. */
diff --git a/target/arm/cpu.c b/target/arm/cpu.c
index 69e2bde..93c28d5 100644
--- a/target/arm/cpu.c
+++ b/target/arm/cpu.c
@@ -677,7 +677,7 @@
}
/*
- * The PSTATE bits only mask the interrupt if we have not overriden the
+ * The PSTATE bits only mask the interrupt if we have not overridden the
* ability above.
*/
return unmasked || pstate_unmasked;
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
index 4d6c0f9..88e5acc 100644
--- a/target/arm/cpu.h
+++ b/target/arm/cpu.h
@@ -2592,7 +2592,7 @@
return aa64;
}
-/* Function for determing whether guest cp register reads and writes should
+/* Function for determining whether guest cp register reads and writes should
* access the secure or non-secure bank of a cp register. When EL3 is
* operating in AArch32 state, the NS-bit determines whether the secure
* instance of a cp register should be used. When EL3 is AArch64 (or if
diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c
index 6012e4e..9615809 100644
--- a/target/arm/cpu64.c
+++ b/target/arm/cpu64.c
@@ -95,7 +95,7 @@
if (kvm_enabled()) {
/*
- * For KVM we have to automatically enable all supported unitialized
+ * For KVM we have to automatically enable all supported uninitialized
* lengths, even when the smaller lengths are not all powers-of-two.
*/
vq_map |= vq_supported & ~vq_init & vq_mask;
diff --git a/target/arm/debug_helper.c b/target/arm/debug_helper.c
index 8362462..abe72e3 100644
--- a/target/arm/debug_helper.c
+++ b/target/arm/debug_helper.c
@@ -21,6 +21,10 @@
bool secure = arm_is_secure(env);
bool route_to_el2 = false;
+ if (arm_feature(env, ARM_FEATURE_M)) {
+ return 1;
+ }
+
if (arm_is_el2_enabled(env)) {
route_to_el2 = env->cp15.hcr_el2 & HCR_TGE ||
env->cp15.mdcr_el2 & MDCR_TDE;
@@ -434,18 +438,20 @@
{
ARMMMUFaultInfo fi = { .type = ARMFault_Debug };
int target_el = arm_debug_target_el(env);
- bool using_lpae = false;
+ bool using_lpae;
- if (target_el == 2 || arm_el_is_aa64(env, target_el)) {
+ if (arm_feature(env, ARM_FEATURE_M)) {
+ using_lpae = false;
+ } else if (target_el == 2 || arm_el_is_aa64(env, target_el)) {
using_lpae = true;
} else if (arm_feature(env, ARM_FEATURE_PMSA) &&
arm_feature(env, ARM_FEATURE_V8)) {
using_lpae = true;
+ } else if (arm_feature(env, ARM_FEATURE_LPAE) &&
+ (env->cp15.tcr_el[target_el] & TTBCR_EAE)) {
+ using_lpae = true;
} else {
- if (arm_feature(env, ARM_FEATURE_LPAE) &&
- (env->cp15.tcr_el[target_el] & TTBCR_EAE)) {
- using_lpae = true;
- }
+ using_lpae = false;
}
if (using_lpae) {
diff --git a/target/arm/helper.c b/target/arm/helper.c
index 8e836aa..50f61e4 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -1674,7 +1674,7 @@
* pmevtyper_rawwrite is called between a pair of pmu_op_start and
* pmu_op_finish calls when loading saved state for a migration. Because
* we're potentially updating the type of event here, the value written to
- * c14_pmevcntr_delta by the preceeding pmu_op_start call may be for a
+ * c14_pmevcntr_delta by the preceding pmu_op_start call may be for a
* different counter type. Therefore, we need to set this value to the
* current count for the counter type we're writing so that pmu_op_finish
* has the correct count for its calculation.
@@ -7009,7 +7009,7 @@
/*
* QEMU does not have a way to invalidate by physical address, thus
* invalidating a range of physical addresses is accomplished by
- * flushing all tlb entries in the outer sharable domain,
+ * flushing all tlb entries in the outer shareable domain,
* just like PAALLOS.
*/
{ .name = "TLBI_RPALOS", .state = ARM_CP_STATE_AA64,
diff --git a/target/arm/ptw.c b/target/arm/ptw.c
index 9aaff15..8f94100 100644
--- a/target/arm/ptw.c
+++ b/target/arm/ptw.c
@@ -19,10 +19,50 @@
#endif
typedef struct S1Translate {
+ /*
+ * in_mmu_idx : specifies which TTBR, TCR, etc to use for the walk.
+ * Together with in_space, specifies the architectural translation regime.
+ */
ARMMMUIdx in_mmu_idx;
+ /*
+ * in_ptw_idx: specifies which mmuidx to use for the actual
+ * page table descriptor load operations. This will be one of the
+ * ARMMMUIdx_Stage2* or one of the ARMMMUIdx_Phys_* indexes.
+ * If a Secure ptw is "downgraded" to NonSecure by an NSTable bit,
+ * this field is updated accordingly.
+ */
ARMMMUIdx in_ptw_idx;
+ /*
+ * in_space: the security space for this walk. This plus
+ * the in_mmu_idx specify the architectural translation regime.
+ * If a Secure ptw is "downgraded" to NonSecure by an NSTable bit,
+ * this field is updated accordingly.
+ *
+ * Note that the security space for the in_ptw_idx may be different
+ * from that for the in_mmu_idx. We do not need to explicitly track
+ * the in_ptw_idx security space because:
+ * - if the in_ptw_idx is an ARMMMUIdx_Phys_* then the mmuidx
+ * itself specifies the security space
+ * - if the in_ptw_idx is an ARMMMUIdx_Stage2* then the security
+ * space used for ptw reads is the same as that of the security
+ * space of the stage 1 translation for all cases except where
+ * stage 1 is Secure; in that case the only possibilities for
+ * the ptw read are Secure and NonSecure, and the in_ptw_idx
+ * value being Stage2 vs Stage2_S distinguishes those.
+ */
ARMSecuritySpace in_space;
+ /*
+ * in_secure: whether the translation regime is a Secure one.
+ * This is always equal to arm_space_is_secure(in_space).
+ * If a Secure ptw is "downgraded" to NonSecure by an NSTable bit,
+ * this field is updated accordingly.
+ */
bool in_secure;
+ /*
+ * in_debug: is this a QEMU debug access (gdbstub, etc)? Debug
+ * accesses will not update the guest page table access flags
+ * and will not change the state of the softmmu TLBs.
+ */
bool in_debug;
/*
* If this is stage 2 of a stage 1+2 page table walk, then this must
@@ -445,11 +485,39 @@
}
}
+static ARMSecuritySpace S2_security_space(ARMSecuritySpace s1_space,
+ ARMMMUIdx s2_mmu_idx)
+{
+ /*
+ * Return the security space to use for stage 2 when doing
+ * the S1 page table descriptor load.
+ */
+ if (regime_is_stage2(s2_mmu_idx)) {
+ /*
+ * The security space for ptw reads is almost always the same
+ * as that of the security space of the stage 1 translation.
+ * The only exception is when stage 1 is Secure; in that case
+ * the ptw read might be to the Secure or the NonSecure space
+ * (but never Realm or Root), and the s2_mmu_idx tells us which.
+ * Root translations are always single-stage.
+ */
+ if (s1_space == ARMSS_Secure) {
+ return arm_secure_to_space(s2_mmu_idx == ARMMMUIdx_Stage2_S);
+ } else {
+ assert(s2_mmu_idx != ARMMMUIdx_Stage2_S);
+ assert(s1_space != ARMSS_Root);
+ return s1_space;
+ }
+ } else {
+ /* ptw loads are from phys: the mmu idx itself says which space */
+ return arm_phys_to_space(s2_mmu_idx);
+ }
+}
+
/* Translate a S1 pagetable walk through S2 if needed. */
static bool S1_ptw_translate(CPUARMState *env, S1Translate *ptw,
hwaddr addr, ARMMMUFaultInfo *fi)
{
- ARMSecuritySpace space = ptw->in_space;
bool is_secure = ptw->in_secure;
ARMMMUIdx mmu_idx = ptw->in_mmu_idx;
ARMMMUIdx s2_mmu_idx = ptw->in_ptw_idx;
@@ -462,13 +530,12 @@
* From gdbstub, do not use softmmu so that we don't modify the
* state of the cpu at all, including softmmu tlb contents.
*/
+ ARMSecuritySpace s2_space = S2_security_space(ptw->in_space, s2_mmu_idx);
S1Translate s2ptw = {
.in_mmu_idx = s2_mmu_idx,
.in_ptw_idx = ptw_idx_for_stage_2(env, s2_mmu_idx),
- .in_secure = s2_mmu_idx == ARMMMUIdx_Stage2_S,
- .in_space = (s2_mmu_idx == ARMMMUIdx_Stage2_S ? ARMSS_Secure
- : space == ARMSS_Realm ? ARMSS_Realm
- : ARMSS_NonSecure),
+ .in_secure = arm_space_is_secure(s2_space),
+ .in_space = s2_space,
.in_debug = true,
};
GetPhysAddrResult s2 = { };
@@ -3051,6 +3118,7 @@
hwaddr ipa;
int s1_prot, s1_lgpgsz;
bool is_secure = ptw->in_secure;
+ ARMSecuritySpace in_space = ptw->in_space;
bool ret, ipa_secure;
ARMCacheAttrs cacheattrs1;
ARMSecuritySpace ipa_space;
@@ -3133,11 +3201,13 @@
* Check if IPA translates to secure or non-secure PA space.
* Note that VSTCR overrides VTCR and {N}SW overrides {N}SA.
*/
- result->f.attrs.secure =
- (is_secure
- && !(env->cp15.vstcr_el2 & (VSTCR_SA | VSTCR_SW))
- && (ipa_secure
- || !(env->cp15.vtcr_el2 & (VTCR_NSA | VTCR_NSW))));
+ if (in_space == ARMSS_Secure) {
+ result->f.attrs.secure =
+ !(env->cp15.vstcr_el2 & (VSTCR_SA | VSTCR_SW))
+ && (ipa_secure
+ || !(env->cp15.vtcr_el2 & (VTCR_NSA | VTCR_NSW)));
+ result->f.attrs.space = arm_secure_to_space(result->f.attrs.secure);
+ }
return false;
}
diff --git a/target/arm/tcg/m_helper.c b/target/arm/tcg/m_helper.c
index 9cef70e..0045c18 100644
--- a/target/arm/tcg/m_helper.c
+++ b/target/arm/tcg/m_helper.c
@@ -148,7 +148,7 @@
* R: 0 because unpriv and A flag not set
* SRVALID: 0 because NS
* MRVALID: 0 because unpriv and A flag not set
- * SREGION: 0 becaus SRVALID is 0
+ * SREGION: 0 because SRVALID is 0
* MREGION: 0 because MRVALID is 0
*/
return 0;
diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c
index 7d0c8f7..ef0c474 100644
--- a/target/arm/tcg/translate-a64.c
+++ b/target/arm/tcg/translate-a64.c
@@ -182,7 +182,7 @@
* + for EL2 and EL3 there is only one TBI bit, and if it is set
* then the address is zero-extended, clearing bits [63:56]
* + for EL0 and EL1, TBI0 controls addresses with bit 55 == 0
- * and TBI1 controls addressses with bit 55 == 1.
+ * and TBI1 controls addresses with bit 55 == 1.
* If the appropriate TBI bit is set for the address then
* the address is sign-extended from bit 55 into bits [63:56]
*
@@ -2313,7 +2313,7 @@
if (!isread && !(ri->type & ARM_CP_SUPPRESS_TB_END)) {
/*
- * A write to any coprocessor regiser that ends a TB
+ * A write to any coprocessor register that ends a TB
* must rebuild the hflags for the next TB.
*/
gen_rebuild_hflags(s);
diff --git a/target/arm/tcg/translate-mve.c b/target/arm/tcg/translate-mve.c
index bbc7b3f..17d8e68 100644
--- a/target/arm/tcg/translate-mve.c
+++ b/target/arm/tcg/translate-mve.c
@@ -2182,7 +2182,7 @@
* execution if it is not in an IT block. For us this means
* only that if PSR.ECI says we should not be executing the beat
* corresponding to the lane of the vector register being accessed
- * then we should skip perfoming the move, and that we need to do
+ * then we should skip performing the move, and that we need to do
* the usual check for bad ECI state and advance of ECI state.
* (If PSR.ECI is non-zero then we cannot be in an IT block.)
*/
@@ -2225,7 +2225,7 @@
* execution if it is not in an IT block. For us this means
* only that if PSR.ECI says we should not be executing the beat
* corresponding to the lane of the vector register being accessed
- * then we should skip perfoming the move, and that we need to do
+ * then we should skip performing the move, and that we need to do
* the usual check for bad ECI state and advance of ECI state.
* (If PSR.ECI is non-zero then we cannot be in an IT block.)
*/
diff --git a/target/arm/tcg/translate-sve.c b/target/arm/tcg/translate-sve.c
index 8350a65..2ba5efa 100644
--- a/target/arm/tcg/translate-sve.c
+++ b/target/arm/tcg/translate-sve.c
@@ -1841,7 +1841,7 @@
/* Perform an inline saturating addition of a 32-bit value within
* a 64-bit register. The second operand is known to be positive,
- * which halves the comparisions we must perform to bound the result.
+ * which halves the comparisons we must perform to bound the result.
*/
static void do_sat_addsub_32(TCGv_i64 reg, TCGv_i64 val, bool u, bool d)
{
diff --git a/target/arm/tcg/translate-vfp.c b/target/arm/tcg/translate-vfp.c
index 359b1e3..d3e89fd 100644
--- a/target/arm/tcg/translate-vfp.c
+++ b/target/arm/tcg/translate-vfp.c
@@ -144,7 +144,7 @@
* Generate code for M-profile FP context handling: update the
* ownership of the FP context, and create a new context if
* necessary. This corresponds to the parts of the pseudocode
- * ExecuteFPCheck() after the inital PreserveFPState() call.
+ * ExecuteFPCheck() after the initial PreserveFPState() call.
*/
static void gen_update_fp_context(DisasContext *s)
{
diff --git a/target/arm/tcg/vec_helper.c b/target/arm/tcg/vec_helper.c
index f59d3b2..6712a2c 100644
--- a/target/arm/tcg/vec_helper.c
+++ b/target/arm/tcg/vec_helper.c
@@ -2626,7 +2626,7 @@
* Process the entire segment at once, writing back the
* results only after we've consumed all of the inputs.
*
- * Key to indicies by column:
+ * Key to indices by column:
* i j i k j k
*/
sum00 = a[s + H4(0 + 0)];
diff --git a/target/cris/helper.c b/target/cris/helper.c
index 81a7269..c0bf987 100644
--- a/target/cris/helper.c
+++ b/target/cris/helper.c
@@ -113,7 +113,7 @@
assert(!(env->pregs[PR_CCS] & PFIX_FLAG));
switch (cs->exception_index) {
case EXCP_BREAK:
- /* These exceptions are genereated by the core itself.
+ /* These exceptions are generated by the core itself.
ERP should point to the insn following the brk. */
ex_vec = env->trap_vector;
env->pregs[PRV10_BRP] = env->pc;
@@ -169,7 +169,7 @@
switch (cs->exception_index) {
case EXCP_BREAK:
- /* These exceptions are genereated by the core itself.
+ /* These exceptions are generated by the core itself.
ERP should point to the insn following the brk. */
ex_vec = env->trap_vector;
env->pregs[PR_ERP] = env->pc;
@@ -228,7 +228,7 @@
undefined. */
env->pc = cpu_ldl_code(env, env->pregs[PR_EBP] + ex_vec * 4);
- /* Clear the excption_index to avoid spurios hw_aborts for recursive
+ /* Clear the excption_index to avoid spurious hw_aborts for recursive
bus faults. */
cs->exception_index = -1;
diff --git a/target/cris/op_helper.c b/target/cris/op_helper.c
index d55a18a..40cb74c 100644
--- a/target/cris/op_helper.c
+++ b/target/cris/op_helper.c
@@ -231,7 +231,7 @@
{
unsigned int x, z, mask;
- /* Extended arithmetics, leave the z flag alone. */
+ /* Extended arithmetic, leave the z flag alone. */
x = env->cc_x;
mask = env->cc_mask | X_FLAG;
if (x) {
diff --git a/target/cris/translate.c b/target/cris/translate.c
index 1445cd8..0b3d724 100644
--- a/target/cris/translate.c
+++ b/target/cris/translate.c
@@ -342,7 +342,7 @@
tcg_gen_add_tl(d, d, t);
}
-/* Extended arithmetics on CRIS. */
+/* Extended arithmetic on CRIS. */
static inline void t_gen_add_flag(TCGv d, int flag)
{
TCGv c;
@@ -646,7 +646,7 @@
switch (op) {
case CC_OP_ADD:
tcg_gen_add_tl(dst, a, b);
- /* Extended arithmetics. */
+ /* Extended arithmetic. */
t_gen_addx_carry(dc, dst);
break;
case CC_OP_ADDC:
@@ -659,7 +659,7 @@
break;
case CC_OP_SUB:
tcg_gen_sub_tl(dst, a, b);
- /* Extended arithmetics. */
+ /* Extended arithmetic. */
t_gen_subx_carry(dc, dst);
break;
case CC_OP_MOVE:
@@ -685,7 +685,7 @@
break;
case CC_OP_NEG:
tcg_gen_neg_tl(dst, b);
- /* Extended arithmetics. */
+ /* Extended arithmetic. */
t_gen_subx_carry(dc, dst);
break;
case CC_OP_LZ:
@@ -708,7 +708,7 @@
break;
case CC_OP_CMP:
tcg_gen_sub_tl(dst, a, b);
- /* Extended arithmetics. */
+ /* Extended arithmetic. */
t_gen_subx_carry(dc, dst);
break;
default:
@@ -2924,12 +2924,12 @@
* On QEMU care needs to be taken when a branch+delayslot sequence is broken
* and the branch and delayslot don't share pages.
*
- * The TB contaning the branch insn will set up env->btarget and evaluate
+ * The TB containing the branch insn will set up env->btarget and evaluate
* env->btaken. When the translation loop exits we will note that the branch
* sequence is broken and let env->dslot be the size of the branch insn (those
* vary in length).
*
- * The TB contaning the delayslot will have the PC of its real insn (i.e no lsb
+ * The TB containing the delayslot will have the PC of its real insn (i.e no lsb
* set). It will also expect to have env->dslot setup with the size of the
* delay slot so that env->pc - env->dslot point to the branch insn. This TB
* will execute the dslot and take the branch, either to btarget or just one
@@ -3143,7 +3143,7 @@
tcg_gen_lookup_and_goto_ptr();
break;
case DISAS_UPDATE:
- /* Indicate that interupts must be re-evaluated before the next TB. */
+ /* Indicate that interrupts must be re-evaluated before the next TB. */
tcg_gen_exit_tb(NULL, 0);
break;
default:
diff --git a/target/hppa/cpu.h b/target/hppa/cpu.h
index 7373177..9fe79b1 100644
--- a/target/hppa/cpu.h
+++ b/target/hppa/cpu.h
@@ -35,7 +35,7 @@
#define MMU_PHYS_IDX 4
#define TARGET_INSN_START_EXTRA_WORDS 1
-/* Hardware exceptions, interupts, faults, and traps. */
+/* Hardware exceptions, interrupts, faults, and traps. */
#define EXCP_HPMC 1 /* high priority machine check */
#define EXCP_POWER_FAIL 2
#define EXCP_RC 3 /* recovery counter */
@@ -276,7 +276,7 @@
/* TB lookup assumes that PC contains the complete virtual address.
If we leave space+offset separate, we'll get ITLB misses to an
incomplete virtual address. This also means that we must separate
- out current cpu priviledge from the low bits of IAOQ_F. */
+ out current cpu privilege from the low bits of IAOQ_F. */
#ifdef CONFIG_USER_ONLY
*pc = env->iaoq_f & -4;
*cs_base = env->iaoq_b & -4;
diff --git a/target/hppa/int_helper.c b/target/hppa/int_helper.c
index d2480b1..bebc732 100644
--- a/target/hppa/int_helper.c
+++ b/target/hppa/int_helper.c
@@ -37,7 +37,7 @@
/* Each CPU has a word mapped into the GSC bus. Anything on the GSC bus
* can write to this word to raise an external interrupt on the target CPU.
- * This includes the system controler (DINO) for regular devices, or
+ * This includes the system controller (DINO) for regular devices, or
* another CPU for SMP interprocessor interrupts.
*/
static uint64_t io_eir_read(void *opaque, hwaddr addr, unsigned size)
diff --git a/target/hppa/translate.c b/target/hppa/translate.c
index d33813d..d66fcb3 100644
--- a/target/hppa/translate.c
+++ b/target/hppa/translate.c
@@ -1964,7 +1964,7 @@
{
/* If by some means we get here with PSW[N]=1, that implies that
the B,GATE instruction would be skipped, and we'd fault on the
- next insn within the privilaged page. */
+ next insn within the privileged page. */
switch (ctx->null_cond.c) {
case TCG_COND_NEVER:
break;
diff --git a/target/loongarch/cpu-csr.h b/target/loongarch/cpu-csr.h
index 4c8ce7f..f8f2403 100644
--- a/target/loongarch/cpu-csr.h
+++ b/target/loongarch/cpu-csr.h
@@ -10,7 +10,7 @@
#include "hw/registerfields.h"
-/* Base on kernal definitions: arch/loongarch/include/asm/loongarch.h */
+/* Based on kernel definitions: arch/loongarch/include/asm/loongarch.h */
/* Basic CSRs */
#define LOONGARCH_CSR_CRMD 0x0 /* Current mode info */
diff --git a/target/loongarch/cpu.h b/target/loongarch/cpu.h
index ed04027..fa371ca 100644
--- a/target/loongarch/cpu.h
+++ b/target/loongarch/cpu.h
@@ -342,6 +342,7 @@
uint64_t CSR_DBG;
uint64_t CSR_DERA;
uint64_t CSR_DSAVE;
+ uint64_t CSR_CPUID;
#ifndef CONFIG_USER_ONLY
LoongArchTLB tlb[LOONGARCH_TLB_MAX];
diff --git a/target/loongarch/csr_helper.c b/target/loongarch/csr_helper.c
index 6526367..5534155 100644
--- a/target/loongarch/csr_helper.c
+++ b/target/loongarch/csr_helper.c
@@ -35,6 +35,15 @@
return v;
}
+target_ulong helper_csrrd_cpuid(CPULoongArchState *env)
+{
+ LoongArchCPU *lac = env_archcpu(env);
+
+ env->CSR_CPUID = CPU(lac)->cpu_index;
+
+ return env->CSR_CPUID;
+}
+
target_ulong helper_csrrd_tval(CPULoongArchState *env)
{
LoongArchCPU *cpu = env_archcpu(env);
diff --git a/target/loongarch/helper.h b/target/loongarch/helper.h
index b9de77d..ffb1e0b 100644
--- a/target/loongarch/helper.h
+++ b/target/loongarch/helper.h
@@ -98,6 +98,7 @@
#ifndef CONFIG_USER_ONLY
/* CSRs helper */
DEF_HELPER_1(csrrd_pgd, i64, env)
+DEF_HELPER_1(csrrd_cpuid, i64, env)
DEF_HELPER_1(csrrd_tval, i64, env)
DEF_HELPER_2(csrwr_estat, i64, env, tl)
DEF_HELPER_2(csrwr_asid, i64, env, tl)
diff --git a/target/loongarch/insn_trans/trans_privileged.c.inc b/target/loongarch/insn_trans/trans_privileged.c.inc
index 02bca7c..9c9de09 100644
--- a/target/loongarch/insn_trans/trans_privileged.c.inc
+++ b/target/loongarch/insn_trans/trans_privileged.c.inc
@@ -99,13 +99,7 @@
CSR_OFF(PWCH),
CSR_OFF(STLBPS),
CSR_OFF(RVACFG),
- [LOONGARCH_CSR_CPUID] = {
- .offset = (int)offsetof(CPUState, cpu_index)
- - (int)offsetof(LoongArchCPU, env),
- .flags = CSRFL_READONLY,
- .readfn = NULL,
- .writefn = NULL
- },
+ CSR_OFF_FUNCS(CPUID, CSRFL_READONLY, gen_helper_csrrd_cpuid, NULL),
CSR_OFF_FLAGS(PRCFG1, CSRFL_READONLY),
CSR_OFF_FLAGS(PRCFG2, CSRFL_READONLY),
CSR_OFF_FLAGS(PRCFG3, CSRFL_READONLY),
diff --git a/target/m68k/helper.c b/target/m68k/helper.c
index 01c18a7..0a1544c 100644
--- a/target/m68k/helper.c
+++ b/target/m68k/helper.c
@@ -590,10 +590,10 @@
#define DUMP_CACHEFLAGS(a) \
switch (a & M68K_DESC_CACHEMODE) { \
- case M68K_DESC_CM_WRTHRU: /* cachable, write-through */ \
+ case M68K_DESC_CM_WRTHRU: /* cacheable, write-through */ \
qemu_printf("T"); \
break; \
- case M68K_DESC_CM_COPYBK: /* cachable, copyback */ \
+ case M68K_DESC_CM_COPYBK: /* cacheable, copyback */ \
qemu_printf("C"); \
break; \
case M68K_DESC_CM_SERIAL: /* noncachable, serialized */ \
diff --git a/target/microblaze/cpu.h b/target/microblaze/cpu.h
index a7b040a..f6cab6c 100644
--- a/target/microblaze/cpu.h
+++ b/target/microblaze/cpu.h
@@ -205,7 +205,7 @@
#define PVR10_TARGET_FAMILY_MASK 0xFF000000
#define PVR10_ASIZE_SHIFT 18
-/* MMU descrtiption */
+/* MMU description */
#define PVR11_USE_MMU 0xC0000000
#define PVR11_MMU_ITLB_SIZE 0x38000000
#define PVR11_MMU_DTLB_SIZE 0x07000000
diff --git a/target/mips/tcg/mxu_translate.c b/target/mips/tcg/mxu_translate.c
index deb8060..e662acd 100644
--- a/target/mips/tcg/mxu_translate.c
+++ b/target/mips/tcg/mxu_translate.c
@@ -609,7 +609,7 @@
static TCGv mxu_gpr[NUMBER_OF_MXU_REGISTERS - 1];
static TCGv mxu_CR;
-static const char mxuregnames[][4] = {
+static const char mxuregnames[NUMBER_OF_MXU_REGISTERS][4] = {
"XR1", "XR2", "XR3", "XR4", "XR5", "XR6", "XR7", "XR8",
"XR9", "XR10", "XR11", "XR12", "XR13", "XR14", "XR15", "XCR",
};
@@ -644,6 +644,16 @@
}
}
+static inline void gen_extract_mxu_gpr(TCGv t, unsigned int reg,
+ unsigned int ofs, unsigned int len)
+{
+ if (reg == 0) {
+ tcg_gen_movi_tl(t, 0);
+ } else if (reg <= 15) {
+ tcg_gen_extract_tl(t, mxu_gpr[reg - 1], ofs, len);
+ }
+}
+
/* MXU control register moves. */
static inline void gen_load_mxu_cr(TCGv t)
{
@@ -2434,8 +2444,12 @@
tcg_gen_movi_tl(mxu_gpr[XRa - 1], 0);
} else {
/* the most general case */
- tcg_gen_setcond_tl(TCG_COND_LT, mxu_gpr[XRa - 1],
- mxu_gpr[XRb - 1], mxu_gpr[XRc - 1]);
+ TCGv t0 = tcg_temp_new();
+ TCGv t1 = tcg_temp_new();
+
+ gen_load_mxu_gpr(t0, XRb);
+ gen_load_mxu_gpr(t1, XRc);
+ tcg_gen_setcond_tl(TCG_COND_LT, mxu_gpr[XRa - 1], t0, t1);
}
}
@@ -3000,10 +3014,10 @@
TCGv t5 = tcg_temp_new();
if (XRa != 0) {
- tcg_gen_extract_tl(t0, mxu_gpr[XRb - 1], 16, 8);
- tcg_gen_extract_tl(t1, mxu_gpr[XRc - 1], 16, 8);
- tcg_gen_extract_tl(t2, mxu_gpr[XRb - 1], 24, 8);
- tcg_gen_extract_tl(t3, mxu_gpr[XRc - 1], 24, 8);
+ gen_extract_mxu_gpr(t0, XRb, 16, 8);
+ gen_extract_mxu_gpr(t1, XRc, 16, 8);
+ gen_extract_mxu_gpr(t2, XRb, 24, 8);
+ gen_extract_mxu_gpr(t3, XRc, 24, 8);
if (aptn2 & 2) {
tcg_gen_sub_tl(t0, t0, t1);
tcg_gen_sub_tl(t2, t2, t3);
@@ -3023,10 +3037,10 @@
tcg_gen_or_tl(t4, t2, t0);
}
if (XRd != 0) {
- tcg_gen_extract_tl(t0, mxu_gpr[XRb - 1], 0, 8);
- tcg_gen_extract_tl(t1, mxu_gpr[XRc - 1], 0, 8);
- tcg_gen_extract_tl(t2, mxu_gpr[XRb - 1], 8, 8);
- tcg_gen_extract_tl(t3, mxu_gpr[XRc - 1], 8, 8);
+ gen_extract_mxu_gpr(t0, XRb, 0, 8);
+ gen_extract_mxu_gpr(t1, XRc, 0, 8);
+ gen_extract_mxu_gpr(t2, XRb, 8, 8);
+ gen_extract_mxu_gpr(t3, XRc, 8, 8);
if (aptn2 & 1) {
tcg_gen_sub_tl(t0, t0, t1);
tcg_gen_sub_tl(t2, t2, t3);
diff --git a/target/mips/tcg/sysemu/tlb_helper.c b/target/mips/tcg/sysemu/tlb_helper.c
index e5e1e9d..7dbc2e2 100644
--- a/target/mips/tcg/sysemu/tlb_helper.c
+++ b/target/mips/tcg/sysemu/tlb_helper.c
@@ -623,18 +623,13 @@
static int walk_directory(CPUMIPSState *env, uint64_t *vaddr,
int directory_index, bool *huge_page, bool *hgpg_directory_hit,
- uint64_t *pw_entrylo0, uint64_t *pw_entrylo1)
+ uint64_t *pw_entrylo0, uint64_t *pw_entrylo1,
+ unsigned directory_shift, unsigned leaf_shift)
{
int dph = (env->CP0_PWCtl >> CP0PC_DPH) & 0x1;
int psn = (env->CP0_PWCtl >> CP0PC_PSN) & 0x3F;
int hugepg = (env->CP0_PWCtl >> CP0PC_HUGEPG) & 0x1;
int pf_ptew = (env->CP0_PWField >> CP0PF_PTEW) & 0x3F;
- int ptew = (env->CP0_PWSize >> CP0PS_PTEW) & 0x3F;
- int native_shift = (((env->CP0_PWSize >> CP0PS_PS) & 1) == 0) ? 2 : 3;
- int directory_shift = (ptew > 1) ? -1 :
- (hugepg && (ptew == 1)) ? native_shift + 1 : native_shift;
- int leaf_shift = (ptew > 1) ? -1 :
- (ptew == 1) ? native_shift + 1 : native_shift;
uint32_t direntry_size = 1 << (directory_shift + 3);
uint32_t leafentry_size = 1 << (leaf_shift + 3);
uint64_t entry;
@@ -735,21 +730,11 @@
/* Other HTW configs */
int hugepg = (env->CP0_PWCtl >> CP0PC_HUGEPG) & 0x1;
-
- /* HTW Shift values (depend on entry size) */
- int directory_shift = (ptew > 1) ? -1 :
- (hugepg && (ptew == 1)) ? native_shift + 1 : native_shift;
- int leaf_shift = (ptew > 1) ? -1 :
- (ptew == 1) ? native_shift + 1 : native_shift;
+ unsigned directory_shift, leaf_shift;
/* Offsets into tables */
- int goffset = gindex << directory_shift;
- int uoffset = uindex << directory_shift;
- int moffset = mindex << directory_shift;
- int ptoffset0 = (ptindex >> 1) << (leaf_shift + 1);
- int ptoffset1 = ptoffset0 | (1 << (leaf_shift));
-
- uint32_t leafentry_size = 1 << (leaf_shift + 3);
+ unsigned goffset, uoffset, moffset, ptoffset0, ptoffset1;
+ uint32_t leafentry_size;
/* Starting address - Page Table Base */
uint64_t vaddr = env->CP0_PWBase;
@@ -771,15 +756,28 @@
/* no structure to walk */
return false;
}
- if ((directory_shift == -1) || (leaf_shift == -1)) {
+ if (ptew > 1) {
return false;
}
+ /* HTW Shift values (depend on entry size) */
+ directory_shift = (hugepg && (ptew == 1)) ? native_shift + 1 : native_shift;
+ leaf_shift = (ptew == 1) ? native_shift + 1 : native_shift;
+
+ goffset = gindex << directory_shift;
+ uoffset = uindex << directory_shift;
+ moffset = mindex << directory_shift;
+ ptoffset0 = (ptindex >> 1) << (leaf_shift + 1);
+ ptoffset1 = ptoffset0 | (1 << (leaf_shift));
+
+ leafentry_size = 1 << (leaf_shift + 3);
+
/* Global Directory */
if (gdw > 0) {
vaddr |= goffset;
switch (walk_directory(env, &vaddr, pf_gdw, &huge_page, &hgpg_gdhit,
- &pw_entrylo0, &pw_entrylo1))
+ &pw_entrylo0, &pw_entrylo1,
+ directory_shift, leaf_shift))
{
case 0:
return false;
@@ -795,7 +793,8 @@
if (udw > 0) {
vaddr |= uoffset;
switch (walk_directory(env, &vaddr, pf_udw, &huge_page, &hgpg_udhit,
- &pw_entrylo0, &pw_entrylo1))
+ &pw_entrylo0, &pw_entrylo1,
+ directory_shift, leaf_shift))
{
case 0:
return false;
@@ -811,7 +810,8 @@
if (mdw > 0) {
vaddr |= moffset;
switch (walk_directory(env, &vaddr, pf_mdw, &huge_page, &hgpg_mdhit,
- &pw_entrylo0, &pw_entrylo1))
+ &pw_entrylo0, &pw_entrylo1,
+ directory_shift, leaf_shift))
{
case 0:
return false;
diff --git a/target/openrisc/cpu.h b/target/openrisc/cpu.h
index 92c38f5..ce4d605 100644
--- a/target/openrisc/cpu.h
+++ b/target/openrisc/cpu.h
@@ -290,7 +290,7 @@
int is_counting;
uint32_t picmr; /* Interrupt mask register */
- uint32_t picsr; /* Interrupt contrl register*/
+ uint32_t picsr; /* Interrupt control register */
#endif
} CPUOpenRISCState;
diff --git a/target/openrisc/translate.c b/target/openrisc/translate.c
index 7760329..a86360d 100644
--- a/target/openrisc/translate.c
+++ b/target/openrisc/translate.c
@@ -273,7 +273,7 @@
tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_sr_ov, srcb, 0);
/* The result of divide-by-zero is undefined.
- Supress the host-side exception by dividing by 1. */
+ Suppress the host-side exception by dividing by 1. */
tcg_gen_or_tl(t0, srcb, cpu_sr_ov);
tcg_gen_div_tl(dest, srca, t0);
@@ -287,7 +287,7 @@
tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_sr_cy, srcb, 0);
/* The result of divide-by-zero is undefined.
- Supress the host-side exception by dividing by 1. */
+ Suppress the host-side exception by dividing by 1. */
tcg_gen_or_tl(t0, srcb, cpu_sr_cy);
tcg_gen_divu_tl(dest, srca, t0);
diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
index 9339c02..6b93b04 100644
--- a/target/riscv/cpu.c
+++ b/target/riscv/cpu.c
@@ -1225,7 +1225,8 @@
}
}
- if (riscv_has_ext(env, RVC)) {
+ /* zca, zcd and zcf has a PRIV 1.12.0 restriction */
+ if (riscv_has_ext(env, RVC) && env->priv_ver >= PRIV_VERSION_1_12_0) {
cpu->cfg.ext_zca = true;
if (riscv_has_ext(env, RVF) && env->misa_mxl_max == MXL_RV32) {
cpu->cfg.ext_zcf = true;
diff --git a/target/riscv/vector_helper.c b/target/riscv/vector_helper.c
index cfacf2e..4d06754 100644
--- a/target/riscv/vector_helper.c
+++ b/target/riscv/vector_helper.c
@@ -43,9 +43,9 @@
xlen - 1 - R_VTYPE_RESERVED_SHIFT);
if (lmul & 4) {
- /* Fractional LMUL. */
+ /* Fractional LMUL - check LMUL * VLEN >= SEW */
if (lmul == 4 ||
- cpu->cfg.elen >> (8 - lmul) < sew) {
+ cpu->cfg.vlen >> (8 - lmul) < sew) {
vill = true;
}
}
diff --git a/target/rx/translate.c b/target/rx/translate.c
index 08cabbd..f552a03 100644
--- a/target/rx/translate.c
+++ b/target/rx/translate.c
@@ -2066,7 +2066,7 @@
tcg_gen_movi_i32(cpu_psw_o, val << 31);
break;
default:
- qemu_log_mask(LOG_GUEST_ERROR, "Invalid distination %d", cb);
+ qemu_log_mask(LOG_GUEST_ERROR, "Invalid destination %d", cb);
break;
}
} else if (is_privileged(ctx, 0)) {
@@ -2084,7 +2084,7 @@
}
break;
default:
- qemu_log_mask(LOG_GUEST_ERROR, "Invalid distination %d", cb);
+ qemu_log_mask(LOG_GUEST_ERROR, "Invalid destination %d", cb);
break;
}
}
diff --git a/target/s390x/cpu_features.c b/target/s390x/cpu_features.c
index ebb155c..d28eb65 100644
--- a/target/s390x/cpu_features.c
+++ b/target/s390x/cpu_features.c
@@ -249,7 +249,7 @@
{
int i;
- /* init all bitmaps from gnerated data initially */
+ /* init all bitmaps from generated data initially */
for (i = 0; i < ARRAY_SIZE(s390_feature_groups); i++) {
s390_init_feat_bitmap(s390_feature_groups[i].init,
s390_feature_groups[i].feat);
diff --git a/target/s390x/cpu_models.c b/target/s390x/cpu_models.c
index 42b52af..91ce896 100644
--- a/target/s390x/cpu_models.c
+++ b/target/s390x/cpu_models.c
@@ -975,7 +975,7 @@
init_ignored_base_feat();
- /* init all bitmaps from gnerated data initially */
+ /* init all bitmaps from generated data initially */
s390_init_feat_bitmap(qemu_max_init, qemu_max_cpu_feat);
for (i = 0; i < ARRAY_SIZE(s390_cpu_defs); i++) {
s390_init_feat_bitmap(s390_cpu_defs[i].base_init,
diff --git a/target/s390x/tcg/excp_helper.c b/target/s390x/tcg/excp_helper.c
index 228aa9f..3da337f 100644
--- a/target/s390x/tcg/excp_helper.c
+++ b/target/s390x/tcg/excp_helper.c
@@ -639,7 +639,7 @@
void HELPER(monitor_call)(CPUS390XState *env, uint64_t monitor_code,
uint32_t monitor_class)
{
- g_assert(monitor_class <= 0xff);
+ g_assert(monitor_class <= 0xf);
if (env->cregs[8] & (0x8000 >> monitor_class)) {
monitor_event(env, monitor_code, monitor_class, GETPC());
diff --git a/target/s390x/tcg/fpu_helper.c b/target/s390x/tcg/fpu_helper.c
index 4b7fa58..c329b31 100644
--- a/target/s390x/tcg/fpu_helper.c
+++ b/target/s390x/tcg/fpu_helper.c
@@ -52,7 +52,8 @@
s390_exc |= (exc & float_flag_divbyzero) ? S390_IEEE_MASK_DIVBYZERO : 0;
s390_exc |= (exc & float_flag_overflow) ? S390_IEEE_MASK_OVERFLOW : 0;
s390_exc |= (exc & float_flag_underflow) ? S390_IEEE_MASK_UNDERFLOW : 0;
- s390_exc |= (exc & float_flag_inexact) ? S390_IEEE_MASK_INEXACT : 0;
+ s390_exc |= (exc & (float_flag_inexact | float_flag_invalid_cvti)) ?
+ S390_IEEE_MASK_INEXACT : 0;
return s390_exc;
}
@@ -86,7 +87,7 @@
/*
* FIXME:
- * 1. Right now, all inexact conditions are inidicated as
+ * 1. Right now, all inexact conditions are indicated as
* "truncated" (0) and never as "incremented" (1) in the DXC.
* 2. Only traps due to invalid/divbyzero are suppressing. Other traps
* are completing, meaning the target register has to be written!
diff --git a/target/s390x/tcg/insn-data.h.inc b/target/s390x/tcg/insn-data.h.inc
index 457ed25..0bfd88d 100644
--- a/target/s390x/tcg/insn-data.h.inc
+++ b/target/s390x/tcg/insn-data.h.inc
@@ -157,7 +157,7 @@
C(0xb2fa, NIAI, E, EH, 0, 0, 0, 0, 0, 0)
/* CHECKSUM */
- C(0xb241, CKSM, RRE, Z, r1_o, ra2, new, r1_32, cksm, 0)
+ C(0xb241, CKSM, RRE, Z, r1_o, ra2_E, new, r1_32, cksm, 0)
/* COPY SIGN */
F(0xb372, CPSDR, RRF_b, FPSSH, f3, f2, new, f1, cps, 0, IF_AFP1 | IF_AFP2 | IF_AFP3)
@@ -529,7 +529,7 @@
/* LOAD LOGICAL HALFWORD RELATIVE LONG */
C(0xc402, LLHRL, RIL_b, GIE, 0, ri2, new, r1_32, ld16u, 0)
C(0xc406, LLGHRL, RIL_b, GIE, 0, ri2, r1, 0, ld16u, 0)
-/* LOAD LOGICAL IMMEDATE */
+/* LOAD LOGICAL IMMEDIATE */
D(0xc00e, LLIHF, RIL_a, EI, 0, i2_32u_shl, 0, r1, mov2, 0, 32)
D(0xc00f, LLILF, RIL_a, EI, 0, i2_32u_shl, 0, r1, mov2, 0, 0)
D(0xa50c, LLIHH, RI_a, Z, 0, i2_16u_shl, 0, r1, mov2, 0, 48)
diff --git a/target/s390x/tcg/mem_helper.c b/target/s390x/tcg/mem_helper.c
index f417fb1..8410325 100644
--- a/target/s390x/tcg/mem_helper.c
+++ b/target/s390x/tcg/mem_helper.c
@@ -667,6 +667,11 @@
HELPER_LOG("%s: r1 0x%x mask 0x%x addr 0x%" PRIx64 "\n", __func__, r1,
mask, addr);
+ if (!mask) {
+ /* Recognize access exceptions for the first byte */
+ probe_read(env, addr, 1, cpu_mmu_index(env, false), ra);
+ }
+
while (mask) {
if (mask & 8) {
uint8_t d = cpu_ldub_data_ra(env, addr, ra);
diff --git a/target/s390x/tcg/translate.c b/target/s390x/tcg/translate.c
index 6661b27..dc7041e 100644
--- a/target/s390x/tcg/translate.c
+++ b/target/s390x/tcg/translate.c
@@ -429,7 +429,7 @@
static void gen_program_exception(DisasContext *s, int code)
{
- /* Remember what pgm exeption this was. */
+ /* Remember what pgm exception this was. */
tcg_gen_st_i32(tcg_constant_i32(code), cpu_env,
offsetof(CPUS390XState, int_pgm_code));
@@ -2515,6 +2515,12 @@
ccm = ((1ull << len) - 1) << pos;
break;
+ case 0:
+ /* Recognize access exceptions for the first byte. */
+ tcg_gen_qemu_ld_i64(tmp, o->in2, get_mem_index(s), MO_UB);
+ gen_op_movi_cc(s, 0);
+ return DISAS_NEXT;
+
default:
/* This is going to be a sequence of loads and inserts. */
pos = base + 32 - 8;
@@ -3171,9 +3177,9 @@
static DisasJumpType op_mc(DisasContext *s, DisasOps *o)
{
- const uint16_t monitor_class = get_field(s, i2);
+ const uint8_t monitor_class = get_field(s, i2);
- if (monitor_class & 0xff00) {
+ if (monitor_class & 0xf0) {
gen_program_exception(s, PGM_SPECIFICATION);
return DISAS_NORETURN;
}
@@ -5779,6 +5785,12 @@
}
#define SPEC_in2_ra2 0
+static void in2_ra2_E(DisasContext *s, DisasOps *o)
+{
+ return in2_ra2(s, o);
+}
+#define SPEC_in2_ra2_E SPEC_r2_even
+
static void in2_a2(DisasContext *s, DisasOps *o)
{
int x2 = have_field(s, x2) ? get_field(s, x2) : 0;
diff --git a/target/s390x/tcg/translate_vx.c.inc b/target/s390x/tcg/translate_vx.c.inc
index 43dfbfd..f8df121 100644
--- a/target/s390x/tcg/translate_vx.c.inc
+++ b/target/s390x/tcg/translate_vx.c.inc
@@ -3047,7 +3047,7 @@
const uint8_t m5 = get_field(s, m5);
gen_helper_gvec_3_ptr *fn;
- if (m6 == 5 || m6 == 6 || m6 == 7 || m6 > 13) {
+ if (m6 == 5 || m6 == 6 || m6 == 7 || m6 >= 13) {
gen_program_exception(s, PGM_SPECIFICATION);
return DISAS_NORETURN;
}
diff --git a/target/sparc/asi.h b/target/sparc/asi.h
index bb58735..3270ed0 100644
--- a/target/sparc/asi.h
+++ b/target/sparc/asi.h
@@ -144,13 +144,13 @@
* ASIs, "(4V)" designates SUN4V specific ASIs. "(NG4)" designates SPARC-T4
* and later ASIs.
*/
-#define ASI_REAL 0x14 /* Real address, cachable */
+#define ASI_REAL 0x14 /* Real address, cacheable */
#define ASI_PHYS_USE_EC 0x14 /* PADDR, E-cachable */
#define ASI_REAL_IO 0x15 /* Real address, non-cachable */
#define ASI_PHYS_BYPASS_EC_E 0x15 /* PADDR, E-bit */
#define ASI_BLK_AIUP_4V 0x16 /* (4V) Prim, user, block ld/st */
#define ASI_BLK_AIUS_4V 0x17 /* (4V) Sec, user, block ld/st */
-#define ASI_REAL_L 0x1c /* Real address, cachable, LE */
+#define ASI_REAL_L 0x1c /* Real address, cacheable, LE */
#define ASI_PHYS_USE_EC_L 0x1c /* PADDR, E-cachable, little endian*/
#define ASI_REAL_IO_L 0x1d /* Real address, non-cachable, LE */
#define ASI_PHYS_BYPASS_EC_E_L 0x1d /* PADDR, E-bit, little endian */
@@ -163,15 +163,15 @@
#define ASI_BLK_INIT_QUAD_LDD_AIUS 0x23 /* (NG) init-store, twin load,
* secondary, user
*/
-#define ASI_NUCLEUS_QUAD_LDD 0x24 /* Cachable, qword load */
+#define ASI_NUCLEUS_QUAD_LDD 0x24 /* Cacheable, qword load */
#define ASI_QUEUE 0x25 /* (4V) Interrupt Queue Registers */
-#define ASI_TWINX_REAL 0x26 /* twin load, real, cachable */
+#define ASI_TWINX_REAL 0x26 /* twin load, real, cacheable */
#define ASI_QUAD_LDD_PHYS_4V 0x26 /* (4V) Physical, qword load */
#define ASI_TWINX_N 0x27 /* twin load, nucleus */
#define ASI_TWINX_AIUP_L 0x2a /* twin load, primary user, LE */
#define ASI_TWINX_AIUS_L 0x2b /* twin load, secondary user, LE */
-#define ASI_NUCLEUS_QUAD_LDD_L 0x2c /* Cachable, qword load, l-endian */
-#define ASI_TWINX_REAL_L 0x2e /* twin load, real, cachable, LE */
+#define ASI_NUCLEUS_QUAD_LDD_L 0x2c /* Cacheable, qword load, l-endian */
+#define ASI_TWINX_REAL_L 0x2e /* twin load, real, cacheable, LE */
#define ASI_QUAD_LDD_PHYS_L_4V 0x2e /* (4V) Phys, qword load, l-endian */
#define ASI_TWINX_NL 0x2f /* twin load, nucleus, LE */
#define ASI_PCACHE_DATA_STATUS 0x30 /* (III) PCache data stat RAM diag */
@@ -231,7 +231,7 @@
#define ASI_INTR_ID 0x63 /* (CMT) Interrupt ID register */
#define ASI_CORE_ID 0x63 /* (CMT) LP ID register */
#define ASI_CESR_ID 0x63 /* (CMT) CESR ID register */
-#define ASI_IC_INSTR 0x66 /* Insn cache instrucion ram diag */
+#define ASI_IC_INSTR 0x66 /* Insn cache instruction ram diag */
#define ASI_IC_TAG 0x67 /* Insn cache tag/valid ram diag */
#define ASI_IC_STAG 0x68 /* (III) Insn cache snoop tag ram */
#define ASI_IC_PRE_DECODE 0x6e /* Insn cache pre-decode ram diag */
diff --git a/target/sparc/cpu.c b/target/sparc/cpu.c
index e329a7a..130ab8f 100644
--- a/target/sparc/cpu.c
+++ b/target/sparc/cpu.c
@@ -673,8 +673,8 @@
"cleanwin: %d cwp: %d\n",
env->cansave, env->canrestore, env->otherwin, env->wstate,
env->cleanwin, env->nwindows - 1 - env->cwp);
- qemu_fprintf(f, "fsr: " TARGET_FMT_lx " y: " TARGET_FMT_lx " fprs: "
- TARGET_FMT_lx "\n", env->fsr, env->y, env->fprs);
+ qemu_fprintf(f, "fsr: " TARGET_FMT_lx " y: " TARGET_FMT_lx " fprs: %016x\n",
+ env->fsr, env->y, env->fprs);
#else
qemu_fprintf(f, "psr: %08x (icc: ", cpu_get_psr(env));
diff --git a/target/sparc/cpu.h b/target/sparc/cpu.h
index 95d2d0d..9804457 100644
--- a/target/sparc/cpu.h
+++ b/target/sparc/cpu.h
@@ -521,7 +521,7 @@
uint64_t igregs[8]; /* interrupt general registers */
uint64_t mgregs[8]; /* mmu general registers */
uint64_t glregs[8 * MAXTL_MAX];
- uint64_t fprs;
+ uint32_t fprs;
uint64_t tick_cmpr, stick_cmpr;
CPUTimer *tick, *stick;
#define TICK_NPT_MASK 0x8000000000000000ULL
diff --git a/target/sparc/machine.c b/target/sparc/machine.c
index 44b9e7d..274e121 100644
--- a/target/sparc/machine.c
+++ b/target/sparc/machine.c
@@ -168,7 +168,8 @@
VMSTATE_UINT64_ARRAY(env.bgregs, SPARCCPU, 8),
VMSTATE_UINT64_ARRAY(env.igregs, SPARCCPU, 8),
VMSTATE_UINT64_ARRAY(env.mgregs, SPARCCPU, 8),
- VMSTATE_UINT64(env.fprs, SPARCCPU),
+ VMSTATE_UNUSED(4), /* was unused high half of uint64_t fprs */
+ VMSTATE_UINT32(env.fprs, SPARCCPU),
VMSTATE_UINT64(env.tick_cmpr, SPARCCPU),
VMSTATE_UINT64(env.stick_cmpr, SPARCCPU),
VMSTATE_CPU_TIMER(env.tick, SPARCCPU),
diff --git a/target/sparc/monitor.c b/target/sparc/monitor.c
index 3184136..73f15aa 100644
--- a/target/sparc/monitor.c
+++ b/target/sparc/monitor.c
@@ -154,7 +154,7 @@
{ "otherwin", offsetof(CPUSPARCState, otherwin) },
{ "wstate", offsetof(CPUSPARCState, wstate) },
{ "cleanwin", offsetof(CPUSPARCState, cleanwin) },
- { "fprs", offsetof(CPUSPARCState, fprs) },
+ { "fprs", offsetof(CPUSPARCState, fprs), NULL, MD_I32 },
#endif
{ NULL },
};
diff --git a/target/tricore/cpu.c b/target/tricore/cpu.c
index f15169b..133a9ac 100644
--- a/target/tricore/cpu.c
+++ b/target/tricore/cpu.c
@@ -104,18 +104,18 @@
}
/* Some features automatically imply others */
- if (tricore_feature(env, TRICORE_FEATURE_162)) {
+ if (tricore_has_feature(env, TRICORE_FEATURE_162)) {
set_feature(env, TRICORE_FEATURE_161);
}
- if (tricore_feature(env, TRICORE_FEATURE_161)) {
+ if (tricore_has_feature(env, TRICORE_FEATURE_161)) {
set_feature(env, TRICORE_FEATURE_16);
}
- if (tricore_feature(env, TRICORE_FEATURE_16)) {
+ if (tricore_has_feature(env, TRICORE_FEATURE_16)) {
set_feature(env, TRICORE_FEATURE_131);
}
- if (tricore_feature(env, TRICORE_FEATURE_131)) {
+ if (tricore_has_feature(env, TRICORE_FEATURE_131)) {
set_feature(env, TRICORE_FEATURE_13);
}
cpu_reset(cs);
diff --git a/target/tricore/cpu.h b/target/tricore/cpu.h
index a50b91c..3708405 100644
--- a/target/tricore/cpu.h
+++ b/target/tricore/cpu.h
@@ -277,7 +277,7 @@
TRICORE_FEATURE_162,
};
-static inline int tricore_feature(CPUTriCoreState *env, int feature)
+static inline int tricore_has_feature(CPUTriCoreState *env, int feature)
{
return (env->features & (1ULL << feature)) != 0;
}
diff --git a/target/tricore/csfr.h.inc b/target/tricore/csfr.h.inc
index ff004cb..cdfaf1d 100644
--- a/target/tricore/csfr.h.inc
+++ b/target/tricore/csfr.h.inc
@@ -1,4 +1,4 @@
-/* A(ll) access permited
+/* A(ll) access permitted
R(ead only) access
E(nd init protected) access
diff --git a/target/tricore/helper.c b/target/tricore/helper.c
index 951024d..6d076ac 100644
--- a/target/tricore/helper.c
+++ b/target/tricore/helper.c
@@ -57,7 +57,7 @@
return phys_addr;
}
-/* TODO: Add exeption support*/
+/* TODO: Add exception support */
static void raise_mmu_exception(CPUTriCoreState *env, target_ulong address,
int rw, int tlb_error)
{
@@ -155,7 +155,7 @@
#define FIELD_GETTER_WITH_FEATURE(NAME, REG, FIELD, FEATURE) \
uint32_t NAME(CPUTriCoreState *env) \
{ \
- if (tricore_feature(env, TRICORE_FEATURE_##FEATURE)) { \
+ if (tricore_has_feature(env, TRICORE_FEATURE_##FEATURE)) { \
return FIELD_EX32(env->REG, REG, FIELD ## _ ## FEATURE); \
} \
return FIELD_EX32(env->REG, REG, FIELD ## _13); \
@@ -170,7 +170,7 @@
#define FIELD_SETTER_WITH_FEATURE(NAME, REG, FIELD, FEATURE) \
void NAME(CPUTriCoreState *env, uint32_t val) \
{ \
- if (tricore_feature(env, TRICORE_FEATURE_##FEATURE)) { \
+ if (tricore_has_feature(env, TRICORE_FEATURE_##FEATURE)) { \
env->REG = FIELD_DP32(env->REG, REG, FIELD ## _ ## FEATURE, val); \
} \
env->REG = FIELD_DP32(env->REG, REG, FIELD ## _13, val); \
diff --git a/target/tricore/op_helper.c b/target/tricore/op_helper.c
index 821a4b6..89be1ed 100644
--- a/target/tricore/op_helper.c
+++ b/target/tricore/op_helper.c
@@ -2584,7 +2584,7 @@
/* PCXI = new_PCXI; */
env->PCXI = new_PCXI;
- if (tricore_feature(env, TRICORE_FEATURE_131)) {
+ if (tricore_has_feature(env, TRICORE_FEATURE_131)) {
/* PSW = {new_PSW[31:26], PSW[25:24], new_PSW[23:0]}; */
psw_write(env, (new_PSW & ~(0x3000000)) + (psw & (0x3000000)));
} else { /* TRICORE_FEATURE_13 only */
@@ -2695,7 +2695,7 @@
env->gpr_a[10] = cpu_ldl_data(env, env->DCX+8);
env->gpr_a[11] = cpu_ldl_data(env, env->DCX+12);
- if (tricore_feature(env, TRICORE_FEATURE_131)) {
+ if (tricore_has_feature(env, TRICORE_FEATURE_131)) {
env->DBGTCR = 0;
}
}
diff --git a/target/tricore/translate.c b/target/tricore/translate.c
index 2f32463..1947733 100644
--- a/target/tricore/translate.c
+++ b/target/tricore/translate.c
@@ -128,7 +128,7 @@
* Functions to generate micro-ops
*/
-/* Makros for generating helpers */
+/* Macros for generating helpers */
#define gen_helper_1arg(name, arg) do { \
TCGv_i32 helper_tmp = tcg_constant_i32(arg); \
@@ -336,8 +336,8 @@
/* We generate loads and store to core special function register (csfr) through
the function gen_mfcr and gen_mtcr. To handle access permissions, we use 3
- makros R, A and E, which allow read-only, all and endinit protected access.
- These makros also specify in which ISA version the csfr was introduced. */
+ macros R, A and E, which allow read-only, all and endinit protected access.
+ These macros also specify in which ISA version the csfr was introduced. */
#define R(ADDRESS, REG, FEATURE) \
case ADDRESS: \
if (has_feature(ctx, FEATURE)) { \
@@ -362,7 +362,7 @@
#undef E
#define R(ADDRESS, REG, FEATURE) /* don't gen writes to read-only reg,
- since no execption occurs */
+ since no exception occurs */
#define A(ADDRESS, REG, FEATURE) R(ADDRESS, REG, FEATURE) \
case ADDRESS: \
if (has_feature(ctx, FEATURE)) { \
diff --git a/tcg/i386/tcg-target-con-set.h b/tcg/i386/tcg-target-con-set.h
index 91ceb0e..5ea3a29 100644
--- a/tcg/i386/tcg-target-con-set.h
+++ b/tcg/i386/tcg-target-con-set.h
@@ -11,6 +11,9 @@
*
* C_N1_Im(...) defines a constraint set with 1 output and <m> inputs,
* except that the output must use a new register.
+ *
+ * C_Nn_Om_Ik(...) defines a constraint set with <n + m> outputs and <k>
+ * inputs, except that the first <n> outputs must use new registers.
*/
C_O0_I1(r)
C_O0_I2(L, L)
@@ -53,4 +56,4 @@
C_O2_I2(a, d, a, r)
C_O2_I2(r, r, L, L)
C_O2_I3(a, d, 0, 1, r)
-C_O2_I4(r, r, 0, 1, re, re)
+C_N1_O1_I4(r, r, 0, 1, re, re)
diff --git a/tcg/i386/tcg-target.c.inc b/tcg/i386/tcg-target.c.inc
index ab997b5..77482da 100644
--- a/tcg/i386/tcg-target.c.inc
+++ b/tcg/i386/tcg-target.c.inc
@@ -3335,7 +3335,7 @@
case INDEX_op_add2_i64:
case INDEX_op_sub2_i32:
case INDEX_op_sub2_i64:
- return C_O2_I4(r, r, 0, 1, re, re);
+ return C_N1_O1_I4(r, r, 0, 1, re, re);
case INDEX_op_ctz_i32:
case INDEX_op_ctz_i64:
diff --git a/tcg/ppc/tcg-target.c.inc b/tcg/ppc/tcg-target.c.inc
index c866f2c..511e14b 100644
--- a/tcg/ppc/tcg-target.c.inc
+++ b/tcg/ppc/tcg-target.c.inc
@@ -2496,11 +2496,10 @@
ptrdiff_t offset = tcg_tbrel_diff(s, (void *)ptr);
tcg_out_mem_long(s, LD, LDX, TCG_REG_TB, TCG_REG_TB, offset);
- /* Direct branch will be patched by tb_target_set_jmp_target. */
+ /* TODO: Use direct branches when possible. */
set_jmp_insn_offset(s, which);
tcg_out32(s, MTSPR | RS(TCG_REG_TB) | CTR);
- /* When branch is out of range, fall through to indirect. */
tcg_out32(s, BCCTR | BO_ALWAYS);
/* For the unlinked case, need to reset TCG_REG_TB. */
@@ -2528,10 +2527,12 @@
intptr_t diff = addr - jmp_rx;
tcg_insn_unit insn;
+ if (USE_REG_TB) {
+ return;
+ }
+
if (in_range_b(diff)) {
insn = B | (diff & 0x3fffffc);
- } else if (USE_REG_TB) {
- insn = MTSPR | RS(TCG_REG_TB) | CTR;
} else {
insn = NOP;
}
diff --git a/tcg/s390x/tcg-target-con-set.h b/tcg/s390x/tcg-target-con-set.h
index cbad91b..9a42037 100644
--- a/tcg/s390x/tcg-target-con-set.h
+++ b/tcg/s390x/tcg-target-con-set.h
@@ -8,6 +8,9 @@
* C_On_Im(...) defines a constraint set with <n> outputs and <m> inputs.
* Each operand should be a sequence of constraint letters as defined by
* tcg-target-con-str.h; the constraint combination is inclusive or.
+ *
+ * C_Nn_Om_Ik(...) defines a constraint set with <n + m> outputs and <k>
+ * inputs, except that the first <n> outputs must use new registers.
*/
C_O0_I1(r)
C_O0_I2(r, r)
@@ -41,6 +44,5 @@
C_O2_I2(o, m, 0, r)
C_O2_I2(o, m, r, r)
C_O2_I3(o, m, 0, 1, r)
-C_O2_I4(r, r, 0, 1, rA, r)
-C_O2_I4(r, r, 0, 1, ri, r)
-C_O2_I4(r, r, 0, 1, r, r)
+C_N1_O1_I4(r, r, 0, 1, ri, r)
+C_N1_O1_I4(r, r, 0, 1, rA, r)
diff --git a/tcg/s390x/tcg-target.c.inc b/tcg/s390x/tcg-target.c.inc
index a878acd..a94f790 100644
--- a/tcg/s390x/tcg-target.c.inc
+++ b/tcg/s390x/tcg-target.c.inc
@@ -3229,11 +3229,11 @@
case INDEX_op_add2_i32:
case INDEX_op_sub2_i32:
- return C_O2_I4(r, r, 0, 1, ri, r);
+ return C_N1_O1_I4(r, r, 0, 1, ri, r);
case INDEX_op_add2_i64:
case INDEX_op_sub2_i64:
- return C_O2_I4(r, r, 0, 1, rA, r);
+ return C_N1_O1_I4(r, r, 0, 1, rA, r);
case INDEX_op_st_vec:
return C_O0_I2(v, r);
diff --git a/tcg/tcg.c b/tcg/tcg.c
index 652e8ea..ddfe9a9 100644
--- a/tcg/tcg.c
+++ b/tcg/tcg.c
@@ -648,6 +648,7 @@
#define C_O2_I2(O1, O2, I1, I2) C_PFX4(c_o2_i2_, O1, O2, I1, I2),
#define C_O2_I3(O1, O2, I1, I2, I3) C_PFX5(c_o2_i3_, O1, O2, I1, I2, I3),
#define C_O2_I4(O1, O2, I1, I2, I3, I4) C_PFX6(c_o2_i4_, O1, O2, I1, I2, I3, I4),
+#define C_N1_O1_I4(O1, O2, I1, I2, I3, I4) C_PFX6(c_n1_o1_i4_, O1, O2, I1, I2, I3, I4),
typedef enum {
#include "tcg-target-con-set.h"
@@ -668,6 +669,7 @@
#undef C_O2_I2
#undef C_O2_I3
#undef C_O2_I4
+#undef C_N1_O1_I4
/* Put all of the constraint sets into an array, indexed by the enum. */
@@ -687,6 +689,7 @@
#define C_O2_I2(O1, O2, I1, I2) { .args_ct_str = { #O1, #O2, #I1, #I2 } },
#define C_O2_I3(O1, O2, I1, I2, I3) { .args_ct_str = { #O1, #O2, #I1, #I2, #I3 } },
#define C_O2_I4(O1, O2, I1, I2, I3, I4) { .args_ct_str = { #O1, #O2, #I1, #I2, #I3, #I4 } },
+#define C_N1_O1_I4(O1, O2, I1, I2, I3, I4) { .args_ct_str = { "&" #O1, #O2, #I1, #I2, #I3, #I4 } },
static const TCGTargetOpDef constraint_sets[] = {
#include "tcg-target-con-set.h"
@@ -706,6 +709,7 @@
#undef C_O2_I2
#undef C_O2_I3
#undef C_O2_I4
+#undef C_N1_O1_I4
/* Expand the enumerator to be returned from tcg_target_op_def(). */
@@ -725,6 +729,7 @@
#define C_O2_I2(O1, O2, I1, I2) C_PFX4(c_o2_i2_, O1, O2, I1, I2)
#define C_O2_I3(O1, O2, I1, I2, I3) C_PFX5(c_o2_i3_, O1, O2, I1, I2, I3)
#define C_O2_I4(O1, O2, I1, I2, I3, I4) C_PFX6(c_o2_i4_, O1, O2, I1, I2, I3, I4)
+#define C_N1_O1_I4(O1, O2, I1, I2, I3, I4) C_PFX6(c_n1_o1_i4_, O1, O2, I1, I2, I3, I4)
#include "tcg-target.c.inc"
@@ -4703,7 +4708,8 @@
* dead after the instruction, we must allocate a new
* register and move it.
*/
- if (temp_readonly(ts) || !IS_DEAD_ARG(i)) {
+ if (temp_readonly(ts) || !IS_DEAD_ARG(i)
+ || def->args_ct[arg_ct->alias_index].newreg) {
allocate_new_reg = true;
} else if (ts->val_type == TEMP_VAL_REG) {
/*
diff --git a/tests/avocado/machine_aarch64_sbsaref.py b/tests/avocado/machine_aarch64_sbsaref.py
index cce6ef9..a794245 100644
--- a/tests/avocado/machine_aarch64_sbsaref.py
+++ b/tests/avocado/machine_aarch64_sbsaref.py
@@ -8,7 +8,6 @@
import os
-from avocado import skip
from avocado import skipUnless
from avocado.utils import archive
@@ -76,6 +75,7 @@ def fetch_firmware(self):
"sbsa-ref",
)
+ @skipUnless(os.getenv('QEMU_TEST_FLAKY_TESTS'), 'Test is not reliable')
def test_sbsaref_edk2_firmware(self):
"""
:avocado: tags=cpu:cortex-a57
diff --git a/tests/avocado/machine_s390_ccw_virtio.py b/tests/avocado/machine_s390_ccw_virtio.py
index 78152f2..e7a2a20 100644
--- a/tests/avocado/machine_s390_ccw_virtio.py
+++ b/tests/avocado/machine_s390_ccw_virtio.py
@@ -159,7 +159,6 @@ def test_s390x_devices(self):
'MemTotal: 115640 kB')
- @skipIf(os.getenv('GITLAB_CI'), 'Running on GitLab')
def test_s390x_fedora(self):
"""
@@ -229,31 +228,35 @@ def test_s390x_fedora(self):
# writing to the framebuffer. Since the PPM is uncompressed, we then
# can simply read the written "magic bytes" back from the PPM file to
# check whether the framebuffer is working as expected.
- self.log.info("Test screendump of virtio-gpu device")
- exec_command_and_wait_for_pattern(self,
+ # Unfortunately, this test is flaky, so we don't run it by default
+ if os.getenv('QEMU_TEST_FLAKY_TESTS'):
+ self.log.info("Test screendump of virtio-gpu device")
+ exec_command_and_wait_for_pattern(self,
'while ! (dmesg | grep gpudrmfb) ; do sleep 1 ; done',
'virtio_gpudrmfb frame buffer device')
- exec_command_and_wait_for_pattern(self,
- 'echo -e "\e[?25l" > /dev/tty0', ':/#')
- exec_command_and_wait_for_pattern(self, 'for ((i=0;i<250;i++)); do '
- 'echo " The qu ick fo x j ump s o ver a laz y d og" >> fox.txt;'
- 'done',
- ':/#')
- exec_command_and_wait_for_pattern(self,
- 'dd if=fox.txt of=/dev/fb0 bs=1000 oflag=sync,nocache ; rm fox.txt',
- '12+0 records out')
- with tempfile.NamedTemporaryFile(suffix='.ppm',
- prefix='qemu-scrdump-') as ppmfile:
- self.vm.command('screendump', filename=ppmfile.name)
- ppmfile.seek(0)
- line = ppmfile.readline()
- self.assertEqual(line, b"P6\n")
- line = ppmfile.readline()
- self.assertEqual(line, b"1280 800\n")
- line = ppmfile.readline()
- self.assertEqual(line, b"255\n")
- line = ppmfile.readline(256)
- self.assertEqual(line, b"The quick fox jumps over a lazy dog\n")
+ exec_command_and_wait_for_pattern(self,
+ 'echo -e "\e[?25l" > /dev/tty0', ':/#')
+ exec_command_and_wait_for_pattern(self, 'for ((i=0;i<250;i++)); do '
+ 'echo " The qu ick fo x j ump s o ver a laz y d og" >> fox.txt;'
+ 'done',
+ ':/#')
+ exec_command_and_wait_for_pattern(self,
+ 'dd if=fox.txt of=/dev/fb0 bs=1000 oflag=sync,nocache ; rm fox.txt',
+ '12+0 records out')
+ with tempfile.NamedTemporaryFile(suffix='.ppm',
+ prefix='qemu-scrdump-') as ppmfile:
+ self.vm.command('screendump', filename=ppmfile.name)
+ ppmfile.seek(0)
+ line = ppmfile.readline()
+ self.assertEqual(line, b"P6\n")
+ line = ppmfile.readline()
+ self.assertEqual(line, b"1280 800\n")
+ line = ppmfile.readline()
+ self.assertEqual(line, b"255\n")
+ line = ppmfile.readline(256)
+ self.assertEqual(line, b"The quick fox jumps over a lazy dog\n")
+ else:
+ self.log.info("Skipped flaky screendump of virtio-gpu device test")
# Hot-plug a virtio-crypto device and see whether it gets accepted
self.log.info("Test hot-plug virtio-crypto device")
diff --git a/tests/avocado/migration.py b/tests/avocado/migration.py
index 8b2ec0e..fdc1d23 100644
--- a/tests/avocado/migration.py
+++ b/tests/avocado/migration.py
@@ -134,21 +134,3 @@ def test_migration_with_unix(self):
def test_migration_with_exec(self):
self.migration_with_exec()
-
-
-@skipUnless('s390x' in os.uname()[4], "host != target")
-class S390X(MigrationTest):
- """
- :avocado: tags=arch:s390x
- :avocado: tags=machine:s390-ccw-virtio
- :avocado: tags=cpu:qemu
- """
-
- def test_migration_with_tcp_localhost(self):
- self.migration_with_tcp_localhost()
-
- def test_migration_with_unix(self):
- self.migration_with_unix()
-
- def test_migration_with_exec(self):
- self.migration_with_exec()
diff --git a/tests/docker/dockerfiles/alpine.docker b/tests/docker/dockerfiles/alpine.docker
index 43370f7..fa455f1 100644
--- a/tests/docker/dockerfiles/alpine.docker
+++ b/tests/docker/dockerfiles/alpine.docker
@@ -77,6 +77,7 @@
numactl-dev \
openssh-client \
pcre-dev \
+ pipewire-dev \
pixman-dev \
pkgconf \
pulseaudio-dev \
diff --git a/tests/docker/dockerfiles/centos8.docker b/tests/docker/dockerfiles/centos8.docker
index 78f454b..da7dc81 100644
--- a/tests/docker/dockerfiles/centos8.docker
+++ b/tests/docker/dockerfiles/centos8.docker
@@ -90,6 +90,7 @@
openssh-clients \
pam-devel \
pcre-static \
+ pipewire-devel \
pixman-devel \
pkgconfig \
pulseaudio-libs-devel \
diff --git a/tests/docker/dockerfiles/debian-amd64-cross.docker b/tests/docker/dockerfiles/debian-amd64-cross.docker
index 016c232..b7bdc01 100644
--- a/tests/docker/dockerfiles/debian-amd64-cross.docker
+++ b/tests/docker/dockerfiles/debian-amd64-cross.docker
@@ -116,6 +116,7 @@
libnfs-dev:amd64 \
libnuma-dev:amd64 \
libpam0g-dev:amd64 \
+ libpipewire-0.3-dev:amd64 \
libpixman-1-dev:amd64 \
libpmem-dev:amd64 \
libpng-dev:amd64 \
diff --git a/tests/docker/dockerfiles/debian-amd64.docker b/tests/docker/dockerfiles/debian-amd64.docker
index e39871c..6d2fa38 100644
--- a/tests/docker/dockerfiles/debian-amd64.docker
+++ b/tests/docker/dockerfiles/debian-amd64.docker
@@ -69,6 +69,7 @@
libnuma-dev \
libpam0g-dev \
libpcre2-dev \
+ libpipewire-0.3-dev \
libpixman-1-dev \
libpmem-dev \
libpng-dev \
diff --git a/tests/docker/dockerfiles/debian-arm64-cross.docker b/tests/docker/dockerfiles/debian-arm64-cross.docker
index 3c114ef..68165c2f 100644
--- a/tests/docker/dockerfiles/debian-arm64-cross.docker
+++ b/tests/docker/dockerfiles/debian-arm64-cross.docker
@@ -116,6 +116,7 @@
libnfs-dev:arm64 \
libnuma-dev:arm64 \
libpam0g-dev:arm64 \
+ libpipewire-0.3-dev:arm64 \
libpixman-1-dev:arm64 \
libpng-dev:arm64 \
libpulse-dev:arm64 \
diff --git a/tests/docker/dockerfiles/debian-armel-cross.docker b/tests/docker/dockerfiles/debian-armel-cross.docker
index dfbd47d..2fb6530 100644
--- a/tests/docker/dockerfiles/debian-armel-cross.docker
+++ b/tests/docker/dockerfiles/debian-armel-cross.docker
@@ -116,6 +116,7 @@
libnfs-dev:armel \
libnuma-dev:armel \
libpam0g-dev:armel \
+ libpipewire-0.3-dev:armel \
libpixman-1-dev:armel \
libpng-dev:armel \
libpulse-dev:armel \
diff --git a/tests/docker/dockerfiles/debian-armhf-cross.docker b/tests/docker/dockerfiles/debian-armhf-cross.docker
index 4e0084e..df77ccb 100644
--- a/tests/docker/dockerfiles/debian-armhf-cross.docker
+++ b/tests/docker/dockerfiles/debian-armhf-cross.docker
@@ -116,6 +116,7 @@
libnfs-dev:armhf \
libnuma-dev:armhf \
libpam0g-dev:armhf \
+ libpipewire-0.3-dev:armhf \
libpixman-1-dev:armhf \
libpng-dev:armhf \
libpulse-dev:armhf \
diff --git a/tests/docker/dockerfiles/debian-mips64el-cross.docker b/tests/docker/dockerfiles/debian-mips64el-cross.docker
index 88adf33..63a3d7a 100644
--- a/tests/docker/dockerfiles/debian-mips64el-cross.docker
+++ b/tests/docker/dockerfiles/debian-mips64el-cross.docker
@@ -115,6 +115,7 @@
libnfs-dev:mips64el \
libnuma-dev:mips64el \
libpam0g-dev:mips64el \
+ libpipewire-0.3-dev:mips64el \
libpixman-1-dev:mips64el \
libpng-dev:mips64el \
libpulse-dev:mips64el \
diff --git a/tests/docker/dockerfiles/debian-mipsel-cross.docker b/tests/docker/dockerfiles/debian-mipsel-cross.docker
index 256e8b5..ac87bbb 100644
--- a/tests/docker/dockerfiles/debian-mipsel-cross.docker
+++ b/tests/docker/dockerfiles/debian-mipsel-cross.docker
@@ -115,6 +115,7 @@
libnfs-dev:mipsel \
libnuma-dev:mipsel \
libpam0g-dev:mipsel \
+ libpipewire-0.3-dev:mipsel \
libpixman-1-dev:mipsel \
libpng-dev:mipsel \
libpulse-dev:mipsel \
diff --git a/tests/docker/dockerfiles/debian-ppc64el-cross.docker b/tests/docker/dockerfiles/debian-ppc64el-cross.docker
index 4d19cd2..def11f1 100644
--- a/tests/docker/dockerfiles/debian-ppc64el-cross.docker
+++ b/tests/docker/dockerfiles/debian-ppc64el-cross.docker
@@ -116,6 +116,7 @@
libnfs-dev:ppc64el \
libnuma-dev:ppc64el \
libpam0g-dev:ppc64el \
+ libpipewire-0.3-dev:ppc64el \
libpixman-1-dev:ppc64el \
libpng-dev:ppc64el \
libpulse-dev:ppc64el \
diff --git a/tests/docker/dockerfiles/debian-s390x-cross.docker b/tests/docker/dockerfiles/debian-s390x-cross.docker
index 642bbde..80028e1 100644
--- a/tests/docker/dockerfiles/debian-s390x-cross.docker
+++ b/tests/docker/dockerfiles/debian-s390x-cross.docker
@@ -116,6 +116,7 @@
libnfs-dev:s390x \
libnuma-dev:s390x \
libpam0g-dev:s390x \
+ libpipewire-0.3-dev:s390x \
libpixman-1-dev:s390x \
libpng-dev:s390x \
libpulse-dev:s390x \
diff --git a/tests/docker/dockerfiles/fedora.docker b/tests/docker/dockerfiles/fedora.docker
index 8a35a17..c5b6c96 100644
--- a/tests/docker/dockerfiles/fedora.docker
+++ b/tests/docker/dockerfiles/fedora.docker
@@ -98,6 +98,7 @@
openssh-clients \
pam-devel \
pcre-static \
+ pipewire-devel \
pixman-devel \
pkgconfig \
pulseaudio-libs-devel \
diff --git a/tests/docker/dockerfiles/opensuse-leap.docker b/tests/docker/dockerfiles/opensuse-leap.docker
index 185abe5..37c83e5 100644
--- a/tests/docker/dockerfiles/opensuse-leap.docker
+++ b/tests/docker/dockerfiles/opensuse-leap.docker
@@ -88,6 +88,7 @@
openssh \
pam-devel \
pcre-devel-static \
+ pipewire-devel \
pkgconfig \
python39-base \
python39-pip \
diff --git a/tests/docker/dockerfiles/ubuntu2204.docker b/tests/docker/dockerfiles/ubuntu2204.docker
index 1d442cd..8f93987 100644
--- a/tests/docker/dockerfiles/ubuntu2204.docker
+++ b/tests/docker/dockerfiles/ubuntu2204.docker
@@ -69,6 +69,7 @@
libnuma-dev \
libpam0g-dev \
libpcre2-dev \
+ libpipewire-0.3-dev \
libpixman-1-dev \
libpmem-dev \
libpng-dev \
diff --git a/tests/lcitool/libvirt-ci b/tests/lcitool/libvirt-ci
index b0f44f9..9bff3b7 160000
--- a/tests/lcitool/libvirt-ci
+++ b/tests/lcitool/libvirt-ci
@@ -1 +1 @@
-Subproject commit b0f44f929a81c0a604fb7fbf8afc34d37ab0eae9
+Subproject commit 9bff3b763b5531a1490e238bfbf77306dc3a6dbb
diff --git a/tests/lcitool/projects/qemu.yml b/tests/lcitool/projects/qemu.yml
index 21fd3d2..d452a89 100644
--- a/tests/lcitool/projects/qemu.yml
+++ b/tests/lcitool/projects/qemu.yml
@@ -85,6 +85,7 @@
- pam
- pcre-static
- pixman
+ - pipewire
- pkg-config
- pulseaudio
- python3
diff --git a/tests/lcitool/refresh b/tests/lcitool/refresh
index b54566e..4584870 100755
--- a/tests/lcitool/refresh
+++ b/tests/lcitool/refresh
@@ -84,6 +84,12 @@
generate(filename, cmd, trailer)
+def generate_pkglist(vm, target):
+ filename = Path(src_dir, "tests", "vm", "generated", vm + ".json")
+ cmd = lcitool_cmd + ["variables", "--format", "json", target, "qemu"]
+ generate(filename, cmd, None)
+
+
# Netmap still needs to be manually built as it is yet to be packaged
# into a distro. We also add cscope and gtags which are used in the CI
# test
@@ -191,6 +197,11 @@
generate_cirrus("freebsd-13")
generate_cirrus("macos-12")
+ #
+ # VM packages lists
+ #
+ generate_pkglist("freebsd", "freebsd-13")
+
sys.exit(0)
except Exception as ex:
print(str(ex), file=sys.stderr)
diff --git a/tests/qtest/migration-test.c b/tests/qtest/migration-test.c
index efa8c72..62d3f37 100644
--- a/tests/qtest/migration-test.c
+++ b/tests/qtest/migration-test.c
@@ -702,6 +702,8 @@
{
g_autofree gchar *arch_source = NULL;
g_autofree gchar *arch_target = NULL;
+ /* options for source and target */
+ g_autofree gchar *arch_opts = NULL;
g_autofree gchar *cmd_source = NULL;
g_autofree gchar *cmd_target = NULL;
const gchar *ignore_stderr;
@@ -709,7 +711,6 @@
g_autofree char *shmem_opts = NULL;
g_autofree char *shmem_path = NULL;
const char *arch = qtest_get_arch();
- const char *machine_opts = NULL;
const char *memory_size;
if (args->use_shmem) {
@@ -727,36 +728,29 @@
assert(sizeof(x86_bootsect) == 512);
init_bootfile(bootpath, x86_bootsect, sizeof(x86_bootsect));
memory_size = "150M";
- arch_source = g_strdup_printf("-drive file=%s,format=raw", bootpath);
- arch_target = g_strdup(arch_source);
+ arch_opts = g_strdup_printf("-drive file=%s,format=raw", bootpath);
start_address = X86_TEST_MEM_START;
end_address = X86_TEST_MEM_END;
} else if (g_str_equal(arch, "s390x")) {
init_bootfile(bootpath, s390x_elf, sizeof(s390x_elf));
memory_size = "128M";
- arch_source = g_strdup_printf("-bios %s", bootpath);
- arch_target = g_strdup(arch_source);
+ arch_opts = g_strdup_printf("-bios %s", bootpath);
start_address = S390_TEST_MEM_START;
end_address = S390_TEST_MEM_END;
} else if (strcmp(arch, "ppc64") == 0) {
- machine_opts = "vsmt=8";
memory_size = "256M";
start_address = PPC_TEST_MEM_START;
end_address = PPC_TEST_MEM_END;
- arch_source = g_strdup_printf("-nodefaults "
- "-prom-env 'use-nvramrc?=true' -prom-env "
+ arch_source = g_strdup_printf("-prom-env 'use-nvramrc?=true' -prom-env "
"'nvramrc=hex .\" _\" begin %x %x "
"do i c@ 1 + i c! 1000 +loop .\" B\" 0 "
"until'", end_address, start_address);
- arch_target = g_strdup("");
+ arch_opts = g_strdup("-nodefaults -machine vsmt=8");
} else if (strcmp(arch, "aarch64") == 0) {
init_bootfile(bootpath, aarch64_kernel, sizeof(aarch64_kernel));
- machine_opts = "virt,gic-version=max";
memory_size = "150M";
- arch_source = g_strdup_printf("-cpu max "
- "-kernel %s",
- bootpath);
- arch_target = g_strdup(arch_source);
+ arch_opts = g_strdup_printf("-machine virt,gic-version=max -cpu max "
+ "-kernel %s", bootpath);
start_address = ARM_TEST_MEM_START;
end_address = ARM_TEST_MEM_END;
@@ -791,17 +785,17 @@
shmem_opts = g_strdup("");
}
- cmd_source = g_strdup_printf("-accel kvm%s -accel tcg%s%s "
+ cmd_source = g_strdup_printf("-accel kvm%s -accel tcg "
"-name source,debug-threads=on "
"-m %s "
"-serial file:%s/src_serial "
- "%s %s %s %s",
+ "%s %s %s %s %s",
args->use_dirty_ring ?
",dirty-ring-size=4096" : "",
- machine_opts ? " -machine " : "",
- machine_opts ? machine_opts : "",
memory_size, tmpfs,
- arch_source, shmem_opts,
+ arch_opts ? arch_opts : "",
+ arch_source ? arch_source : "",
+ shmem_opts,
args->opts_source ? args->opts_source : "",
ignore_stderr);
if (!args->only_target) {
@@ -811,18 +805,18 @@
&got_src_stop);
}
- cmd_target = g_strdup_printf("-accel kvm%s -accel tcg%s%s "
+ cmd_target = g_strdup_printf("-accel kvm%s -accel tcg "
"-name target,debug-threads=on "
"-m %s "
"-serial file:%s/dest_serial "
"-incoming %s "
- "%s %s %s %s",
+ "%s %s %s %s %s",
args->use_dirty_ring ?
",dirty-ring-size=4096" : "",
- machine_opts ? " -machine " : "",
- machine_opts ? machine_opts : "",
memory_size, tmpfs, uri,
- arch_target, shmem_opts,
+ arch_opts ? arch_opts : "",
+ arch_target ? arch_target : "",
+ shmem_opts,
args->opts_target ? args->opts_target : "",
ignore_stderr);
*to = qtest_init(cmd_target);
@@ -1245,10 +1239,9 @@
QTestState **to_ptr,
MigrateCommon *args)
{
- g_autofree char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs);
QTestState *from, *to;
- if (test_migrate_start(&from, &to, uri, &args->start)) {
+ if (test_migrate_start(&from, &to, "defer", &args->start)) {
return -1;
}
@@ -1268,10 +1261,13 @@
migrate_ensure_non_converge(from);
migrate_prepare_for_dirty_mem(from);
+ qtest_qmp_assert_success(to, "{ 'execute': 'migrate-incoming',"
+ " 'arguments': { 'uri': 'tcp:127.0.0.1:0' }}");
/* Wait for the first serial output from the source */
wait_for_serial("src_serial");
+ g_autofree char *uri = migrate_get_socket_address(to, "socket-address");
migrate_qmp(from, uri, "{}");
migrate_wait_for_dirty_mem(from, to);
@@ -2481,7 +2477,7 @@
migrate_qmp(from, uri, "{}");
- migrate_wait_for_dirty_mem(from, to);
+ migrate_wait_for_dirty_mem(from, to2);
migrate_ensure_converge(from);
diff --git a/tests/tcg/Makefile.target b/tests/tcg/Makefile.target
index 2462c26..462289f 100644
--- a/tests/tcg/Makefile.target
+++ b/tests/tcg/Makefile.target
@@ -120,7 +120,7 @@
%: %.S
$(CC) $(CFLAGS) $(EXTRA_CFLAGS) $< -o $@ $(LDFLAGS)
else
-# For softmmu targets we include a different Makefile fragement as the
+# For softmmu targets we include a different Makefile fragment as the
# build options for bare programs are usually pretty different. They
# are expected to provide their own build recipes.
EXTRA_CFLAGS += -ffreestanding
@@ -154,7 +154,7 @@
# pre-requistes manually here as we can't use stems to handle it. We
# only expand MULTIARCH_TESTS which are common on most of our targets
# to avoid an exponential explosion as new tests are added. We also
-# add some special helpers the run-plugin- rules can use bellow.
+# add some special helpers the run-plugin- rules can use below.
ifneq ($(MULTIARCH_TESTS),)
$(foreach p,$(PLUGINS), \
diff --git a/tests/tcg/aarch64/gdbstub/test-sve.py b/tests/tcg/aarch64/gdbstub/test-sve.py
index b96bdbb..ef57c74 100644
--- a/tests/tcg/aarch64/gdbstub/test-sve.py
+++ b/tests/tcg/aarch64/gdbstub/test-sve.py
@@ -1,6 +1,6 @@
from __future__ import print_function
#
-# Test the SVE registers are visable and changeable via gdbstub
+# Test the SVE registers are visible and changeable via gdbstub
#
# This is launched via tests/guest-debug/run-test.py
#
diff --git a/tests/tcg/aarch64/sme-outprod1.c b/tests/tcg/aarch64/sme-outprod1.c
index 6e5972d..0c814ed 100644
--- a/tests/tcg/aarch64/sme-outprod1.c
+++ b/tests/tcg/aarch64/sme-outprod1.c
@@ -28,7 +28,7 @@
" fmopa za1.s, p0/m, p0/m, z0.s, z0.s\n"
/*
* Read the first 4x4 sub-matrix of elements from tile 1:
- * Note that za1h should be interchangable here.
+ * Note that za1h should be interchangeable here.
*/
" mov w12, #0\n"
" mova z0.s, p0/m, za1v.s[w12, #0]\n"
diff --git a/tests/tcg/aarch64/system/boot.S b/tests/tcg/aarch64/system/boot.S
index f136363..501685d 100644
--- a/tests/tcg/aarch64/system/boot.S
+++ b/tests/tcg/aarch64/system/boot.S
@@ -9,7 +9,7 @@
/*
* Semihosting interface on ARM AArch64
- * See "Semihosting for AArch32 and AArch64 Relase 2.0" by ARM
+ * See "Semihosting for AArch32 and AArch64 Release 2.0" by ARM
* w0 - semihosting call number
* x1 - semihosting parameter
*/
@@ -147,7 +147,7 @@
* T0SZ[5:0] = 2^(64 - 25)
*
* The size of T0SZ controls what the initial lookup level. It
- * would be nice to start at level 2 but unfortunatly for a
+ * would be nice to start at level 2 but unfortunately for a
* flat-mapping on the virt machine we need to handle IA's
* with at least 1gb range to see RAM. So we start with a
* level 1 lookup.
@@ -189,7 +189,7 @@
msr cpacr_el1, x0
/* Setup some stack space and enter the test code.
- * Assume everthing except the return value is garbage when we
+ * Assume everything except the return value is garbage when we
* return, we won't need it.
*/
adrp x0, stack_end
diff --git a/tests/tcg/aarch64/system/semiheap.c b/tests/tcg/aarch64/system/semiheap.c
index 693a1b0..1a8c0f3 100644
--- a/tests/tcg/aarch64/system/semiheap.c
+++ b/tests/tcg/aarch64/system/semiheap.c
@@ -86,7 +86,7 @@
}
ptr_to_heap++;
}
- ml_printf("r/w to heap upto %p\n", ptr_to_heap);
+ ml_printf("r/w to heap up to %p\n", ptr_to_heap);
ml_printf("Passed HeapInfo checks\n");
return 0;
diff --git a/tests/tcg/multiarch/sha512.c b/tests/tcg/multiarch/sha512.c
index 9e701bc..12c2b6c 100644
--- a/tests/tcg/multiarch/sha512.c
+++ b/tests/tcg/multiarch/sha512.c
@@ -453,7 +453,7 @@
/* From hex.h */
/**
* hex_decode - Unpack a hex string.
- * @str: the hexidecimal string
+ * @str: the hexadecimal string
* @slen: the length of @str
* @buf: the buffer to write the data into
* @bufsize: the length of @buf
diff --git a/tests/tcg/multiarch/system/Makefile.softmmu-target b/tests/tcg/multiarch/system/Makefile.softmmu-target
index fe40195..7ba9053 100644
--- a/tests/tcg/multiarch/system/Makefile.softmmu-target
+++ b/tests/tcg/multiarch/system/Makefile.softmmu-target
@@ -3,7 +3,7 @@
# Multiarch system tests
#
# We just collect the tests together here and rely on the actual guest
-# architecture to add to the test dependancies and deal with the
+# architecture to add to the test dependencies and deal with the
# complications of building.
#
diff --git a/tests/tcg/s390x/Makefile.softmmu-target b/tests/tcg/s390x/Makefile.softmmu-target
index 242c7b0..76345b6 100644
--- a/tests/tcg/s390x/Makefile.softmmu-target
+++ b/tests/tcg/s390x/Makefile.softmmu-target
@@ -16,13 +16,18 @@
ASM_TESTS = \
bal \
+ cksm \
+ clm \
exrl-ssm-early \
+ icm \
sam \
lpsw \
lpswe-early \
lra \
+ mc \
ssm-early \
stosm-early \
+ stpq \
unaligned-lowcore
include $(S390X_SRC)/pgm-specification.mak
diff --git a/tests/tcg/s390x/Makefile.target b/tests/tcg/s390x/Makefile.target
index 19fbbc6..1fc9809 100644
--- a/tests/tcg/s390x/Makefile.target
+++ b/tests/tcg/s390x/Makefile.target
@@ -39,12 +39,17 @@
TESTS+=epsw
TESTS+=larl
TESTS+=mdeb
+TESTS+=cgebra
+TESTS+=clgebr
cdsg: CFLAGS+=-pthread
cdsg: LDFLAGS+=-pthread
rxsbg: CFLAGS+=-O2
+cgebra: LDFLAGS+=-lm
+clgebr: LDFLAGS+=-lm
+
include $(S390X_SRC)/pgm-specification.mak
$(PGM_SPECIFICATION_TESTS): pgm-specification-user.o
$(PGM_SPECIFICATION_TESTS): LDFLAGS+=pgm-specification-user.o
@@ -53,6 +58,7 @@
Z13_TESTS=vistr
Z13_TESTS+=lcbb
Z13_TESTS+=locfhr
+Z13_TESTS+=vcksm
$(Z13_TESTS): CFLAGS+=-march=z13 -O2
TESTS+=$(Z13_TESTS)
diff --git a/tests/tcg/s390x/cgebra.c b/tests/tcg/s390x/cgebra.c
new file mode 100644
index 0000000..f91e10d
--- /dev/null
+++ b/tests/tcg/s390x/cgebra.c
@@ -0,0 +1,32 @@
+/*
+ * Test the CGEBRA instruction.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+#include <assert.h>
+#include <fenv.h>
+#include <stdlib.h>
+
+int main(void)
+{
+ float r2 = 1E+300;
+ long long r1;
+ int cc;
+
+ feclearexcept(FE_ALL_EXCEPT);
+ asm("cgebra %[r1],%[m3],%[r2],%[m4]\n"
+ "ipm %[cc]\n"
+ : [r1] "=r" (r1)
+ , [cc] "=r" (cc)
+ : [m3] "i" (5) /* round toward 0 */
+ , [r2] "f" (r2)
+ , [m4] "i" (8) /* bit 0 is set, but must be ignored; XxC is not set */
+ : "cc");
+ cc >>= 28;
+
+ assert(r1 == 0x7fffffffffffffffLL);
+ assert(cc == 3);
+ assert(fetestexcept(FE_ALL_EXCEPT) == (FE_INVALID | FE_INEXACT));
+
+ return EXIT_SUCCESS;
+}
diff --git a/tests/tcg/s390x/cksm.S b/tests/tcg/s390x/cksm.S
new file mode 100644
index 0000000..563fd3d
--- /dev/null
+++ b/tests/tcg/s390x/cksm.S
@@ -0,0 +1,29 @@
+ .org 0x8e
+program_interruption_code:
+ .org 0x1d0 /* program new PSW */
+ .quad 0,pgm
+ .org 0x200 /* lowcore padding */
+ .globl _start
+_start:
+ lmg %r0,%r1,cksm_args
+ cksm %r2,%r0
+ c %r2,cksm_exp
+ jne failure
+ .insn rre,0xb2410000,%r2,%r15 /* cksm %r2,%r15 */
+failure:
+ lpswe failure_psw
+pgm:
+ chhsi program_interruption_code,6 /* specification exception? */
+ jne failure
+ lpswe success_psw
+cksm_args:
+ .quad cksm_buf, 16
+cksm_buf:
+ .quad 0xaaaabbbbcccc0000, 0x12345678
+cksm_exp:
+ .long 0x89ab1234
+ .align 8
+success_psw:
+ .quad 0x2000000000000,0xfff /* see is_special_wait_psw() */
+failure_psw:
+ .quad 0x2000000000000,0 /* disabled wait */
diff --git a/tests/tcg/s390x/clgebr.c b/tests/tcg/s390x/clgebr.c
new file mode 100644
index 0000000..d491899
--- /dev/null
+++ b/tests/tcg/s390x/clgebr.c
@@ -0,0 +1,32 @@
+/*
+ * Test the CLGEBR instruction.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+#include <assert.h>
+#include <fenv.h>
+#include <stdlib.h>
+
+int main(void)
+{
+ float r2 = -1;
+ long long r1;
+ int cc;
+
+ feclearexcept(FE_ALL_EXCEPT);
+ asm("clgebr %[r1],%[m3],%[r2],%[m4]\n"
+ "ipm %[cc]\n"
+ : [r1] "=r" (r1)
+ , [cc] "=r" (cc)
+ : [m3] "i" (5) /* round toward 0 */
+ , [r2] "f" (r2)
+ , [m4] "i" (8) /* bit 0 is set, but must be ignored; XxC is not set */
+ : "cc");
+ cc >>= 28;
+
+ assert(r1 == 0);
+ assert(cc == 3);
+ assert(fetestexcept(FE_ALL_EXCEPT) == (FE_INVALID | FE_INEXACT));
+
+ return EXIT_SUCCESS;
+}
diff --git a/tests/tcg/s390x/clm.S b/tests/tcg/s390x/clm.S
new file mode 100644
index 0000000..17156a8
--- /dev/null
+++ b/tests/tcg/s390x/clm.S
@@ -0,0 +1,29 @@
+ .org 0x8e
+program_interruption_code:
+ .org 0x1d0 /* program new PSW */
+ .quad 0,pgm
+ .org 0x200 /* lowcore padding */
+ .globl _start
+_start:
+ lgrl %r0,op1
+ clm %r0,6,op2
+ jle failure
+ lgrl %r1,bad_addr
+ clm %r0,0,0(%r1)
+failure:
+ lpswe failure_psw
+pgm:
+ chhsi program_interruption_code,5 /* addressing exception? */
+ jne failure
+ lpswe success_psw
+ .align 8
+op1:
+ .quad 0x1234567887654321
+op2:
+ .quad 0x3456789abcdef012
+bad_addr:
+ .quad 0xffffffff00000000
+success_psw:
+ .quad 0x2000000000000,0xfff /* see is_special_wait_psw() */
+failure_psw:
+ .quad 0x2000000000000,0 /* disabled wait */
diff --git a/tests/tcg/s390x/icm.S b/tests/tcg/s390x/icm.S
new file mode 100644
index 0000000..d24d1f5
--- /dev/null
+++ b/tests/tcg/s390x/icm.S
@@ -0,0 +1,32 @@
+ .org 0x8e
+program_interruption_code:
+ .org 0x1d0 /* program new PSW */
+ .quad 0,pgm
+ .org 0x200 /* lowcore padding */
+ .globl _start
+_start:
+ lgrl %r0,op1
+ icm %r0,10,op2
+ cg %r0,exp
+ jne failure
+ lgrl %r1,bad_addr
+ icm %r0,0,0(%r1)
+failure:
+ lpswe failure_psw
+pgm:
+ chhsi program_interruption_code,5 /* addressing exception? */
+ jne failure
+ lpswe success_psw
+ .align 8
+op1:
+ .quad 0x1234567887654321
+op2:
+ .quad 0x0011223344556677
+exp:
+ .quad 0x1234567800651121
+bad_addr:
+ .quad 0xffffffff00000000
+success_psw:
+ .quad 0x2000000000000,0xfff /* see is_special_wait_psw() */
+failure_psw:
+ .quad 0x2000000000000,0 /* disabled wait */
diff --git a/tests/tcg/s390x/mc.S b/tests/tcg/s390x/mc.S
new file mode 100644
index 0000000..e7466bb
--- /dev/null
+++ b/tests/tcg/s390x/mc.S
@@ -0,0 +1,56 @@
+ .org 0x8d
+ilc:
+ .org 0x8e
+program_interruption_code:
+ .org 0x94
+monitor_class:
+ .org 0xb0
+monitor_code:
+ .org 0x150
+program_old_psw:
+ .org 0x1d0 /* program new PSW */
+ .quad 0x180000000,pgm /* 64-bit mode */
+ .org 0x200 /* lowcore padding */
+ .globl _start
+_start:
+ stctg %c8,%c8,c8 /* enable only monitor class 1 */
+ mvhhi c8+6,0x4000
+ lctlg %c8,%c8,c8
+mc_nop:
+ mc 123,0
+mc_monitor_event:
+ mc 321,1
+ j failure
+mc_specification:
+ mc 333,16
+ j failure
+pgm:
+ lgrl %r0,program_old_psw+8 /* ilc adjustment */
+ llgc %r1,ilc
+ sgr %r0,%r1
+ larl %r1,mc_monitor_event /* dispatch based on old PSW */
+ cgrje %r0,%r1,pgm_monitor_event
+ larl %r1,mc_specification
+ cgrje %r0,%r1,pgm_specification
+ j failure
+pgm_monitor_event:
+ chhsi program_interruption_code,0x40 /* monitor event? */
+ jne failure
+ chhsi monitor_class,1 /* class from mc_monitor_event? */
+ jne failure
+ cghsi monitor_code,321 /* code from mc_monitor_event? */
+ jne failure
+ j mc_specification /* next test */
+pgm_specification:
+ chhsi program_interruption_code,6 /* specification exception? */
+ jne failure
+ lpswe success_psw
+failure:
+ lpswe failure_psw
+ .align 8
+c8:
+ .quad 0
+success_psw:
+ .quad 0x2000000000000,0xfff /* see is_special_wait_psw() */
+failure_psw:
+ .quad 0x2000000000000,0 /* disabled wait */
diff --git a/tests/tcg/s390x/mvc.c b/tests/tcg/s390x/mvc.c
index 7ae4c44..b572aa3 100644
--- a/tests/tcg/s390x/mvc.c
+++ b/tests/tcg/s390x/mvc.c
@@ -85,7 +85,7 @@
}
}
- /* test if MVC works now correctly accross page boundaries */
+ /* test if MVC works now correctly across page boundaries */
mvc_256(dst + 4096 - 128, src + 4096 - 128);
for (i = 0; i < ALLOC_SIZE; i++) {
if (src[i] != 0xff) {
diff --git a/tests/tcg/s390x/stpq.S b/tests/tcg/s390x/stpq.S
new file mode 100644
index 0000000..687a52e
--- /dev/null
+++ b/tests/tcg/s390x/stpq.S
@@ -0,0 +1,20 @@
+ .org 0x200 /* lowcore padding */
+ .globl _start
+_start:
+ lgrl %r0,value
+ lgrl %r1,value+8
+ stpq %r0,stored_value
+ clc stored_value(16),value
+ jne failure
+ lpswe success_psw
+failure:
+ lpswe failure_psw
+ .align 16
+value:
+ .quad 0x1234567887654321, 0x8765432112345678
+stored_value:
+ .quad 0, 0
+success_psw:
+ .quad 0x2000000000000,0xfff /* see is_special_wait_psw() */
+failure_psw:
+ .quad 0x2000000000000,0 /* disabled wait */
diff --git a/tests/tcg/s390x/vcksm.c b/tests/tcg/s390x/vcksm.c
new file mode 100644
index 0000000..452daaa
--- /dev/null
+++ b/tests/tcg/s390x/vcksm.c
@@ -0,0 +1,31 @@
+/*
+ * Test the VCKSM instruction.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+#include "vx.h"
+
+int main(void)
+{
+ S390Vector v1;
+ S390Vector v2 = {
+ .d[0] = 0xb2261c8140edce49ULL,
+ .d[1] = 0x387bf5a433af39d1ULL,
+ };
+ S390Vector v3 = {
+ .d[0] = 0x73b03d2c7f9e654eULL,
+ .d[1] = 0x23d74e51fb479877ULL,
+ };
+ S390Vector exp = {.d[0] = 0xdedd7f8eULL, .d[1] = 0ULL};
+
+ asm volatile("vcksm %[v1],%[v2],%[v3]"
+ : [v1] "=v" (v1.v)
+ : [v2] "v" (v2.v)
+ , [v3] "v" (v3.v));
+ assert(memcmp(&v1, &exp, sizeof(v1)) == 0);
+
+ return EXIT_SUCCESS;
+}
diff --git a/tests/tcg/s390x/vx.h b/tests/tcg/s390x/vx.h
index 02e7fd5..00701db 100644
--- a/tests/tcg/s390x/vx.h
+++ b/tests/tcg/s390x/vx.h
@@ -1,6 +1,8 @@
#ifndef QEMU_TESTS_S390X_VX_H
#define QEMU_TESTS_S390X_VX_H
+#include <stdint.h>
+
typedef union S390Vector {
uint64_t d[2]; /* doubleword */
uint32_t w[4]; /* word */
diff --git a/tests/tcg/tricore/c/crt0-tc2x.S b/tests/tcg/tricore/c/crt0-tc2x.S
index 3100da1..399f112 100644
--- a/tests/tcg/tricore/c/crt0-tc2x.S
+++ b/tests/tcg/tricore/c/crt0-tc2x.S
@@ -263,7 +263,7 @@
ld.w %d3,[%a13+]4 # %d3 = block length
jeq %d3,-1,__copy_table_done # length == -1 => end of table
sh %d0,%d3,-3 # %d0 = length / 8 (doublewords)
- and %d1,%d3,7 # %d1 = lenght % 8 (rem. bytes)
+ and %d1,%d3,7 # %d1 = length % 8 (rem. bytes)
jz %d0,__copy_word # block size < 8 => copy word
addi %d0,%d0,-1 # else doublewords -= 1
mov.a %a2,%d0 # %a2 = loop counter
@@ -274,7 +274,7 @@
__copy_word:
jz %d1,__copy_table_next
sh %d0,%d1,-2 # %d0 = length / 4 (words)
- and %d1,%d1,3 # %d1 = lenght % 4 (rem. bytes)
+ and %d1,%d1,3 # %d1 = length % 4 (rem. bytes)
jz %d0,__copy_hword # block size < 4 => copy hword
ld.w %d14,[%a15+]4 # copy one word
st.w [%a14+]4,%d14
diff --git a/tests/tcg/x86_64/system/boot.S b/tests/tcg/x86_64/system/boot.S
index ed0f638..dac9bd5 100644
--- a/tests/tcg/x86_64/system/boot.S
+++ b/tests/tcg/x86_64/system/boot.S
@@ -121,7 +121,7 @@
// Setup stack ASAP
movq $stack_end,%rsp
- /* don't worry about stack frame, assume everthing is garbage when we return */
+ /* don't worry about stack frame, assume everything is garbage when we return */
call main
_exit: /* output any non-zero result in eax to isa-debug-exit device */
@@ -195,7 +195,7 @@
*
* This describes various memory areas (segments) through
* segment descriptors. In 32 bit mode each segment each
- * segement is associated with segment registers which are
+ * segment is associated with segment registers which are
* implicitly (or explicitly) referenced depending on the
* instruction. However in 64 bit mode selectors are flat and
* segmented addressing isn't used.
diff --git a/tests/vm/basevm.py b/tests/vm/basevm.py
index 23229e2..a97e23b 100644
--- a/tests/vm/basevm.py
+++ b/tests/vm/basevm.py
@@ -27,6 +27,7 @@
import multiprocessing
import traceback
import shlex
+import json
from qemu.machine import QEMUMachine
from qemu.utils import get_info_usernet_hostfwd_port, kvm_available
@@ -501,6 +502,16 @@ def gen_cloud_init_iso(self):
stderr=self._stdout)
return os.path.join(cidir, "cloud-init.iso")
+ def get_qemu_packages_from_lcitool_json(self, json_path=None):
+ """Parse a lcitool variables json file and return the PKGS list."""
+ if json_path is None:
+ json_path = os.path.join(
+ os.path.dirname(__file__), "generated", self.name + ".json"
+ )
+ with open(json_path, "r") as fh:
+ return json.load(fh)["pkgs"]
+
+
def get_qemu_path(arch, build_path=None):
"""Fetch the path to the qemu binary."""
# If QEMU environment variable set, it takes precedence
diff --git a/tests/vm/freebsd b/tests/vm/freebsd
index 11de647..ac51376 100755
--- a/tests/vm/freebsd
+++ b/tests/vm/freebsd
@@ -31,45 +31,6 @@
link = "https://download.freebsd.org/releases/CI-IMAGES/13.2-RELEASE/amd64/Latest/FreeBSD-13.2-RELEASE-amd64-BASIC-CI.raw.xz"
csum = "a4fb3b6c7b75dd4d58fb0d75e4caf72844bffe0ca00e66459c028b198ffb3c0e"
size = "20G"
- pkgs = [
- # build tools
- "git",
- "pkgconf",
- "bzip2",
- "python39",
- "ninja",
-
- # gnu tools
- "bash",
- "gmake",
- "gsed",
- "gettext",
-
- # libs: crypto
- "gnutls",
-
- # libs: images
- "jpeg-turbo",
- "png",
-
- # libs: ui
- "sdl2",
- "gtk3",
- "libxkbcommon",
-
- # libs: opengl
- "libepoxy",
- "mesa-libs",
-
- # libs: migration
- "zstd",
-
- # libs: networking
- "libslirp",
-
- # libs: sndio
- "sndio",
- ]
BUILD_SCRIPT = """
set -e;
@@ -151,8 +112,9 @@
self.console_wait(prompt)
self.console_send("echo 'chmod 666 /dev/vtbd1' >> /etc/rc.local\n")
+ pkgs = self.get_qemu_packages_from_lcitool_json()
self.print_step("Installing packages")
- self.ssh_root_check("pkg install -y %s\n" % " ".join(self.pkgs))
+ self.ssh_root_check("pkg install -y %s\n" % " ".join(pkgs))
# shutdown
self.ssh_root(self.poweroff)
diff --git a/tests/vm/generated/README b/tests/vm/generated/README
new file mode 100644
index 0000000..7ccc6ff
--- /dev/null
+++ b/tests/vm/generated/README
@@ -0,0 +1,5 @@
+# FILES IN THIS FOLDER WERE AUTO-GENERATED
+#
+# $ make lcitool-refresh
+#
+# https://gitlab.com/libvirt/libvirt-ci
diff --git a/tests/vm/generated/freebsd.json b/tests/vm/generated/freebsd.json
new file mode 100644
index 0000000..7c435cf
--- /dev/null
+++ b/tests/vm/generated/freebsd.json
@@ -0,0 +1,77 @@
+{
+ "ccache": "/usr/local/bin/ccache",
+ "cpan_pkgs": [],
+ "cross_pkgs": [],
+ "make": "/usr/local/bin/gmake",
+ "ninja": "/usr/local/bin/ninja",
+ "packaging_command": "pkg",
+ "pip3": "/usr/local/bin/pip-3.8",
+ "pkgs": [
+ "alsa-lib",
+ "bash",
+ "bison",
+ "bzip2",
+ "ca_root_nss",
+ "capstone4",
+ "ccache",
+ "cmocka",
+ "ctags",
+ "curl",
+ "cyrus-sasl",
+ "dbus",
+ "diffutils",
+ "dtc",
+ "flex",
+ "fusefs-libs3",
+ "gettext",
+ "git",
+ "glib",
+ "gmake",
+ "gnutls",
+ "gsed",
+ "gtk3",
+ "json-c",
+ "libepoxy",
+ "libffi",
+ "libgcrypt",
+ "libjpeg-turbo",
+ "libnfs",
+ "libslirp",
+ "libspice-server",
+ "libssh",
+ "libtasn1",
+ "llvm",
+ "lzo2",
+ "meson",
+ "mtools",
+ "ncurses",
+ "nettle",
+ "ninja",
+ "opencv",
+ "pixman",
+ "pkgconf",
+ "png",
+ "py39-numpy",
+ "py39-pillow",
+ "py39-pip",
+ "py39-sphinx",
+ "py39-sphinx_rtd_theme",
+ "py39-yaml",
+ "python3",
+ "rpm2cpio",
+ "sdl2",
+ "sdl2_image",
+ "snappy",
+ "sndio",
+ "socat",
+ "spice-protocol",
+ "tesseract",
+ "usbredir",
+ "virglrenderer",
+ "vte3",
+ "xorriso",
+ "zstd"
+ ],
+ "pypi_pkgs": [],
+ "python": "/usr/local/bin/python3"
+}
diff --git a/ui/console.c b/ui/console.c
index c1544e0..8da2170 100644
--- a/ui/console.c
+++ b/ui/console.c
@@ -1898,6 +1898,7 @@
static const char placeholder_msg[] = "Display output is not active.";
DisplayState *s = con->ds;
DisplaySurface *old_surface = con->surface;
+ DisplaySurface *new_surface = surface;
DisplayChangeListener *dcl;
int width;
int height;
@@ -1911,19 +1912,19 @@
height = 480;
}
- surface = qemu_create_placeholder_surface(width, height, placeholder_msg);
+ new_surface = qemu_create_placeholder_surface(width, height, placeholder_msg);
}
- assert(old_surface != surface);
+ assert(old_surface != new_surface);
con->scanout.kind = SCANOUT_SURFACE;
- con->surface = surface;
- dpy_gfx_create_texture(con, surface);
+ con->surface = new_surface;
+ dpy_gfx_create_texture(con, new_surface);
QLIST_FOREACH(dcl, &s->listeners, next) {
if (con != (dcl->con ? dcl->con : active_console)) {
continue;
}
- displaychangelistener_gfx_switch(dcl, surface, FALSE);
+ displaychangelistener_gfx_switch(dcl, new_surface, surface ? FALSE : TRUE);
}
dpy_gfx_destroy_texture(con, old_surface);
qemu_free_displaysurface(old_surface);
diff --git a/ui/curses_keys.h b/ui/curses_keys.h
index 71e04ac..88a2208 100644
--- a/ui/curses_keys.h
+++ b/ui/curses_keys.h
@@ -210,6 +210,12 @@
['N' - '@'] = 49 | CNTRL, /* Control + n */
/* Control + m collides with the keycode for Enter */
+ ['@' - '@'] = 3 | CNTRL, /* Control + @ */
+ /* Control + [ collides with the keycode for Escape */
+ ['\\' - '@'] = 43 | CNTRL, /* Control + Backslash */
+ [']' - '@'] = 27 | CNTRL, /* Control + ] */
+ ['^' - '@'] = 7 | CNTRL, /* Control + ^ */
+ ['_' - '@'] = 12 | CNTRL, /* Control + Underscore */
};
static const int _curseskey2keycode[CURSES_KEYS] = {
diff --git a/ui/dbus-listener.c b/ui/dbus-listener.c
index 0240c39..68ff343 100644
--- a/ui/dbus-listener.c
+++ b/ui/dbus-listener.c
@@ -415,13 +415,13 @@
backing_width, backing_height, x, y, w, h);
#ifdef CONFIG_GBM
QemuDmaBuf dmabuf = {
- .width = backing_width,
- .height = backing_height,
+ .width = w,
+ .height = h,
.y0_top = backing_y_0_top,
.x = x,
.y = y,
- .scanout_width = w,
- .scanout_height = h,
+ .backing_width = backing_width,
+ .backing_height = backing_height,
};
assert(tex_id);
diff --git a/ui/egl-helpers.c b/ui/egl-helpers.c
index 8f9fbf5..3d19dbe 100644
--- a/ui/egl-helpers.c
+++ b/ui/egl-helpers.c
@@ -148,8 +148,8 @@
if (src->dmabuf) {
x1 = src->dmabuf->x;
y1 = src->dmabuf->y;
- w = src->dmabuf->scanout_width;
- h = src->dmabuf->scanout_height;
+ w = src->dmabuf->width;
+ h = src->dmabuf->height;
}
w = (x1 + w) > src->width ? src->width - x1 : w;
@@ -314,9 +314,9 @@
}
attrs[i++] = EGL_WIDTH;
- attrs[i++] = dmabuf->width;
+ attrs[i++] = dmabuf->backing_width;
attrs[i++] = EGL_HEIGHT;
- attrs[i++] = dmabuf->height;
+ attrs[i++] = dmabuf->backing_height;
attrs[i++] = EGL_LINUX_DRM_FOURCC_EXT;
attrs[i++] = dmabuf->fourcc;
diff --git a/ui/gtk-egl.c b/ui/gtk-egl.c
index d59b8cd..4c29ac1 100644
--- a/ui/gtk-egl.c
+++ b/ui/gtk-egl.c
@@ -32,6 +32,8 @@
vc->gfx.scanout_mode = scanout;
if (!vc->gfx.scanout_mode) {
+ eglMakeCurrent(qemu_egl_display, vc->gfx.esurface,
+ vc->gfx.esurface, vc->gfx.ectx);
egl_fb_destroy(&vc->gfx.guest_fb);
if (vc->gfx.surface) {
surface_gl_destroy_texture(vc->gfx.gls, vc->gfx.ds);
@@ -135,6 +137,8 @@
vc->gfx.esurface, vc->gfx.ectx);
surface_gl_update_texture(vc->gfx.gls, vc->gfx.ds, x, y, w, h);
vc->gfx.glupdates++;
+ eglMakeCurrent(qemu_egl_display, EGL_NO_SURFACE,
+ EGL_NO_SURFACE, EGL_NO_CONTEXT);
}
void gd_egl_refresh(DisplayChangeListener *dcl)
@@ -144,6 +148,10 @@
gd_update_monitor_refresh_rate(
vc, vc->window ? vc->window : vc->gfx.drawing_area);
+ if (vc->gfx.guest_fb.dmabuf && vc->gfx.guest_fb.dmabuf->draw_submitted) {
+ return;
+ }
+
if (!vc->gfx.esurface) {
gd_egl_init(vc);
if (!vc->gfx.esurface) {
@@ -238,7 +246,6 @@
eglMakeCurrent(qemu_egl_display, vc->gfx.esurface,
vc->gfx.esurface, vc->gfx.ectx);
- gtk_egl_set_scanout_mode(vc, true);
egl_fb_setup_for_tex(&vc->gfx.guest_fb, backing_width, backing_height,
backing_id, false);
}
@@ -258,9 +265,10 @@
}
gd_egl_scanout_texture(dcl, dmabuf->texture,
- dmabuf->y0_top, dmabuf->width, dmabuf->height,
- dmabuf->x, dmabuf->y, dmabuf->scanout_width,
- dmabuf->scanout_height, NULL);
+ dmabuf->y0_top,
+ dmabuf->backing_width, dmabuf->backing_height,
+ dmabuf->x, dmabuf->y, dmabuf->width,
+ dmabuf->height, NULL);
if (dmabuf->allow_fences) {
vc->gfx.guest_fb.dmabuf = dmabuf;
@@ -280,7 +288,8 @@
if (!dmabuf->texture) {
return;
}
- egl_fb_setup_for_tex(&vc->gfx.cursor_fb, dmabuf->width, dmabuf->height,
+ egl_fb_setup_for_tex(&vc->gfx.cursor_fb,
+ dmabuf->backing_width, dmabuf->backing_height,
dmabuf->texture, false);
} else {
egl_fb_destroy(&vc->gfx.cursor_fb);
@@ -347,6 +356,7 @@
if (vc->gfx.guest_fb.dmabuf && !vc->gfx.guest_fb.dmabuf->draw_submitted) {
graphic_hw_gl_block(vc->gfx.dcl.con, true);
vc->gfx.guest_fb.dmabuf->draw_submitted = true;
+ gtk_egl_set_scanout_mode(vc, true);
gtk_widget_queue_draw_area(area, x, y, w, h);
return;
}
diff --git a/ui/gtk-gl-area.c b/ui/gtk-gl-area.c
index 7367dfd..1ce34a2 100644
--- a/ui/gtk-gl-area.c
+++ b/ui/gtk-gl-area.c
@@ -26,6 +26,7 @@
vc->gfx.scanout_mode = scanout;
if (!vc->gfx.scanout_mode) {
+ gtk_gl_area_make_current(GTK_GL_AREA(vc->gfx.drawing_area));
egl_fb_destroy(&vc->gfx.guest_fb);
if (vc->gfx.surface) {
surface_gl_destroy_texture(vc->gfx.gls, vc->gfx.ds);
@@ -115,6 +116,7 @@
gtk_gl_area_make_current(GTK_GL_AREA(vc->gfx.drawing_area));
surface_gl_update_texture(vc->gfx.gls, vc->gfx.ds, x, y, w, h);
vc->gfx.glupdates++;
+ gdk_gl_context_clear_current();
}
void gd_gl_area_refresh(DisplayChangeListener *dcl)
@@ -123,6 +125,10 @@
gd_update_monitor_refresh_rate(vc, vc->window ? vc->window : vc->gfx.drawing_area);
+ if (vc->gfx.guest_fb.dmabuf && vc->gfx.guest_fb.dmabuf->draw_submitted) {
+ return;
+ }
+
if (!vc->gfx.gls) {
if (!gtk_widget_get_realized(vc->gfx.drawing_area)) {
return;
@@ -262,7 +268,6 @@
return;
}
- gtk_gl_area_set_scanout_mode(vc, true);
egl_fb_setup_for_tex(&vc->gfx.guest_fb, backing_width, backing_height,
backing_id, false);
}
@@ -282,6 +287,7 @@
if (vc->gfx.guest_fb.dmabuf && !vc->gfx.guest_fb.dmabuf->draw_submitted) {
graphic_hw_gl_block(vc->gfx.dcl.con, true);
vc->gfx.guest_fb.dmabuf->draw_submitted = true;
+ gtk_gl_area_set_scanout_mode(vc, true);
}
gtk_gl_area_queue_render(GTK_GL_AREA(vc->gfx.drawing_area));
}
@@ -299,9 +305,10 @@
}
gd_gl_area_scanout_texture(dcl, dmabuf->texture,
- dmabuf->y0_top, dmabuf->width, dmabuf->height,
- dmabuf->x, dmabuf->y, dmabuf->scanout_width,
- dmabuf->scanout_height, NULL);
+ dmabuf->y0_top,
+ dmabuf->backing_width, dmabuf->backing_height,
+ dmabuf->x, dmabuf->y, dmabuf->width,
+ dmabuf->height, NULL);
if (dmabuf->allow_fences) {
vc->gfx.guest_fb.dmabuf = dmabuf;
diff --git a/ui/vnc-clipboard.c b/ui/vnc-clipboard.c
index 8aeadfa..c759be3 100644
--- a/ui/vnc-clipboard.c
+++ b/ui/vnc-clipboard.c
@@ -50,8 +50,11 @@
ret = inflate(&stream, Z_FINISH);
switch (ret) {
case Z_OK:
- case Z_STREAM_END:
break;
+ case Z_STREAM_END:
+ *size = stream.total_out;
+ inflateEnd(&stream);
+ return out;
case Z_BUF_ERROR:
out_len <<= 1;
if (out_len > (1 << 20)) {
@@ -66,11 +69,6 @@
}
}
- *size = stream.total_out;
- inflateEnd(&stream);
-
- return out;
-
err_end:
inflateEnd(&stream);
err: