From 4d31ff32a65adfae015e035931b864bd1c521d6e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Volker=20R=C3=BCmelin?= Date: Fri, 23 Sep 2022 20:36:29 +0200 Subject: [PATCH 01/26] audio: refactor code in audio_run_out() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Refactoring the code in audio_run_out() avoids code duplication in the next patch. There's no functional change. Signed-off-by: Volker Rümelin Reviewed-by: Marc-André Lureau Message-Id: <20220923183640.8314-1-vr_qemu@t-online.de> Signed-off-by: Gerd Hoffmann --- audio/audio.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/audio/audio.c b/audio/audio.c index df6818ed55..08aec51e70 100644 --- a/audio/audio.c +++ b/audio/audio.c @@ -1121,8 +1121,12 @@ static void audio_run_out (AudioState *s) HWVoiceOut *hw = NULL; SWVoiceOut *sw; - if (!audio_get_pdo_out(s->dev)->mixing_engine) { - while ((hw = audio_pcm_hw_find_any_enabled_out(s, hw))) { + while ((hw = audio_pcm_hw_find_any_enabled_out(s, hw))) { + size_t played, live, prev_rpos; + size_t hw_free = audio_pcm_hw_get_free(hw); + int nb_live; + + if (!audio_get_pdo_out(s->dev)->mixing_engine) { /* there is exactly 1 sw for each hw with no mixeng */ sw = hw->sw_head.lh_first; @@ -1137,14 +1141,9 @@ static void audio_run_out (AudioState *s) if (sw->active) { sw->callback.fn(sw->callback.opaque, INT_MAX); } - } - return; - } - while ((hw = audio_pcm_hw_find_any_enabled_out(s, hw))) { - size_t played, live, prev_rpos; - size_t hw_free = audio_pcm_hw_get_free(hw); - int nb_live; + continue; + } for (sw = hw->sw_head.lh_first; sw; sw = sw->entries.le_next) { if (sw->active) { From 7099a6a220c33d9c115e19e9f03ac61caa8358b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Volker=20R=C3=BCmelin?= Date: Fri, 23 Sep 2022 20:36:30 +0200 Subject: [PATCH 02/26] audio: fix GUS audio playback with out.mixing-engine=off MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix GUS audio playback with out.mixing-engine=off. The GUS audio device needs to know the amount of samples to produce in advance. To reproduce start qemu with -parallel none -device gus,audiodev=audio0 -audiodev pa,id=audio0,out.mixing-engine=off and start the cartoon.exe demo in a FreeDOS guest. The demo file is available on the download page of the GUSemu32 author. Signed-off-by: Volker Rümelin Acked-by: Marc-André Lureau Message-Id: <20220923183640.8314-2-vr_qemu@t-online.de> Signed-off-by: Gerd Hoffmann --- audio/audio.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/audio/audio.c b/audio/audio.c index 08aec51e70..29da359b41 100644 --- a/audio/audio.c +++ b/audio/audio.c @@ -1139,7 +1139,8 @@ static void audio_run_out (AudioState *s) } if (sw->active) { - sw->callback.fn(sw->callback.opaque, INT_MAX); + sw->callback.fn(sw->callback.opaque, + hw_free * sw->info.bytes_per_frame); } continue; From dd052dbfbf608cc656082173541973f09867747a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Volker=20R=C3=BCmelin?= Date: Fri, 23 Sep 2022 20:36:31 +0200 Subject: [PATCH 03/26] audio: run downstream playback queue unconditionally MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Run the downstream playback queue even if the emulated audio device didn't write new samples. There still may be buffered audio samples downstream. This is for the -audiodev out.mixing-engine=off case. Commit a8a98cfd42 ("audio: run downstream playback queue uncondition- ally") fixed the out.mixing-engine=on case. Signed-off-by: Volker Rümelin Acked-by: Marc-André Lureau Message-Id: <20220923183640.8314-3-vr_qemu@t-online.de> Signed-off-by: Gerd Hoffmann --- audio/audio.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/audio/audio.c b/audio/audio.c index 29da359b41..567f953e66 100644 --- a/audio/audio.c +++ b/audio/audio.c @@ -1143,6 +1143,10 @@ static void audio_run_out (AudioState *s) hw_free * sw->info.bytes_per_frame); } + if (hw->pcm_ops->run_buffer_out) { + hw->pcm_ops->run_buffer_out(hw); + } + continue; } @@ -1501,10 +1505,6 @@ size_t audio_generic_write(HWVoiceOut *hw, void *buf, size_t size) } } - if (hw->pcm_ops->run_buffer_out) { - hw->pcm_ops->run_buffer_out(hw); - } - return total; } From 5a9d7ae25175d19f9380128ac17f87816fe6f049 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Volker=20R=C3=BCmelin?= Date: Fri, 23 Sep 2022 20:36:32 +0200 Subject: [PATCH 04/26] alsaaudio: reduce playback latency MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change the buffer_get_free pcm_ops function to report the free ALSA playback buffer. The generic buffer becomes a temporary buffer and is empty after a call to audio_run_out(). Signed-off-by: Volker Rümelin Acked-by: Marc-André Lureau Message-Id: <20220923183640.8314-4-vr_qemu@t-online.de> Signed-off-by: Gerd Hoffmann --- audio/alsaaudio.c | 38 +++++++++++++++++++++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/audio/alsaaudio.c b/audio/alsaaudio.c index 4a61378cd7..7a2a94cd42 100644 --- a/audio/alsaaudio.c +++ b/audio/alsaaudio.c @@ -602,6 +602,42 @@ static int alsa_open(bool in, struct alsa_params_req *req, return -1; } +static size_t alsa_buffer_get_free(HWVoiceOut *hw) +{ + ALSAVoiceOut *alsa = (ALSAVoiceOut *)hw; + snd_pcm_sframes_t avail; + size_t alsa_free, generic_free, generic_in_use; + + avail = snd_pcm_avail_update(alsa->handle); + if (avail < 0) { + if (avail == -EPIPE) { + if (!alsa_recover(alsa->handle)) { + avail = snd_pcm_avail_update(alsa->handle); + } + } + if (avail < 0) { + alsa_logerr(avail, + "Could not obtain number of available frames\n"); + avail = 0; + } + } + + alsa_free = avail * hw->info.bytes_per_frame; + generic_free = audio_generic_buffer_get_free(hw); + generic_in_use = hw->samples * hw->info.bytes_per_frame - generic_free; + if (generic_in_use) { + /* + * This code can only be reached in the unlikely case that + * snd_pcm_avail_update() returned a larger number of frames + * than snd_pcm_writei() could write. Make sure that all + * remaining bytes in the generic buffer can be written. + */ + alsa_free = alsa_free > generic_in_use ? alsa_free - generic_in_use : 0; + } + + return alsa_free; +} + static size_t alsa_write(HWVoiceOut *hw, void *buf, size_t len) { ALSAVoiceOut *alsa = (ALSAVoiceOut *) hw; @@ -916,7 +952,7 @@ static struct audio_pcm_ops alsa_pcm_ops = { .init_out = alsa_init_out, .fini_out = alsa_fini_out, .write = alsa_write, - .buffer_get_free = audio_generic_buffer_get_free, + .buffer_get_free = alsa_buffer_get_free, .run_buffer_out = audio_generic_run_buffer_out, .enable_out = alsa_enable_out, From 02732641c0ffdedb6533b9ddeaf8e95a3be88ec6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Volker=20R=C3=BCmelin?= Date: Fri, 23 Sep 2022 20:36:33 +0200 Subject: [PATCH 05/26] audio: add more audio rate control functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The next patch needs two new rate control functions. The first one returns the bytes needed at call time to maintain the selected rate. The second one adjusts the bytes actually sent. Split the audio_rate_get_bytes() function into these two functions and reintroduce audio_rate_get_bytes(). Signed-off-by: Volker Rümelin Reviewed-by: Marc-André Lureau Message-Id: <20220923183640.8314-5-vr_qemu@t-online.de> Signed-off-by: Gerd Hoffmann --- audio/audio.c | 35 ++++++++++++++++++++++++----------- audio/audio_int.h | 2 ++ 2 files changed, 26 insertions(+), 11 deletions(-) diff --git a/audio/audio.c b/audio/audio.c index 567f953e66..61cdd73df5 100644 --- a/audio/audio.c +++ b/audio/audio.c @@ -2251,26 +2251,39 @@ void audio_rate_start(RateCtl *rate) rate->start_ticks = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); } -size_t audio_rate_get_bytes(struct audio_pcm_info *info, RateCtl *rate, - size_t bytes_avail) +size_t audio_rate_peek_bytes(RateCtl *rate, struct audio_pcm_info *info) { int64_t now; int64_t ticks; int64_t bytes; - int64_t samples; - size_t ret; + int64_t frames; now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); ticks = now - rate->start_ticks; bytes = muldiv64(ticks, info->bytes_per_second, NANOSECONDS_PER_SECOND); - samples = (bytes - rate->bytes_sent) / info->bytes_per_frame; - if (samples < 0 || samples > 65536) { - AUD_log(NULL, "Resetting rate control (%" PRId64 " samples)\n", samples); + frames = (bytes - rate->bytes_sent) / info->bytes_per_frame; + if (frames < 0 || frames > 65536) { + AUD_log(NULL, "Resetting rate control (%" PRId64 " frames)\n", frames); audio_rate_start(rate); - samples = 0; + frames = 0; } - ret = MIN(samples * info->bytes_per_frame, bytes_avail); - rate->bytes_sent += ret; - return ret; + return frames * info->bytes_per_frame; +} + +void audio_rate_add_bytes(RateCtl *rate, size_t bytes_used) +{ + rate->bytes_sent += bytes_used; +} + +size_t audio_rate_get_bytes(struct audio_pcm_info *info, RateCtl *rate, + size_t bytes_avail) +{ + size_t bytes; + + bytes = audio_rate_peek_bytes(rate, info); + bytes = MIN(bytes, bytes_avail); + audio_rate_add_bytes(rate, bytes); + + return bytes; } diff --git a/audio/audio_int.h b/audio/audio_int.h index 2a6914d2aa..97e20e8429 100644 --- a/audio/audio_int.h +++ b/audio/audio_int.h @@ -263,6 +263,8 @@ typedef struct RateCtl { } RateCtl; void audio_rate_start(RateCtl *rate); +size_t audio_rate_peek_bytes(RateCtl *rate, struct audio_pcm_info *info); +void audio_rate_add_bytes(RateCtl *rate, size_t bytes_used); size_t audio_rate_get_bytes(struct audio_pcm_info *info, RateCtl *rate, size_t bytes_avail); From 90320051ea998b6ac336cd635f8014ccb31154bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Volker=20R=C3=BCmelin?= Date: Fri, 23 Sep 2022 20:36:34 +0200 Subject: [PATCH 06/26] spiceaudio: add a pcm_ops buffer_get_free function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It seems there is a demand [1] for low latency playback over SPICE. Add a pcm_ops buffer_get_free function to reduce the playback latency. The mixing engine buffer becomes a temporary buffer. [1] https://lists.nongnu.org/archive/html/qemu-devel/2022-01/msg01644.html Signed-off-by: Volker Rümelin Reviewed-by: Marc-André Lureau Message-Id: <20220923183640.8314-6-vr_qemu@t-online.de> Signed-off-by: Gerd Hoffmann --- audio/spiceaudio.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/audio/spiceaudio.c b/audio/spiceaudio.c index a8d370fe6f..22892a7b9d 100644 --- a/audio/spiceaudio.c +++ b/audio/spiceaudio.c @@ -120,6 +120,13 @@ static void line_out_fini (HWVoiceOut *hw) spice_server_remove_interface (&out->sin.base); } +static size_t line_out_get_free(HWVoiceOut *hw) +{ + SpiceVoiceOut *out = container_of(hw, SpiceVoiceOut, hw); + + return audio_rate_peek_bytes(&out->rate, &hw->info); +} + static void *line_out_get_buffer(HWVoiceOut *hw, size_t *size) { SpiceVoiceOut *out = container_of(hw, SpiceVoiceOut, hw); @@ -133,8 +140,6 @@ static void *line_out_get_buffer(HWVoiceOut *hw, size_t *size) *size = MIN((out->fsize - out->fpos) << 2, *size); } - *size = audio_rate_get_bytes(&hw->info, &out->rate, *size); - return out->frame + out->fpos; } @@ -142,6 +147,8 @@ static size_t line_out_put_buffer(HWVoiceOut *hw, void *buf, size_t size) { SpiceVoiceOut *out = container_of(hw, SpiceVoiceOut, hw); + audio_rate_add_bytes(&out->rate, size); + if (buf) { assert(buf == out->frame + out->fpos && out->fpos <= out->fsize); out->fpos += size >> 2; @@ -282,6 +289,7 @@ static struct audio_pcm_ops audio_callbacks = { .init_out = line_out_init, .fini_out = line_out_fini, .write = audio_generic_write, + .buffer_get_free = line_out_get_free, .get_buffer_out = line_out_get_buffer, .put_buffer_out = line_out_put_buffer, .enable_out = line_out_enable, From 70ded68b45b90cf43a9a757df6483503055485f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Volker=20R=C3=BCmelin?= Date: Fri, 23 Sep 2022 20:36:35 +0200 Subject: [PATCH 07/26] spiceaudio: update comment MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace a comment with a question with the answer. Signed-off-by: Volker Rümelin Reviewed-by: Marc-André Lureau Message-Id: <20220923183640.8314-7-vr_qemu@t-online.de> Signed-off-by: Gerd Hoffmann --- audio/spiceaudio.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/audio/spiceaudio.c b/audio/spiceaudio.c index 22892a7b9d..f52f3a8bbb 100644 --- a/audio/spiceaudio.c +++ b/audio/spiceaudio.c @@ -242,7 +242,10 @@ static size_t line_in_read(HWVoiceIn *hw, void *buf, size_t len) uint64_t to_read = audio_rate_get_bytes(&hw->info, &in->rate, len) >> 2; size_t ready = spice_server_record_get_samples(&in->sin, buf, to_read); - /* XXX: do we need this? */ + /* + * If the client didn't send new frames, it most likely disconnected. + * Generate silence in this case to avoid a stalled audio stream. + */ if (ready == 0) { memset(buf, 0, to_read << 2); ready = to_read; From 613fe02b2a127d921b37843cb514e919ecbe53f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Volker=20R=C3=BCmelin?= Date: Fri, 23 Sep 2022 20:36:36 +0200 Subject: [PATCH 08/26] audio: swap audio_rate_get_bytes() function parameters MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Swap the rate and info parameters of the audio_rate_get_bytes() function to align the parameter order with the rest of the audio_rate_*() functions. Signed-off-by: Volker Rümelin Reviewed-by: Marc-André Lureau Message-Id: <20220923183640.8314-8-vr_qemu@t-online.de> Signed-off-by: Gerd Hoffmann --- audio/audio.c | 2 +- audio/audio_int.h | 2 +- audio/dbusaudio.c | 4 ++-- audio/noaudio.c | 4 ++-- audio/spiceaudio.c | 2 +- audio/wavaudio.c | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/audio/audio.c b/audio/audio.c index 61cdd73df5..7213f8bf07 100644 --- a/audio/audio.c +++ b/audio/audio.c @@ -2276,7 +2276,7 @@ void audio_rate_add_bytes(RateCtl *rate, size_t bytes_used) rate->bytes_sent += bytes_used; } -size_t audio_rate_get_bytes(struct audio_pcm_info *info, RateCtl *rate, +size_t audio_rate_get_bytes(RateCtl *rate, struct audio_pcm_info *info, size_t bytes_avail) { size_t bytes; diff --git a/audio/audio_int.h b/audio/audio_int.h index 97e20e8429..e87ce014a0 100644 --- a/audio/audio_int.h +++ b/audio/audio_int.h @@ -265,7 +265,7 @@ typedef struct RateCtl { void audio_rate_start(RateCtl *rate); size_t audio_rate_peek_bytes(RateCtl *rate, struct audio_pcm_info *info); void audio_rate_add_bytes(RateCtl *rate, size_t bytes_used); -size_t audio_rate_get_bytes(struct audio_pcm_info *info, RateCtl *rate, +size_t audio_rate_get_bytes(RateCtl *rate, struct audio_pcm_info *info, size_t bytes_avail); static inline size_t audio_ring_dist(size_t dst, size_t src, size_t len) diff --git a/audio/dbusaudio.c b/audio/dbusaudio.c index a3d656d3b0..722df0355e 100644 --- a/audio/dbusaudio.c +++ b/audio/dbusaudio.c @@ -82,7 +82,7 @@ static void *dbus_get_buffer_out(HWVoiceOut *hw, size_t *size) } *size = MIN(vo->buf_size - vo->buf_pos, *size); - *size = audio_rate_get_bytes(&hw->info, &vo->rate, *size); + *size = audio_rate_get_bytes(&vo->rate, &hw->info, *size); return vo->buf + vo->buf_pos; @@ -343,7 +343,7 @@ dbus_read(HWVoiceIn *hw, void *buf, size_t size) trace_dbus_audio_read(size); - /* size = audio_rate_get_bytes(&hw->info, &vo->rate, size); */ + /* size = audio_rate_get_bytes(&vo->rate, &hw->info, size); */ g_hash_table_iter_init(&iter, da->in_listeners); while (g_hash_table_iter_next(&iter, NULL, (void **)&listener)) { diff --git a/audio/noaudio.c b/audio/noaudio.c index 84a6bfbb1c..4fdee5adec 100644 --- a/audio/noaudio.c +++ b/audio/noaudio.c @@ -44,7 +44,7 @@ typedef struct NoVoiceIn { static size_t no_write(HWVoiceOut *hw, void *buf, size_t len) { NoVoiceOut *no = (NoVoiceOut *) hw; - return audio_rate_get_bytes(&hw->info, &no->rate, len); + return audio_rate_get_bytes(&no->rate, &hw->info, len); } static int no_init_out(HWVoiceOut *hw, struct audsettings *as, void *drv_opaque) @@ -89,7 +89,7 @@ static void no_fini_in (HWVoiceIn *hw) static size_t no_read(HWVoiceIn *hw, void *buf, size_t size) { NoVoiceIn *no = (NoVoiceIn *) hw; - int64_t bytes = audio_rate_get_bytes(&hw->info, &no->rate, size); + int64_t bytes = audio_rate_get_bytes(&no->rate, &hw->info, size); audio_pcm_info_clear_buf(&hw->info, buf, bytes / hw->info.bytes_per_frame); return bytes; diff --git a/audio/spiceaudio.c b/audio/spiceaudio.c index f52f3a8bbb..d17ef1a25e 100644 --- a/audio/spiceaudio.c +++ b/audio/spiceaudio.c @@ -239,7 +239,7 @@ static void line_in_fini (HWVoiceIn *hw) static size_t line_in_read(HWVoiceIn *hw, void *buf, size_t len) { SpiceVoiceIn *in = container_of (hw, SpiceVoiceIn, hw); - uint64_t to_read = audio_rate_get_bytes(&hw->info, &in->rate, len) >> 2; + uint64_t to_read = audio_rate_get_bytes(&in->rate, &hw->info, len) >> 2; size_t ready = spice_server_record_get_samples(&in->sin, buf, to_read); /* diff --git a/audio/wavaudio.c b/audio/wavaudio.c index ac666335c7..3e1d84db83 100644 --- a/audio/wavaudio.c +++ b/audio/wavaudio.c @@ -42,7 +42,7 @@ typedef struct WAVVoiceOut { static size_t wav_write_out(HWVoiceOut *hw, void *buf, size_t len) { WAVVoiceOut *wav = (WAVVoiceOut *) hw; - int64_t bytes = audio_rate_get_bytes(&hw->info, &wav->rate, len); + int64_t bytes = audio_rate_get_bytes(&wav->rate, &hw->info, len); assert(bytes % hw->info.bytes_per_frame == 0); if (bytes && fwrite(buf, bytes, 1, wav->f) != 1) { From c4e592647e161fe23adc3eccd8743b285e4b342b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Volker=20R=C3=BCmelin?= Date: Fri, 23 Sep 2022 20:36:37 +0200 Subject: [PATCH 09/26] audio: rename audio_sw_bytes_free() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rename and refactor audio_sw_bytes_free(). This function is not limited to calculate the free audio buffer size. The renamed function returns the number of frames instead of bytes. Signed-off-by: Volker Rümelin Reviewed-by: Marc-André Lureau Message-Id: <20220923183640.8314-9-vr_qemu@t-online.de> Signed-off-by: Gerd Hoffmann --- audio/audio.c | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/audio/audio.c b/audio/audio.c index 7213f8bf07..28262ffd58 100644 --- a/audio/audio.c +++ b/audio/audio.c @@ -1010,9 +1010,16 @@ static size_t audio_get_avail (SWVoiceIn *sw) return (((int64_t) live << 32) / sw->ratio) * sw->info.bytes_per_frame; } -static size_t audio_sw_bytes_free(SWVoiceOut *sw, size_t free) +/** + * audio_frontend_frames_out() - returns the number of frames needed to + * get frames_out frames after resampling + * + * @sw: audio playback frontend + * @frames_out: number of frames + */ +static size_t audio_frontend_frames_out(SWVoiceOut *sw, size_t frames_out) { - return (((int64_t)free << 32) / sw->ratio) * sw->info.bytes_per_frame; + return ((int64_t)frames_out << 32) / sw->ratio; } static size_t audio_get_free(SWVoiceOut *sw) @@ -1034,8 +1041,8 @@ static size_t audio_get_free(SWVoiceOut *sw) dead = sw->hw->mix_buf->size - live; #ifdef DEBUG_OUT - dolog("%s: get_free live %zu dead %zu sw_bytes %zu\n", - SW_NAME(sw), live, dead, audio_sw_bytes_free(sw, dead)); + dolog("%s: get_free live %zu dead %zu frontend frames %zu\n", + SW_NAME(sw), live, dead, audio_frontend_frames_out(sw, dead)); #endif return dead; @@ -1156,13 +1163,14 @@ static void audio_run_out (AudioState *s) size_t free; if (hw_free > sw->total_hw_samples_mixed) { - free = audio_sw_bytes_free(sw, + free = audio_frontend_frames_out(sw, MIN(sw_free, hw_free - sw->total_hw_samples_mixed)); } else { free = 0; } if (free > 0) { - sw->callback.fn(sw->callback.opaque, free); + sw->callback.fn(sw->callback.opaque, + free * sw->info.bytes_per_frame); } } } From 0724c57988f4ad826b02f12093ace5ef657cec21 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Volker=20R=C3=BCmelin?= Date: Fri, 23 Sep 2022 20:36:38 +0200 Subject: [PATCH 10/26] audio: refactor audio_get_avail() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Split out the code in audio_get_avail() that calculates the buffer size that the audio frontend can read. This is similar to the code changes in audio_get_free(). Signed-off-by: Volker Rümelin Reviewed-by: Marc-André Lureau Message-Id: <20220923183640.8314-10-vr_qemu@t-online.de> Signed-off-by: Gerd Hoffmann --- audio/audio.c | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/audio/audio.c b/audio/audio.c index 28262ffd58..ed2b9d5f7e 100644 --- a/audio/audio.c +++ b/audio/audio.c @@ -986,6 +986,18 @@ void AUD_set_active_in (SWVoiceIn *sw, int on) } } +/** + * audio_frontend_frames_in() - returns the number of frames the resampling + * code generates from frames_in frames + * + * @sw: audio recording frontend + * @frames_in: number of frames + */ +static size_t audio_frontend_frames_in(SWVoiceIn *sw, size_t frames_in) +{ + return ((int64_t)frames_in << 32) / sw->ratio; +} + static size_t audio_get_avail (SWVoiceIn *sw) { size_t live; @@ -1002,12 +1014,12 @@ static size_t audio_get_avail (SWVoiceIn *sw) } ldebug ( - "%s: get_avail live %zu ret %" PRId64 "\n", + "%s: get_avail live %zu frontend frames %zu\n", SW_NAME (sw), - live, (((int64_t) live << 32) / sw->ratio) * sw->info.bytes_per_frame + live, audio_frontend_frames_in(sw, live) ); - return (((int64_t) live << 32) / sw->ratio) * sw->info.bytes_per_frame; + return live; } /** @@ -1309,11 +1321,13 @@ static void audio_run_in (AudioState *s) sw->total_hw_samples_acquired -= min; if (sw->active) { + size_t sw_avail = audio_get_avail(sw); size_t avail; - avail = audio_get_avail (sw); + avail = audio_frontend_frames_in(sw, sw_avail); if (avail > 0) { - sw->callback.fn (sw->callback.opaque, avail); + sw->callback.fn(sw->callback.opaque, + avail * sw->info.bytes_per_frame); } } } From b73ef11ff68f05418c8b60945b1e1783a72bd822 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Volker=20R=C3=BCmelin?= Date: Fri, 23 Sep 2022 20:36:39 +0200 Subject: [PATCH 11/26] audio: fix sw->buf size for audio recording MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The calculation of the buffer size needed to store audio samples after resampling is wrong for audio recording. For audio recording sw->ratio is calculated as sw->ratio = frontend sample rate / backend sample rate. From this follows frontend samples = frontend sample rate / backend sample rate * backend samples frontend samples = sw->ratio * backend samples In 2 of 3 places in the audio recording code where sw->ratio is used in a calculation to get the number of frontend frames, the calculation is wrong. Fix this. The 3rd formula in audio_pcm_sw_read() is correct. Resolves: https://gitlab.com/qemu-project/qemu/-/issues/71 Signed-off-by: Volker Rümelin Acked-by: Marc-André Lureau Message-Id: <20220923183640.8314-11-vr_qemu@t-online.de> Signed-off-by: Gerd Hoffmann --- audio/audio.c | 2 +- audio/audio_template.h | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/audio/audio.c b/audio/audio.c index ed2b9d5f7e..886725747b 100644 --- a/audio/audio.c +++ b/audio/audio.c @@ -995,7 +995,7 @@ void AUD_set_active_in (SWVoiceIn *sw, int on) */ static size_t audio_frontend_frames_in(SWVoiceIn *sw, size_t frames_in) { - return ((int64_t)frames_in << 32) / sw->ratio; + return (int64_t)frames_in * sw->ratio >> 32; } static size_t audio_get_avail (SWVoiceIn *sw) diff --git a/audio/audio_template.h b/audio/audio_template.h index 98ab557684..720a32e57e 100644 --- a/audio/audio_template.h +++ b/audio/audio_template.h @@ -110,7 +110,11 @@ static int glue (audio_pcm_sw_alloc_resources_, TYPE) (SW *sw) return 0; } +#ifdef DAC samples = ((int64_t) sw->HWBUF->size << 32) / sw->ratio; +#else + samples = (int64_t)sw->HWBUF->size * sw->ratio >> 32; +#endif sw->buf = audio_calloc(__func__, samples, sizeof(struct st_sample)); if (!sw->buf) { From b6d93282ccac79e42d87d02652db353894cd1db9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Volker=20R=C3=BCmelin?= Date: Fri, 23 Sep 2022 20:36:40 +0200 Subject: [PATCH 12/26] audio: prevent an integer overflow in resampling code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There are corner cases where rate->opos can overflow. For example, if QEMU is started with -audiodev pa,id=audio0, out.frequency=11025 -device ich9-intel-hda -device hda-duplex, audiodev=audio0 and the guest plays audio with a sampling frequency of 44100Hz, rate->opos will overflow after 27.05h and the audio stream will be silent for a long time. To prevent a rate->opos and also a rate->ipos overflow, both are wrapped around after a short time. The wrap around point rate->ipos >= 0x10001 is an arbitrarily selected value and can be any small value, 0 and 1 included. The comment that an ipos overflow will result in an infinite loop has been removed, because in this case the resampling code only generates no more output samples and the audio stream stalls. However, there is no infinite loop. Signed-off-by: Volker Rümelin Message-Id: <20220923183640.8314-12-vr_qemu@t-online.de> Signed-off-by: Gerd Hoffmann --- audio/rate_template.h | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/audio/rate_template.h b/audio/rate_template.h index f94c940c61..b432719ebb 100644 --- a/audio/rate_template.h +++ b/audio/rate_template.h @@ -72,11 +72,6 @@ void NAME (void *opaque, struct st_sample *ibuf, struct st_sample *obuf, ilast = *ibuf++; rate->ipos++; - /* if ipos overflow, there is a infinite loop */ - if (rate->ipos == 0xffffffff) { - rate->ipos = 1; - rate->opos = rate->opos & 0xffffffff; - } /* See if we finished the input buffer yet */ if (ibuf >= iend) { goto the_end; @@ -85,6 +80,12 @@ void NAME (void *opaque, struct st_sample *ibuf, struct st_sample *obuf, icur = *ibuf; + /* wrap ipos and opos around long before they overflow */ + if (rate->ipos >= 0x10001) { + rate->ipos = 1; + rate->opos &= 0xffffffff; + } + /* interpolate */ #ifdef FLOAT_MIXENG #ifdef RECIPROCAL From d307040b18bfcb1393b910f1bae753d5c12a4dc7 Mon Sep 17 00:00:00 2001 From: Mauro Matteo Cascella Date: Sun, 25 Sep 2022 22:45:11 +0200 Subject: [PATCH 13/26] ui/vnc-clipboard: fix integer underflow in vnc_client_cut_text_ext Extended ClientCutText messages start with a 4-byte header. If len < 4, an integer underflow occurs in vnc_client_cut_text_ext. The result is used to decompress data in a while loop in inflate_buffer, leading to CPU consumption and denial of service. Prevent this by checking dlen in protocol_client_msg. Fixes: CVE-2022-3165 Fixes: 0bf41cab93e5 ("ui/vnc: clipboard support") Reported-by: TangPeng Signed-off-by: Mauro Matteo Cascella Message-Id: <20220925204511.1103214-1-mcascell@redhat.com> Signed-off-by: Gerd Hoffmann --- ui/vnc.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/ui/vnc.c b/ui/vnc.c index 6a05d06147..acb3629cd8 100644 --- a/ui/vnc.c +++ b/ui/vnc.c @@ -2442,8 +2442,8 @@ static int protocol_client_msg(VncState *vs, uint8_t *data, size_t len) if (len == 1) { return 8; } + uint32_t dlen = abs(read_s32(data, 4)); if (len == 8) { - uint32_t dlen = abs(read_s32(data, 4)); if (dlen > (1 << 20)) { error_report("vnc: client_cut_text msg payload has %u bytes" " which exceeds our limit of 1MB.", dlen); @@ -2456,8 +2456,13 @@ static int protocol_client_msg(VncState *vs, uint8_t *data, size_t len) } if (read_s32(data, 4) < 0) { - vnc_client_cut_text_ext(vs, abs(read_s32(data, 4)), - read_u32(data, 8), data + 12); + if (dlen < 4) { + error_report("vnc: malformed payload (header less than 4 bytes)" + " in extended clipboard pseudo-encoding."); + vnc_client_error(vs); + break; + } + vnc_client_cut_text_ext(vs, dlen, read_u32(data, 8), data + 12); break; } vnc_client_cut_text(vs, read_u32(data, 4), data + 8); From 604a86895feb6639417fe957dfc95191f7f63565 Mon Sep 17 00:00:00 2001 From: Dongwon Kim Date: Wed, 28 Sep 2022 14:58:05 -0700 Subject: [PATCH 14/26] ui/gtk-egl: egl context needs to be unbound in the end of gd_egl_switch A thread often fails to bind an egl context to itself after guest VM is rebooted because the context is still owned by another thread. It is not very clear what condition makes this happen but this can be prevented by unbinding the context from the thread in the end of gd_egl_switch. Cc: Gerd Hoffmann Signed-off-by: Dongwon Kim Message-Id: <20220928215805.4661-1-dongwon.kim@intel.com> Signed-off-by: Gerd Hoffmann --- ui/gtk-egl.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ui/gtk-egl.c b/ui/gtk-egl.c index b5bffbab25..35f917ceb1 100644 --- a/ui/gtk-egl.c +++ b/ui/gtk-egl.c @@ -195,6 +195,9 @@ void gd_egl_switch(DisplayChangeListener *dcl, if (resized) { gd_update_windowsize(vc); } + + eglMakeCurrent(qemu_egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, + EGL_NO_CONTEXT); } QEMUGLContext gd_egl_create_context(DisplayGLCtx *dgc, From 2fba4e9c4938406fa676bfd3566e416e095cf93a Mon Sep 17 00:00:00 2001 From: lu zhipeng Date: Thu, 29 Sep 2022 20:23:52 +0800 Subject: [PATCH 15/26] cirrus_vga: fix potential memory overflow Signed-off-by: lu zhipeng Message-Id: <20220929122352.1891-1-luzhipeng@cestc.cn> Signed-off-by: Gerd Hoffmann --- hw/display/cirrus_vga.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/display/cirrus_vga.c b/hw/display/cirrus_vga.c index 3bb6a58698..2577005d03 100644 --- a/hw/display/cirrus_vga.c +++ b/hw/display/cirrus_vga.c @@ -834,7 +834,7 @@ static void cirrus_bitblt_cputovideo_next(CirrusVGAState * s) word alignment, so we keep them for the next line */ /* XXX: keep alignment to speed up transfer */ end_ptr = s->cirrus_bltbuf + s->cirrus_blt_srcpitch; - copy_count = s->cirrus_srcptr_end - end_ptr; + copy_count = MIN(s->cirrus_srcptr_end - end_ptr, CIRRUS_BLTBUFSIZE); memmove(s->cirrus_bltbuf, end_ptr, copy_count); s->cirrus_srcptr = s->cirrus_bltbuf + copy_count; s->cirrus_srcptr_end = s->cirrus_bltbuf + s->cirrus_blt_srcpitch; From 23b45173faf37b13d2f6ae77353b7b27e7abf8e1 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Fri, 30 Sep 2022 15:32:20 +0200 Subject: [PATCH 16/26] docs: add firmware feature flags Add new firmware feature flags for the recently added confidential computing operating modes by amd and intel. While being at it also fix the path to the amd sev documentation. Signed-off-by: Gerd Hoffmann Reviewed-by: Kashyap Chamarthy Message-Id: <20220930133220.1771336-1-kraxel@redhat.com> --- docs/interop/firmware.json | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/docs/interop/firmware.json b/docs/interop/firmware.json index 4e049b1c7c..56814f02b3 100644 --- a/docs/interop/firmware.json +++ b/docs/interop/firmware.json @@ -113,13 +113,22 @@ # Virtualization, as specified in the AMD64 Architecture # Programmer's Manual. QEMU command line options related to # this feature are documented in -# "docs/amd-memory-encryption.txt". +# "docs/system/i386/amd-memory-encryption.rst". # # @amd-sev-es: The firmware supports running under AMD Secure Encrypted # Virtualization - Encrypted State, as specified in the AMD64 # Architecture Programmer's Manual. QEMU command line options # related to this feature are documented in -# "docs/amd-memory-encryption.txt". +# "docs/system/i386/amd-memory-encryption.rst". +# +# @amd-sev-snp: The firmware supports running under AMD Secure Encrypted +# Virtualization - Secure Nested Paging, as specified in the +# AMD64 Architecture Programmer's Manual. QEMU command line +# options related to this feature are documented in +# "docs/system/i386/amd-memory-encryption.rst". +# +# @intel-tdx: The firmware supports running under Intel Trust Domain +# Extensions (TDX). # # @enrolled-keys: The variable store (NVRAM) template associated with # the firmware binary has the UEFI Secure Boot @@ -185,9 +194,11 @@ # Since: 3.0 ## { 'enum' : 'FirmwareFeature', - 'data' : [ 'acpi-s3', 'acpi-s4', 'amd-sev', 'amd-sev-es', 'enrolled-keys', - 'requires-smm', 'secure-boot', 'verbose-dynamic', - 'verbose-static' ] } + 'data' : [ 'acpi-s3', 'acpi-s4', + 'amd-sev', 'amd-sev-es', 'amd-sev-snp', + 'intel-tdx', + 'enrolled-keys', 'requires-smm', 'secure-boot', + 'verbose-dynamic', 'verbose-static' ] } ## # @FirmwareFlashFile: From c82190fa1ba738b66513cf8869f25d45b1061ac6 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Tue, 4 Oct 2022 13:20:56 +0200 Subject: [PATCH 17/26] pci-ids: drop PCI_DEVICE_ID_VIRTIO_IOMMU Not needed for a virtio 1.0 device. virtio_pci_device_plugged() overrides them anyway (so no functional change). Signed-off-by: Gerd Hoffmann Reviewed-by: Eric Auger Tested-by: Eric Auger Message-Id: <20221004112100.301935-2-kraxel@redhat.com> --- hw/virtio/virtio-iommu-pci.c | 4 +--- include/hw/pci/pci.h | 1 - 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/hw/virtio/virtio-iommu-pci.c b/hw/virtio/virtio-iommu-pci.c index 844d647704..79ea8334f0 100644 --- a/hw/virtio/virtio-iommu-pci.c +++ b/hw/virtio/virtio-iommu-pci.c @@ -74,8 +74,6 @@ static void virtio_iommu_pci_class_init(ObjectClass *klass, void *data) k->realize = virtio_iommu_pci_realize; set_bit(DEVICE_CATEGORY_MISC, dc->categories); device_class_set_props(dc, virtio_iommu_pci_properties); - pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET; - pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_IOMMU; pcidev_k->revision = VIRTIO_PCI_ABI_VERSION; pcidev_k->class_id = PCI_CLASS_OTHERS; dc->hotpluggable = false; @@ -90,7 +88,7 @@ static void virtio_iommu_pci_instance_init(Object *obj) } static const VirtioPCIDeviceTypeInfo virtio_iommu_pci_info = { - .generic_name = TYPE_VIRTIO_IOMMU_PCI, + .generic_name = TYPE_VIRTIO_IOMMU_PCI, .instance_size = sizeof(VirtIOIOMMUPCI), .instance_init = virtio_iommu_pci_instance_init, .class_init = virtio_iommu_pci_class_init, diff --git a/include/hw/pci/pci.h b/include/hw/pci/pci.h index b54b6ef88f..89eaca4293 100644 --- a/include/hw/pci/pci.h +++ b/include/hw/pci/pci.h @@ -85,7 +85,6 @@ extern bool pci_available; #define PCI_DEVICE_ID_VIRTIO_9P 0x1009 #define PCI_DEVICE_ID_VIRTIO_VSOCK 0x1012 #define PCI_DEVICE_ID_VIRTIO_PMEM 0x1013 -#define PCI_DEVICE_ID_VIRTIO_IOMMU 0x1014 #define PCI_DEVICE_ID_VIRTIO_MEM 0x1015 #define PCI_VENDOR_ID_REDHAT 0x1b36 From 58de96e2ebc4977e3d0a042946a70a3e4bdde4ba Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Tue, 4 Oct 2022 13:20:57 +0200 Subject: [PATCH 18/26] pci-ids: drop PCI_DEVICE_ID_VIRTIO_MEM Not needed for a virtio 1.0 device. virtio_pci_device_plugged() overrides them anyway (so no functional change). Signed-off-by: Gerd Hoffmann Reviewed-by: David Hildenbrand Message-Id: <20221004112100.301935-3-kraxel@redhat.com> --- hw/virtio/virtio-mem-pci.c | 2 -- include/hw/pci/pci.h | 1 - 2 files changed, 3 deletions(-) diff --git a/hw/virtio/virtio-mem-pci.c b/hw/virtio/virtio-mem-pci.c index be2383b0c5..5c5c1e3ae3 100644 --- a/hw/virtio/virtio-mem-pci.c +++ b/hw/virtio/virtio-mem-pci.c @@ -104,8 +104,6 @@ static void virtio_mem_pci_class_init(ObjectClass *klass, void *data) k->realize = virtio_mem_pci_realize; set_bit(DEVICE_CATEGORY_MISC, dc->categories); - pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET; - pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_MEM; pcidev_k->revision = VIRTIO_PCI_ABI_VERSION; pcidev_k->class_id = PCI_CLASS_OTHERS; diff --git a/include/hw/pci/pci.h b/include/hw/pci/pci.h index 89eaca4293..b6aefb33fb 100644 --- a/include/hw/pci/pci.h +++ b/include/hw/pci/pci.h @@ -85,7 +85,6 @@ extern bool pci_available; #define PCI_DEVICE_ID_VIRTIO_9P 0x1009 #define PCI_DEVICE_ID_VIRTIO_VSOCK 0x1012 #define PCI_DEVICE_ID_VIRTIO_PMEM 0x1013 -#define PCI_DEVICE_ID_VIRTIO_MEM 0x1015 #define PCI_VENDOR_ID_REDHAT 0x1b36 #define PCI_DEVICE_ID_REDHAT_BRIDGE 0x0001 From cbd56573f769f8ebefd6a1241169a101ca639f85 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Tue, 4 Oct 2022 13:20:58 +0200 Subject: [PATCH 19/26] pci-ids: drop PCI_DEVICE_ID_VIRTIO_PMEM Not needed for a virtio 1.0 device. virtio_pci_device_plugged() overrides them anyway (so no functional change). Signed-off-by: Gerd Hoffmann Reviewed-by: David Hildenbrand Reviewed-by: Pankaj Gupta Tested-by: Pankaj Gupta Message-Id: <20221004112100.301935-4-kraxel@redhat.com> --- hw/virtio/virtio-pmem-pci.c | 2 -- include/hw/pci/pci.h | 1 - 2 files changed, 3 deletions(-) diff --git a/hw/virtio/virtio-pmem-pci.c b/hw/virtio/virtio-pmem-pci.c index 2b2a0b1eae..7d9f4ec189 100644 --- a/hw/virtio/virtio-pmem-pci.c +++ b/hw/virtio/virtio-pmem-pci.c @@ -90,8 +90,6 @@ static void virtio_pmem_pci_class_init(ObjectClass *klass, void *data) k->realize = virtio_pmem_pci_realize; set_bit(DEVICE_CATEGORY_MISC, dc->categories); - pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET; - pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_PMEM; pcidev_k->revision = VIRTIO_PCI_ABI_VERSION; pcidev_k->class_id = PCI_CLASS_OTHERS; diff --git a/include/hw/pci/pci.h b/include/hw/pci/pci.h index b6aefb33fb..42c83cb5ed 100644 --- a/include/hw/pci/pci.h +++ b/include/hw/pci/pci.h @@ -84,7 +84,6 @@ extern bool pci_available; #define PCI_DEVICE_ID_VIRTIO_RNG 0x1005 #define PCI_DEVICE_ID_VIRTIO_9P 0x1009 #define PCI_DEVICE_ID_VIRTIO_VSOCK 0x1012 -#define PCI_DEVICE_ID_VIRTIO_PMEM 0x1013 #define PCI_VENDOR_ID_REDHAT 0x1b36 #define PCI_DEVICE_ID_REDHAT_BRIDGE 0x0001 From 55f01e76a305df90fe6b8f02dbeb88a2d7a04f97 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Tue, 4 Oct 2022 13:20:59 +0200 Subject: [PATCH 20/26] pci-ids: drop list of modern virtio devices Drop the list of modern virtio devices and explain how they are calculated instead. Signed-off-by: Gerd Hoffmann Reviewed-by: Eric Auger Message-Id: <20221004112100.301935-5-kraxel@redhat.com> --- docs/specs/pci-ids.txt | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/docs/specs/pci-ids.txt b/docs/specs/pci-ids.txt index dd6859d039..e463c4cb3a 100644 --- a/docs/specs/pci-ids.txt +++ b/docs/specs/pci-ids.txt @@ -22,16 +22,14 @@ maintained as part of the virtio specification. 1af4:1004 SCSI host bus adapter device (legacy) 1af4:1005 entropy generator device (legacy) 1af4:1009 9p filesystem device (legacy) +1af4:1012 vsock device (bug compatibility) -1af4:1041 network device (modern) -1af4:1042 block device (modern) -1af4:1043 console device (modern) -1af4:1044 entropy generator device (modern) -1af4:1045 balloon device (modern) -1af4:1048 SCSI host bus adapter device (modern) -1af4:1049 9p filesystem device (modern) -1af4:1050 virtio gpu device (modern) -1af4:1052 virtio input device (modern) +1af4:1040 Start of ID range for modern virtio devices. The PCI device + to ID is calculated from the virtio device ID by adding the +1af4:10ef 0x1040 offset. The virtio IDs are defined in the virtio + specification. The Linux kernel has a header file with + defines for all virtio IDs (linux/virtio_ids.h), qemu has a + copy in include/standard-headers/. 1af4:10f0 Available for experimental usage without registration. Must get to official ID when the code leaves the test lab (i.e. when seeking From 0468fe82d32e99b6d84085e76d1e946bbe1e80ac Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Tue, 4 Oct 2022 13:21:00 +0200 Subject: [PATCH 21/26] pci-ids: document modern virtio-pci ids in pci.h too While being at it add a #define for the magic 0x1040 number. Signed-off-by: Gerd Hoffmann Reviewed-by: Eric Auger Message-Id: <20221004112100.301935-6-kraxel@redhat.com> --- hw/virtio/virtio-pci.c | 2 +- include/hw/pci/pci.h | 10 ++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c index a50c5a57d7..e7d80242b7 100644 --- a/hw/virtio/virtio-pci.c +++ b/hw/virtio/virtio-pci.c @@ -1688,7 +1688,7 @@ static void virtio_pci_device_plugged(DeviceState *d, Error **errp) pci_set_word(config + PCI_VENDOR_ID, PCI_VENDOR_ID_REDHAT_QUMRANET); pci_set_word(config + PCI_DEVICE_ID, - 0x1040 + virtio_bus_get_vdev_id(bus)); + PCI_DEVICE_ID_VIRTIO_10_BASE + virtio_bus_get_vdev_id(bus)); pci_config_set_revision(config, 1); } config[PCI_INTERRUPT_PIN] = 1; diff --git a/include/hw/pci/pci.h b/include/hw/pci/pci.h index 42c83cb5ed..d1ac308574 100644 --- a/include/hw/pci/pci.h +++ b/include/hw/pci/pci.h @@ -76,6 +76,7 @@ extern bool pci_available; #define PCI_SUBVENDOR_ID_REDHAT_QUMRANET 0x1af4 #define PCI_SUBDEVICE_ID_QEMU 0x1100 +/* legacy virtio-pci devices */ #define PCI_DEVICE_ID_VIRTIO_NET 0x1000 #define PCI_DEVICE_ID_VIRTIO_BLOCK 0x1001 #define PCI_DEVICE_ID_VIRTIO_BALLOON 0x1002 @@ -85,6 +86,15 @@ extern bool pci_available; #define PCI_DEVICE_ID_VIRTIO_9P 0x1009 #define PCI_DEVICE_ID_VIRTIO_VSOCK 0x1012 +/* + * modern virtio-pci devices get their id assigned automatically, + * there is no need to add #defines here. It gets calculated as + * + * PCI_DEVICE_ID = PCI_DEVICE_ID_VIRTIO_10_BASE + + * virtio_bus_get_vdev_id(bus) + */ +#define PCI_DEVICE_ID_VIRTIO_10_BASE 0x1040 + #define PCI_VENDOR_ID_REDHAT 0x1b36 #define PCI_DEVICE_ID_REDHAT_BRIDGE 0x0001 #define PCI_DEVICE_ID_REDHAT_SERIAL 0x0002 From 8af5f82b90cc860d79171ade228ccea59c7f525e Mon Sep 17 00:00:00 2001 From: Akihiko Odaki Date: Sat, 8 Oct 2022 23:01:16 +0900 Subject: [PATCH 22/26] ui/gtk: Fix the implicit mouse ungrabbing logic Although the grab menu item represents the tabbed displays, the old implicit mouse ungrabbing logic changes the grab menu item even for an untabbed display. Leave the grab menu item when implicitly ungrabbing mouse for an untabbed display. The new ungrabbing logic introduced in gd_mouse_mode_change() strictly follows the corresponding grabbing logic found in gd_button_event(). Signed-off-by: Akihiko Odaki Message-Id: <20221008140116.11473-1-akihiko.odaki@daynix.com> Signed-off-by: Gerd Hoffmann --- ui/gtk.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/ui/gtk.c b/ui/gtk.c index 1467b8c7d7..6fc2e23963 100644 --- a/ui/gtk.c +++ b/ui/gtk.c @@ -681,9 +681,13 @@ static void gd_mouse_mode_change(Notifier *notify, void *data) s = container_of(notify, GtkDisplayState, mouse_mode_notifier); /* release the grab at switching to absolute mode */ - if (qemu_input_is_absolute() && gd_is_grab_active(s)) { - gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(s->grab_item), - FALSE); + if (qemu_input_is_absolute() && s->ptr_owner) { + if (!s->ptr_owner->window) { + gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(s->grab_item), + FALSE); + } else { + gd_ungrab_pointer(s); + } } for (i = 0; i < s->nb_vcs; i++) { VirtualConsole *vc = &s->vc[i]; From 82a628f887409f8a863482627c6d6ea6f208d3b2 Mon Sep 17 00:00:00 2001 From: Sebastian Mitterle Date: Tue, 11 Oct 2022 17:12:16 +0200 Subject: [PATCH 23/26] qemu-edid: Restrict input parameter -d to avoid division by zero A zero value for dpi will lead to a division by zero in qemu_edid_dpi_to_mm(). Tested by runnig qemu-edid -dX, X = 0, 100. Resolves: qemu-project/qemu#1249 Suggested-by: Thomas Huth Signed-off-by: Sebastian Mitterle Message-Id: <20221011151216.64897-1-smitterl@redhat.com> Signed-off-by: Gerd Hoffmann --- qemu-edid.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/qemu-edid.c b/qemu-edid.c index 20c958d9c7..92e1a660a7 100644 --- a/qemu-edid.c +++ b/qemu-edid.c @@ -92,6 +92,10 @@ int main(int argc, char *argv[]) fprintf(stderr, "not a number: %s\n", optarg); exit(1); } + if (dpi == 0) { + fprintf(stderr, "cannot be zero: %s\n", optarg); + exit(1); + } break; case 'v': info.vendor = optarg; From dbccb1a5a1b5b14b78ea6b27bb562e8cd0a8f317 Mon Sep 17 00:00:00 2001 From: Bryce Mills Date: Tue, 11 Oct 2022 13:58:21 +0000 Subject: [PATCH 24/26] gtk: Add show_menubar=on|off command line option. The patch adds "show_menubar" command line option for GTK UI similar to "show_tabs". This option allows to hide menu bar initially, it still can be toggled by shortcut and other shortcuts still work. Signed-off-by: Bryce Mills Acked-by: Markus Armbruster Message-Id: Signed-off-by: Gerd Hoffmann --- qapi/ui.json | 5 ++++- qemu-options.hx | 3 +++ ui/gtk.c | 15 ++++++++++----- 3 files changed, 17 insertions(+), 6 deletions(-) diff --git a/qapi/ui.json b/qapi/ui.json index 286c5731d1..0abba3e930 100644 --- a/qapi/ui.json +++ b/qapi/ui.json @@ -1199,13 +1199,16 @@ # interfaces (e.g. VGA and virtual console character devices) # by default. # Since 7.1 +# @show-menubar: Display the main window menubar. Defaults to "on". +# Since 8.0 # # Since: 2.12 ## { 'struct' : 'DisplayGTK', 'data' : { '*grab-on-hover' : 'bool', '*zoom-to-fit' : 'bool', - '*show-tabs' : 'bool' } } + '*show-tabs' : 'bool', + '*show-menubar' : 'bool' } } ## # @DisplayEGLHeadless: diff --git a/qemu-options.hx b/qemu-options.hx index 95b998a13b..bb0979bef9 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -1969,6 +1969,7 @@ DEF("display", HAS_ARG, QEMU_OPTION_display, #if defined(CONFIG_GTK) "-display gtk[,full-screen=on|off][,gl=on|off][,grab-on-hover=on|off]\n" " [,show-tabs=on|off][,show-cursor=on|off][,window-close=on|off]\n" + " [,show-menubar=on|off]\n" #endif #if defined(CONFIG_VNC) "-display vnc=[,]\n" @@ -2061,6 +2062,8 @@ SRST ``window-close=on|off`` : Allow to quit qemu with window close button + ``show-menubar=on|off`` : Display the main window menubar, defaults to "on" + ``curses[,charset=]`` Display video output via curses. For graphics device models which support a text mode, QEMU can display this output using a diff --git a/ui/gtk.c b/ui/gtk.c index 6fc2e23963..92daaa6a6e 100644 --- a/ui/gtk.c +++ b/ui/gtk.c @@ -2171,7 +2171,7 @@ static GSList *gd_vc_gfx_init(GtkDisplayState *s, VirtualConsole *vc, return group; } -static GtkWidget *gd_create_menu_view(GtkDisplayState *s) +static GtkWidget *gd_create_menu_view(GtkDisplayState *s, DisplayOptions *opts) { GSList *group = NULL; GtkWidget *view_menu; @@ -2269,7 +2269,8 @@ static GtkWidget *gd_create_menu_view(GtkDisplayState *s) s->show_menubar_item = gtk_check_menu_item_new_with_mnemonic( _("Show Menubar")); gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(s->show_menubar_item), - TRUE); + !opts->u.gtk.has_show_menubar || + opts->u.gtk.show_menubar); gtk_accel_group_connect(s->accel_group, GDK_KEY_m, HOTKEY_MODIFIERS, 0, g_cclosure_new_swap(G_CALLBACK(gd_accel_show_menubar), s, NULL)); gtk_accel_label_set_accel( @@ -2280,13 +2281,13 @@ static GtkWidget *gd_create_menu_view(GtkDisplayState *s) return view_menu; } -static void gd_create_menus(GtkDisplayState *s) +static void gd_create_menus(GtkDisplayState *s, DisplayOptions *opts) { GtkSettings *settings; s->accel_group = gtk_accel_group_new(); s->machine_menu = gd_create_menu_machine(s); - s->view_menu = gd_create_menu_view(s); + s->view_menu = gd_create_menu_view(s, opts); s->machine_menu_item = gtk_menu_item_new_with_mnemonic(_("_Machine")); gtk_menu_item_set_submenu(GTK_MENU_ITEM(s->machine_menu_item), @@ -2363,7 +2364,7 @@ static void gtk_display_init(DisplayState *ds, DisplayOptions *opts) gtk_window_set_icon_name(GTK_WINDOW(s->window), "qemu"); - gd_create_menus(s); + gd_create_menus(s, opts); gd_connect_signals(s); @@ -2378,6 +2379,10 @@ static void gtk_display_init(DisplayState *ds, DisplayOptions *opts) gtk_container_add(GTK_CONTAINER(s->window), s->vbox); gtk_widget_show_all(s->window); + if (opts->u.gtk.has_show_menubar && + !opts->u.gtk.show_menubar) { + gtk_widget_hide(s->menu_bar); + } vc = gd_vc_find_current(s); gtk_widget_set_sensitive(s->view_menu, vc != NULL); From a7b7802bfe971b1b33cf85b328a521333e68ce97 Mon Sep 17 00:00:00 2001 From: Helge Konetzka Date: Wed, 12 Oct 2022 13:49:24 +0200 Subject: [PATCH 25/26] audio: fix in.voices test MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Calling qemu with valid -audiodev ...,in.voices=0 results in an obsolete warning: audio: Bogus number of capture voices 0, setting to 0 This patch fixes the in.voices test. Signed-off-by: Helge Konetzka Reviewed-by: Marc-André Lureau Message-Id: <20221012114925.5084-2-hk@zapateado.de> Signed-off-by: Gerd Hoffmann --- audio/audio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/audio/audio.c b/audio/audio.c index 886725747b..1ecdbc4191 100644 --- a/audio/audio.c +++ b/audio/audio.c @@ -1778,7 +1778,7 @@ static AudioState *audio_init(Audiodev *dev, const char *name) s->nb_hw_voices_out = 1; } - if (s->nb_hw_voices_in <= 0) { + if (s->nb_hw_voices_in < 0) { dolog ("Bogus number of capture voices %d, setting to 0\n", s->nb_hw_voices_in); s->nb_hw_voices_in = 0; From 61ddafbcfac4975ee245cd3453be86b0632a5605 Mon Sep 17 00:00:00 2001 From: Helge Konetzka Date: Wed, 12 Oct 2022 13:49:25 +0200 Subject: [PATCH 26/26] audio: improve out.voices test MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Improve readability of audio out.voices test: If 1 is logged and set after positive test, 1 should be tested. Signed-off-by: Helge Konetzka Reviewed-by: Marc-André Lureau Message-Id: <20221012114925.5084-3-hk@zapateado.de> Signed-off-by: Gerd Hoffmann --- audio/audio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/audio/audio.c b/audio/audio.c index 1ecdbc4191..cc664271eb 100644 --- a/audio/audio.c +++ b/audio/audio.c @@ -1772,7 +1772,7 @@ static AudioState *audio_init(Audiodev *dev, const char *name) s->nb_hw_voices_out = audio_get_pdo_out(dev)->voices; s->nb_hw_voices_in = audio_get_pdo_in(dev)->voices; - if (s->nb_hw_voices_out <= 0) { + if (s->nb_hw_voices_out < 1) { dolog ("Bogus number of playback voices %d, setting to 1\n", s->nb_hw_voices_out); s->nb_hw_voices_out = 1;