diff options
153 files changed, 3099 insertions, 630 deletions
diff --git a/.travis.yml b/.travis.yml index 708c886017..01a57399b5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,12 +13,13 @@ addons: - libattr1-dev - libbrlapi-dev - libcap-ng-dev + - libgcc-6-dev - libgnutls-dev - libgtk-3-dev - libiscsi-dev - liblttng-ust-dev - - libnfs-dev - libncurses5-dev + - libnfs-dev - libnss3-dev - libpixman-1-dev - libpng12-dev diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c index f290f487a5..b91fcb7160 100644 --- a/accel/kvm/kvm-all.c +++ b/accel/kvm/kvm-all.c @@ -235,6 +235,7 @@ static int kvm_set_user_memory_region(KVMMemoryListener *kml, KVMSlot *slot) { KVMState *s = kvm_state; struct kvm_userspace_memory_region mem; + int ret; mem.slot = slot->slot | (kml->as_id << 16); mem.guest_phys_addr = slot->start_addr; @@ -248,7 +249,10 @@ static int kvm_set_user_memory_region(KVMMemoryListener *kml, KVMSlot *slot) kvm_vm_ioctl(s, KVM_SET_USER_MEMORY_REGION, &mem); } mem.memory_size = slot->memory_size; - return kvm_vm_ioctl(s, KVM_SET_USER_MEMORY_REGION, &mem); + ret = kvm_vm_ioctl(s, KVM_SET_USER_MEMORY_REGION, &mem); + trace_kvm_set_user_memory(mem.slot, mem.flags, mem.guest_phys_addr, + mem.memory_size, mem.userspace_addr, ret); + return ret; } int kvm_destroy_vcpu(CPUState *cpu) diff --git a/accel/kvm/trace-events b/accel/kvm/trace-events index f89ba5578d..58e98efe5d 100644 --- a/accel/kvm/trace-events +++ b/accel/kvm/trace-events @@ -12,4 +12,5 @@ kvm_irqchip_commit_routes(void) "" kvm_irqchip_add_msi_route(char *name, int vector, int virq) "dev %s vector %d virq %d" kvm_irqchip_update_msi_route(int virq) "Updating MSI route virq=%d" kvm_irqchip_release_virq(int virq) "virq %d" +kvm_set_user_memory(uint32_t slot, uint32_t flags, uint64_t guest_phys_addr, uint64_t memory_size, uint64_t userspace_addr, int ret) "Slot#%d flags=0x%x gpa=0x%"PRIx64 " size=0x%"PRIx64 " ua=0x%"PRIx64 " ret=%d" diff --git a/accel/stubs/Makefile.objs b/accel/stubs/Makefile.objs index 779343b0c0..3894caf95d 100644 --- a/accel/stubs/Makefile.objs +++ b/accel/stubs/Makefile.objs @@ -1,4 +1,5 @@ -obj-$(call lnot,$(CONFIG_HAX)) += hax-stub.o -obj-$(call lnot,$(CONFIG_HVF)) += hvf-stub.o -obj-$(call lnot,$(CONFIG_KVM)) += kvm-stub.o -obj-$(call lnot,$(CONFIG_TCG)) += tcg-stub.o +obj-$(call lnot,$(CONFIG_HAX)) += hax-stub.o +obj-$(call lnot,$(CONFIG_HVF)) += hvf-stub.o +obj-$(call lnot,$(CONFIG_WHPX)) += whpx-stub.o +obj-$(call lnot,$(CONFIG_KVM)) += kvm-stub.o +obj-$(call lnot,$(CONFIG_TCG)) += tcg-stub.o diff --git a/accel/stubs/whpx-stub.c b/accel/stubs/whpx-stub.c new file mode 100644 index 0000000000..5fb049c281 --- /dev/null +++ b/accel/stubs/whpx-stub.c @@ -0,0 +1,48 @@ +/* + * QEMU Windows Hypervisor Platform accelerator (WHPX) stub + * + * Copyright Microsoft Corp. 2017 + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + * + */ + +#include "qemu/osdep.h" +#include "qemu-common.h" +#include "cpu.h" +#include "sysemu/whpx.h" + +int whpx_init_vcpu(CPUState *cpu) +{ + return -1; +} + +int whpx_vcpu_exec(CPUState *cpu) +{ + return -1; +} + +void whpx_destroy_vcpu(CPUState *cpu) +{ +} + +void whpx_vcpu_kick(CPUState *cpu) +{ +} + +void whpx_cpu_synchronize_state(CPUState *cpu) +{ +} + +void whpx_cpu_synchronize_post_reset(CPUState *cpu) +{ +} + +void whpx_cpu_synchronize_post_init(CPUState *cpu) +{ +} + +void whpx_cpu_synchronize_pre_loadvm(CPUState *cpu) +{ +} diff --git a/accel/tcg/user-exec.c b/accel/tcg/user-exec.c index a0a4a1924e..77899584f2 100644 --- a/accel/tcg/user-exec.c +++ b/accel/tcg/user-exec.c @@ -503,39 +503,6 @@ int cpu_signal_handler(int host_signum, void *pinfo, void *puc) return handle_cpu_signal(pc, info, is_write, &uc->uc_sigmask); } -#elif defined(__ia64) - -#ifndef __ISR_VALID - /* This ought to be in <bits/siginfo.h>... */ -# define __ISR_VALID 1 -#endif - -int cpu_signal_handler(int host_signum, void *pinfo, void *puc) -{ - siginfo_t *info = pinfo; - ucontext_t *uc = puc; - unsigned long ip; - int is_write = 0; - - ip = uc->uc_mcontext.sc_ip; - switch (host_signum) { - case SIGILL: - case SIGFPE: - case SIGSEGV: - case SIGBUS: - case SIGTRAP: - if (info->si_code && (info->si_segvflags & __ISR_VALID)) { - /* ISR.W (write-access) is bit 33: */ - is_write = (info->si_isr >> 33) & 1; - } - break; - - default: - break; - } - return handle_cpu_signal(ip, info, is_write, (sigset_t *)&uc->uc_sigmask); -} - #elif defined(__s390__) int cpu_signal_handler(int host_signum, void *pinfo, diff --git a/audio/alsaaudio.c b/audio/alsaaudio.c index 3652a7b5fa..92a96f8b2b 100644 --- a/audio/alsaaudio.c +++ b/audio/alsaaudio.c @@ -823,7 +823,7 @@ static int alsa_init_out(HWVoiceOut *hw, struct audsettings *as, audio_pcm_init_info (&hw->info, &obt_as); hw->samples = obt.samples; - alsa->pcm_buf = audio_calloc (AUDIO_FUNC, obt.samples, 1 << hw->info.shift); + alsa->pcm_buf = audio_calloc(__func__, obt.samples, 1 << hw->info.shift); if (!alsa->pcm_buf) { dolog ("Could not allocate DAC buffer (%d samples, each %d bytes)\n", hw->samples, 1 << hw->info.shift); @@ -934,7 +934,7 @@ static int alsa_init_in(HWVoiceIn *hw, struct audsettings *as, void *drv_opaque) audio_pcm_init_info (&hw->info, &obt_as); hw->samples = obt.samples; - alsa->pcm_buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift); + alsa->pcm_buf = audio_calloc(__func__, hw->samples, 1 << hw->info.shift); if (!alsa->pcm_buf) { dolog ("Could not allocate ADC buffer (%d samples, each %d bytes)\n", hw->samples, 1 << hw->info.shift); diff --git a/audio/audio.c b/audio/audio.c index beafed209b..7658d2af66 100644 --- a/audio/audio.c +++ b/audio/audio.c @@ -424,12 +424,12 @@ static void audio_process_options (const char *prefix, const char qemu_prefix[] = "QEMU_"; size_t preflen, optlen; - if (audio_bug (AUDIO_FUNC, !prefix)) { + if (audio_bug(__func__, !prefix)) { dolog ("prefix = NULL\n"); return; } - if (audio_bug (AUDIO_FUNC, !opt)) { + if (audio_bug(__func__, !opt)) { dolog ("opt = NULL\n"); return; } @@ -792,7 +792,7 @@ static int audio_attach_capture (HWVoiceOut *hw) SWVoiceOut *sw; HWVoiceOut *hw_cap = &cap->hw; - sc = audio_calloc (AUDIO_FUNC, 1, sizeof (*sc)); + sc = audio_calloc(__func__, 1, sizeof(*sc)); if (!sc) { dolog ("Could not allocate soft capture voice (%zu bytes)\n", sizeof (*sc)); @@ -848,7 +848,7 @@ static int audio_pcm_hw_find_min_in (HWVoiceIn *hw) int audio_pcm_hw_get_live_in (HWVoiceIn *hw) { int live = hw->total_samples_captured - audio_pcm_hw_find_min_in (hw); - if (audio_bug (AUDIO_FUNC, live < 0 || live > hw->samples)) { + if (audio_bug(__func__, live < 0 || live > hw->samples)) { dolog ("live=%d hw->samples=%d\n", live, hw->samples); return 0; } @@ -886,7 +886,7 @@ static int audio_pcm_sw_get_rpos_in (SWVoiceIn *sw) int live = hw->total_samples_captured - sw->total_hw_samples_acquired; int rpos; - if (audio_bug (AUDIO_FUNC, live < 0 || live > hw->samples)) { + if (audio_bug(__func__, live < 0 || live > hw->samples)) { dolog ("live=%d hw->samples=%d\n", live, hw->samples); return 0; } @@ -909,7 +909,7 @@ int audio_pcm_sw_read (SWVoiceIn *sw, void *buf, int size) rpos = audio_pcm_sw_get_rpos_in (sw) % hw->samples; live = hw->total_samples_captured - sw->total_hw_samples_acquired; - if (audio_bug (AUDIO_FUNC, live < 0 || live > hw->samples)) { + if (audio_bug(__func__, live < 0 || live > hw->samples)) { dolog ("live_in=%d hw->samples=%d\n", live, hw->samples); return 0; } @@ -935,7 +935,7 @@ int audio_pcm_sw_read (SWVoiceIn *sw, void *buf, int size) } osamp = swlim; - if (audio_bug (AUDIO_FUNC, osamp < 0)) { + if (audio_bug(__func__, osamp < 0)) { dolog ("osamp=%d\n", osamp); return 0; } @@ -990,7 +990,7 @@ static int audio_pcm_hw_get_live_out (HWVoiceOut *hw, int *nb_live) if (nb_live1) { int live = smin; - if (audio_bug (AUDIO_FUNC, live < 0 || live > hw->samples)) { + if (audio_bug(__func__, live < 0 || live > hw->samples)) { dolog ("live=%d hw->samples=%d\n", live, hw->samples); return 0; } @@ -1014,7 +1014,7 @@ int audio_pcm_sw_write (SWVoiceOut *sw, void *buf, int size) hwsamples = sw->hw->samples; live = sw->total_hw_samples_mixed; - if (audio_bug (AUDIO_FUNC, live < 0 || live > hwsamples)){ + if (audio_bug(__func__, live < 0 || live > hwsamples)) { dolog ("live=%d hw->samples=%d\n", live, hwsamples); return 0; } @@ -1263,7 +1263,7 @@ static int audio_get_avail (SWVoiceIn *sw) } live = sw->hw->total_samples_captured - sw->total_hw_samples_acquired; - if (audio_bug (AUDIO_FUNC, live < 0 || live > sw->hw->samples)) { + if (audio_bug(__func__, live < 0 || live > sw->hw->samples)) { dolog ("live=%d sw->hw->samples=%d\n", live, sw->hw->samples); return 0; } @@ -1287,7 +1287,7 @@ static int audio_get_free (SWVoiceOut *sw) live = sw->total_hw_samples_mixed; - if (audio_bug (AUDIO_FUNC, live < 0 || live > sw->hw->samples)) { + if (audio_bug(__func__, live < 0 || live > sw->hw->samples)) { dolog ("live=%d sw->hw->samples=%d\n", live, sw->hw->samples); return 0; } @@ -1354,7 +1354,7 @@ static void audio_run_out (AudioState *s) live = 0; } - if (audio_bug (AUDIO_FUNC, live < 0 || live > hw->samples)) { + if (audio_bug(__func__, live < 0 || live > hw->samples)) { dolog ("live=%d hw->samples=%d\n", live, hw->samples); continue; } @@ -1389,7 +1389,7 @@ static void audio_run_out (AudioState *s) prev_rpos = hw->rpos; played = hw->pcm_ops->run_out (hw, live); replay_audio_out(&played); - if (audio_bug (AUDIO_FUNC, hw->rpos >= hw->samples)) { + if (audio_bug(__func__, hw->rpos >= hw->samples)) { dolog ("hw->rpos=%d hw->samples=%d played=%d\n", hw->rpos, hw->samples, played); hw->rpos = 0; @@ -1410,7 +1410,7 @@ static void audio_run_out (AudioState *s) continue; } - if (audio_bug (AUDIO_FUNC, played > sw->total_hw_samples_mixed)) { + if (audio_bug(__func__, played > sw->total_hw_samples_mixed)) { dolog ("played=%d sw->total_hw_samples_mixed=%d\n", played, sw->total_hw_samples_mixed); played = sw->total_hw_samples_mixed; @@ -1513,7 +1513,7 @@ static void audio_run_capture (AudioState *s) continue; } - if (audio_bug (AUDIO_FUNC, captured > sw->total_hw_samples_mixed)) { + if (audio_bug(__func__, captured > sw->total_hw_samples_mixed)) { dolog ("captured=%d sw->total_hw_samples_mixed=%d\n", captured, sw->total_hw_samples_mixed); captured = sw->total_hw_samples_mixed; @@ -1924,7 +1924,7 @@ CaptureVoiceOut *AUD_add_capture ( goto err0; } - cb = audio_calloc (AUDIO_FUNC, 1, sizeof (*cb)); + cb = audio_calloc(__func__, 1, sizeof(*cb)); if (!cb) { dolog ("Could not allocate capture callback information, size %zu\n", sizeof (*cb)); @@ -1942,7 +1942,7 @@ CaptureVoiceOut *AUD_add_capture ( HWVoiceOut *hw; CaptureVoiceOut *cap; - cap = audio_calloc (AUDIO_FUNC, 1, sizeof (*cap)); + cap = audio_calloc(__func__, 1, sizeof(*cap)); if (!cap) { dolog ("Could not allocate capture voice, size %zu\n", sizeof (*cap)); @@ -1955,8 +1955,8 @@ CaptureVoiceOut *AUD_add_capture ( /* XXX find a more elegant way */ hw->samples = 4096 * 4; - hw->mix_buf = audio_calloc (AUDIO_FUNC, hw->samples, - sizeof (struct st_sample)); + hw->mix_buf = audio_calloc(__func__, hw->samples, + sizeof(struct st_sample)); if (!hw->mix_buf) { dolog ("Could not allocate capture mix buffer (%d samples)\n", hw->samples); @@ -1965,7 +1965,7 @@ CaptureVoiceOut *AUD_add_capture ( audio_pcm_init_info (&hw->info, as); - cap->buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift); + cap->buf = audio_calloc(__func__, hw->samples, 1 << hw->info.shift); if (!cap->buf) { dolog ("Could not allocate capture buffer " "(%d samples, each %d bytes)\n", diff --git a/audio/audio_int.h b/audio/audio_int.h index 5bcb1c60e1..5b25da0a37 100644 --- a/audio/audio_int.h +++ b/audio/audio_int.h @@ -252,10 +252,4 @@ static inline int audio_ring_dist (int dst, int src, int len) #define AUDIO_STRINGIFY_(n) #n #define AUDIO_STRINGIFY(n) AUDIO_STRINGIFY_(n) -#if defined _MSC_VER || defined __GNUC__ -#define AUDIO_FUNC __FUNCTION__ -#else -#define AUDIO_FUNC __FILE__ ":" AUDIO_STRINGIFY (__LINE__) -#endif - #endif /* QEMU_AUDIO_INT_H */ diff --git a/audio/audio_pt_int.c b/audio/audio_pt_int.c index 21ff9c5803..3fe56d8514 100644 --- a/audio/audio_pt_int.c +++ b/audio/audio_pt_int.c @@ -31,7 +31,7 @@ int audio_pt_init (struct audio_pt *p, void *(*func) (void *), err = sigfillset (&set); if (err) { - logerr (p, errno, "%s(%s): sigfillset failed", cap, AUDIO_FUNC); + logerr(p, errno, "%s(%s): sigfillset failed", cap, __func__); return -1; } @@ -57,8 +57,8 @@ int audio_pt_init (struct audio_pt *p, void *(*func) (void *), err2 = pthread_sigmask (SIG_SETMASK, &old_set, NULL); if (err2) { - logerr (p, err2, "%s(%s): pthread_sigmask (restore) failed", - cap, AUDIO_FUNC); + logerr(p, err2, "%s(%s): pthread_sigmask (restore) failed", + cap, __func__); /* We have failed to restore original signal mask, all bets are off, so terminate the process */ exit (EXIT_FAILURE); @@ -74,17 +74,17 @@ int audio_pt_init (struct audio_pt *p, void *(*func) (void *), err2: err2 = pthread_cond_destroy (&p->cond); if (err2) { - logerr (p, err2, "%s(%s): pthread_cond_destroy failed", cap, AUDIO_FUNC); + logerr(p, err2, "%s(%s): pthread_cond_destroy failed", cap, __func__); } err1: err2 = pthread_mutex_destroy (&p->mutex); if (err2) { - logerr (p, err2, "%s(%s): pthread_mutex_destroy failed", cap, AUDIO_FUNC); + logerr(p, err2, "%s(%s): pthread_mutex_destroy failed", cap, __func__); } err0: - logerr (p, err, "%s(%s): %s failed", cap, AUDIO_FUNC, efunc); + logerr(p, err, "%s(%s): %s failed", cap, __func__, efunc); return -1; } @@ -94,13 +94,13 @@ int audio_pt_fini (struct audio_pt *p, const char *cap) err = pthread_cond_destroy (&p->cond); if (err) { - logerr (p, err, "%s(%s): pthread_cond_destroy failed", cap, AUDIO_FUNC); + logerr(p, err, "%s(%s): pthread_cond_destroy failed", cap, __func__); ret = -1; } err = pthread_mutex_destroy (&p->mutex); if (err) { - logerr (p, err, "%s(%s): pthread_mutex_destroy failed", cap, AUDIO_FUNC); + logerr(p, err, "%s(%s): pthread_mutex_destroy failed", cap, __func__); ret = -1; } return ret; @@ -112,7 +112,7 @@ int audio_pt_lock (struct audio_pt *p, const char *cap) err = pthread_mutex_lock (&p->mutex); if (err) { - logerr (p, err, "%s(%s): pthread_mutex_lock failed", cap, AUDIO_FUNC); + logerr(p, err, "%s(%s): pthread_mutex_lock failed", cap, __func__); return -1; } return 0; @@ -124,7 +124,7 @@ int audio_pt_unlock (struct audio_pt *p, const char *cap) err = pthread_mutex_unlock (&p->mutex); if (err) { - logerr (p, err, "%s(%s): pthread_mutex_unlock failed", cap, AUDIO_FUNC); + logerr(p, err, "%s(%s): pthread_mutex_unlock failed", cap, __func__); return -1; } return 0; @@ -136,7 +136,7 @@ int audio_pt_wait (struct audio_pt *p, const char *cap) err = pthread_cond_wait (&p->cond, &p->mutex); if (err) { - logerr (p, err, "%s(%s): pthread_cond_wait failed", cap, AUDIO_FUNC); + logerr(p, err, "%s(%s): pthread_cond_wait failed", cap, __func__); return -1; } return 0; @@ -148,12 +148,12 @@ int audio_pt_unlock_and_signal (struct audio_pt *p, const char *cap) err = pthread_mutex_unlock (&p->mutex); if (err) { - logerr (p, err, "%s(%s): pthread_mutex_unlock failed", cap, AUDIO_FUNC); + logerr(p, err, "%s(%s): pthread_mutex_unlock failed", cap, __func__); return -1; } err = pthread_cond_signal (&p->cond); if (err) { - logerr (p, err, "%s(%s): pthread_cond_signal failed", cap, AUDIO_FUNC); + logerr(p, err, "%s(%s): pthread_cond_signal failed", cap, __func__); return -1; } return 0; @@ -166,7 +166,7 @@ int audio_pt_join (struct audio_pt *p, void **arg, const char *cap) err = pthread_join (p->thread, &ret); if (err) { - logerr (p, err, "%s(%s): pthread_join failed", cap, AUDIO_FUNC); + logerr(p, err, "%s(%s): pthread_join failed", cap, __func__); return -1; } *arg = ret; diff --git a/audio/audio_template.h b/audio/audio_template.h index 99b27b285e..7de227d2d1 100644 --- a/audio/audio_template.h +++ b/audio/audio_template.h @@ -57,13 +57,13 @@ static void glue (audio_init_nb_voices_, TYPE) (struct audio_driver *drv) glue (s->nb_hw_voices_, TYPE) = max_voices; } - if (audio_bug (AUDIO_FUNC, !voice_size && max_voices)) { + if (audio_bug(__func__, !voice_size && max_voices)) { dolog ("drv=`%s' voice_size=0 max_voices=%d\n", drv->name, max_voices); glue (s->nb_hw_voices_, TYPE) = 0; } - if (audio_bug (AUDIO_FUNC, voice_size && !max_voices)) { + if (audio_bug(__func__, voice_size && !max_voices)) { dolog ("drv=`%s' voice_size=%d max_voices=0\n", drv->name, voice_size); } @@ -77,7 +77,7 @@ static void glue (audio_pcm_hw_free_resources_, TYPE) (HW *hw) static int glue (audio_pcm_hw_alloc_resources_, TYPE) (HW *hw) { - HWBUF = audio_calloc (AUDIO_FUNC, hw->samples, sizeof (struct st_sample)); + HWBUF = audio_calloc(__func__, hw->samples, sizeof(struct st_sample)); if (!HWBUF) { dolog ("Could not allocate " NAME " buffer (%d samples)\n", hw->samples); @@ -105,7 +105,7 @@ static int glue (audio_pcm_sw_alloc_resources_, TYPE) (SW *sw) samples = ((int64_t) sw->hw->samples << 32) / sw->ratio; - sw->buf = audio_calloc (AUDIO_FUNC, samples, sizeof (struct st_sample)); + sw->buf = audio_calloc(__func__, samples, sizeof(struct st_sample)); if (!sw->buf) { dolog ("Could not allocate buffer for `%s' (%d samples)\n", SW_NAME (sw), samples); @@ -238,17 +238,17 @@ static HW *glue (audio_pcm_hw_add_new_, TYPE) (struct audsettings *as) return NULL; } - if (audio_bug (AUDIO_FUNC, !drv)) { + if (audio_bug(__func__, !drv)) { dolog ("No host audio driver\n"); return NULL; } - if (audio_bug (AUDIO_FUNC, !drv->pcm_ops)) { + if (audio_bug(__func__, !drv->pcm_ops)) { dolog ("Host audio driver without pcm_ops\n"); return NULL; } - hw = audio_calloc (AUDIO_FUNC, 1, glue (drv->voice_size_, TYPE)); + hw = audio_calloc(__func__, 1, glue(drv->voice_size_, TYPE)); if (!hw) { dolog ("Can not allocate voice `%s' size %d\n", drv->name, glue (drv->voice_size_, TYPE)); @@ -266,7 +266,7 @@ static HW *glue (audio_pcm_hw_add_new_, TYPE) (struct audsettings *as) goto err0; } - if (audio_bug (AUDIO_FUNC, hw->samples <= 0)) { + if (audio_bug(__func__, hw->samples <= 0)) { dolog ("hw->samples=%d\n", hw->samples); goto err1; } @@ -339,7 +339,7 @@ static SW *glue (audio_pcm_create_voice_pair_, TYPE) ( hw_as = *as; } - sw = audio_calloc (AUDIO_FUNC, 1, sizeof (*sw)); + sw = audio_calloc(__func__, 1, sizeof(*sw)); if (!sw) { dolog ("Could not allocate soft voice `%s' (%zu bytes)\n", sw_name ? sw_name : "unknown", sizeof (*sw)); @@ -379,7 +379,7 @@ static void glue (audio_close_, TYPE) (SW *sw) void glue (AUD_close_, TYPE) (QEMUSoundCard *card, SW *sw) { if (sw) { - if (audio_bug (AUDIO_FUNC, !card)) { + if (audio_bug(__func__, !card)) { dolog ("card=%p\n", card); return; } @@ -399,7 +399,7 @@ SW *glue (AUD_open_, TYPE) ( { AudioState *s = &glob_audio_state; - if (audio_bug (AUDIO_FUNC, !card || !name || !callback_fn || !as)) { + if (audio_bug(__func__, !card || !name || !callback_fn || !as)) { dolog ("card=%p name=%p callback_fn=%p as=%p\n", card, name, callback_fn, as); goto fail; @@ -408,12 +408,12 @@ SW *glue (AUD_open_, TYPE) ( ldebug ("open %s, freq %d, nchannels %d, fmt %d\n", name, as->freq, as->nchannels, as->fmt); - if (audio_bug (AUDIO_FUNC, audio_validate_settings (as))) { + if (audio_bug(__func__, audio_validate_settings(as))) { audio_print_settings (as); goto fail; } - if (audio_bug (AUDIO_FUNC, !s->drv)) { + if (audio_bug(__func__, !s->drv)) { dolog ("Can not open `%s' (no host audio driver)\n", name); goto fail; } diff --git a/audio/dsoundaudio.c b/audio/dsoundaudio.c index 516846eb80..bc39cb9b4d 100644 --- a/audio/dsoundaudio.c +++ b/audio/dsoundaudio.c @@ -543,7 +543,7 @@ static int dsound_run_out (HWVoiceOut *hw, int live) } } - if (audio_bug (AUDIO_FUNC, len < 0 || len > bufsize)) { + if (audio_bug(__func__, len < 0 || len > bufsize)) { dolog ("len=%d bufsize=%d old_pos=%ld ppos=%ld\n", len, bufsize, old_pos, ppos); return 0; diff --git a/audio/mixeng.c b/audio/mixeng.c index 0bf9b5360f..2ab22df2aa 100644 --- a/audio/mixeng.c +++ b/audio/mixeng.c @@ -344,7 +344,7 @@ struct rate { */ void *st_rate_start (int inrate, int outrate) { - struct rate *rate = audio_calloc (AUDIO_FUNC, 1, sizeof (*rate)); + struct rate *rate = audio_calloc(__func__, 1, sizeof(*rate)); if (!rate) { dolog ("Could not allocate resampler (%zu bytes)\n", sizeof (*rate)); diff --git a/audio/ossaudio.c b/audio/ossaudio.c index 0edd7ea5fe..a0428881c2 100644 --- a/audio/ossaudio.c +++ b/audio/ossaudio.c @@ -582,11 +582,9 @@ static int oss_init_out(HWVoiceOut *hw, struct audsettings *as, } if (!oss->mmapped) { - oss->pcm_buf = audio_calloc ( - AUDIO_FUNC, - hw->samples, - 1 << hw->info.shift - ); + oss->pcm_buf = audio_calloc(__func__, + hw->samples, + 1 << hw->info.shift); if (!oss->pcm_buf) { dolog ( "Could not allocate DAC buffer (%d samples, each %d bytes)\n", @@ -705,7 +703,7 @@ static int oss_init_in(HWVoiceIn *hw, struct audsettings *as, void *drv_opaque) } hw->samples = (obt.nfrags * obt.fragsize) >> hw->info.shift; - oss->pcm_buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift); + oss->pcm_buf = audio_calloc(__func__, hw->samples, 1 << hw->info.shift); if (!oss->pcm_buf) { dolog ("Could not allocate ADC buffer (%d samples, each %d bytes)\n", hw->samples, 1 << hw->info.shift); diff --git a/audio/paaudio.c b/audio/paaudio.c index 2a35e6f82c..aa0a7477d3 100644 --- a/audio/paaudio.c +++ b/audio/paaudio.c @@ -206,7 +206,7 @@ static void *qpa_thread_out (void *arg) PAVoiceOut *pa = arg; HWVoiceOut *hw = &pa->hw; - if (audio_pt_lock (&pa->pt, AUDIO_FUNC)) { + if (audio_pt_lock(&pa->pt, __func__)) { return NULL; } @@ -222,7 +222,7 @@ static void *qpa_thread_out (void *arg) break; } - if (audio_pt_wait (&pa->pt, AUDIO_FUNC)) { + if (audio_pt_wait(&pa->pt, __func__)) { goto exit; } } @@ -230,7 +230,7 @@ static void *qpa_thread_out (void *arg) decr = to_mix = audio_MIN (pa->live, pa->g->conf.samples >> 2); rpos = pa->rpos; - if (audio_pt_unlock (&pa->pt, AUDIO_FUNC)) { + if (audio_pt_unlock(&pa->pt, __func__)) { return NULL; } @@ -251,7 +251,7 @@ static void *qpa_thread_out (void *arg) to_mix -= chunk; } - if (audio_pt_lock (&pa->pt, AUDIO_FUNC)) { + if (audio_pt_lock(&pa->pt, __func__)) { return NULL; } @@ -261,7 +261,7 @@ static void *qpa_thread_out (void *arg) } exit: - audio_pt_unlock (&pa->pt, AUDIO_FUNC); + audio_pt_unlock(&pa->pt, __func__); return NULL; } @@ -270,7 +270,7 @@ static int qpa_run_out (HWVoiceOut *hw, int live) int decr; PAVoiceOut *pa = (PAVoiceOut *) hw; - if (audio_pt_lock (&pa->pt, AUDIO_FUNC)) { + if (audio_pt_lock(&pa->pt, __func__)) { return 0; } @@ -279,10 +279,10 @@ static int qpa_run_out (HWVoiceOut *hw, int live) pa->live = live - decr; hw->rpos = pa->rpos; if (pa->live > 0) { - audio_pt_unlock_and_signal (&pa->pt, AUDIO_FUNC); + audio_pt_unlock_and_signal(&pa->pt, __func__); } else { - audio_pt_unlock (&pa->pt, AUDIO_FUNC); + audio_pt_unlock(&pa->pt, __func__); } return decr; } @@ -298,7 +298,7 @@ static void *qpa_thread_in (void *arg) PAVoiceIn *pa = arg; HWVoiceIn *hw = &pa->hw; - if (audio_pt_lock (&pa->pt, AUDIO_FUNC)) { + if (audio_pt_lock(&pa->pt, __func__)) { return NULL; } @@ -314,7 +314,7 @@ static void *qpa_thread_in (void *arg) break; } - if (audio_pt_wait (&pa->pt, AUDIO_FUNC)) { + if (audio_pt_wait(&pa->pt, __func__)) { goto exit; } } @@ -322,7 +322,7 @@ static void *qpa_thread_in (void *arg) incr = to_grab = audio_MIN (pa->dead, pa->g->conf.samples >> 2); wpos = pa->wpos; - if (audio_pt_unlock (&pa->pt, AUDIO_FUNC)) { + if (audio_pt_unlock(&pa->pt, __func__)) { return NULL; } @@ -342,7 +342,7 @@ static void *qpa_thread_in (void *arg) to_grab -= chunk; } - if (audio_pt_lock (&pa->pt, AUDIO_FUNC)) { + if (audio_pt_lock(&pa->pt, __func__)) { return NULL; } @@ -352,7 +352,7 @@ static void *qpa_thread_in (void *arg) } exit: - audio_pt_unlock (&pa->pt, AUDIO_FUNC); + audio_pt_unlock(&pa->pt, __func__); return NULL; } @@ -361,7 +361,7 @@ static int qpa_run_in (HWVoiceIn *hw) int live, incr, dead; PAVoiceIn *pa = (PAVoiceIn *) hw; - if (audio_pt_lock (&pa->pt, AUDIO_FUNC)) { + if (audio_pt_lock(&pa->pt, __func__)) { return 0; } @@ -372,10 +372,10 @@ static int qpa_run_in (HWVoiceIn *hw) pa->dead = dead - incr; hw->wpos = pa->wpos; if (pa->dead > 0) { - audio_pt_unlock_and_signal (&pa->pt, AUDIO_FUNC); + audio_pt_unlock_and_signal(&pa->pt, __func__); } else { - audio_pt_unlock (&pa->pt, AUDIO_FUNC); + audio_pt_unlock(&pa->pt, __func__); } return incr; } @@ -579,7 +579,7 @@ static int qpa_init_out(HWVoiceOut *hw, struct audsettings *as, audio_pcm_init_info (&hw->info, &obt_as); hw->samples = g->conf.samples; - pa->pcm_buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift); + pa->pcm_buf = audio_calloc(__func__, hw->samples, 1 << hw->info.shift); pa->rpos = hw->rpos; if (!pa->pcm_buf) { dolog ("Could not allocate buffer (%d bytes)\n", @@ -587,7 +587,7 @@ static int qpa_init_out(HWVoiceOut *hw, struct audsettings *as, goto fail2; } - if (audio_pt_init (&pa->pt, qpa_thread_out, hw, AUDIO_CAP, AUDIO_FUNC)) { + if (audio_pt_init(&pa->pt, qpa_thread_out, hw, AUDIO_CAP, __func__)) { goto fail3; } @@ -636,7 +636,7 @@ static int qpa_init_in(HWVoiceIn *hw, struct audsettings *as, void *drv_opaque) audio_pcm_init_info (&hw->info, &obt_as); hw->samples = g->conf.samples; - pa->pcm_buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift); + pa->pcm_buf = audio_calloc(__func__, hw->samples, 1 << hw->info.shift); pa->wpos = hw->wpos; if (!pa->pcm_buf) { dolog ("Could not allocate buffer (%d bytes)\n", @@ -644,7 +644,7 @@ static int qpa_init_in(HWVoiceIn *hw, struct audsettings *as, void *drv_opaque) goto fail2; } - if (audio_pt_init (&pa->pt, qpa_thread_in, hw, AUDIO_CAP, AUDIO_FUNC)) { + if (audio_pt_init(&pa->pt, qpa_thread_in, hw, AUDIO_CAP, __func__)) { goto fail3; } @@ -667,17 +667,17 @@ static void qpa_fini_out (HWVoiceOut *hw) void *ret; PAVoiceOut *pa = (PAVoiceOut *) hw; - audio_pt_lock (&pa->pt, AUDIO_FUNC); + audio_pt_lock(&pa->pt, __func__); pa->done = 1; - audio_pt_unlock_and_signal (&pa->pt, AUDIO_FUNC); - audio_pt_join (&pa->pt, &ret, AUDIO_FUNC); + audio_pt_unlock_and_signal(&pa->pt, __func__); + audio_pt_join(&pa->pt, &ret, __func__); if (pa->stream) { pa_stream_unref (pa->stream); pa->stream = NULL; } - audio_pt_fini (&pa->pt, AUDIO_FUNC); + audio_pt_fini(&pa->pt, __func__); g_free (pa->pcm_buf); pa->pcm_buf = NULL; } @@ -687,17 +687,17 @@ static void qpa_fini_in (HWVoiceIn *hw) void *ret; PAVoiceIn *pa = (PAVoiceIn *) hw; - audio_pt_lock (&pa->pt, AUDIO_FUNC); + audio_pt_lock(&pa->pt, __func__); pa->done = 1; - audio_pt_unlock_and_signal (&pa->pt, AUDIO_FUNC); - audio_pt_join (&pa->pt, &ret, AUDIO_FUNC); + audio_pt_unlock_and_signal(&pa->pt, __func__); + audio_pt_join(&pa->pt, &ret, __func__); if (pa->stream) { pa_stream_unref (pa->stream); pa->stream = NULL; } - audio_pt_fini (&pa->pt, AUDIO_FUNC); + audio_pt_fini(&pa->pt, __func__); g_free (pa->pcm_buf); pa->pcm_buf = NULL; } diff --git a/audio/sdlaudio.c b/audio/sdlaudio.c index e8d91d22af..e92135bd2f 100644 --- a/audio/sdlaudio.c +++ b/audio/sdlaudio.c @@ -277,7 +277,7 @@ static void sdl_callback (void *opaque, Uint8 *buf, int len) return; } - if (audio_bug (AUDIO_FUNC, sdl->live < 0 || sdl->live > hw->samples)) { + if (audio_bug(__func__, sdl->live < 0 || sdl->live > hw->samples)) { dolog ("sdl->live=%d hw->samples=%d\n", sdl->live, hw->samples); return; diff --git a/audio/wavaudio.c b/audio/wavaudio.c index 341eec3121..068a595732 100644 --- a/audio/wavaudio.c +++ b/audio/wavaudio.c @@ -139,7 +139,7 @@ static int wav_init_out(HWVoiceOut *hw, struct audsettings *as, audio_pcm_init_info (&hw->info, &wav_as); hw->samples = 1024; - wav->pcm_buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift); + wav->pcm_buf = audio_calloc(__func__, hw->samples, 1 << hw->info.shift); if (!wav->pcm_buf) { dolog ("Could not allocate buffer (%d bytes)\n", hw->samples << hw->info.shift); diff --git a/backends/Makefile.objs b/backends/Makefile.objs index 0400799efd..67eeeba5fc 100644 --- a/backends/Makefile.objs +++ b/backends/Makefile.objs @@ -8,3 +8,5 @@ common-obj-$(CONFIG_LINUX) += hostmem-file.o common-obj-y += cryptodev.o common-obj-y += cryptodev-builtin.o + +common-obj-$(CONFIG_LINUX) += hostmem-memfd.o diff --git a/backends/hostmem-memfd.c b/backends/hostmem-memfd.c new file mode 100644 index 0000000000..1e20fe0ba8 --- /dev/null +++ b/backends/hostmem-memfd.c @@ -0,0 +1,170 @@ +/* + * QEMU host memfd memory backend + * + * Copyright (C) 2018 Red Hat Inc + * + * Authors: + * Marc-André Lureau <marcandre.lureau@redhat.com> + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ +#include "qemu/osdep.h" +#include "qemu-common.h" +#include "sysemu/hostmem.h" +#include "sysemu/sysemu.h" +#include "qom/object_interfaces.h" +#include "qemu/memfd.h" +#include "qapi/error.h" + +#define TYPE_MEMORY_BACKEND_MEMFD "memory-backend-memfd" + +#define MEMORY_BACKEND_MEMFD(obj) \ + OBJECT_CHECK(HostMemoryBackendMemfd, (obj), TYPE_MEMORY_BACKEND_MEMFD) + +typedef struct HostMemoryBackendMemfd HostMemoryBackendMemfd; + +struct HostMemoryBackendMemfd { + HostMemoryBackend parent_obj; + + bool hugetlb; + uint64_t hugetlbsize; + bool seal; +}; + +static void +memfd_backend_memory_alloc(HostMemoryBackend *backend, Error **errp) +{ + HostMemoryBackendMemfd *m = MEMORY_BACKEND_MEMFD(backend); + char *name; + int fd; + + if (!backend->size) { + error_setg(errp, "can't create backend with size 0"); + return; + } + + if (host_memory_backend_mr_inited(backend)) { + return; + } + + backend->force_prealloc = mem_prealloc; + fd = qemu_memfd_create(TYPE_MEMORY_BACKEND_MEMFD, backend->size, + m->hugetlb, m->hugetlbsize, m->seal ? + F_SEAL_GROW | F_SEAL_SHRINK | F_SEAL_SEAL : 0, + errp); + if (fd == -1) { + return; + } + + name = object_get_canonical_path(OBJECT(backend)); + memory_region_init_ram_from_fd(&backend->mr, OBJECT(backend), + name, backend->size, true, fd, errp); + g_free(name); +} + +static bool +memfd_backend_get_hugetlb(Object *o, Error **errp) +{ + return MEMORY_BACKEND_MEMFD(o)->hugetlb; +} + +static void +memfd_backend_set_hugetlb(Object *o, bool value, Error **errp) +{ + MEMORY_BACKEND_MEMFD(o)->hugetlb = value; +} + +static void +memfd_backend_set_hugetlbsize(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp) +{ + HostMemoryBackendMemfd *m = MEMORY_BACKEND_MEMFD(obj); + Error *local_err = NULL; + uint64_t value; + + if (host_memory_backend_mr_inited(MEMORY_BACKEND(obj))) { + error_setg(&local_err, "cannot change property value"); + goto out; + } + + visit_type_size(v, name, &value, &local_err); + if (local_err) { + goto out; + } + if (!value) { + error_setg(&local_err, "Property '%s.%s' doesn't take value '%" + PRIu64 "'", object_get_typename(obj), name, value); + goto out; + } + m->hugetlbsize = value; +out: + error_propagate(errp, local_err); +} + +static void +memfd_backend_get_hugetlbsize(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp) +{ + HostMemoryBackendMemfd *m = MEMORY_BACKEND_MEMFD(obj); + uint64_t value = m->hugetlbsize; + + visit_type_size(v, name, &value, errp); +} + +static bool +memfd_backend_get_seal(Object *o, Error **errp) +{ + return MEMORY_BACKEND_MEMFD(o)->seal; +} + +static void +memfd_backend_set_seal(Object *o, bool value, Error **errp) +{ + MEMORY_BACKEND_MEMFD(o)->seal = value; +} + +static void +memfd_backend_instance_init(Object *obj) +{ + HostMemoryBackendMemfd *m = MEMORY_BACKEND_MEMFD(obj); + + /* default to sealed file */ + m->seal = true; +} + +static void +memfd_backend_class_init(ObjectClass *oc, void *data) +{ + HostMemoryBackendClass *bc = MEMORY_BACKEND_CLASS(oc); + + bc->alloc = memfd_backend_memory_alloc; + + object_class_property_add_bool(oc, "hugetlb", + memfd_backend_get_hugetlb, + memfd_backend_set_hugetlb, + &error_abort); + object_class_property_add(oc, "hugetlbsize", "int", + memfd_backend_get_hugetlbsize, + memfd_backend_set_hugetlbsize, + NULL, NULL, &error_abort); + object_class_property_add_bool(oc, "seal", + memfd_backend_get_seal, + memfd_backend_set_seal, + &error_abort); +} + +static const TypeInfo memfd_backend_info = { + .name = TYPE_MEMORY_BACKEND_MEMFD, + .parent = TYPE_MEMORY_BACKEND, + .instance_init = memfd_backend_instance_init, + .class_init = memfd_backend_class_init, + .instance_size = sizeof(HostMemoryBackendMemfd), +}; + +static void register_types(void) +{ + type_register_static(&memfd_backend_info); +} + +type_init(register_types); diff --git a/chardev/char-pty.c b/chardev/char-pty.c index 89315e6807..68fd4e20c3 100644 --- a/chardev/char-pty.c +++ b/chardev/char-pty.c @@ -51,15 +51,32 @@ typedef struct { static void pty_chr_update_read_handler_locked(Chardev *chr); static void pty_chr_state(Chardev *chr, int connected); +static void pty_chr_timer_cancel(PtyChardev *s) +{ + if (s->timer_src) { + g_source_destroy(s->timer_src); + g_source_unref(s->timer_src); + s->timer_src = NULL; + } +} + +static void pty_chr_open_src_cancel(PtyChardev *s) +{ + if (s->open_source) { + g_source_destroy(s->open_source); + g_source_unref(s->open_source); + s->open_source = NULL; + } +} + static gboolean pty_chr_timer(gpointer opaque) { struct Chardev *chr = CHARDEV(opaque); PtyChardev *s = PTY_CHARDEV(opaque); qemu_mutex_lock(&chr->chr_write_lock); - s->timer_src = NULL; - g_source_unref(s->open_source); - s->open_source = NULL; + pty_chr_timer_cancel(s); + pty_chr_open_src_cancel(s); if (!s->connected) { /* Next poll ... */ pty_chr_update_read_handler_locked(chr); @@ -68,15 +85,6 @@ static gboolean pty_chr_timer(gpointer opaque) return FALSE; } -static void pty_chr_timer_cancel(PtyChardev *s) -{ - if (s->timer_src) { - g_source_destroy(s->timer_src); - g_source_unref(s->timer_src); - s->timer_src = NULL; - } -} - /* Called with chr_write_lock held. */ static void pty_chr_rearm_timer(Chardev *chr, int ms) { @@ -195,11 +203,7 @@ static void pty_chr_state(Chardev *chr, int connected) PtyChardev *s = PTY_CHARDEV(chr); if (!connected) { - if (s->open_source) { - g_source_destroy(s->open_source); - g_source_unref(s->open_source); - s->open_source = NULL; - } + pty_chr_open_src_cancel(s); remove_fd_in_watch(chr); s->connected = 0; /* (re-)connect poll interval for idle guests: once per second. diff --git a/chardev/char-socket.c b/chardev/char-socket.c index 77cdf487eb..a340af6cd3 100644 --- a/chardev/char-socket.c +++ b/chardev/char-socket.c @@ -42,6 +42,7 @@ typedef struct { QIOChannel *ioc; /* Client I/O channel */ QIOChannelSocket *sioc; /* Client master channel */ QIONetListener *listener; + GSource *hup_source; QCryptoTLSCreds *tls_creds; int connected; int max_size; @@ -352,6 +353,12 @@ static void tcp_chr_free_connection(Chardev *chr) s->read_msgfds_num = 0; } + if (s->hup_source != NULL) { + g_source_destroy(s->hup_source); + g_source_unref(s->hup_source); + s->hup_source = NULL; + } + tcp_set_msgfds(chr, NULL, 0); remove_fd_in_watch(chr); object_unref(OBJECT(s->sioc)); @@ -455,6 +462,15 @@ static gboolean tcp_chr_read(QIOChannel *chan, GIOCondition cond, void *opaque) return TRUE; } +static gboolean tcp_chr_hup(QIOChannel *channel, + GIOCondition cond, + void *opaque) +{ + Chardev *chr = CHARDEV(opaque); + tcp_chr_disconnect(chr); + return G_SOURCE_REMOVE; +} + static int tcp_chr_sync_read(Chardev *chr, const uint8_t *buf, int len) { SocketChardev *s = SOCKET_CHARDEV(chr); @@ -528,6 +544,12 @@ static void tcp_chr_connect(void *opaque) tcp_chr_read, chr, chr->gcontext); } + + s->hup_source = qio_channel_create_watch(s->ioc, G_IO_HUP); + g_source_set_callback(s->hup_source, (GSourceFunc)tcp_chr_hup, + chr, NULL); + g_source_attach(s->hup_source, chr->gcontext); + qemu_chr_be_event(chr, CHR_EVENT_OPENED); } @@ -222,6 +222,17 @@ supported_hvf_target() { return 1 } +supported_whpx_target() { + test "$whpx" = "yes" || return 1 + glob "$1" "*-softmmu" || return 1 + case "${1%-softmmu}" in + i386|x86_64) + return 0 + ;; + esac + return 1 +} + supported_target() { case "$1" in *-softmmu) @@ -248,6 +259,7 @@ supported_target() { supported_xen_target "$1" && return 0 supported_hax_target "$1" && return 0 supported_hvf_target "$1" && return 0 + supported_whpx_target "$1" && return 0 print_error "TCG disabled, but hardware accelerator not available for '$target'" return 1 } @@ -338,10 +350,12 @@ vhost_user="" kvm="no" hax="no" hvf="no" +whpx="no" rdma="" gprof="no" debug_tcg="no" debug="no" +sanitizers="no" fortify_source="" strip_opt="yes" tcg_interpreter="no" @@ -636,8 +650,6 @@ elif check_define _ARCH_PPC ; then fi elif check_define __mips__ ; then cpu="mips" -elif check_define __ia64__ ; then - cpu="ia64" elif check_define __s390__ ; then if check_define __s390x__ ; then cpu="s390x" @@ -995,6 +1007,10 @@ for opt do strip_opt="no" fortify_source="no" ;; + --enable-sanitizers) sanitizers="yes" + ;; + --disable-sanitizers) sanitizers="no" + ;; --enable-sparse) sparse="yes" ;; --disable-sparse) sparse="no" @@ -1055,6 +1071,10 @@ for opt do ;; --enable-hvf) hvf="yes" ;; + --disable-whpx) whpx="no" + ;; + --enable-whpx) whpx="yes" + ;; --disable-tcg-interpreter) tcg_interpreter="no" ;; --enable-tcg-interpreter) tcg_interpreter="yes" @@ -1476,6 +1496,7 @@ Advanced options (experts only): --firmwarepath=PATH search PATH for firmware files --with-confsuffix=SUFFIX suffix for QEMU data inside datadir/libdir/sysconfdir [$confsuffix] --enable-debug enable common debug build options + --enable-sanitizers enable default sanitizers --disable-strip disable stripping binaries --disable-werror disable compilation abort on warning --disable-stack-protector disable compiler-provided stack protection @@ -1553,6 +1574,7 @@ disabled with --disable-FEATURE, default is enabled if available: kvm KVM acceleration support hax HAX acceleration support hvf Hypervisor.framework acceleration support + whpx Windows Hypervisor Platform acceleration support rdma RDMA-based migration support vde support for vde network netmap support for netmap network @@ -2451,6 +2473,30 @@ if test "$xen_pv_domain_build" = "yes" && fi ########################################## +# Windows Hypervisor Platform accelerator (WHPX) check +if test "$whpx" != "no" ; then + cat > $TMPC << EOF +#include <windows.h> +#include <winhvplatform.h> +#include <winhvemulation.h> +int main(void) { + WHV_CAPABILITY whpx_cap; + WHvGetCapability(WHvCapabilityCodeFeatures, &whpx_cap, sizeof(whpx_cap)); + return 0; +} +EOF + if compile_prog "" "-lwinhvplatform -lwinhvemulation" ; then + libs_softmmu="$libs_softmmu -lwinhvplatform -lwinhvemulation" + whpx="yes" + else + if test "$whpx" = "yes"; then + feature_not_found "winhvplatform" "winhvemulation is not installed" + fi + whpx="no" + fi +fi + +########################################## # Sparse probe if test "$sparse" != "no" ; then if has cgcc; then @@ -4743,9 +4789,6 @@ if test "$coroutine_pool" = ""; then fi if test "$debug_stack_usage" = "yes"; then - if test "$cpu" = "ia64" -o "$cpu" = "hppa"; then - error_exit "stack usage debugging is not supported for $cpu" - fi if test "$coroutine_pool" = "yes"; then echo "WARN: disabling coroutine pool for stack usage debugging" coroutine_pool=no @@ -5205,9 +5248,45 @@ if compile_prog "" "" ; then fi ########################################## +# checks for sanitizers + +write_c_skeleton + +have_asan=no +have_ubsan=no +have_asan_iface_h=no +have_asan_iface_fiber=no + +if test "$sanitizers" = "yes" ; then + if compile_prog "$CPU_CFLAGS -Werror -fsanitize=address" ""; then + have_asan=yes + fi + if compile_prog "$CPU_CFLAGS -Werror -fsanitize=undefined" ""; then + have_ubsan=yes + fi + + if check_include "sanitizer/asan_interface.h" ; then + have_asan_iface_h=yes + fi + + cat > $TMPC << EOF +#include <sanitizer/asan_interface.h> +int main(void) { + __sanitizer_start_switch_fiber(0, 0, 0); + return 0; +} +EOF + if compile_prog "$CPU_CFLAGS -Werror -fsanitize=address" "" ; then + have_asan_iface_fiber=yes + fi +fi + +########################################## # End of CC checks # After here, no more $cc or $ld runs +write_c_skeleton + if test "$gcov" = "yes" ; then CFLAGS="-fprofile-arcs -ftest-coverage -g $CFLAGS" LDFLAGS="-fprofile-arcs -ftest-coverage $LDFLAGS" @@ -5228,6 +5307,20 @@ else CFLAGS="-O2 $CFLAGS" fi +if test "$have_asan" = "yes"; then + CFLAGS="-fsanitize=address $CFLAGS" + if test "$have_asan_iface_h" = "no" ; then + echo "ASAN build enabled, but ASAN header missing." \ + "Without code annotation, the report may be inferior." + elif test "$have_asan_iface_fiber" = "no" ; then + echo "ASAN build enabled, but ASAN header is too old." \ + "Without code annotation, the report may be inferior." + fi +fi +if test "$have_ubsan" = "yes"; then + CFLAGS="-fsanitize=undefined $CFLAGS" +fi + ########################################## # Do we have libnfs if test "$libnfs" != "no" ; then @@ -5596,6 +5689,7 @@ echo "Install blobs $blobs" echo "KVM support $kvm" echo "HAX support $hax" echo "HVF support $hvf" +echo "WHPX support $whpx" echo "TCG support $tcg" if test "$tcg" = "yes" ; then echo "TCG debug enabled $debug_tcg" @@ -5763,7 +5857,7 @@ if test "$mingw32" = "yes" ; then echo "CONFIG_QGA_NTDDDISK=y" >> $config_host_mak fi if test "$guest_agent_msi" = "yes"; then - echo "QEMU_GA_MSI_ENABLED=yes" >> $config_host_mak + echo "QEMU_GA_MSI_ENABLED=yes" >> $config_host_mak echo "QEMU_GA_MSI_MINGW_DLL_PATH=${QEMU_GA_MSI_MINGW_DLL_PATH}" >> $config_host_mak echo "QEMU_GA_MSI_WITH_VSS=${QEMU_GA_MSI_WITH_VSS}" >> $config_host_mak echo "QEMU_GA_MSI_ARCH=${QEMU_GA_MSI_ARCH}" >> $config_host_mak @@ -6211,6 +6305,10 @@ if test "$valgrind_h" = "yes" ; then echo "CONFIG_VALGRIND_H=y" >> $config_host_mak fi +if test "$have_asan_iface_fiber" = "yes" ; then + echo "CONFIG_ASAN_IFACE_FIBER=y" >> $config_host_mak +fi + if test "$has_environ" = "yes" ; then echo "CONFIG_HAS_ENVIRON=y" >> $config_host_mak fi @@ -6692,6 +6790,9 @@ fi if supported_hvf_target $target; then echo "CONFIG_HVF=y" >> $config_target_mak fi +if supported_whpx_target $target; then + echo "CONFIG_WHPX=y" >> $config_target_mak +fi if test "$target_bigendian" = "yes" ; then echo "TARGET_WORDS_BIGENDIAN=y" >> $config_target_mak fi @@ -38,6 +38,7 @@ #include "sysemu/kvm.h" #include "sysemu/hax.h" #include "sysemu/hvf.h" +#include "sysemu/whpx.h" #include "qmp-commands.h" #include "exec/exec-all.h" @@ -259,7 +260,7 @@ int64_t cpu_get_icount_raw(void) if (cpu && cpu->running) { if (!cpu->can_do_io) { - fprintf(stderr, "Bad icount read\n"); + error_report("Bad icount read"); exit(1); } /* Take into account what has run */ @@ -1181,7 +1182,7 @@ static void *qemu_kvm_cpu_thread_fn(void *arg) r = kvm_init_vcpu(cpu); if (r < 0) { - fprintf(stderr, "kvm_init_vcpu failed: %s\n", strerror(-r)); + error_report("kvm_init_vcpu failed: %s", strerror(-r)); exit(1); } @@ -1205,13 +1206,14 @@ static void *qemu_kvm_cpu_thread_fn(void *arg) cpu->created = false; qemu_cond_signal(&qemu_cpu_cond); qemu_mutex_unlock_iothread(); + rcu_unregister_thread(); return NULL; } static void *qemu_dummy_cpu_thread_fn(void *arg) { #ifdef _WIN32 - fprintf(stderr, "qtest is not supported under Windows\n"); + error_report("qtest is not supported under Windows"); exit(1); #else CPUState *cpu = arg; @@ -1233,7 +1235,7 @@ static void *qemu_dummy_cpu_thread_fn(void *arg) cpu->created = true; qemu_cond_signal(&qemu_cpu_cond); - while (1) { + do { qemu_mutex_unlock_iothread(); do { int sig; @@ -1245,8 +1247,9 @@ static void *qemu_dummy_cpu_thread_fn(void *arg) } qemu_mutex_lock_iothread(); qemu_wait_io_event(cpu); - } + } while (!cpu->unplug); + rcu_unregister_thread(); return NULL; #endif } @@ -1465,6 +1468,7 @@ static void *qemu_tcg_rr_cpu_thread_fn(void *arg) deal_with_unplugged_cpus(); } + rcu_unregister_thread(); return NULL; } @@ -1473,6 +1477,7 @@ static void *qemu_hax_cpu_thread_fn(void *arg) CPUState *cpu = arg; int r; + rcu_register_thread(); qemu_mutex_lock_iothread(); qemu_thread_get_self(cpu->thread); @@ -1484,7 +1489,7 @@ static void *qemu_hax_cpu_thread_fn(void *arg) hax_init_vcpu(cpu); qemu_cond_signal(&qemu_cpu_cond); - while (1) { + do { if (cpu_can_run(cpu)) { r = hax_smp_cpu_exec(cpu); if (r == EXCP_DEBUG) { @@ -1493,7 +1498,8 @@ static void *qemu_hax_cpu_thread_fn(void *arg) } qemu_wait_io_event(cpu); - } + } while (!cpu->unplug || cpu_can_run(cpu)); + rcu_unregister_thread(); return NULL; } @@ -1536,6 +1542,50 @@ static void *qemu_hvf_cpu_thread_fn(void *arg) cpu->created = false; qemu_cond_signal(&qemu_cpu_cond); qemu_mutex_unlock_iothread(); + rcu_unregister_thread(); + return NULL; +} + +static void *qemu_whpx_cpu_thread_fn(void *arg) +{ + CPUState *cpu = arg; + int r; + + rcu_register_thread(); + + qemu_mutex_lock_iothread(); + qemu_thread_get_self(cpu->thread); + cpu->thread_id = qemu_get_thread_id(); + current_cpu = cpu; + + r = whpx_init_vcpu(cpu); + if (r < 0) { + fprintf(stderr, "whpx_init_vcpu failed: %s\n", strerror(-r)); + exit(1); + } + + /* signal CPU creation */ + cpu->created = true; + qemu_cond_signal(&qemu_cpu_cond); + + do { + if (cpu_can_run(cpu)) { + r = whpx_vcpu_exec(cpu); + if (r == EXCP_DEBUG) { + cpu_handle_guest_debug(cpu); + } + } + while (cpu_thread_is_idle(cpu)) { + qemu_cond_wait(cpu->halt_cond, &qemu_global_mutex); + } + qemu_wait_io_event_common(cpu); + } while (!cpu->unplug || cpu_can_run(cpu)); + + whpx_destroy_vcpu(cpu); + cpu->created = false; + qemu_cond_signal(&qemu_cpu_cond); + qemu_mutex_unlock_iothread(); + rcu_unregister_thread(); return NULL; } @@ -1599,18 +1649,17 @@ static void *qemu_tcg_cpu_thread_fn(void *arg) /* Ignore everything else? */ break; } - } else if (cpu->unplug) { - qemu_tcg_destroy_vcpu(cpu); - cpu->created = false; - qemu_cond_signal(&qemu_cpu_cond); - qemu_mutex_unlock_iothread(); - return NULL; } atomic_mb_set(&cpu->exit_request, 0); qemu_wait_io_event(cpu); - } + } while (!cpu->unplug || cpu_can_run(cpu)); + qemu_tcg_destroy_vcpu(cpu); + cpu->created = false; + qemu_cond_signal(&qemu_cpu_cond); + qemu_mutex_unlock_iothread(); + rcu_unregister_thread(); return NULL; } @@ -1630,7 +1679,9 @@ static void qemu_cpu_kick_thread(CPUState *cpu) } #else /* _WIN32 */ if (!qemu_cpu_is_self(cpu)) { - if (!QueueUserAPC(dummy_apc_func, cpu->hThread, 0)) { + if (whpx_enabled()) { + whpx_vcpu_kick(cpu); + } else if (!QueueUserAPC(dummy_apc_func, cpu->hThread, 0)) { fprintf(stderr, "%s: QueueUserAPC failed with error %lu\n", __func__, GetLastError()); exit(1); @@ -1747,19 +1798,14 @@ void resume_all_vcpus(void) } } -void cpu_remove(CPUState *cpu) +void cpu_remove_sync(CPUState *cpu) { cpu->stop = true; cpu->unplug = true; qemu_cpu_kick(cpu); -} - -void cpu_remove_sync(CPUState *cpu) -{ - cpu_remove(cpu); - while (cpu->created) { - qemu_cond_wait(&qemu_cpu_cond, &qemu_global_mutex); - } + qemu_mutex_unlock_iothread(); + qemu_thread_join(cpu->thread); + qemu_mutex_lock_iothread(); } /* For temporary buffers for forming a name */ @@ -1877,6 +1923,25 @@ static void qemu_hvf_start_vcpu(CPUState *cpu) } } +static void qemu_whpx_start_vcpu(CPUState *cpu) +{ + char thread_name[VCPU_THREAD_NAME_SIZE]; + + cpu->thread = g_malloc0(sizeof(QemuThread)); + cpu->halt_cond = g_malloc0(sizeof(QemuCond)); + qemu_cond_init(cpu->halt_cond); + snprintf(thread_name, VCPU_THREAD_NAME_SIZE, "CPU %d/WHPX", + cpu->cpu_index); + qemu_thread_create(cpu->thread, thread_name, qemu_whpx_cpu_thread_fn, + cpu, QEMU_THREAD_JOINABLE); +#ifdef _WIN32 + cpu->hThread = qemu_thread_get_handle(cpu->thread); +#endif + while (!cpu->created) { + qemu_cond_wait(&qemu_cpu_cond, &qemu_global_mutex); + } +} + static void qemu_dummy_start_vcpu(CPUState *cpu) { char thread_name[VCPU_THREAD_NAME_SIZE]; @@ -1915,6 +1980,8 @@ void qemu_init_vcpu(CPUState *cpu) qemu_hvf_start_vcpu(cpu); } else if (tcg_enabled()) { qemu_tcg_init_vcpu(cpu); + } else if (whpx_enabled()) { + qemu_whpx_start_vcpu(cpu); } else { qemu_dummy_start_vcpu(cpu); } diff --git a/default-configs/arm-softmmu.mak b/default-configs/arm-softmmu.mak index b0d6e65038..ca34cf4462 100644 --- a/default-configs/arm-softmmu.mak +++ b/default-configs/arm-softmmu.mak @@ -67,6 +67,7 @@ CONFIG_CADENCE=y CONFIG_XGMAC=y CONFIG_EXYNOS4=y CONFIG_PXA2XX=y +CONFIG_I2C=y CONFIG_BITBANG_I2C=y CONFIG_FRAMEBUFFER=y CONFIG_XILINX_SPIPS=y diff --git a/default-configs/i386-softmmu.mak b/default-configs/i386-softmmu.mak index ac27700e79..3326e3e0bb 100644 --- a/default-configs/i386-softmmu.mak +++ b/default-configs/i386-softmmu.mak @@ -62,3 +62,4 @@ CONFIG_HYPERV_TESTDEV=$(CONFIG_KVM) CONFIG_PXB=y CONFIG_ACPI_VMGENID=y CONFIG_FW_CFG_DMA=y +CONFIG_I2C=y diff --git a/default-configs/mips-softmmu-common.mak b/default-configs/mips-softmmu-common.mak index 7d8f5db983..e31f046b3b 100644 --- a/default-configs/mips-softmmu-common.mak +++ b/default-configs/mips-softmmu-common.mak @@ -34,3 +34,4 @@ CONFIG_ISA_TESTDEV=y CONFIG_EMPTY_SLOT=y CONFIG_MIPS_CPS=y CONFIG_MIPS_ITU=y +CONFIG_I2C=y diff --git a/default-configs/ppc-softmmu.mak b/default-configs/ppc-softmmu.mak index 3baed6a8fd..65680d85bc 100644 --- a/default-configs/ppc-softmmu.mak +++ b/default-configs/ppc-softmmu.mak @@ -23,6 +23,7 @@ CONFIG_PLATFORM_BUS=y CONFIG_ETSEC=y CONFIG_SM501=y CONFIG_IDE_SII3112=y +CONFIG_I2C=y # For Macs CONFIG_MAC=y diff --git a/default-configs/ppcemb-softmmu.mak b/default-configs/ppcemb-softmmu.mak index 5db4618a5a..bc5e1b3ffe 100644 --- a/default-configs/ppcemb-softmmu.mak +++ b/default-configs/ppcemb-softmmu.mak @@ -17,3 +17,4 @@ CONFIG_XILINX=y CONFIG_XILINX_ETHLITE=y CONFIG_SM501=y CONFIG_IDE_SII3112=y +CONFIG_I2C=y diff --git a/default-configs/x86_64-softmmu.mak b/default-configs/x86_64-softmmu.mak index b2104ade19..1c6cda1d9a 100644 --- a/default-configs/x86_64-softmmu.mak +++ b/default-configs/x86_64-softmmu.mak @@ -62,3 +62,4 @@ CONFIG_HYPERV_TESTDEV=$(CONFIG_KVM) CONFIG_PXB=y CONFIG_ACPI_VMGENID=y CONFIG_FW_CFG_DMA=y +CONFIG_I2C=y @@ -2216,9 +2216,9 @@ void qemu_ram_remap(ram_addr_t addr, ram_addr_t length) flags, -1, 0); } if (area != vaddr) { - fprintf(stderr, "Could not remap addr: " - RAM_ADDR_FMT "@" RAM_ADDR_FMT "\n", - length, addr); + error_report("Could not remap addr: " + RAM_ADDR_FMT "@" RAM_ADDR_FMT "", + length, addr); exit(1); } memory_try_enable_merging(vaddr, length); diff --git a/hw/arm/armv7m.c b/hw/arm/armv7m.c index bb2dfc942b..56770a7048 100644 --- a/hw/arm/armv7m.c +++ b/hw/arm/armv7m.c @@ -278,7 +278,7 @@ void armv7m_load_kernel(ARMCPU *cpu, const char *kernel_filename, int mem_size) #endif if (!kernel_filename && !qtest_enabled()) { - fprintf(stderr, "Guest image must be specified (using -kernel)\n"); + error_report("Guest image must be specified (using -kernel)"); exit(1); } diff --git a/hw/arm/boot.c b/hw/arm/boot.c index c2720c8046..bb244ec359 100644 --- a/hw/arm/boot.c +++ b/hw/arm/boot.c @@ -8,6 +8,7 @@ */ #include "qemu/osdep.h" +#include "qemu/error-report.h" #include "qapi/error.h" #include <libfdt.h> #include "hw/hw.h" @@ -690,7 +691,7 @@ static void load_image_to_fw_cfg(FWCfgState *fw_cfg, uint16_t size_key, gsize length; if (!g_file_get_contents(image_name, &contents, &length, NULL)) { - fprintf(stderr, "failed to load \"%s\"\n", image_name); + error_report("failed to load \"%s\"", image_name); exit(1); } size = length; @@ -956,8 +957,7 @@ static void arm_load_kernel_notify(Notifier *notifier, void *data) is_linux = 1; } if (kernel_size < 0) { - fprintf(stderr, "qemu: could not load kernel '%s'\n", - info->kernel_filename); + error_report("could not load kernel '%s'", info->kernel_filename); exit(1); } info->entry = entry; @@ -976,8 +976,8 @@ static void arm_load_kernel_notify(Notifier *notifier, void *data) info->initrd_start); } if (initrd_size < 0) { - fprintf(stderr, "qemu: could not load initrd '%s'\n", - info->initrd_filename); + error_report("could not load initrd '%s'", + info->initrd_filename); exit(1); } } else { @@ -1021,9 +1021,9 @@ static void arm_load_kernel_notify(Notifier *notifier, void *data) } else { fixupcontext[FIXUP_ARGPTR] = info->loader_start + KERNEL_ARGS_ADDR; if (info->ram_size >= (1ULL << 32)) { - fprintf(stderr, "qemu: RAM size must be less than 4GB to boot" - " Linux kernel using ATAGS (try passing a device tree" - " using -dtb)\n"); + error_report("RAM size must be less than 4GB to boot" + " Linux kernel using ATAGS (try passing a device tree" + " using -dtb)"); exit(1); } } diff --git a/hw/arm/gumstix.c b/hw/arm/gumstix.c index bba9e9f57a..ea2a3c532d 100644 --- a/hw/arm/gumstix.c +++ b/hw/arm/gumstix.c @@ -35,6 +35,7 @@ */ #include "qemu/osdep.h" +#include "qemu/error-report.h" #include "hw/hw.h" #include "hw/arm/pxa.h" #include "net/net.h" @@ -62,8 +63,8 @@ static void connex_init(MachineState *machine) dinfo = drive_get(IF_PFLASH, 0, 0); if (!dinfo && !qtest_enabled()) { - fprintf(stderr, "A flash image must be given with the " - "'pflash' parameter\n"); + error_report("A flash image must be given with the " + "'pflash' parameter"); exit(1); } @@ -76,7 +77,7 @@ static void connex_init(MachineState *machine) dinfo ? blk_by_legacy_dinfo(dinfo) : NULL, sector_len, connex_rom / sector_len, 2, 0, 0, 0, 0, be)) { - fprintf(stderr, "qemu: Error registering flash memory.\n"); + error_report("Error registering flash memory"); exit(1); } @@ -99,8 +100,8 @@ static void verdex_init(MachineState *machine) dinfo = drive_get(IF_PFLASH, 0, 0); if (!dinfo && !qtest_enabled()) { - fprintf(stderr, "A flash image must be given with the " - "'pflash' parameter\n"); + error_report("A flash image must be given with the " + "'pflash' parameter"); exit(1); } @@ -113,7 +114,7 @@ static void verdex_init(MachineState *machine) dinfo ? blk_by_legacy_dinfo(dinfo) : NULL, sector_len, verdex_rom / sector_len, 2, 0, 0, 0, 0, be)) { - fprintf(stderr, "qemu: Error registering flash memory.\n"); + error_report("Error registering flash memory"); exit(1); } diff --git a/hw/arm/mainstone.c b/hw/arm/mainstone.c index d07972a966..4215c025fc 100644 --- a/hw/arm/mainstone.c +++ b/hw/arm/mainstone.c @@ -12,6 +12,7 @@ * GNU GPL, version 2 or (at your option) any later version. */ #include "qemu/osdep.h" +#include "qemu/error-report.h" #include "qapi/error.h" #include "hw/hw.h" #include "hw/arm/pxa.h" @@ -143,8 +144,8 @@ static void mainstone_common_init(MemoryRegion *address_space_mem, if (qtest_enabled()) { break; } - fprintf(stderr, "Two flash images must be given with the " - "'pflash' parameter\n"); + error_report("Two flash images must be given with the " + "'pflash' parameter"); exit(1); } @@ -154,7 +155,7 @@ static void mainstone_common_init(MemoryRegion *address_space_mem, blk_by_legacy_dinfo(dinfo), sector_len, MAINSTONE_FLASH / sector_len, 4, 0, 0, 0, 0, be)) { - fprintf(stderr, "qemu: Error registering flash memory.\n"); + error_report("Error registering flash memory"); exit(1); } } diff --git a/hw/arm/musicpal.c b/hw/arm/musicpal.c index 4172caf5db..38d7322a19 100644 --- a/hw/arm/musicpal.c +++ b/hw/arm/musicpal.c @@ -1627,7 +1627,7 @@ static void musicpal_init(MachineState *machine) flash_size = blk_getlength(blk); if (flash_size != 8*1024*1024 && flash_size != 16*1024*1024 && flash_size != 32*1024*1024) { - fprintf(stderr, "Invalid flash image size\n"); + error_report("Invalid flash image size"); exit(1); } diff --git a/hw/arm/omap1.c b/hw/arm/omap1.c index 92e58f09c8..b3a23a83d1 100644 --- a/hw/arm/omap1.c +++ b/hw/arm/omap1.c @@ -18,6 +18,7 @@ */ #include "qemu/osdep.h" +#include "qemu/error-report.h" #include "qapi/error.h" #include "qemu-common.h" #include "cpu.h" @@ -2313,7 +2314,7 @@ void omap_uwire_attach(struct omap_uwire_s *s, uWireSlave *slave, int chipselect) { if (chipselect < 0 || chipselect > 3) { - fprintf(stderr, "%s: Bad chipselect %i\n", __func__, chipselect); + error_report("%s: Bad chipselect %i", __func__, chipselect); exit(-1); } @@ -3987,7 +3988,7 @@ struct omap_mpu_state_s *omap310_mpu_init(MemoryRegion *system_memory, dinfo = drive_get(IF_SD, 0, 0); if (!dinfo) { - fprintf(stderr, "qemu: missing SecureDigital device\n"); + error_report("missing SecureDigital device"); exit(1); } s->mmc = omap_mmc_init(0xfffb7800, system_memory, diff --git a/hw/arm/omap2.c b/hw/arm/omap2.c index b53878b8b9..647b119ba9 100644 --- a/hw/arm/omap2.c +++ b/hw/arm/omap2.c @@ -19,6 +19,7 @@ */ #include "qemu/osdep.h" +#include "qemu/error-report.h" #include "qapi/error.h" #include "qemu-common.h" #include "cpu.h" @@ -2486,7 +2487,7 @@ struct omap_mpu_state_s *omap2420_mpu_init(MemoryRegion *sysmem, dinfo = drive_get(IF_SD, 0, 0); if (!dinfo) { - fprintf(stderr, "qemu: missing SecureDigital device\n"); + error_report("missing SecureDigital device"); exit(1); } s->mmc = omap2_mmc_init(omap_l4tao(s->l4, 9), diff --git a/hw/arm/omap_sx1.c b/hw/arm/omap_sx1.c index 9a14270795..eccc19c77b 100644 --- a/hw/arm/omap_sx1.c +++ b/hw/arm/omap_sx1.c @@ -194,7 +194,7 @@ static void sx1_init(MachineState *machine, const int version) } if (!machine->kernel_filename && !fl_idx && !qtest_enabled()) { - fprintf(stderr, "Kernel or Flash image must be specified\n"); + error_report("Kernel or Flash image must be specified"); exit(1); } diff --git a/hw/arm/pxa2xx.c b/hw/arm/pxa2xx.c index db860c238e..5805a2c858 100644 --- a/hw/arm/pxa2xx.c +++ b/hw/arm/pxa2xx.c @@ -8,6 +8,7 @@ */ #include "qemu/osdep.h" +#include "qemu/error-report.h" #include "qapi/error.h" #include "qemu-common.h" #include "cpu.h" @@ -2062,7 +2063,7 @@ PXA2xxState *pxa270_init(MemoryRegion *address_space, s = g_new0(PXA2xxState, 1); if (strncmp(cpu_type, "pxa27", 5)) { - fprintf(stderr, "Machine requires a PXA27x processor.\n"); + error_report("Machine requires a PXA27x processor"); exit(1); } @@ -2095,7 +2096,7 @@ PXA2xxState *pxa270_init(MemoryRegion *address_space, dinfo = drive_get(IF_SD, 0, 0); if (!dinfo) { - fprintf(stderr, "qemu: missing SecureDigital device\n"); + error_report("missing SecureDigital device"); exit(1); } s->mmc = pxa2xx_mmci_init(address_space, 0x41100000, @@ -2220,7 +2221,7 @@ PXA2xxState *pxa255_init(MemoryRegion *address_space, unsigned int sdram_size) dinfo = drive_get(IF_SD, 0, 0); if (!dinfo) { - fprintf(stderr, "qemu: missing SecureDigital device\n"); + error_report("missing SecureDigital device"); exit(1); } s->mmc = pxa2xx_mmci_init(address_space, 0x41100000, diff --git a/hw/arm/vexpress.c b/hw/arm/vexpress.c index efb5a29475..dc5928ae1a 100644 --- a/hw/arm/vexpress.c +++ b/hw/arm/vexpress.c @@ -266,7 +266,7 @@ static void a9_daughterboard_init(const VexpressMachineState *vms, if (ram_size > 0x40000000) { /* 1GB is the maximum the address space permits */ - fprintf(stderr, "vexpress-a9: cannot model more than 1GB RAM\n"); + error_report("vexpress-a9: cannot model more than 1GB RAM"); exit(1); } @@ -355,7 +355,7 @@ static void a15_daughterboard_init(const VexpressMachineState *vms, */ uint64_t rsz = ram_size; if (rsz > (30ULL * 1024 * 1024 * 1024)) { - fprintf(stderr, "vexpress-a15: cannot model more than 30GB RAM\n"); + error_report("vexpress-a15: cannot model more than 30GB RAM"); exit(1); } } @@ -640,7 +640,7 @@ static void vexpress_common_init(MachineState *machine) pflash0 = ve_pflash_cfi01_register(map[VE_NORFLASH0], "vexpress.flash0", dinfo); if (!pflash0) { - fprintf(stderr, "vexpress: error registering flash 0.\n"); + error_report("vexpress: error registering flash 0"); exit(1); } @@ -655,7 +655,7 @@ static void vexpress_common_init(MachineState *machine) dinfo = drive_get_next(IF_PFLASH); if (!ve_pflash_cfi01_register(map[VE_NORFLASH1], "vexpress.flash1", dinfo)) { - fprintf(stderr, "vexpress: error registering flash 1.\n"); + error_report("vexpress: error registering flash 1"); exit(1); } diff --git a/hw/arm/z2.c b/hw/arm/z2.c index 300e933c82..730a5392e9 100644 --- a/hw/arm/z2.c +++ b/hw/arm/z2.c @@ -320,8 +320,8 @@ static void z2_init(MachineState *machine) #endif dinfo = drive_get(IF_PFLASH, 0, 0); if (!dinfo && !qtest_enabled()) { - fprintf(stderr, "Flash image must be given with the " - "'pflash' parameter\n"); + error_report("Flash image must be given with the " + "'pflash' parameter"); exit(1); } @@ -330,7 +330,7 @@ static void z2_init(MachineState *machine) dinfo ? blk_by_legacy_dinfo(dinfo) : NULL, sector_len, Z2_FLASH_SIZE / sector_len, 4, 0, 0, 0, 0, be)) { - fprintf(stderr, "qemu: Error registering flash memory.\n"); + error_report("Error registering flash memory"); exit(1); } diff --git a/hw/core/qdev-properties.c b/hw/core/qdev-properties.c index 24c17800e3..5bbc2d98b5 100644 --- a/hw/core/qdev-properties.c +++ b/hw/core/qdev-properties.c @@ -1317,3 +1317,14 @@ const PropertyInfo qdev_prop_link = { .name = "link", .create = create_link_property, }; + +/* --- OffAutoPCIBAR off/auto/bar0/bar1/bar2/bar3/bar4/bar5 --- */ + +const PropertyInfo qdev_prop_off_auto_pcibar = { + .name = "OffAutoPCIBAR", + .description = "off/auto/bar0/bar1/bar2/bar3/bar4/bar5", + .enum_table = &OffAutoPCIBAR_lookup, + .get = get_enum, + .set = set_enum, + .set_default_value = set_default_value_enum, +}; diff --git a/hw/core/qdev.c b/hw/core/qdev.c index 2456035d1a..11f8a27a69 100644 --- a/hw/core/qdev.c +++ b/hw/core/qdev.c @@ -1075,6 +1075,30 @@ static void device_class_init(ObjectClass *class, void *data) dc->user_creatable = true; } +void device_class_set_parent_reset(DeviceClass *dc, + DeviceReset dev_reset, + DeviceReset *parent_reset) +{ + *parent_reset = dc->reset; + dc->reset = dev_reset; +} + +void device_class_set_parent_realize(DeviceClass *dc, + DeviceRealize dev_realize, + DeviceRealize *parent_realize) +{ + *parent_realize = dc->realize; + dc->realize = dev_realize; +} + +void device_class_set_parent_unrealize(DeviceClass *dc, + DeviceUnrealize dev_unrealize, + DeviceUnrealize *parent_unrealize) +{ + *parent_unrealize = dc->unrealize; + dc->unrealize = dev_unrealize; +} + void device_reset(DeviceState *dev) { DeviceClass *klass = DEVICE_GET_CLASS(dev); diff --git a/hw/display/exynos4210_fimd.c b/hw/display/exynos4210_fimd.c index fd0b2bec65..86e37e93e9 100644 --- a/hw/display/exynos4210_fimd.c +++ b/hw/display/exynos4210_fimd.c @@ -98,7 +98,7 @@ #define FIMD_WINCON_BUFSTATUS ((1 << 21) | (1 << 31)) #define FIMD_WINCON_BUF0_STAT ((0 << 21) | (0 << 31)) #define FIMD_WINCON_BUF1_STAT ((1 << 21) | (0 << 31)) -#define FIMD_WINCON_BUF2_STAT ((0 << 21) | (1 << 31)) +#define FIMD_WINCON_BUF2_STAT ((0 << 21) | (1U << 31)) #define FIMD_WINCON_BUFSELECT ((1 << 20) | (1 << 30)) #define FIMD_WINCON_BUF0_SEL ((0 << 20) | (0 << 30)) #define FIMD_WINCON_BUF1_SEL ((1 << 20) | (0 << 30)) diff --git a/hw/dma/soc_dma.c b/hw/dma/soc_dma.c index 9bb499bf9c..45516241c6 100644 --- a/hw/dma/soc_dma.c +++ b/hw/dma/soc_dma.c @@ -18,6 +18,7 @@ * with this program; if not, see <http://www.gnu.org/licenses/>. */ #include "qemu/osdep.h" +#include "qemu/error-report.h" #include "qemu-common.h" #include "qemu/timer.h" #include "hw/arm/soc_dma.h" @@ -270,11 +271,11 @@ void soc_dma_port_add_fifo(struct soc_dma_s *soc, hwaddr virt_base, if (entry->type == soc_dma_port_mem) { if (entry->addr <= virt_base && entry->addr + entry->u.mem.size > virt_base) { - fprintf(stderr, "%s: FIFO at %"PRIx64 - " collides with RAM region at %"PRIx64 - "-%"PRIx64 "\n", __func__, - virt_base, entry->addr, - (entry->addr + entry->u.mem.size)); + error_report("%s: FIFO at %"PRIx64 + " collides with RAM region at %"PRIx64 + "-%"PRIx64, __func__, + virt_base, entry->addr, + (entry->addr + entry->u.mem.size)); exit(-1); } @@ -284,9 +285,9 @@ void soc_dma_port_add_fifo(struct soc_dma_s *soc, hwaddr virt_base, while (entry < dma->memmap + dma->memmap_size && entry->addr <= virt_base) { if (entry->addr == virt_base && entry->u.fifo.out == out) { - fprintf(stderr, "%s: FIFO at %"PRIx64 - " collides FIFO at %"PRIx64 "\n", - __func__, virt_base, entry->addr); + error_report("%s: FIFO at %"PRIx64 + " collides FIFO at %"PRIx64, + __func__, virt_base, entry->addr); exit(-1); } @@ -321,11 +322,11 @@ void soc_dma_port_add_mem(struct soc_dma_s *soc, uint8_t *phys_base, if ((entry->addr >= virt_base && entry->addr < virt_base + size) || (entry->addr <= virt_base && entry->addr + entry->u.mem.size > virt_base)) { - fprintf(stderr, "%s: RAM at %"PRIx64 "-%"PRIx64 - " collides with RAM region at %"PRIx64 - "-%"PRIx64 "\n", __func__, - virt_base, virt_base + size, - entry->addr, entry->addr + entry->u.mem.size); + error_report("%s: RAM at %"PRIx64 "-%"PRIx64 + " collides with RAM region at %"PRIx64 + "-%"PRIx64, __func__, + virt_base, virt_base + size, + entry->addr, entry->addr + entry->u.mem.size); exit(-1); } @@ -334,11 +335,10 @@ void soc_dma_port_add_mem(struct soc_dma_s *soc, uint8_t *phys_base, } else { if (entry->addr >= virt_base && entry->addr < virt_base + size) { - fprintf(stderr, "%s: RAM at %"PRIx64 "-%"PRIx64 - " collides with FIFO at %"PRIx64 - "\n", __func__, - virt_base, virt_base + size, - entry->addr); + error_report("%s: RAM at %"PRIx64 "-%"PRIx64 + " collides with FIFO at %"PRIx64, + __func__, virt_base, virt_base + size, + entry->addr); exit(-1); } diff --git a/hw/i2c/Makefile.objs b/hw/i2c/Makefile.objs index 0594dea3ae..37cacde978 100644 --- a/hw/i2c/Makefile.objs +++ b/hw/i2c/Makefile.objs @@ -1,4 +1,4 @@ -common-obj-y += core.o smbus.o smbus_eeprom.o +common-obj-$(CONFIG_I2C) += core.o smbus.o smbus_eeprom.o common-obj-$(CONFIG_DDC) += i2c-ddc.o common-obj-$(CONFIG_VERSATILE_I2C) += versatile_i2c.o common-obj-$(CONFIG_ACPI_X86) += smbus_ich9.o diff --git a/hw/i386/kvm/i8254.c b/hw/i386/kvm/i8254.c index 521a58498a..13f20f47d9 100644 --- a/hw/i386/kvm/i8254.c +++ b/hw/i386/kvm/i8254.c @@ -315,8 +315,8 @@ static void kvm_pit_class_init(ObjectClass *klass, void *data) PITCommonClass *k = PIT_COMMON_CLASS(klass); DeviceClass *dc = DEVICE_CLASS(klass); - kpc->parent_realize = dc->realize; - dc->realize = kvm_pit_realizefn; + device_class_set_parent_realize(dc, kvm_pit_realizefn, + &kpc->parent_realize); k->set_channel_gate = kvm_pit_set_gate; k->get_channel_info = kvm_pit_get_channel_info; dc->reset = kvm_pit_reset; diff --git a/hw/i386/kvm/i8259.c b/hw/i386/kvm/i8259.c index b91e98074e..05394cdb7b 100644 --- a/hw/i386/kvm/i8259.c +++ b/hw/i386/kvm/i8259.c @@ -142,8 +142,7 @@ static void kvm_i8259_class_init(ObjectClass *klass, void *data) DeviceClass *dc = DEVICE_CLASS(klass); dc->reset = kvm_pic_reset; - kpc->parent_realize = dc->realize; - dc->realize = kvm_pic_realize; + device_class_set_parent_realize(dc, kvm_pic_realize, &kpc->parent_realize); k->pre_save = kvm_pic_get; k->post_load = kvm_pic_put; } diff --git a/hw/input/adb-kbd.c b/hw/input/adb-kbd.c index 354f56e41e..266aed1b7b 100644 --- a/hw/input/adb-kbd.c +++ b/hw/input/adb-kbd.c @@ -374,8 +374,8 @@ static void adb_kbd_class_init(ObjectClass *oc, void *data) ADBDeviceClass *adc = ADB_DEVICE_CLASS(oc); ADBKeyboardClass *akc = ADB_KEYBOARD_CLASS(oc); - akc->parent_realize = dc->realize; - dc->realize = adb_kbd_realizefn; + device_class_set_parent_realize(dc, adb_kbd_realizefn, + &akc->parent_realize); set_bit(DEVICE_CATEGORY_INPUT, dc->categories); adc->devreq = adb_kbd_request; diff --git a/hw/input/adb-mouse.c b/hw/input/adb-mouse.c index c9004233b8..47e88faf25 100644 --- a/hw/input/adb-mouse.c +++ b/hw/input/adb-mouse.c @@ -228,8 +228,8 @@ static void adb_mouse_class_init(ObjectClass *oc, void *data) ADBDeviceClass *adc = ADB_DEVICE_CLASS(oc); ADBMouseClass *amc = ADB_MOUSE_CLASS(oc); - amc->parent_realize = dc->realize; - dc->realize = adb_mouse_realizefn; + device_class_set_parent_realize(dc, adb_mouse_realizefn, + &amc->parent_realize); set_bit(DEVICE_CATEGORY_INPUT, dc->categories); adc->devreq = adb_mouse_request; diff --git a/hw/intc/arm_gic.c b/hw/intc/arm_gic.c index 724bc9fa61..ea0323f969 100644 --- a/hw/intc/arm_gic.c +++ b/hw/intc/arm_gic.c @@ -1461,8 +1461,7 @@ static void arm_gic_class_init(ObjectClass *klass, void *data) DeviceClass *dc = DEVICE_CLASS(klass); ARMGICClass *agc = ARM_GIC_CLASS(klass); - agc->parent_realize = dc->realize; - dc->realize = arm_gic_realize; + device_class_set_parent_realize(dc, arm_gic_realize, &agc->parent_realize); } static const TypeInfo arm_gic_info = { diff --git a/hw/intc/arm_gic_kvm.c b/hw/intc/arm_gic_kvm.c index ae095d08a3..6f467e68a8 100644 --- a/hw/intc/arm_gic_kvm.c +++ b/hw/intc/arm_gic_kvm.c @@ -591,10 +591,9 @@ static void kvm_arm_gic_class_init(ObjectClass *klass, void *data) agcc->pre_save = kvm_arm_gic_get; agcc->post_load = kvm_arm_gic_put; - kgc->parent_realize = dc->realize; - kgc->parent_reset = dc->reset; - dc->realize = kvm_arm_gic_realize; - dc->reset = kvm_arm_gic_reset; + device_class_set_parent_realize(dc, kvm_arm_gic_realize, + &kgc->parent_realize); + device_class_set_parent_reset(dc, kvm_arm_gic_reset, &kgc->parent_reset); } static const TypeInfo kvm_arm_gic_info = { diff --git a/hw/intc/arm_gicv3.c b/hw/intc/arm_gicv3.c index f0c967b304..479c66733c 100644 --- a/hw/intc/arm_gicv3.c +++ b/hw/intc/arm_gicv3.c @@ -385,8 +385,7 @@ static void arm_gicv3_class_init(ObjectClass *klass, void *data) ARMGICv3Class *agc = ARM_GICV3_CLASS(klass); agcc->post_load = arm_gicv3_post_load; - agc->parent_realize = dc->realize; - dc->realize = arm_gic_realize; + device_class_set_parent_realize(dc, arm_gic_realize, &agc->parent_realize); } static const TypeInfo arm_gicv3_info = { diff --git a/hw/intc/arm_gicv3_its_kvm.c b/hw/intc/arm_gicv3_its_kvm.c index bf290b8bff..eea6a73df2 100644 --- a/hw/intc/arm_gicv3_its_kvm.c +++ b/hw/intc/arm_gicv3_its_kvm.c @@ -245,11 +245,10 @@ static void kvm_arm_its_class_init(ObjectClass *klass, void *data) dc->realize = kvm_arm_its_realize; dc->props = kvm_arm_its_props; - ic->parent_reset = dc->reset; + device_class_set_parent_reset(dc, kvm_arm_its_reset, &ic->parent_reset); icc->send_msi = kvm_its_send_msi; icc->pre_save = kvm_arm_its_pre_save; icc->post_load = kvm_arm_its_post_load; - dc->reset = kvm_arm_its_reset; } static const TypeInfo kvm_arm_its_info = { diff --git a/hw/intc/arm_gicv3_kvm.c b/hw/intc/arm_gicv3_kvm.c index 481fe5405a..ec371772b3 100644 --- a/hw/intc/arm_gicv3_kvm.c +++ b/hw/intc/arm_gicv3_kvm.c @@ -795,10 +795,9 @@ static void kvm_arm_gicv3_class_init(ObjectClass *klass, void *data) agcc->pre_save = kvm_arm_gicv3_get; agcc->post_load = kvm_arm_gicv3_put; - kgc->parent_realize = dc->realize; - kgc->parent_reset = dc->reset; - dc->realize = kvm_arm_gicv3_realize; - dc->reset = kvm_arm_gicv3_reset; + device_class_set_parent_realize(dc, kvm_arm_gicv3_realize, + &kgc->parent_realize); + device_class_set_parent_reset(dc, kvm_arm_gicv3_reset, &kgc->parent_reset); } static const TypeInfo kvm_arm_gicv3_info = { diff --git a/hw/intc/i8259.c b/hw/intc/i8259.c index 1602255a87..76f3d873b8 100644 --- a/hw/intc/i8259.c +++ b/hw/intc/i8259.c @@ -443,8 +443,7 @@ static void i8259_class_init(ObjectClass *klass, void *data) PICClass *k = PIC_CLASS(klass); DeviceClass *dc = DEVICE_CLASS(klass); - k->parent_realize = dc->realize; - dc->realize = pic_realize; + device_class_set_parent_realize(dc, pic_realize, &k->parent_realize); dc->reset = pic_reset; } diff --git a/hw/lm32/lm32_boards.c b/hw/lm32/lm32_boards.c index 002d638edd..527bcc229c 100644 --- a/hw/lm32/lm32_boards.c +++ b/hw/lm32/lm32_boards.c @@ -18,6 +18,7 @@ */ #include "qemu/osdep.h" +#include "qemu/error-report.h" #include "qemu-common.h" #include "cpu.h" #include "hw/sysbus.h" @@ -148,8 +149,7 @@ static void lm32_evr_init(MachineState *machine) } if (kernel_size < 0) { - fprintf(stderr, "qemu: could not load kernel '%s'\n", - kernel_filename); + error_report("could not load kernel '%s'", kernel_filename); exit(1); } } @@ -242,8 +242,7 @@ static void lm32_uclinux_init(MachineState *machine) } if (kernel_size < 0) { - fprintf(stderr, "qemu: could not load kernel '%s'\n", - kernel_filename); + error_report("could not load kernel '%s'", kernel_filename); exit(1); } } diff --git a/hw/lm32/milkymist.c b/hw/lm32/milkymist.c index d4e765f2eb..85d64fe58d 100644 --- a/hw/lm32/milkymist.c +++ b/hw/lm32/milkymist.c @@ -18,6 +18,7 @@ */ #include "qemu/osdep.h" +#include "qemu/error-report.h" #include "qemu-common.h" #include "cpu.h" #include "hw/sysbus.h" @@ -145,8 +146,7 @@ milkymist_init(MachineState *machine) /* if no kernel is given no valid bios rom is a fatal error */ if (!kernel_filename && !dinfo && !bios_filename && !qtest_enabled()) { - fprintf(stderr, "qemu: could not load Milkymist One bios '%s'\n", - bios_name); + error_report("could not load Milkymist One bios '%s'", bios_name); exit(1); } g_free(bios_filename); @@ -184,8 +184,7 @@ milkymist_init(MachineState *machine) } if (kernel_size < 0) { - fprintf(stderr, "qemu: could not load kernel '%s'\n", - kernel_filename); + error_report("could not load kernel '%s'", kernel_filename); exit(1); } } diff --git a/hw/mips/mips_fulong2e.c b/hw/mips/mips_fulong2e.c index 725e25a134..f68c625666 100644 --- a/hw/mips/mips_fulong2e.c +++ b/hw/mips/mips_fulong2e.c @@ -120,7 +120,7 @@ static int64_t load_kernel (CPUMIPSState *env) (uint64_t *)&kernel_low, (uint64_t *)&kernel_high, 0, EM_MIPS, 1, 0); if (kernel_size < 0) { - error_report("qemu: could not load kernel '%s': %s", + error_report("could not load kernel '%s': %s", loaderparams.kernel_filename, load_elf_strerror(kernel_size)); exit(1); @@ -134,17 +134,16 @@ static int64_t load_kernel (CPUMIPSState *env) if (initrd_size > 0) { initrd_offset = (kernel_high + ~INITRD_PAGE_MASK) & INITRD_PAGE_MASK; if (initrd_offset + initrd_size > ram_size) { - fprintf(stderr, - "qemu: memory too small for initial ram disk '%s'\n", - loaderparams.initrd_filename); + error_report("memory too small for initial ram disk '%s'", + loaderparams.initrd_filename); exit(1); } initrd_size = load_image_targphys(loaderparams.initrd_filename, initrd_offset, ram_size - initrd_offset); } if (initrd_size == (target_ulong) -1) { - fprintf(stderr, "qemu: could not load initial ram disk '%s'\n", - loaderparams.initrd_filename); + error_report("could not load initial ram disk '%s'", + loaderparams.initrd_filename); exit(1); } } @@ -338,7 +337,7 @@ static void mips_fulong2e_init(MachineState *machine) isa_bus = vt82c686b_init(pci_bus, PCI_DEVFN(FULONG2E_VIA_SLOT, 0)); if (!isa_bus) { - fprintf(stderr, "vt82c686b_init error\n"); + error_report("vt82c686b_init error"); exit(1); } diff --git a/hw/mips/mips_jazz.c b/hw/mips/mips_jazz.c index 0d2c0683ba..596f3c210e 100644 --- a/hw/mips/mips_jazz.c +++ b/hw/mips/mips_jazz.c @@ -268,10 +268,10 @@ static void mips_jazz_init(MachineState *machine, sysbus_connect_irq(sysbus, 0, qdev_get_gpio_in(rc4030, 4)); break; } else if (is_help_option(nd->model)) { - fprintf(stderr, "qemu: Supported NICs: dp83932\n"); + error_report("Supported NICs: dp83932"); exit(1); } else { - fprintf(stderr, "qemu: Unsupported NIC: %s\n", nd->model); + error_report("Unsupported NIC: %s", nd->model); exit(1); } } diff --git a/hw/mips/mips_malta.c b/hw/mips/mips_malta.c index 37f19428d6..7ca8ba2086 100644 --- a/hw/mips/mips_malta.c +++ b/hw/mips/mips_malta.c @@ -812,7 +812,7 @@ static int64_t load_kernel (void) NULL, (uint64_t *)&kernel_entry, NULL, (uint64_t *)&kernel_high, big_endian, EM_MIPS, 1, 0); if (kernel_size < 0) { - error_report("qemu: could not load kernel '%s': %s", + error_report("could not load kernel '%s': %s", loaderparams.kernel_filename, load_elf_strerror(kernel_size)); exit(1); @@ -846,9 +846,8 @@ static int64_t load_kernel (void) initrd_offset = (loaderparams.ram_low_size - initrd_size - 131072 - ~INITRD_PAGE_MASK) & INITRD_PAGE_MASK; if (kernel_high >= initrd_offset) { - fprintf(stderr, - "qemu: memory too small for initial ram disk '%s'\n", - loaderparams.initrd_filename); + error_report("memory too small for initial ram disk '%s'", + loaderparams.initrd_filename); exit(1); } initrd_size = load_image_targphys(loaderparams.initrd_filename, @@ -856,8 +855,8 @@ static int64_t load_kernel (void) ram_size - initrd_offset); } if (initrd_size == (target_ulong) -1) { - fprintf(stderr, "qemu: could not load initial ram disk '%s'\n", - loaderparams.initrd_filename); + error_report("could not load initial ram disk '%s'", + loaderparams.initrd_filename); exit(1); } } @@ -1034,9 +1033,8 @@ void mips_malta_init(MachineState *machine) /* allocate RAM */ if (ram_size > (2048u << 20)) { - fprintf(stderr, - "qemu: Too much memory for this machine: %d MB, maximum 2048 MB\n", - ((unsigned int)ram_size / (1 << 20))); + error_report("Too much memory for this machine: %dMB, maximum 2048MB", + ((unsigned int)ram_size / (1 << 20))); exit(1); } diff --git a/hw/mips/mips_mipssim.c b/hw/mips/mips_mipssim.c index e5d3654586..e0ba5efc84 100644 --- a/hw/mips/mips_mipssim.c +++ b/hw/mips/mips_mipssim.c @@ -78,7 +78,7 @@ static int64_t load_kernel(void) if ((entry & ~0x7fffffffULL) == 0x80000000) entry = (int32_t)entry; } else { - error_report("qemu: could not load kernel '%s': %s", + error_report("could not load kernel '%s': %s", loaderparams.kernel_filename, load_elf_strerror(kernel_size)); exit(1); @@ -92,17 +92,16 @@ static int64_t load_kernel(void) if (initrd_size > 0) { initrd_offset = (kernel_high + ~INITRD_PAGE_MASK) & INITRD_PAGE_MASK; if (initrd_offset + initrd_size > loaderparams.ram_size) { - fprintf(stderr, - "qemu: memory too small for initial ram disk '%s'\n", - loaderparams.initrd_filename); + error_report("memory too small for initial ram disk '%s'", + loaderparams.initrd_filename); exit(1); } initrd_size = load_image_targphys(loaderparams.initrd_filename, initrd_offset, loaderparams.ram_size - initrd_offset); } if (initrd_size == (target_ulong) -1) { - fprintf(stderr, "qemu: could not load initial ram disk '%s'\n", - loaderparams.initrd_filename); + error_report("could not load initial ram disk '%s'", + loaderparams.initrd_filename); exit(1); } } diff --git a/hw/mips/mips_r4k.c b/hw/mips/mips_r4k.c index 244bd41813..830ee7732c 100644 --- a/hw/mips/mips_r4k.c +++ b/hw/mips/mips_r4k.c @@ -98,7 +98,7 @@ static int64_t load_kernel(void) if ((entry & ~0x7fffffffULL) == 0x80000000) entry = (int32_t)entry; } else { - error_report("qemu: could not load kernel '%s': %s", + error_report("could not load kernel '%s': %s", loaderparams.kernel_filename, load_elf_strerror(kernel_size)); exit(1); @@ -112,9 +112,8 @@ static int64_t load_kernel(void) if (initrd_size > 0) { initrd_offset = (kernel_high + ~INITRD_PAGE_MASK) & INITRD_PAGE_MASK; if (initrd_offset + initrd_size > ram_size) { - fprintf(stderr, - "qemu: memory too small for initial ram disk '%s'\n", - loaderparams.initrd_filename); + error_report("memory too small for initial ram disk '%s'", + loaderparams.initrd_filename); exit(1); } initrd_size = load_image_targphys(loaderparams.initrd_filename, @@ -122,8 +121,8 @@ static int64_t load_kernel(void) ram_size - initrd_offset); } if (initrd_size == (target_ulong) -1) { - fprintf(stderr, "qemu: could not load initial ram disk '%s'\n", - loaderparams.initrd_filename); + error_report("could not load initial ram disk '%s'", + loaderparams.initrd_filename); exit(1); } } @@ -196,9 +195,8 @@ void mips_r4k_init(MachineState *machine) /* allocate RAM */ if (ram_size > (256 << 20)) { - fprintf(stderr, - "qemu: Too much memory for this machine: %d MB, maximum 256 MB\n", - ((unsigned int)ram_size / (1 << 20))); + error_report("Too much memory for this machine: %dMB, maximum 256MB", + ((unsigned int)ram_size / (1 << 20))); exit(1); } memory_region_allocate_system_memory(ram, NULL, "mips_r4k.ram", ram_size); diff --git a/hw/misc/ivshmem.c b/hw/misc/ivshmem.c index 4919011f38..16f03701b7 100644 --- a/hw/misc/ivshmem.c +++ b/hw/misc/ivshmem.c @@ -76,6 +76,7 @@ typedef struct Peer { typedef struct MSIVector { PCIDevice *pdev; int virq; + bool unmasked; } MSIVector; typedef struct IVShmemState { @@ -316,6 +317,11 @@ static int ivshmem_vector_unmask(PCIDevice *dev, unsigned vector, int ret; IVSHMEM_DPRINTF("vector unmask %p %d\n", dev, vector); + if (!v->pdev) { + error_report("ivshmem: vector %d route does not exist", vector); + return -EINVAL; + } + assert(!v->unmasked); ret = kvm_irqchip_update_msi_route(kvm_state, v->virq, msg, dev); if (ret < 0) { @@ -323,22 +329,35 @@ static int ivshmem_vector_unmask(PCIDevice *dev, unsigned vector, } kvm_irqchip_commit_routes(kvm_state); - return kvm_irqchip_add_irqfd_notifier_gsi(kvm_state, n, NULL, v->virq); + ret = kvm_irqchip_add_irqfd_notifier_gsi(kvm_state, n, NULL, v->virq); + if (ret < 0) { + return ret; + } + v->unmasked = true; + + return 0; } static void ivshmem_vector_mask(PCIDevice *dev, unsigned vector) { IVShmemState *s = IVSHMEM_COMMON(dev); EventNotifier *n = &s->peers[s->vm_id].eventfds[vector]; + MSIVector *v = &s->msi_vectors[vector]; int ret; IVSHMEM_DPRINTF("vector mask %p %d\n", dev, vector); + if (!v->pdev) { + error_report("ivshmem: vector %d route does not exist", vector); + return; + } + assert(v->unmasked); - ret = kvm_irqchip_remove_irqfd_notifier_gsi(kvm_state, n, - s->msi_vectors[vector].virq); - if (ret != 0) { + ret = kvm_irqchip_remove_irqfd_notifier_gsi(kvm_state, n, v->virq); + if (ret < 0) { error_report("remove_irqfd_notifier_gsi failed"); + return; } + v->unmasked = false; } static void ivshmem_vector_poll(PCIDevice *dev, @@ -738,10 +757,14 @@ static void ivshmem_msix_vector_use(IVShmemState *s) } } +static void ivshmem_disable_irqfd(IVShmemState *s); + static void ivshmem_reset(DeviceState *d) { IVShmemState *s = IVSHMEM_COMMON(d); + ivshmem_disable_irqfd(s); + s->intrstatus = 0; s->intrmask = 0; if (ivshmem_has_feature(s, IVSHMEM_MSI)) { @@ -766,6 +789,20 @@ static int ivshmem_setup_interrupts(IVShmemState *s, Error **errp) return 0; } +static void ivshmem_remove_kvm_msi_virq(IVShmemState *s, int vector) +{ + IVSHMEM_DPRINTF("ivshmem_remove_kvm_msi_virq vector:%d\n", vector); + + if (s->msi_vectors[vector].pdev == NULL) { + return; + } + + /* it was cleaned when masked in the frontend. */ + kvm_irqchip_release_virq(kvm_state, s->msi_vectors[vector].virq); + + s->msi_vectors[vector].pdev = NULL; +} + static void ivshmem_enable_irqfd(IVShmemState *s) { PCIDevice *pdev = PCI_DEVICE(s); @@ -777,7 +814,7 @@ static void ivshmem_enable_irqfd(IVShmemState *s) ivshmem_add_kvm_msi_virq(s, i, &err); if (err) { error_report_err(err); - /* TODO do we need to handle the error? */ + goto undo; } } @@ -786,21 +823,14 @@ static void ivshmem_enable_irqfd(IVShmemState *s) ivshmem_vector_mask, ivshmem_vector_poll)) { error_report("ivshmem: msix_set_vector_notifiers failed"); + goto undo; } -} + return; -static void ivshmem_remove_kvm_msi_virq(IVShmemState *s, int vector) -{ - IVSHMEM_DPRINTF("ivshmem_remove_kvm_msi_virq vector:%d\n", vector); - - if (s->msi_vectors[vector].pdev == NULL) { - return; +undo: + while (--i >= 0) { + ivshmem_remove_kvm_msi_virq(s, i); } - - /* it was cleaned when masked in the frontend. */ - kvm_irqchip_release_virq(kvm_state, s->msi_vectors[vector].virq); - - s->msi_vectors[vector].pdev = NULL; } static void ivshmem_disable_irqfd(IVShmemState *s) @@ -808,11 +838,24 @@ static void ivshmem_disable_irqfd(IVShmemState *s) PCIDevice *pdev = PCI_DEVICE(s); int i; + if (!pdev->msix_vector_use_notifier) { + return; + } + + msix_unset_vector_notifiers(pdev); + for (i = 0; i < s->peers[s->vm_id].nb_eventfds; i++) { + /* + * MSI-X is already disabled here so msix_unset_vector_notifiers() + * didn't call our release notifier. Do it now to keep our masks and + * unmasks balanced. + */ + if (s->msi_vectors[i].unmasked) { + ivshmem_vector_mask(pdev, i); + } ivshmem_remove_kvm_msi_virq(s, i); } - msix_unset_vector_notifiers(pdev); } static void ivshmem_write_config(PCIDevice *pdev, uint32_t address, diff --git a/hw/moxie/moxiesim.c b/hw/moxie/moxiesim.c index 6c200becab..0bbf770795 100644 --- a/hw/moxie/moxiesim.c +++ b/hw/moxie/moxiesim.c @@ -63,8 +63,8 @@ static void load_kernel(MoxieCPU *cpu, LoaderParams *loader_params) 0, 0); if (kernel_size <= 0) { - fprintf(stderr, "qemu: could not load kernel '%s'\n", - loader_params->kernel_filename); + error_report("could not load kernel '%s'", + loader_params->kernel_filename); exit(1); } @@ -77,9 +77,8 @@ static void load_kernel(MoxieCPU *cpu, LoaderParams *loader_params) initrd_offset = (kernel_high + ~TARGET_PAGE_MASK) & TARGET_PAGE_MASK; if (initrd_offset + initrd_size > loader_params->ram_size) { - fprintf(stderr, - "qemu: memory too small for initial ram disk '%s'\n", - loader_params->initrd_filename); + error_report("memory too small for initial ram disk '%s'", + loader_params->initrd_filename); exit(1); } initrd_size = load_image_targphys(loader_params->initrd_filename, @@ -87,8 +86,8 @@ static void load_kernel(MoxieCPU *cpu, LoaderParams *loader_params) ram_size); } if (initrd_size == (target_ulong)-1) { - fprintf(stderr, "qemu: could not load initial ram disk '%s'\n", - loader_params->initrd_filename); + error_report("could not load initial ram disk '%s'", + loader_params->initrd_filename); exit(1); } } diff --git a/hw/net/vmxnet3.c b/hw/net/vmxnet3.c index 0654d594c1..3648630386 100644 --- a/hw/net/vmxnet3.c +++ b/hw/net/vmxnet3.c @@ -2664,8 +2664,8 @@ static void vmxnet3_class_init(ObjectClass *class, void *data) c->class_id = PCI_CLASS_NETWORK_ETHERNET; c->subsystem_vendor_id = PCI_VENDOR_ID_VMWARE; c->subsystem_id = PCI_DEVICE_ID_VMWARE_VMXNET3; - vc->parent_dc_realize = dc->realize; - dc->realize = vmxnet3_realize; + device_class_set_parent_realize(dc, vmxnet3_realize, + &vc->parent_dc_realize); dc->desc = "VMWare Paravirtualized Ethernet v3"; dc->reset = vmxnet3_qdev_reset; dc->vmsd = &vmstate_vmxnet3; diff --git a/hw/nvram/Makefile.objs b/hw/nvram/Makefile.objs index 0f4ee71dcb..a912d25391 100644 --- a/hw/nvram/Makefile.objs +++ b/hw/nvram/Makefile.objs @@ -1,6 +1,6 @@ common-obj-$(CONFIG_DS1225Y) += ds1225y.o common-obj-y += eeprom93xx.o -common-obj-y += eeprom_at24c.o +common-obj-$(CONFIG_I2C) += eeprom_at24c.o common-obj-y += fw_cfg.o common-obj-y += chrp_nvram.o common-obj-$(CONFIG_MAC_NVRAM) += mac_nvram.o diff --git a/hw/openrisc/openrisc_sim.c b/hw/openrisc/openrisc_sim.c index e9558f1ca4..c755f11efd 100644 --- a/hw/openrisc/openrisc_sim.c +++ b/hw/openrisc/openrisc_sim.c @@ -19,6 +19,7 @@ */ #include "qemu/osdep.h" +#include "qemu/error-report.h" #include "qapi/error.h" #include "qemu-common.h" #include "cpu.h" @@ -114,8 +115,7 @@ static void openrisc_load_kernel(ram_addr_t ram_size, } if (kernel_size < 0) { - fprintf(stderr, "QEMU: couldn't load the kernel '%s'\n", - kernel_filename); + error_report("couldn't load the kernel '%s'", kernel_filename); exit(1); } boot_info.bootstrap_pc = entry; diff --git a/hw/pci-bridge/gen_pcie_root_port.c b/hw/pci-bridge/gen_pcie_root_port.c index 0e2f2e8bf1..3dbacc6cea 100644 --- a/hw/pci-bridge/gen_pcie_root_port.c +++ b/hw/pci-bridge/gen_pcie_root_port.c @@ -137,8 +137,7 @@ static void gen_rp_dev_class_init(ObjectClass *klass, void *data) dc->vmsd = &vmstate_rp_dev; dc->props = gen_rp_props; - rpc->parent_realize = dc->realize; - dc->realize = gen_rp_realize; + device_class_set_parent_realize(dc, gen_rp_realize, &rpc->parent_realize); rpc->aer_vector = gen_rp_aer_vector; rpc->interrupts_init = gen_rp_interrupts_init; diff --git a/hw/pci-host/bonito.c b/hw/pci-host/bonito.c index 0d8cacb884..2d25e9bf7c 100644 --- a/hw/pci-host/bonito.c +++ b/hw/pci-host/bonito.c @@ -38,7 +38,7 @@ */ #include "qemu/osdep.h" - +#include "qemu/error-report.h" #include "hw/hw.h" #include "hw/pci/pci.h" #include "hw/i386/pc.h" @@ -449,8 +449,8 @@ static uint32_t bonito_sbridge_pciaddr(void *opaque, hwaddr addr) regno = (cfgaddr & BONITO_PCICONF_REG_MASK) >> BONITO_PCICONF_REG_OFFSET; if (idsel == 0) { - fprintf(stderr, "error in bonito pci config address " TARGET_FMT_plx - ",pcimap_cfg=%x\n", addr, s->regs[BONITO_PCIMAP_CFG]); + error_report("error in bonito pci config address " TARGET_FMT_plx + ",pcimap_cfg=%x", addr, s->regs[BONITO_PCIMAP_CFG]); exit(1); } pciaddr = PCI_ADDR(pci_bus_num(phb->bus), devno, funno, regno); diff --git a/hw/pci/pci.c b/hw/pci/pci.c index e8f9fc1c27..fc25cdecba 100644 --- a/hw/pci/pci.c +++ b/hw/pci/pci.c @@ -1115,8 +1115,8 @@ void pci_register_bar(PCIDevice *pci_dev, int region_num, assert(region_num >= 0); assert(region_num < PCI_NUM_REGIONS); if (size & (size-1)) { - fprintf(stderr, "ERROR: PCI region size must be pow2 " - "type=0x%x, size=0x%"FMT_PCIBUS"\n", type, size); + error_report("ERROR: PCI region size must be pow2 " + "type=0x%x, size=0x%"FMT_PCIBUS"", type, size); exit(1); } diff --git a/hw/ppc/e500.c b/hw/ppc/e500.c index c4fe06ea2a..343bba93ce 100644 --- a/hw/ppc/e500.c +++ b/hw/ppc/e500.c @@ -811,8 +811,8 @@ void ppce500_init(MachineState *machine, PPCE500Params *params) cs = CPU(cpu); if (env->mmu_model != POWERPC_MMU_BOOKE206) { - fprintf(stderr, "MMU model %i not supported by this machine.\n", - env->mmu_model); + error_report("MMU model %i not supported by this machine", + env->mmu_model); exit(1); } @@ -959,8 +959,8 @@ void ppce500_init(MachineState *machine, PPCE500Params *params) cur_base, ram_size - cur_base); if (kernel_size < 0) { - fprintf(stderr, "qemu: could not load kernel '%s'\n", - machine->kernel_filename); + error_report("could not load kernel '%s'", + machine->kernel_filename); exit(1); } @@ -974,8 +974,8 @@ void ppce500_init(MachineState *machine, PPCE500Params *params) ram_size - initrd_base); if (initrd_size < 0) { - fprintf(stderr, "qemu: could not load initial ram disk '%s'\n", - machine->initrd_filename); + error_report("could not load initial ram disk '%s'", + machine->initrd_filename); exit(1); } @@ -1016,7 +1016,7 @@ void ppce500_init(MachineState *machine, PPCE500Params *params) kernel_size = load_uimage(filename, &bios_entry, &loadaddr, NULL, NULL, NULL); if (kernel_size < 0) { - fprintf(stderr, "qemu: could not load firmware '%s'\n", filename); + error_report("could not load firmware '%s'", filename); exit(1); } } @@ -1029,7 +1029,7 @@ void ppce500_init(MachineState *machine, PPCE500Params *params) initrd_base, initrd_size, kernel_base, kernel_size); if (dt_size < 0) { - fprintf(stderr, "couldn't load device tree\n"); + error_report("couldn't load device tree"); exit(1); } assert(dt_size < DTB_MAX_SIZE); diff --git a/hw/ppc/mac_newworld.c b/hw/ppc/mac_newworld.c index 3fa7c429d5..b832417a56 100644 --- a/hw/ppc/mac_newworld.c +++ b/hw/ppc/mac_newworld.c @@ -270,7 +270,7 @@ static void ppc_core99_init(MachineState *machine) } } if (ppc_boot_device == '\0') { - fprintf(stderr, "No valid boot device for Mac99 machine\n"); + error_report("No valid boot device for Mac99 machine"); exit(1); } } diff --git a/hw/ppc/mac_oldworld.c b/hw/ppc/mac_oldworld.c index 010ea36bf2..d1f4546613 100644 --- a/hw/ppc/mac_oldworld.c +++ b/hw/ppc/mac_oldworld.c @@ -218,7 +218,7 @@ static void ppc_heathrow_init(MachineState *machine) #endif } if (ppc_boot_device == '\0') { - fprintf(stderr, "No valid boot device for G3 Beige machine\n"); + error_report("No valid boot device for G3 Beige machine"); exit(1); } } diff --git a/hw/ppc/ppc405_boards.c b/hw/ppc/ppc405_boards.c index 6f7f2ee168..0b658931ee 100644 --- a/hw/ppc/ppc405_boards.c +++ b/hw/ppc/ppc405_boards.c @@ -331,8 +331,7 @@ static void ref405ep_init(MachineState *machine) kernel_size = load_image_targphys(kernel_filename, kernel_base, ram_size - kernel_base); if (kernel_size < 0) { - fprintf(stderr, "qemu: could not load kernel '%s'\n", - kernel_filename); + error_report("could not load kernel '%s'", kernel_filename); exit(1); } printf("Load kernel size %ld at " TARGET_FMT_lx, @@ -343,8 +342,8 @@ static void ref405ep_init(MachineState *machine) initrd_size = load_image_targphys(initrd_filename, initrd_base, ram_size - initrd_base); if (initrd_size < 0) { - fprintf(stderr, "qemu: could not load initial ram disk '%s'\n", - initrd_filename); + error_report("could not load initial ram disk '%s'", + initrd_filename); exit(1); } } else { @@ -621,8 +620,7 @@ static void taihu_405ep_init(MachineState *machine) kernel_size = load_image_targphys(kernel_filename, kernel_base, ram_size - kernel_base); if (kernel_size < 0) { - fprintf(stderr, "qemu: could not load kernel '%s'\n", - kernel_filename); + error_report("could not load kernel '%s'", kernel_filename); exit(1); } /* load initrd */ @@ -631,9 +629,8 @@ static void taihu_405ep_init(MachineState *machine) initrd_size = load_image_targphys(initrd_filename, initrd_base, ram_size - initrd_base); if (initrd_size < 0) { - fprintf(stderr, - "qemu: could not load initial ram disk '%s'\n", - initrd_filename); + error_report("could not load initial ram disk '%s'", + initrd_filename); exit(1); } } else { diff --git a/hw/ppc/ppc440_bamboo.c b/hw/ppc/ppc440_bamboo.c index a299206fd4..8641986a71 100644 --- a/hw/ppc/ppc440_bamboo.c +++ b/hw/ppc/ppc440_bamboo.c @@ -12,6 +12,7 @@ */ #include "qemu/osdep.h" +#include "qemu/error-report.h" #include "qemu-common.h" #include "qemu/error-report.h" #include "net/net.h" @@ -188,8 +189,8 @@ static void bamboo_init(MachineState *machine) env = &cpu->env; if (env->mmu_model != POWERPC_MMU_BOOKE) { - fprintf(stderr, "MMU model %i not supported by this machine.\n", - env->mmu_model); + error_report("MMU model %i not supported by this machine", + env->mmu_model); exit(1); } @@ -229,7 +230,7 @@ static void bamboo_init(MachineState *machine) NULL); pcibus = (PCIBus *)qdev_get_child_bus(dev, "pci.0"); if (!pcibus) { - fprintf(stderr, "couldn't create PCI controller!\n"); + error_report("couldn't create PCI controller"); exit(1); } @@ -270,8 +271,7 @@ static void bamboo_init(MachineState *machine) } /* XXX try again as binary */ if (success < 0) { - fprintf(stderr, "qemu: could not load kernel '%s'\n", - kernel_filename); + error_report("could not load kernel '%s'", kernel_filename); exit(1); } } @@ -282,8 +282,8 @@ static void bamboo_init(MachineState *machine) ram_size - RAMDISK_ADDR); if (initrd_size < 0) { - fprintf(stderr, "qemu: could not load ram disk '%s' at %x\n", - initrd_filename, RAMDISK_ADDR); + error_report("could not load ram disk '%s' at %x", + initrd_filename, RAMDISK_ADDR); exit(1); } } @@ -292,7 +292,7 @@ static void bamboo_init(MachineState *machine) if (kernel_filename) { if (bamboo_load_device_tree(FDT_ADDR, ram_size, RAMDISK_ADDR, initrd_size, kernel_cmdline) < 0) { - fprintf(stderr, "couldn't load device tree\n"); + error_report("couldn't load device tree"); exit(1); } } diff --git a/hw/ppc/prep.c b/hw/ppc/prep.c index af08ac319a..096d4d4cfb 100644 --- a/hw/ppc/prep.c +++ b/hw/ppc/prep.c @@ -574,7 +574,7 @@ static void ppc_prep_init(MachineState *machine) } } if (ppc_boot_device == '\0') { - fprintf(stderr, "No valid boot device for Mac99 machine\n"); + error_report("No valid boot device for Mac99 machine"); exit(1); } } @@ -595,7 +595,7 @@ static void ppc_prep_init(MachineState *machine) qdev_init_nofail(dev); pci_bus = (PCIBus *)qdev_get_child_bus(dev, "pci.0"); if (pci_bus == NULL) { - fprintf(stderr, "Couldn't create PCI host controller.\n"); + error_report("Couldn't create PCI host controller"); exit(1); } sysctrl->contiguous_map_irq = qdev_get_gpio_in(dev, 0); diff --git a/hw/ppc/spapr_iommu.c b/hw/ppc/spapr_iommu.c index 5ccd785d5a..aaa6010d5c 100644 --- a/hw/ppc/spapr_iommu.c +++ b/hw/ppc/spapr_iommu.c @@ -160,6 +160,19 @@ static uint64_t spapr_tce_get_min_page_size(IOMMUMemoryRegion *iommu) return 1ULL << tcet->page_shift; } +static int spapr_tce_get_attr(IOMMUMemoryRegion *iommu, + enum IOMMUMemoryRegionAttr attr, void *data) +{ + sPAPRTCETable *tcet = container_of(iommu, sPAPRTCETable, iommu); + + if (attr == IOMMU_ATTR_SPAPR_TCE_FD && kvmppc_has_cap_spapr_vfio()) { + *(int *) data = tcet->fd; + return 0; + } + + return -EINVAL; +} + static void spapr_tce_notify_flag_changed(IOMMUMemoryRegion *iommu, IOMMUNotifierFlag old, IOMMUNotifierFlag new) @@ -284,6 +297,10 @@ void spapr_tce_set_need_vfio(sPAPRTCETable *tcet, bool need_vfio) tcet->need_vfio = need_vfio; + if (!need_vfio || (tcet->fd != -1 && kvmppc_has_cap_spapr_vfio())) { + return; + } + oldtable = tcet->table; tcet->table = spapr_tce_alloc_table(tcet->liobn, @@ -643,6 +660,7 @@ static void spapr_iommu_memory_region_class_init(ObjectClass *klass, void *data) imrc->translate = spapr_tce_translate_iommu; imrc->get_min_page_size = spapr_tce_get_min_page_size; imrc->notify_flag_changed = spapr_tce_notify_flag_changed; + imrc->get_attr = spapr_tce_get_attr; } static const TypeInfo spapr_iommu_memory_region_info = { diff --git a/hw/ppc/virtex_ml507.c b/hw/ppc/virtex_ml507.c index 9fe7655074..485d9affb2 100644 --- a/hw/ppc/virtex_ml507.c +++ b/hw/ppc/virtex_ml507.c @@ -223,8 +223,8 @@ static void virtex_init(MachineState *machine) env = &cpu->env; if (env->mmu_model != POWERPC_MMU_BOOKE) { - fprintf(stderr, "MMU model %i not supported by this machine.\n", - env->mmu_model); + error_report("MMU model %i not supported by this machine", + env->mmu_model); exit(1); } diff --git a/hw/scsi/scsi-generic.c b/hw/scsi/scsi-generic.c index ba70c0dc19..7414fe2d67 100644 --- a/hw/scsi/scsi-generic.c +++ b/hw/scsi/scsi-generic.c @@ -482,7 +482,6 @@ static void scsi_generic_realize(SCSIDevice *s, Error **errp) int rc; int sg_version; struct sg_scsi_id scsiid; - Error *local_err = NULL; if (!s->conf.blk) { error_setg(errp, "drive property not set"); @@ -516,11 +515,9 @@ static void scsi_generic_realize(SCSIDevice *s, Error **errp) error_setg(errp, "SG_GET_SCSI_ID ioctl failed"); return; } - blkconf_apply_backend_options(&s->conf, - blk_is_read_only(s->conf.blk), - true, &local_err); - if (local_err) { - error_propagate(errp, local_err); + if (!blkconf_apply_backend_options(&s->conf, + blk_is_read_only(s->conf.blk), + true, errp)) { return; } diff --git a/hw/scsi/vmw_pvscsi.c b/hw/scsi/vmw_pvscsi.c index 27749c0e42..a3a019e30a 100644 --- a/hw/scsi/vmw_pvscsi.c +++ b/hw/scsi/vmw_pvscsi.c @@ -1284,8 +1284,8 @@ static void pvscsi_class_init(ObjectClass *klass, void *data) k->device_id = PCI_DEVICE_ID_VMWARE_PVSCSI; k->class_id = PCI_CLASS_STORAGE_SCSI; k->subsystem_id = 0x1000; - pvs_k->parent_dc_realize = dc->realize; - dc->realize = pvscsi_realize; + device_class_set_parent_realize(dc, pvscsi_realize, + &pvs_k->parent_dc_realize); dc->reset = pvscsi_reset; dc->vmsd = &vmstate_pvscsi; dc->props = pvscsi_properties; diff --git a/hw/sd/sd.c b/hw/sd/sd.c index 35347a5bbc..73e405a04f 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -1564,9 +1564,10 @@ send_response: if (rsplen) { int i; DPRINTF("Response:"); - for (i = 0; i < rsplen; i++) - fprintf(stderr, " %02x", response[i]); - fprintf(stderr, " state %d\n", sd->state); + for (i = 0; i < rsplen; i++) { + DPRINTF(" %02x", response[i]); + } + DPRINTF(" state %d\n", sd->state); } else { DPRINTF("No response %d\n", sd->state); } diff --git a/hw/sparc/leon3.c b/hw/sparc/leon3.c index 8c66d5af24..bba3aa3dee 100644 --- a/hw/sparc/leon3.c +++ b/hw/sparc/leon3.c @@ -22,6 +22,7 @@ * THE SOFTWARE. */ #include "qemu/osdep.h" +#include "qemu/error-report.h" #include "qapi/error.h" #include "qemu-common.h" #include "cpu.h" @@ -139,9 +140,8 @@ static void leon3_generic_hw_init(MachineState *machine) /* Allocate RAM */ if ((uint64_t)ram_size > (1UL << 30)) { - fprintf(stderr, - "qemu: Too much memory for this machine: %d, maximum 1G\n", - (unsigned int)(ram_size / (1024 * 1024))); + error_report("Too much memory for this machine: %d, maximum 1G", + (unsigned int)(ram_size / (1024 * 1024))); exit(1); } @@ -167,19 +167,18 @@ static void leon3_generic_hw_init(MachineState *machine) } if (bios_size > prom_size) { - fprintf(stderr, "qemu: could not load prom '%s': file too big\n", - filename); + error_report("could not load prom '%s': file too big", filename); exit(1); } if (bios_size > 0) { ret = load_image_targphys(filename, 0x00000000, bios_size); if (ret < 0 || ret > prom_size) { - fprintf(stderr, "qemu: could not load prom '%s'\n", filename); + error_report("could not load prom '%s'", filename); exit(1); } } else if (kernel_filename == NULL && !qtest_enabled()) { - fprintf(stderr, "Can't read bios image %s\n", filename); + error_report("Can't read bios image %s", filename); exit(1); } g_free(filename); @@ -192,8 +191,7 @@ static void leon3_generic_hw_init(MachineState *machine) kernel_size = load_elf(kernel_filename, NULL, NULL, &entry, NULL, NULL, 1 /* big endian */, EM_SPARC, 0, 0); if (kernel_size < 0) { - fprintf(stderr, "qemu: could not load kernel '%s'\n", - kernel_filename); + error_report("could not load kernel '%s'", kernel_filename); exit(1); } if (bios_size <= 0) { diff --git a/hw/sparc/sun4m.c b/hw/sparc/sun4m.c index dd0038095b..f9892e38c3 100644 --- a/hw/sparc/sun4m.c +++ b/hw/sparc/sun4m.c @@ -259,8 +259,7 @@ static unsigned long sun4m_load_kernel(const char *kernel_filename, KERNEL_LOAD_ADDR, RAM_size - KERNEL_LOAD_ADDR); if (kernel_size < 0) { - fprintf(stderr, "qemu: could not load kernel '%s'\n", - kernel_filename); + error_report("could not load kernel '%s'", kernel_filename); exit(1); } @@ -271,8 +270,8 @@ static unsigned long sun4m_load_kernel(const char *kernel_filename, INITRD_LOAD_ADDR, RAM_size - INITRD_LOAD_ADDR); if (initrd_size < 0) { - fprintf(stderr, "qemu: could not load initial ram disk '%s'\n", - initrd_filename); + error_report("could not load initial ram disk '%s'", + initrd_filename); exit(1); } } @@ -680,7 +679,7 @@ static void prom_init(hwaddr addr, const char *bios_name) ret = -1; } if (ret < 0 || ret > PROM_SIZE_MAX) { - fprintf(stderr, "qemu: could not load prom '%s'\n", bios_name); + error_report("could not load prom '%s'", bios_name); exit(1); } } @@ -746,10 +745,9 @@ static void ram_init(hwaddr addr, ram_addr_t RAM_size, /* allocate RAM */ if ((uint64_t)RAM_size > max_mem) { - fprintf(stderr, - "qemu: Too much memory for this machine: %d, maximum %d\n", - (unsigned int)(RAM_size / (1024 * 1024)), - (unsigned int)(max_mem / (1024 * 1024))); + error_report("Too much memory for this machine: %d, maximum %d", + (unsigned int)(RAM_size / (1024 * 1024)), + (unsigned int)(max_mem / (1024 * 1024))); exit(1); } dev = qdev_create(NULL, "memory"); diff --git a/hw/sparc64/niagara.c b/hw/sparc64/niagara.c index 7a723326c5..996ce2ada0 100644 --- a/hw/sparc64/niagara.c +++ b/hw/sparc64/niagara.c @@ -152,8 +152,8 @@ static void niagara_init(MachineState *machine) dinfo->is_default = 1; rom_add_file_fixed(blk_bs(blk)->filename, NIAGARA_VDISK_BASE, -1); } else { - fprintf(stderr, "qemu: could not load ram disk '%s'\n", - blk_bs(blk)->filename); + error_report("could not load ram disk '%s'", + blk_bs(blk)->filename); exit(1); } } diff --git a/hw/sparc64/sun4u.c b/hw/sparc64/sun4u.c index a23cb26b0d..da28ab9413 100644 --- a/hw/sparc64/sun4u.c +++ b/hw/sparc64/sun4u.c @@ -22,6 +22,7 @@ * THE SOFTWARE. */ #include "qemu/osdep.h" +#include "qemu/error-report.h" #include "qapi/error.h" #include "qemu-common.h" #include "cpu.h" @@ -168,8 +169,7 @@ static uint64_t sun4u_load_kernel(const char *kernel_filename, RAM_size - KERNEL_LOAD_ADDR); } if (kernel_size < 0) { - fprintf(stderr, "qemu: could not load kernel '%s'\n", - kernel_filename); + error_report("could not load kernel '%s'", kernel_filename); exit(1); } /* load initrd above kernel */ @@ -181,8 +181,8 @@ static uint64_t sun4u_load_kernel(const char *kernel_filename, *initrd_addr, RAM_size - *initrd_addr); if ((int)*initrd_size < 0) { - fprintf(stderr, "qemu: could not load initial ram disk '%s'\n", - initrd_filename); + error_report("could not load initial ram disk '%s'", + initrd_filename); exit(1); } } @@ -422,7 +422,7 @@ static void prom_init(hwaddr addr, const char *bios_name) ret = -1; } if (ret < 0 || ret > PROM_SIZE_MAX) { - fprintf(stderr, "qemu: could not load prom '%s'\n", bios_name); + error_report("could not load prom '%s'", bios_name); exit(1); } } diff --git a/hw/timer/i8254.c b/hw/timer/i8254.c index dbc4a0baec..1057850808 100644 --- a/hw/timer/i8254.c +++ b/hw/timer/i8254.c @@ -358,8 +358,7 @@ static void pit_class_initfn(ObjectClass *klass, void *data) PITCommonClass *k = PIT_COMMON_CLASS(klass); DeviceClass *dc = DEVICE_CLASS(klass); - pc->parent_realize = dc->realize; - dc->realize = pit_realizefn; + device_class_set_parent_realize(dc, pit_realizefn, &pc->parent_realize); k->set_channel_gate = pit_set_channel_gate; k->get_channel_info = pit_get_channel_info_common; k->post_load = pit_post_load; diff --git a/hw/vfio/amd-xgbe.c b/hw/vfio/amd-xgbe.c index fab196cebf..0c4ec4ba25 100644 --- a/hw/vfio/amd-xgbe.c +++ b/hw/vfio/amd-xgbe.c @@ -34,8 +34,8 @@ static void vfio_amd_xgbe_class_init(ObjectClass *klass, void *data) DeviceClass *dc = DEVICE_CLASS(klass); VFIOAmdXgbeDeviceClass *vcxc = VFIO_AMD_XGBE_DEVICE_CLASS(klass); - vcxc->parent_realize = dc->realize; - dc->realize = amd_xgbe_realize; + device_class_set_parent_realize(dc, amd_xgbe_realize, + &vcxc->parent_realize); dc->desc = "VFIO AMD XGBE"; dc->vmsd = &vfio_platform_amd_xgbe_vmstate; /* Supported by TYPE_VIRT_MACHINE */ diff --git a/hw/vfio/calxeda-xgmac.c b/hw/vfio/calxeda-xgmac.c index 7bb17af7ad..24cee6d065 100644 --- a/hw/vfio/calxeda-xgmac.c +++ b/hw/vfio/calxeda-xgmac.c @@ -34,8 +34,8 @@ static void vfio_calxeda_xgmac_class_init(ObjectClass *klass, void *data) DeviceClass *dc = DEVICE_CLASS(klass); VFIOCalxedaXgmacDeviceClass *vcxc = VFIO_CALXEDA_XGMAC_DEVICE_CLASS(klass); - vcxc->parent_realize = dc->realize; - dc->realize = calxeda_xgmac_realize; + device_class_set_parent_realize(dc, calxeda_xgmac_realize, + &vcxc->parent_realize); dc->desc = "VFIO Calxeda XGMAC"; dc->vmsd = &vfio_platform_calxeda_xgmac_vmstate; /* Supported by TYPE_VIRT_MACHINE */ diff --git a/hw/vfio/common.c b/hw/vfio/common.c index b77be3a8b3..f895e3c335 100644 --- a/hw/vfio/common.c +++ b/hw/vfio/common.c @@ -435,7 +435,6 @@ static void vfio_listener_region_add(MemoryListener *listener, end = int128_get64(int128_sub(llend, int128_one())); if (container->iommu_type == VFIO_SPAPR_TCE_v2_IOMMU) { - VFIOHostDMAWindow *hostwin; hwaddr pgsize = 0; /* For now intersections are not allowed, we may relax this later */ @@ -457,6 +456,33 @@ static void vfio_listener_region_add(MemoryListener *listener, vfio_host_win_add(container, section->offset_within_address_space, section->offset_within_address_space + int128_get64(section->size) - 1, pgsize); +#ifdef CONFIG_KVM + if (kvm_enabled()) { + VFIOGroup *group; + IOMMUMemoryRegion *iommu_mr = IOMMU_MEMORY_REGION(section->mr); + struct kvm_vfio_spapr_tce param; + struct kvm_device_attr attr = { + .group = KVM_DEV_VFIO_GROUP, + .attr = KVM_DEV_VFIO_GROUP_SET_SPAPR_TCE, + .addr = (uint64_t)(unsigned long)¶m, + }; + + if (!memory_region_iommu_get_attr(iommu_mr, IOMMU_ATTR_SPAPR_TCE_FD, + ¶m.tablefd)) { + QLIST_FOREACH(group, &container->group_list, container_next) { + param.groupfd = group->fd; + if (ioctl(vfio_kvm_device_fd, KVM_SET_DEVICE_ATTR, &attr)) { + error_report("vfio: failed to setup fd %d " + "for a group with fd %d: %s", + param.tablefd, param.groupfd, + strerror(errno)); + return; + } + trace_vfio_spapr_group_attach(param.groupfd, param.tablefd); + } + } + } +#endif } hostwin_found = false; @@ -1161,19 +1187,27 @@ static void vfio_disconnect_container(VFIOGroup *group) { VFIOContainer *container = group->container; + QLIST_REMOVE(group, container_next); + group->container = NULL; + + /* + * Explicitly release the listener first before unset container, + * since unset may destroy the backend container if it's the last + * group. + */ + if (QLIST_EMPTY(&container->group_list)) { + vfio_listener_release(container); + } + if (ioctl(group->fd, VFIO_GROUP_UNSET_CONTAINER, &container->fd)) { error_report("vfio: error disconnecting group %d from container", group->groupid); } - QLIST_REMOVE(group, container_next); - group->container = NULL; - if (QLIST_EMPTY(&container->group_list)) { VFIOAddressSpace *space = container->space; VFIOGuestIOMMU *giommu, *tmp; - vfio_listener_release(container); QLIST_REMOVE(container, next); QLIST_FOREACH_SAFE(giommu, &container->giommu_list, giommu_next, tmp) { diff --git a/hw/vfio/pci-quirks.c b/hw/vfio/pci-quirks.c index 60ad5fb91a..e5779a7ad3 100644 --- a/hw/vfio/pci-quirks.c +++ b/hw/vfio/pci-quirks.c @@ -542,7 +542,8 @@ static void vfio_vga_probe_nvidia_3d0_quirk(VFIOPCIDevice *vdev) VFIOQuirk *quirk; VFIONvidia3d0Quirk *data; - if (!vfio_pci_is(vdev, PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID) || + if (vdev->no_geforce_quirks || + !vfio_pci_is(vdev, PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID) || !vdev->bars[1].region.size) { return; } @@ -660,7 +661,8 @@ static void vfio_probe_nvidia_bar5_quirk(VFIOPCIDevice *vdev, int nr) VFIONvidiaBAR5Quirk *bar5; VFIOConfigWindowQuirk *window; - if (!vfio_pci_is(vdev, PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID) || + if (vdev->no_geforce_quirks || + !vfio_pci_is(vdev, PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID) || !vdev->vga || nr != 5 || !vdev->bars[5].ioport) { return; } @@ -754,7 +756,8 @@ static void vfio_probe_nvidia_bar0_quirk(VFIOPCIDevice *vdev, int nr) VFIOQuirk *quirk; VFIOConfigMirrorQuirk *mirror; - if (!vfio_pci_is(vdev, PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID) || + if (vdev->no_geforce_quirks || + !vfio_pci_is(vdev, PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID) || !vfio_is_vga(vdev) || nr != 0) { return; } diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c index 2c71295125..879510c046 100644 --- a/hw/vfio/pci.c +++ b/hw/vfio/pci.c @@ -1087,7 +1087,7 @@ static void vfio_sub_page_bar_update_mapping(PCIDevice *pdev, int bar) { VFIOPCIDevice *vdev = DO_UPCAST(VFIOPCIDevice, pdev, pdev); VFIORegion *region = &vdev->bars[bar].region; - MemoryRegion *mmap_mr, *mr; + MemoryRegion *mmap_mr, *region_mr, *base_mr; PCIIORegion *r; pcibus_t bar_addr; uint64_t size = region->size; @@ -1100,7 +1100,8 @@ static void vfio_sub_page_bar_update_mapping(PCIDevice *pdev, int bar) r = &pdev->io_regions[bar]; bar_addr = r->addr; - mr = region->mem; + base_mr = vdev->bars[bar].mr; + region_mr = region->mem; mmap_mr = ®ion->mmaps[0].mem; /* If BAR is mapped and page aligned, update to fill PAGE_SIZE */ @@ -1111,12 +1112,15 @@ static void vfio_sub_page_bar_update_mapping(PCIDevice *pdev, int bar) memory_region_transaction_begin(); - memory_region_set_size(mr, size); + if (vdev->bars[bar].size < size) { + memory_region_set_size(base_mr, size); + } + memory_region_set_size(region_mr, size); memory_region_set_size(mmap_mr, size); - if (size != region->size && memory_region_is_mapped(mr)) { - memory_region_del_subregion(r->address_space, mr); + if (size != vdev->bars[bar].size && memory_region_is_mapped(base_mr)) { + memory_region_del_subregion(r->address_space, base_mr); memory_region_add_subregion_overlap(r->address_space, - bar_addr, mr, 0); + bar_addr, base_mr, 0); } memory_region_transaction_commit(); @@ -1218,8 +1222,8 @@ void vfio_pci_write_config(PCIDevice *pdev, for (bar = 0; bar < PCI_ROM_SLOT; bar++) { if (old_addr[bar] != pdev->io_regions[bar].addr && - pdev->io_regions[bar].size > 0 && - pdev->io_regions[bar].size < qemu_real_host_page_size) { + vdev->bars[bar].region.size > 0 && + vdev->bars[bar].region.size < qemu_real_host_page_size) { vfio_sub_page_bar_update_mapping(pdev, bar); } } @@ -1352,6 +1356,98 @@ static void vfio_pci_fixup_msix_region(VFIOPCIDevice *vdev) } } +static void vfio_pci_relocate_msix(VFIOPCIDevice *vdev, Error **errp) +{ + int target_bar = -1; + size_t msix_sz; + + if (!vdev->msix || vdev->msix_relo == OFF_AUTOPCIBAR_OFF) { + return; + } + + /* The actual minimum size of MSI-X structures */ + msix_sz = (vdev->msix->entries * PCI_MSIX_ENTRY_SIZE) + + (QEMU_ALIGN_UP(vdev->msix->entries, 64) / 8); + /* Round up to host pages, we don't want to share a page */ + msix_sz = REAL_HOST_PAGE_ALIGN(msix_sz); + /* PCI BARs must be a power of 2 */ + msix_sz = pow2ceil(msix_sz); + + if (vdev->msix_relo == OFF_AUTOPCIBAR_AUTO) { + /* + * TODO: Lookup table for known devices. + * + * Logically we might use an algorithm here to select the BAR adding + * the least additional MMIO space, but we cannot programatically + * predict the driver dependency on BAR ordering or sizing, therefore + * 'auto' becomes a lookup for combinations reported to work. + */ + if (target_bar < 0) { + error_setg(errp, "No automatic MSI-X relocation available for " + "device %04x:%04x", vdev->vendor_id, vdev->device_id); + return; + } + } else { + target_bar = (int)(vdev->msix_relo - OFF_AUTOPCIBAR_BAR0); + } + + /* I/O port BARs cannot host MSI-X structures */ + if (vdev->bars[target_bar].ioport) { + error_setg(errp, "Invalid MSI-X relocation BAR %d, " + "I/O port BAR", target_bar); + return; + } + + /* Cannot use a BAR in the "shadow" of a 64-bit BAR */ + if (!vdev->bars[target_bar].size && + target_bar > 0 && vdev->bars[target_bar - 1].mem64) { + error_setg(errp, "Invalid MSI-X relocation BAR %d, " + "consumed by 64-bit BAR %d", target_bar, target_bar - 1); + return; + } + + /* 2GB max size for 32-bit BARs, cannot double if already > 1G */ + if (vdev->bars[target_bar].size > (1 * 1024 * 1024 * 1024) && + !vdev->bars[target_bar].mem64) { + error_setg(errp, "Invalid MSI-X relocation BAR %d, " + "no space to extend 32-bit BAR", target_bar); + return; + } + + /* + * If adding a new BAR, test if we can make it 64bit. We make it + * prefetchable since QEMU MSI-X emulation has no read side effects + * and doing so makes mapping more flexible. + */ + if (!vdev->bars[target_bar].size) { + if (target_bar < (PCI_ROM_SLOT - 1) && + !vdev->bars[target_bar + 1].size) { + vdev->bars[target_bar].mem64 = true; + vdev->bars[target_bar].type = PCI_BASE_ADDRESS_MEM_TYPE_64; + } + vdev->bars[target_bar].type |= PCI_BASE_ADDRESS_MEM_PREFETCH; + vdev->bars[target_bar].size = msix_sz; + vdev->msix->table_offset = 0; + } else { + vdev->bars[target_bar].size = MAX(vdev->bars[target_bar].size * 2, + msix_sz * 2); + /* + * Due to above size calc, MSI-X always starts halfway into the BAR, + * which will always be a separate host page. + */ + vdev->msix->table_offset = vdev->bars[target_bar].size / 2; + } + + vdev->msix->table_bar = target_bar; + vdev->msix->pba_bar = target_bar; + /* Requires 8-byte alignment, but PCI_MSIX_ENTRY_SIZE guarantees that */ + vdev->msix->pba_offset = vdev->msix->table_offset + + (vdev->msix->entries * PCI_MSIX_ENTRY_SIZE); + + trace_vfio_msix_relo(vdev->vbasedev.name, + vdev->msix->table_bar, vdev->msix->table_offset); +} + /* * We don't have any control over how pci_add_capability() inserts * capabilities into the chain. In order to setup MSI-X we need a @@ -1430,6 +1526,8 @@ static void vfio_msix_early_setup(VFIOPCIDevice *vdev, Error **errp) vdev->msix = msix; vfio_pci_fixup_msix_region(vdev); + + vfio_pci_relocate_msix(vdev, errp); } static int vfio_msix_setup(VFIOPCIDevice *vdev, int pos, Error **errp) @@ -1440,9 +1538,9 @@ static int vfio_msix_setup(VFIOPCIDevice *vdev, int pos, Error **errp) vdev->msix->pending = g_malloc0(BITS_TO_LONGS(vdev->msix->entries) * sizeof(unsigned long)); ret = msix_init(&vdev->pdev, vdev->msix->entries, - vdev->bars[vdev->msix->table_bar].region.mem, + vdev->bars[vdev->msix->table_bar].mr, vdev->msix->table_bar, vdev->msix->table_offset, - vdev->bars[vdev->msix->pba_bar].region.mem, + vdev->bars[vdev->msix->pba_bar].mr, vdev->msix->pba_bar, vdev->msix->pba_offset, pos, &err); if (ret < 0) { @@ -1482,8 +1580,8 @@ static void vfio_teardown_msi(VFIOPCIDevice *vdev) if (vdev->msix) { msix_uninit(&vdev->pdev, - vdev->bars[vdev->msix->table_bar].region.mem, - vdev->bars[vdev->msix->pba_bar].region.mem); + vdev->bars[vdev->msix->table_bar].mr, + vdev->bars[vdev->msix->pba_bar].mr); g_free(vdev->msix->pending); } } @@ -1500,12 +1598,11 @@ static void vfio_mmap_set_enabled(VFIOPCIDevice *vdev, bool enabled) } } -static void vfio_bar_setup(VFIOPCIDevice *vdev, int nr) +static void vfio_bar_prepare(VFIOPCIDevice *vdev, int nr) { VFIOBAR *bar = &vdev->bars[nr]; uint32_t pci_bar; - uint8_t type; int ret; /* Skip both unimplemented BARs and the upper half of 64bit BARS. */ @@ -1524,23 +1621,52 @@ static void vfio_bar_setup(VFIOPCIDevice *vdev, int nr) pci_bar = le32_to_cpu(pci_bar); bar->ioport = (pci_bar & PCI_BASE_ADDRESS_SPACE_IO); bar->mem64 = bar->ioport ? 0 : (pci_bar & PCI_BASE_ADDRESS_MEM_TYPE_64); - type = pci_bar & (bar->ioport ? ~PCI_BASE_ADDRESS_IO_MASK : - ~PCI_BASE_ADDRESS_MEM_MASK); + bar->type = pci_bar & (bar->ioport ? ~PCI_BASE_ADDRESS_IO_MASK : + ~PCI_BASE_ADDRESS_MEM_MASK); + bar->size = bar->region.size; +} + +static void vfio_bars_prepare(VFIOPCIDevice *vdev) +{ + int i; - if (vfio_region_mmap(&bar->region)) { - error_report("Failed to mmap %s BAR %d. Performance may be slow", - vdev->vbasedev.name, nr); + for (i = 0; i < PCI_ROM_SLOT; i++) { + vfio_bar_prepare(vdev, i); } +} + +static void vfio_bar_register(VFIOPCIDevice *vdev, int nr) +{ + VFIOBAR *bar = &vdev->bars[nr]; + char *name; - pci_register_bar(&vdev->pdev, nr, type, bar->region.mem); + if (!bar->size) { + return; + } + + bar->mr = g_new0(MemoryRegion, 1); + name = g_strdup_printf("%s base BAR %d", vdev->vbasedev.name, nr); + memory_region_init_io(bar->mr, OBJECT(vdev), NULL, NULL, name, bar->size); + g_free(name); + + if (bar->region.size) { + memory_region_add_subregion(bar->mr, 0, bar->region.mem); + + if (vfio_region_mmap(&bar->region)) { + error_report("Failed to mmap %s BAR %d. Performance may be slow", + vdev->vbasedev.name, nr); + } + } + + pci_register_bar(&vdev->pdev, nr, bar->type, bar->mr); } -static void vfio_bars_setup(VFIOPCIDevice *vdev) +static void vfio_bars_register(VFIOPCIDevice *vdev) { int i; for (i = 0; i < PCI_ROM_SLOT; i++) { - vfio_bar_setup(vdev, i); + vfio_bar_register(vdev, i); } } @@ -1549,8 +1675,13 @@ static void vfio_bars_exit(VFIOPCIDevice *vdev) int i; for (i = 0; i < PCI_ROM_SLOT; i++) { + VFIOBAR *bar = &vdev->bars[i]; + vfio_bar_quirk_exit(vdev, i); - vfio_region_exit(&vdev->bars[i].region); + vfio_region_exit(&bar->region); + if (bar->region.size) { + memory_region_del_subregion(bar->mr, bar->region.mem); + } } if (vdev->vga) { @@ -1564,8 +1695,14 @@ static void vfio_bars_finalize(VFIOPCIDevice *vdev) int i; for (i = 0; i < PCI_ROM_SLOT; i++) { + VFIOBAR *bar = &vdev->bars[i]; + vfio_bar_quirk_finalize(vdev, i); - vfio_region_finalize(&vdev->bars[i].region); + vfio_region_finalize(&bar->region); + if (bar->size) { + object_unparent(OBJECT(bar->mr)); + g_free(bar->mr); + } } if (vdev->vga) { @@ -2734,6 +2871,8 @@ static void vfio_realize(PCIDevice *pdev, Error **errp) /* QEMU can choose to expose the ROM or not */ memset(vdev->emulated_config_bits + PCI_ROM_ADDRESS, 0xff, 4); + /* QEMU can also add or extend BARs */ + memset(vdev->emulated_config_bits + PCI_BASE_ADDRESS_0, 0xff, 6 * 4); /* * The PCI spec reserves vendor ID 0xffff as an invalid value. The @@ -2804,13 +2943,15 @@ static void vfio_realize(PCIDevice *pdev, Error **errp) vfio_pci_size_rom(vdev); + vfio_bars_prepare(vdev); + vfio_msix_early_setup(vdev, &err); if (err) { error_propagate(errp, err); goto error; } - vfio_bars_setup(vdev); + vfio_bars_register(vdev); ret = vfio_add_capabilities(vdev, errp); if (ret) { @@ -2989,6 +3130,8 @@ static Property vfio_pci_dev_properties[] = { DEFINE_PROP_BOOL("x-no-kvm-intx", VFIOPCIDevice, no_kvm_intx, false), DEFINE_PROP_BOOL("x-no-kvm-msi", VFIOPCIDevice, no_kvm_msi, false), DEFINE_PROP_BOOL("x-no-kvm-msix", VFIOPCIDevice, no_kvm_msix, false), + DEFINE_PROP_BOOL("x-no-geforce-quirks", VFIOPCIDevice, + no_geforce_quirks, false), DEFINE_PROP_UINT32("x-pci-vendor-id", VFIOPCIDevice, vendor_id, PCI_ANY_ID), DEFINE_PROP_UINT32("x-pci-device-id", VFIOPCIDevice, device_id, PCI_ANY_ID), DEFINE_PROP_UINT32("x-pci-sub-vendor-id", VFIOPCIDevice, @@ -2999,6 +3142,8 @@ static Property vfio_pci_dev_properties[] = { DEFINE_PROP_UNSIGNED_NODEFAULT("x-nv-gpudirect-clique", VFIOPCIDevice, nv_gpudirect_clique, qdev_prop_nv_gpudirect_clique, uint8_t), + DEFINE_PROP_OFF_AUTO_PCIBAR("x-msix-relocation", VFIOPCIDevice, msix_relo, + OFF_AUTOPCIBAR_OFF), /* * TODO - support passed fds... is this necessary? * DEFINE_PROP_STRING("vfiofd", VFIOPCIDevice, vfiofd_name), diff --git a/hw/vfio/pci.h b/hw/vfio/pci.h index a8fb3b3422..f4aa13e021 100644 --- a/hw/vfio/pci.h +++ b/hw/vfio/pci.h @@ -33,6 +33,9 @@ typedef struct VFIOQuirk { typedef struct VFIOBAR { VFIORegion region; + MemoryRegion *mr; + size_t size; + uint8_t type; bool ioport; bool mem64; QLIST_HEAD(, VFIOQuirk) quirks; @@ -86,7 +89,7 @@ enum { VFIO_INT_MSIX = 3, }; -/* Cache of MSI-X setup plus extra mmap and memory region for split BAR map */ +/* Cache of MSI-X setup */ typedef struct VFIOMSIXInfo { uint8_t table_bar; uint8_t pba_bar; @@ -132,6 +135,7 @@ typedef struct VFIOPCIDevice { (1 << VFIO_FEATURE_ENABLE_IGD_OPREGION_BIT) int32_t bootindex; uint32_t igd_gms; + OffAutoPCIBAR msix_relo; uint8_t pm_cap; uint8_t nv_gpudirect_clique; bool pci_aer; @@ -142,6 +146,7 @@ typedef struct VFIOPCIDevice { bool no_kvm_intx; bool no_kvm_msi; bool no_kvm_msix; + bool no_geforce_quirks; } VFIOPCIDevice; uint32_t vfio_pci_read_config(PCIDevice *pdev, uint32_t addr, int len); diff --git a/hw/vfio/platform.c b/hw/vfio/platform.c index da84abf4fc..0d4bc0aae8 100644 --- a/hw/vfio/platform.c +++ b/hw/vfio/platform.c @@ -643,6 +643,8 @@ static void vfio_platform_realize(DeviceState *dev, Error **errp) vbasedev->dev = dev; vbasedev->ops = &vfio_platform_ops; + qemu_mutex_init(&vdev->intp_mutex); + trace_vfio_platform_realize(vbasedev->sysfsdev ? vbasedev->sysfsdev : vbasedev->name, vdev->compat); diff --git a/hw/vfio/trace-events b/hw/vfio/trace-events index fae096c072..79f63a2ff6 100644 --- a/hw/vfio/trace-events +++ b/hw/vfio/trace-events @@ -16,6 +16,8 @@ vfio_msix_pba_disable(const char *name) " (%s)" vfio_msix_pba_enable(const char *name) " (%s)" vfio_msix_disable(const char *name) " (%s)" vfio_msix_fixup(const char *name, int bar, uint64_t start, uint64_t end) " (%s) MSI-X region %d mmap fixup [0x%"PRIx64" - 0x%"PRIx64"]" +vfio_msix_relo_cost(const char *name, int bar, uint64_t cost) " (%s) BAR %d cost 0x%"PRIx64"" +vfio_msix_relo(const char *name, int bar, uint64_t offset) " (%s) BAR %d offset 0x%"PRIx64"" vfio_msi_enable(const char *name, int nr_vectors) " (%s) Enabled %d MSI vectors" vfio_msi_disable(const char *name) " (%s)" vfio_pci_load_rom(const char *name, unsigned long size, unsigned long offset, unsigned long flags) "Device %s ROM:\n size: 0x%lx, offset: 0x%lx, flags: 0x%lx" @@ -123,3 +125,4 @@ vfio_prereg_register(uint64_t va, uint64_t size, int ret) "va=0x%"PRIx64" size=0 vfio_prereg_unregister(uint64_t va, uint64_t size, int ret) "va=0x%"PRIx64" size=0x%"PRIx64" ret=%d" vfio_spapr_create_window(int ps, uint64_t ws, uint64_t off) "pageshift=0x%x winsize=0x%"PRIx64" offset=0x%"PRIx64 vfio_spapr_remove_window(uint64_t off) "offset=0x%"PRIx64 +vfio_spapr_group_attach(int groupfd, int tablefd) "Attached groupfd %d to liobn fd %d" diff --git a/hw/virtio/trace-events b/hw/virtio/trace-events index 775461ae98..2b8f81eb25 100644 --- a/hw/virtio/trace-events +++ b/hw/virtio/trace-events @@ -25,3 +25,9 @@ virtio_balloon_handle_output(const char *name, uint64_t gpa) "section name: %s g virtio_balloon_get_config(uint32_t num_pages, uint32_t actual) "num_pages: %d actual: %d" virtio_balloon_set_config(uint32_t actual, uint32_t oldactual) "actual: %d oldactual: %d" virtio_balloon_to_target(uint64_t target, uint32_t num_pages) "balloon target: 0x%"PRIx64" num_pages: %d" + +# hw/virtio/vhost.c +vhost_region_add(void *p, const char *mr) "dev %p mr %s" +vhost_region_del(void *p, const char *mr) "dev %p mr %s" +vhost_iommu_region_add(void *p, const char *mr) "dev %p mr %s" +vhost_iommu_region_del(void *p, const char *mr) "dev %p mr %s" diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c index 386aef85be..338e4395b7 100644 --- a/hw/virtio/vhost.c +++ b/hw/virtio/vhost.c @@ -27,6 +27,7 @@ #include "hw/virtio/virtio-access.h" #include "migration/blocker.h" #include "sysemu/dma.h" +#include "trace.h" /* enabled until disconnected backend stabilizes */ #define _VHOST_DEBUG 1 @@ -329,6 +330,7 @@ static uint64_t vhost_get_log_size(struct vhost_dev *dev) static struct vhost_log *vhost_log_alloc(uint64_t size, bool share) { + Error *err = NULL; struct vhost_log *log; uint64_t logsize = size * sizeof(*(log->log)); int fd = -1; @@ -337,7 +339,12 @@ static struct vhost_log *vhost_log_alloc(uint64_t size, bool share) if (share) { log->log = qemu_memfd_alloc("vhost-log", logsize, F_SEAL_GROW | F_SEAL_SHRINK | F_SEAL_SEAL, - &fd); + &fd, &err); + if (err) { + error_report_err(err); + g_free(log); + return NULL; + } memset(log->log, 0, logsize); } else { log->log = g_malloc0(logsize); @@ -687,6 +694,7 @@ static void vhost_region_add(MemoryListener *listener, return; } + trace_vhost_region_add(dev, section->mr->name ?: NULL); ++dev->n_mem_sections; dev->mem_sections = g_renew(MemoryRegionSection, dev->mem_sections, dev->n_mem_sections); @@ -706,6 +714,7 @@ static void vhost_region_del(MemoryListener *listener, return; } + trace_vhost_region_del(dev, section->mr->name ?: NULL); vhost_set_memory(listener, section, false); memory_region_unref(section->mr); for (i = 0; i < dev->n_mem_sections; ++i) { @@ -743,6 +752,8 @@ static void vhost_iommu_region_add(MemoryListener *listener, return; } + trace_vhost_iommu_region_add(dev, section->mr->name ?: NULL); + iommu = g_malloc0(sizeof(*iommu)); end = int128_add(int128_make64(section->offset_within_region), section->size); @@ -771,6 +782,8 @@ static void vhost_iommu_region_del(MemoryListener *listener, return; } + trace_vhost_iommu_region_del(dev, section->mr->name ?: NULL); + QLIST_FOREACH(iommu, &dev->iommu_list, iommu_next) { if (iommu->mr == section->mr && iommu->n.start == section->offset_within_region) { @@ -1361,10 +1374,6 @@ void vhost_dev_cleanup(struct vhost_dev *hdev) if (hdev->mem) { /* those are only safe after successful init */ memory_listener_unregister(&hdev->memory_listener); - for (i = 0; i < hdev->n_mem_sections; ++i) { - MemoryRegionSection *section = &hdev->mem_sections[i]; - memory_region_unref(section->mr); - } QLIST_REMOVE(hdev, entry); } if (hdev->migration_blocker) { diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c index 9ae10f0cdd..c20537f31d 100644 --- a/hw/virtio/virtio-pci.c +++ b/hw/virtio/virtio-pci.c @@ -1907,8 +1907,8 @@ static void virtio_pci_class_init(ObjectClass *klass, void *data) k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET; k->revision = VIRTIO_PCI_ABI_VERSION; k->class_id = PCI_CLASS_OTHERS; - vpciklass->parent_dc_realize = dc->realize; - dc->realize = virtio_pci_dc_realize; + device_class_set_parent_realize(dc, virtio_pci_dc_realize, + &vpciklass->parent_dc_realize); dc->reset = virtio_pci_reset; } diff --git a/hw/xen/xen-common.c b/hw/xen/xen-common.c index 632a938dcc..afa1e3f404 100644 --- a/hw/xen/xen-common.c +++ b/hw/xen/xen-common.c @@ -9,6 +9,7 @@ */ #include "qemu/osdep.h" +#include "qemu/error-report.h" #include "hw/xen/xen_backend.h" #include "qmp-commands.h" #include "chardev/char.h" @@ -96,13 +97,13 @@ static void xenstore_record_dm_state(struct xs_handle *xs, const char *state) char path[50]; if (xs == NULL) { - fprintf(stderr, "xenstore connection not initialized\n"); + error_report("xenstore connection not initialized"); exit(1); } snprintf(path, sizeof (path), "device-model/%u/state", xen_domid); if (!xs_write(xs, XBT_NULL, path, state, strlen(state))) { - fprintf(stderr, "error recording dm state\n"); + error_report("error recording dm state"); exit(1); } } diff --git a/hw/xenpv/xen_machine_pv.c b/hw/xenpv/xen_machine_pv.c index 69a52a9f93..44d67b87c4 100644 --- a/hw/xenpv/xen_machine_pv.c +++ b/hw/xenpv/xen_machine_pv.c @@ -23,6 +23,7 @@ */ #include "qemu/osdep.h" +#include "qemu/error-report.h" #include "hw/hw.h" #include "hw/boards.h" #include "hw/xen/xen_backend.h" @@ -36,7 +37,7 @@ static void xen_init_pv(MachineState *machine) /* Initialize backend core & drivers */ if (xen_be_init() != 0) { - fprintf(stderr, "%s: xen backend core setup failed\n", __func__); + error_report("%s: xen backend core setup failed", __func__); exit(1); } @@ -51,18 +52,18 @@ static void xen_init_pv(MachineState *machine) const char *initrd_filename = machine->initrd_filename; if (xen_domain_build_pv(kernel_filename, initrd_filename, kernel_cmdline) < 0) { - fprintf(stderr, "xen pv domain creation failed\n"); + error_report("xen pv domain creation failed"); exit(1); } break; } #endif case XEN_EMULATE: - fprintf(stderr, "xen emulation not implemented (yet)\n"); + error_report("xen emulation not implemented (yet)"); exit(1); break; default: - fprintf(stderr, "unhandled xen_mode %d\n", xen_mode); + error_report("unhandled xen_mode %d", xen_mode); exit(1); break; } diff --git a/include/exec/memory-internal.h b/include/exec/memory-internal.h index 98d82964cc..4162474fd5 100644 --- a/include/exec/memory-internal.h +++ b/include/exec/memory-internal.h @@ -1,5 +1,5 @@ /* - * Declarations for obsolete exec.c functions + * Declarations for functions which are internal to the memory subsystem. * * Copyright 2011 Red Hat, Inc. and/or its affiliates * @@ -12,8 +12,9 @@ */ /* - * This header is for use by exec.c and memory.c ONLY. Do not include it. - * The functions declared here will be removed soon. + * This header is for use by exec.c, memory.c and accel/tcg/cputlb.c ONLY, + * for declarations which are shared between the memory subsystem's + * internals and the TCG TLB code. Do not include it from elsewhere. */ #ifndef MEMORY_INTERNAL_H diff --git a/include/exec/memory.h b/include/exec/memory.h index 07c5d6d597..783ef64570 100644 --- a/include/exec/memory.h +++ b/include/exec/memory.h @@ -190,6 +190,10 @@ struct MemoryRegionOps { const MemoryRegionMmio old_mmio; }; +enum IOMMUMemoryRegionAttr { + IOMMU_ATTR_SPAPR_TCE_FD +}; + typedef struct IOMMUMemoryRegionClass { /* private */ struct DeviceClass parent_class; @@ -210,6 +214,10 @@ typedef struct IOMMUMemoryRegionClass { IOMMUNotifierFlag new_flags); /* Set this up to provide customized IOMMU replay function */ void (*replay)(IOMMUMemoryRegion *iommu, IOMMUNotifier *notifier); + + /* Get IOMMU misc attributes */ + int (*get_attr)(IOMMUMemoryRegion *iommu, enum IOMMUMemoryRegionAttr, + void *data); } IOMMUMemoryRegionClass; typedef struct CoalescedMemoryRange CoalescedMemoryRange; @@ -324,7 +332,7 @@ FlatView *address_space_to_flatview(AddressSpace *as); * MemoryRegionSection: describes a fragment of a #MemoryRegion * * @mr: the region, or %NULL if empty - * @address_space: the address space the region is mapped in + * @fv: the flat view of the address space the region is mapped in * @offset_within_region: the beginning of the section, relative to @mr's start * @size: the size of the section; will not exceed @mr's boundaries * @offset_within_address_space: the address of the first byte of the section @@ -610,6 +618,7 @@ void memory_region_init_rom_nomigrate(MemoryRegion *mr, * @mr: the #MemoryRegion to be initialized. * @owner: the object that tracks the region's reference count * @ops: callbacks for write access handling (must not be NULL). + * @opaque: passed to the read and write callbacks of the @ops structure. * @name: Region name, becomes part of RAMBlock name used in migration stream * must be unique within any device * @size: size of the region. @@ -653,11 +662,10 @@ static inline void memory_region_init_reservation(MemoryRegion *mr, * An IOMMU region translates addresses and forwards accesses to a target * memory region. * - * @typename: QOM class name * @_iommu_mr: the #IOMMUMemoryRegion to be initialized * @instance_size: the IOMMUMemoryRegion subclass instance size + * @mrtypename: the type name of the #IOMMUMemoryRegion * @owner: the object that tracks the region's reference count - * @ops: a function that translates addresses into the @target region * @name: used for debugging; not visible to the user or ABI * @size: size of the region. */ @@ -827,8 +835,8 @@ static inline IOMMUMemoryRegion *memory_region_get_iommu(MemoryRegion *mr) * memory_region_get_iommu_class_nocheck: returns iommu memory region class * if an iommu or NULL if not * - * Returns pointer to IOMMUMemoryRegioniClass if a memory region is an iommu, - * otherwise NULL. This is fast path avoinding QOM checking, use with caution. + * Returns pointer to IOMMUMemoryRegionClass if a memory region is an iommu, + * otherwise NULL. This is fast path avoiding QOM checking, use with caution. * * @mr: the memory region being queried */ @@ -927,6 +935,20 @@ void memory_region_unregister_iommu_notifier(MemoryRegion *mr, IOMMUNotifier *n); /** + * memory_region_iommu_get_attr: return an IOMMU attr if get_attr() is + * defined on the IOMMU. + * + * Returns 0 if succeded, error code otherwise. + * + * @iommu_mr: the memory region + * @attr: the requested attribute + * @data: a pointer to the requested attribute data + */ +int memory_region_iommu_get_attr(IOMMUMemoryRegion *iommu_mr, + enum IOMMUMemoryRegionAttr attr, + void *data); + +/** * memory_region_name: get a memory region's name * * Returns the string that was used to initialize the memory region. @@ -993,7 +1015,8 @@ int memory_region_get_fd(MemoryRegion *mr); * protecting the pointer, such as a reference to the region that includes * the incoming ram_addr_t. * - * @mr: the memory region being queried. + * @ptr: the host pointer to be converted + * @offset: the offset within memory region */ MemoryRegion *memory_region_from_host(void *ptr, ram_addr_t *offset); @@ -1270,7 +1293,7 @@ void memory_region_clear_global_locking(MemoryRegion *mr); * @size: the size of the access to trigger the eventfd * @match_data: whether to match against @data, instead of just @addr * @data: the data to match against the guest write - * @fd: the eventfd to be triggered when @addr, @size, and @data all match. + * @e: event notifier to be triggered when @addr, @size, and @data all match. **/ void memory_region_add_eventfd(MemoryRegion *mr, hwaddr addr, @@ -1290,7 +1313,7 @@ void memory_region_add_eventfd(MemoryRegion *mr, * @size: the size of the access to trigger the eventfd * @match_data: whether to match against @data, instead of just @addr * @data: the data to match against the guest write - * @fd: the eventfd to be triggered when @addr, @size, and @data all match. + * @e: event notifier to be triggered when @addr, @size, and @data all match. */ void memory_region_del_eventfd(MemoryRegion *mr, hwaddr addr, @@ -1526,7 +1549,7 @@ bool memory_region_request_mmio_ptr(MemoryRegion *mr, hwaddr addr); * will need to request the pointer again. * * @mr: #MemoryRegion associated to the pointer. - * @addr: address within that region + * @offset: offset within the memory region * @size: size of that area. */ void memory_region_invalidate_mmio_ptr(MemoryRegion *mr, hwaddr offset, @@ -1595,6 +1618,7 @@ void address_space_destroy(AddressSpace *as); * @addr: address within that address space * @attrs: memory transaction attributes * @buf: buffer with the data transferred + * @len: the number of bytes to read or write * @is_write: indicates the transfer direction */ MemTxResult address_space_rw(AddressSpace *as, hwaddr addr, @@ -1612,6 +1636,7 @@ MemTxResult address_space_rw(AddressSpace *as, hwaddr addr, * @addr: address within that address space * @attrs: memory transaction attributes * @buf: buffer with the data transferred + * @len: the number of bytes to write */ MemTxResult address_space_write(AddressSpace *as, hwaddr addr, MemTxAttrs attrs, @@ -1810,7 +1835,7 @@ IOMMUTLBEntry address_space_get_iotlb_entry(AddressSpace *as, hwaddr addr, * called from an RCU critical section, to avoid that the last reference * to the returned region disappears after address_space_translate returns. * - * @as: #AddressSpace to be accessed + * @fv: #FlatView to be accessed * @addr: address within that address space * @xlat: pointer to address within the returned memory region section's * #MemoryRegion. @@ -1868,7 +1893,7 @@ void *address_space_map(AddressSpace *as, hwaddr addr, * the amount of memory that was actually read or written by the caller. * * @as: #AddressSpace used - * @addr: address within that address space + * @buffer: host pointer as returned by address_space_map() * @len: buffer length as returned by address_space_map() * @access_len: amount of data actually transferred * @is_write: indicates the transfer direction @@ -1905,7 +1930,7 @@ static inline bool memory_access_is_direct(MemoryRegion *mr, bool is_write) * or failed (eg unassigned memory, device rejected the transaction, * IOMMU fault). * - * @as: #AddressSpace to be accessed + * @fv: #FlatView to be accessed * @addr: address within that address space * @attrs: memory transaction attributes * @buf: buffer with the data transferred diff --git a/include/hw/qdev-core.h b/include/hw/qdev-core.h index 51473eee7b..18c0251b40 100644 --- a/include/hw/qdev-core.h +++ b/include/hw/qdev-core.h @@ -32,9 +32,9 @@ typedef enum DeviceCategory { typedef int (*qdev_initfn)(DeviceState *dev); typedef int (*qdev_event)(DeviceState *dev); -typedef void (*qdev_resetfn)(DeviceState *dev); typedef void (*DeviceRealize)(DeviceState *dev, Error **errp); typedef void (*DeviceUnrealize)(DeviceState *dev, Error **errp); +typedef void (*DeviceReset)(DeviceState *dev); typedef void (*BusRealize)(BusState *bus, Error **errp); typedef void (*BusUnrealize)(BusState *bus, Error **errp); @@ -117,7 +117,7 @@ typedef struct DeviceClass { bool hotpluggable; /* callbacks */ - void (*reset)(DeviceState *dev); + DeviceReset reset; DeviceRealize realize; DeviceUnrealize unrealize; @@ -382,6 +382,16 @@ void qdev_machine_init(void); */ void device_reset(DeviceState *dev); +void device_class_set_parent_reset(DeviceClass *dc, + DeviceReset dev_reset, + DeviceReset *parent_reset); +void device_class_set_parent_realize(DeviceClass *dc, + DeviceRealize dev_realize, + DeviceRealize *parent_realize); +void device_class_set_parent_unrealize(DeviceClass *dc, + DeviceUnrealize dev_unrealize, + DeviceUnrealize *parent_unrealize); + const struct VMStateDescription *qdev_get_vmsd(DeviceState *dev); const char *qdev_fw_name(DeviceState *dev); diff --git a/include/hw/qdev-properties.h b/include/hw/qdev-properties.h index 5bbfec634b..1d61a35108 100644 --- a/include/hw/qdev-properties.h +++ b/include/hw/qdev-properties.h @@ -34,6 +34,7 @@ extern const PropertyInfo qdev_prop_pci_host_devaddr; extern const PropertyInfo qdev_prop_uuid; extern const PropertyInfo qdev_prop_arraylen; extern const PropertyInfo qdev_prop_link; +extern const PropertyInfo qdev_prop_off_auto_pcibar; #define DEFINE_PROP(_name, _state, _field, _prop, _type) { \ .name = (_name), \ @@ -214,6 +215,9 @@ extern const PropertyInfo qdev_prop_link; DEFINE_PROP(_n, _s, _f, qdev_prop_pci_host_devaddr, PCIHostDeviceAddress) #define DEFINE_PROP_MEMORY_REGION(_n, _s, _f) \ DEFINE_PROP(_n, _s, _f, qdev_prop_ptr, MemoryRegion *) +#define DEFINE_PROP_OFF_AUTO_PCIBAR(_n, _s, _f, _d) \ + DEFINE_PROP_SIGNED(_n, _s, _f, _d, qdev_prop_off_auto_pcibar, \ + OffAutoPCIBAR) #define DEFINE_PROP_UUID(_name, _state, _field) { \ .name = (_name), \ diff --git a/include/qapi/error.h b/include/qapi/error.h index 341b229066..c2115a6a4a 100644 --- a/include/qapi/error.h +++ b/include/qapi/error.h @@ -230,6 +230,12 @@ void error_prepend(Error **errp, const char *fmt, ...) /* * Append a printf-style human-readable explanation to an existing error. + * If the error is later reported to a human user with + * error_report_err() or warn_report_err(), the hints will be shown, + * too. If it's reported via QMP, the hints will be ignored. + * Intended use is adding helpful hints on the human user interface, + * e.g. a list of valid values. It's not for clarifying a confusing + * error message. * @errp may be NULL, but not &error_fatal or &error_abort. * Trivially the case if you call it only after error_setg() or * error_propagate(). @@ -267,11 +273,13 @@ void error_free_or_abort(Error **errp); /* * Convenience function to warn_report() and free @err. + * The report includes hints added with error_append_hint(). */ void warn_report_err(Error *err); /* * Convenience function to error_report() and free @err. + * The report includes hints added with error_append_hint(). */ void error_report_err(Error *err); diff --git a/include/qemu/compiler.h b/include/qemu/compiler.h index 340e5fdc09..5fcc4f7ec7 100644 --- a/include/qemu/compiler.h +++ b/include/qemu/compiler.h @@ -111,4 +111,8 @@ #define GCC_FMT_ATTR(n, m) #endif +#ifndef __has_feature +#define __has_feature(x) 0 /* compatibility with non-clang compilers */ +#endif + #endif /* COMPILER_H */ diff --git a/include/qemu/memfd.h b/include/qemu/memfd.h index 41c24d807c..de10198ed6 100644 --- a/include/qemu/memfd.h +++ b/include/qemu/memfd.h @@ -16,9 +16,10 @@ #define F_SEAL_WRITE 0x0008 /* prevent writes */ #endif -int qemu_memfd_create(const char *name, size_t size, unsigned int seals); +int qemu_memfd_create(const char *name, size_t size, bool hugetlb, + uint64_t hugetlbsize, unsigned int seals, Error **errp); void *qemu_memfd_alloc(const char *name, size_t size, unsigned int seals, - int *fd); + int *fd, Error **errp); void qemu_memfd_free(void *ptr, size_t size, int fd); bool qemu_memfd_check(void); diff --git a/include/qemu/processor.h b/include/qemu/processor.h index 8b2570283a..8e16c9277d 100644 --- a/include/qemu/processor.h +++ b/include/qemu/processor.h @@ -12,9 +12,6 @@ #if defined(__i386__) || defined(__x86_64__) # define cpu_relax() asm volatile("rep; nop" ::: "memory") -#elif defined(__ia64__) -# define cpu_relax() asm volatile("hint @pause" ::: "memory") - #elif defined(__aarch64__) # define cpu_relax() asm volatile("yield" ::: "memory") diff --git a/include/qemu/timer.h b/include/qemu/timer.h index 1b518bca30..3b5a54b014 100644 --- a/include/qemu/timer.h +++ b/include/qemu/timer.h @@ -931,15 +931,6 @@ static inline int64_t cpu_get_host_ticks(void) return val; } -#elif defined(__ia64) - -static inline int64_t cpu_get_host_ticks(void) -{ - int64_t val; - asm volatile ("mov %0 = ar.itc" : "=r"(val) :: "memory"); - return val; -} - #elif defined(__s390__) static inline int64_t cpu_get_host_ticks(void) diff --git a/include/sysemu/hw_accel.h b/include/sysemu/hw_accel.h index 469ffda460..d2ddfb5ad0 100644 --- a/include/sysemu/hw_accel.h +++ b/include/sysemu/hw_accel.h @@ -14,6 +14,7 @@ #include "qom/cpu.h" #include "sysemu/hax.h" #include "sysemu/kvm.h" +#include "sysemu/whpx.h" static inline void cpu_synchronize_state(CPUState *cpu) { @@ -23,6 +24,9 @@ static inline void cpu_synchronize_state(CPUState *cpu) if (hax_enabled()) { hax_cpu_synchronize_state(cpu); } + if (whpx_enabled()) { + whpx_cpu_synchronize_state(cpu); + } } static inline void cpu_synchronize_post_reset(CPUState *cpu) @@ -33,6 +37,9 @@ static inline void cpu_synchronize_post_reset(CPUState *cpu) if (hax_enabled()) { hax_cpu_synchronize_post_reset(cpu); } + if (whpx_enabled()) { + whpx_cpu_synchronize_post_reset(cpu); + } } static inline void cpu_synchronize_post_init(CPUState *cpu) @@ -43,6 +50,9 @@ static inline void cpu_synchronize_post_init(CPUState *cpu) if (hax_enabled()) { hax_cpu_synchronize_post_init(cpu); } + if (whpx_enabled()) { + whpx_cpu_synchronize_post_init(cpu); + } } static inline void cpu_synchronize_pre_loadvm(CPUState *cpu) @@ -53,6 +63,9 @@ static inline void cpu_synchronize_pre_loadvm(CPUState *cpu) if (hax_enabled()) { hax_cpu_synchronize_pre_loadvm(cpu); } + if (whpx_enabled()) { + whpx_cpu_synchronize_pre_loadvm(cpu); + } } #endif /* QEMU_HW_ACCEL_H */ diff --git a/include/sysemu/whpx.h b/include/sysemu/whpx.h new file mode 100644 index 0000000000..89592ae4fa --- /dev/null +++ b/include/sysemu/whpx.h @@ -0,0 +1,40 @@ +/* + * QEMU Windows Hypervisor Platform accelerator (WHPX) support + * + * Copyright Microsoft, Corp. 2017 + * + * Authors: + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + * + */ + +#ifndef QEMU_WHPX_H +#define QEMU_WHPX_H + +#include "config-host.h" +#include "qemu-common.h" + +int whpx_init_vcpu(CPUState *cpu); +int whpx_vcpu_exec(CPUState *cpu); +void whpx_destroy_vcpu(CPUState *cpu); +void whpx_vcpu_kick(CPUState *cpu); + + +void whpx_cpu_synchronize_state(CPUState *cpu); +void whpx_cpu_synchronize_post_reset(CPUState *cpu); +void whpx_cpu_synchronize_post_init(CPUState *cpu); +void whpx_cpu_synchronize_pre_loadvm(CPUState *cpu); + +#ifdef CONFIG_WHPX + +int whpx_enabled(void); + +#else /* CONFIG_WHPX */ + +#define whpx_enabled() (0) + +#endif /* CONFIG_WHPX */ + +#endif /* QEMU_WHPX_H */ diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 74378947f0..df1edf0cd3 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -36,10 +36,6 @@ #include <linux/capability.h> #include <sched.h> #include <sys/timex.h> -#ifdef __ia64__ -int __clone2(int (*fn)(void *), void *child_stack_base, - size_t stack_size, int flags, void *arg, ...); -#endif #include <sys/socket.h> #include <sys/un.h> #include <sys/uio.h> @@ -246,8 +242,7 @@ static type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5, \ #define __NR_sys_inotify_add_watch __NR_inotify_add_watch #define __NR_sys_inotify_rm_watch __NR_inotify_rm_watch -#if defined(__alpha__) || defined (__ia64__) || defined(__x86_64__) || \ - defined(__s390x__) +#if defined(__alpha__) || defined(__x86_64__) || defined(__s390x__) #define __NR__llseek __NR_lseek #endif @@ -1091,6 +1091,7 @@ void memory_region_transaction_commit(void) address_space_update_ioeventfds(as); } memory_region_update_pending = false; + ioeventfd_update_pending = false; MEMORY_LISTENER_CALL_GLOBAL(commit, Forward); } else if (ioeventfd_update_pending) { QTAILQ_FOREACH(as, &address_spaces, address_spaces_link) { @@ -1922,6 +1923,19 @@ void memory_region_notify_iommu(IOMMUMemoryRegion *iommu_mr, } } +int memory_region_iommu_get_attr(IOMMUMemoryRegion *iommu_mr, + enum IOMMUMemoryRegionAttr attr, + void *data) +{ + IOMMUMemoryRegionClass *imrc = IOMMU_MEMORY_REGION_GET_CLASS(iommu_mr); + + if (!imrc->get_attr) { + return -EINVAL; + } + + return imrc->get_attr(iommu_mr, attr, data); +} + void memory_region_set_log(MemoryRegion *mr, bool log, unsigned client) { uint8_t mask = 1 << client; @@ -2611,6 +2625,32 @@ static void listener_add_address_space(MemoryListener *listener, flatview_unref(view); } +static void listener_del_address_space(MemoryListener *listener, + AddressSpace *as) +{ + FlatView *view; + FlatRange *fr; + + if (listener->begin) { + listener->begin(listener); + } + view = address_space_get_flatview(as); + FOR_EACH_FLAT_RANGE(fr, view) { + MemoryRegionSection section = section_from_flat_range(fr, view); + + if (fr->dirty_log_mask && listener->log_stop) { + listener->log_stop(listener, §ion, fr->dirty_log_mask, 0); + } + if (listener->region_del) { + listener->region_del(listener, §ion); + } + } + if (listener->commit) { + listener->commit(listener); + } + flatview_unref(view); +} + void memory_listener_register(MemoryListener *listener, AddressSpace *as) { MemoryListener *other = NULL; @@ -2651,6 +2691,7 @@ void memory_listener_unregister(MemoryListener *listener) return; } + listener_del_address_space(listener, listener->address_space); QTAILQ_REMOVE(&memory_listeners, listener, link); QTAILQ_REMOVE(&listener->address_space->listeners, listener, link_as); listener->address_space = NULL; @@ -463,6 +463,7 @@ static void allocate_system_memory_nonnuma(MemoryRegion *mr, Object *owner, if (mem_prealloc) { exit(1); } + error_report("falling back to regular RAM allocation."); /* Legacy behavior: if allocation failed, fall back to * regular RAM allocation. diff --git a/qapi/common.json b/qapi/common.json index 6eb01821ef..d9b14dd429 100644 --- a/qapi/common.json +++ b/qapi/common.json @@ -100,3 +100,29 @@ { 'alternate': 'StrOrNull', 'data': { 's': 'str', 'n': 'null' } } + +## +# @OffAutoPCIBAR: +# +# An enumeration of options for specifying a PCI BAR +# +# @off: The specified feature is disabled +# +# @auto: The PCI BAR for the feature is automatically selected +# +# @bar0: PCI BAR0 is used for the feature +# +# @bar1: PCI BAR1 is used for the feature +# +# @bar2: PCI BAR2 is used for the feature +# +# @bar3: PCI BAR3 is used for the feature +# +# @bar4: PCI BAR4 is used for the feature +# +# @bar5: PCI BAR5 is used for the feature +# +# Since: 2.12 +## +{ 'enum': 'OffAutoPCIBAR', + 'data': [ 'off', 'auto', 'bar0', 'bar1', 'bar2', 'bar3', 'bar4', 'bar5' ] } diff --git a/qemu-options.hx b/qemu-options.hx index 8ce427da78..d15c1713d1 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -31,7 +31,7 @@ DEF("machine", HAS_ARG, QEMU_OPTION_machine, \ "-machine [type=]name[,prop[=value][,...]]\n" " selects emulated machine ('-machine help' for list)\n" " property accel=accel1[:accel2[:...]] selects accelerator\n" - " supported accelerators are kvm, xen, hax, hvf or tcg (default: tcg)\n" + " supported accelerators are kvm, xen, hax, hvf, whpx or tcg (default: tcg)\n" " kernel_irqchip=on|off|split controls accelerated irqchip support (default=off)\n" " vmport=on|off|auto controls emulation of vmport (default: auto)\n" " kvm_shadow_mem=size of KVM shadow MMU in bytes\n" @@ -66,7 +66,7 @@ Supported machine properties are: @table @option @item accel=@var{accels1}[:@var{accels2}[:...]] This is used to enable an accelerator. Depending on the target architecture, -kvm, xen, hax, hvf or tcg can be available. By default, tcg is used. If there is +kvm, xen, hax, hvf, whpx or tcg can be available. By default, tcg is used. If there is more than one accelerator specified, the next one is used if the previous one fails to initialize. @item kernel_irqchip=on|off @@ -126,13 +126,13 @@ ETEXI DEF("accel", HAS_ARG, QEMU_OPTION_accel, "-accel [accel=]accelerator[,thread=single|multi]\n" - " select accelerator (kvm, xen, hax, hvf or tcg; use 'help' for a list)\n" + " select accelerator (kvm, xen, hax, hvf, whpx or tcg; use 'help' for a list)\n" " thread=single|multi (enable multi-threaded TCG)", QEMU_ARCH_ALL) STEXI @item -accel @var{name}[,prop=@var{value}[,...]] @findex -accel This is used to enable an accelerator. Depending on the target architecture, -kvm, xen, hax, hvf or tcg can be available. By default, tcg is used. If there is +kvm, xen, hax, hvf, whpx or tcg can be available. By default, tcg is used. If there is more than one accelerator specified, the next one is used if the previous one fails to initialize. @table @option @@ -4024,6 +4024,28 @@ Memory backend objects offer more control than the @option{-m} option that is traditionally used to define guest RAM. Please refer to @option{memory-backend-file} for a description of the options. +@item -object memory-backend-memfd,id=@var{id},merge=@var{on|off},dump=@var{on|off},prealloc=@var{on|off},size=@var{size},host-nodes=@var{host-nodes},policy=@var{default|preferred|bind|interleave},seal=@var{on|off},hugetlb=@var{on|off},hugetlbsize=@var{size} + +Creates an anonymous memory file backend object, which allows QEMU to +share the memory with an external process (e.g. when using +vhost-user). The memory is allocated with memfd and optional +sealing. (Linux only) + +The @option{seal} option creates a sealed-file, that will block +further resizing the memory ('on' by default). + +The @option{hugetlb} option specify the file to be created resides in +the hugetlbfs filesystem (since Linux 4.14). Used in conjunction with +the @option{hugetlb} option, the @option{hugetlbsize} option specify +the hugetlb page size on systems that support multiple hugetlb page +sizes (it must be a power of 2 value supported by the system). + +In some versions of Linux, the @option{hugetlb} option is incompatible +with the @option{seal} option (requires at least Linux 4.16). + +Please refer to @option{memory-backend-file} for a description of the +other options. + @item -object rng-random,id=@var{id},filename=@var{/dev/random} Creates a random number generator backend which obtains entropy from diff --git a/scripts/qemugdb/timers.py b/scripts/qemugdb/timers.py index be71a001e3..51ea04b5e2 100644 --- a/scripts/qemugdb/timers.py +++ b/scripts/qemugdb/timers.py @@ -1,4 +1,5 @@ #!/usr/bin/python +# -*- coding: utf-8 -*- # GDB debugging support # # Copyright 2017 Linaro Ltd diff --git a/target/alpha/cpu.c b/target/alpha/cpu.c index 7d6366bae9..55675ce419 100644 --- a/target/alpha/cpu.c +++ b/target/alpha/cpu.c @@ -233,8 +233,8 @@ static void alpha_cpu_class_init(ObjectClass *oc, void *data) CPUClass *cc = CPU_CLASS(oc); AlphaCPUClass *acc = ALPHA_CPU_CLASS(oc); - acc->parent_realize = dc->realize; - dc->realize = alpha_cpu_realizefn; + device_class_set_parent_realize(dc, alpha_cpu_realizefn, + &acc->parent_realize); cc->class_by_name = alpha_cpu_class_by_name; cc->has_work = alpha_cpu_has_work; diff --git a/target/arm/cpu.c b/target/arm/cpu.c index 9da6ea505c..89ccdeae12 100644 --- a/target/arm/cpu.c +++ b/target/arm/cpu.c @@ -1722,8 +1722,8 @@ static void arm_cpu_class_init(ObjectClass *oc, void *data) CPUClass *cc = CPU_CLASS(acc); DeviceClass *dc = DEVICE_CLASS(oc); - acc->parent_realize = dc->realize; - dc->realize = arm_cpu_realizefn; + device_class_set_parent_realize(dc, arm_cpu_realizefn, + &acc->parent_realize); dc->props = arm_cpu_properties; acc->parent_reset = cc->reset; diff --git a/target/arm/kvm.c b/target/arm/kvm.c index 211a7bf7be..1219d0062b 100644 --- a/target/arm/kvm.c +++ b/target/arm/kvm.c @@ -266,7 +266,6 @@ static void kvm_arm_machine_init_done(Notifier *notifier, void *data) { KVMDevice *kd, *tkd; - memory_listener_unregister(&devlistener); QSLIST_FOREACH_SAFE(kd, &kvm_devices_head, entries, tkd) { if (kd->kda.addr != -1) { kvm_arm_set_device_addr(kd); @@ -274,6 +273,7 @@ static void kvm_arm_machine_init_done(Notifier *notifier, void *data) memory_region_unref(kd->mr); g_free(kd); } + memory_listener_unregister(&devlistener); } static Notifier notify = { diff --git a/target/cris/cpu.c b/target/cris/cpu.c index 949c7a6e25..db8d0884a1 100644 --- a/target/cris/cpu.c +++ b/target/cris/cpu.c @@ -260,8 +260,8 @@ static void cris_cpu_class_init(ObjectClass *oc, void *data) CPUClass *cc = CPU_CLASS(oc); CRISCPUClass *ccc = CRIS_CPU_CLASS(oc); - ccc->parent_realize = dc->realize; - dc->realize = cris_cpu_realizefn; + device_class_set_parent_realize(dc, cris_cpu_realizefn, + &ccc->parent_realize); ccc->parent_reset = cc->reset; cc->reset = cris_cpu_reset; diff --git a/target/hppa/cpu.c b/target/hppa/cpu.c index 5213347720..7b635cc4ac 100644 --- a/target/hppa/cpu.c +++ b/target/hppa/cpu.c @@ -168,8 +168,8 @@ static void hppa_cpu_class_init(ObjectClass *oc, void *data) CPUClass *cc = CPU_CLASS(oc); HPPACPUClass *acc = HPPA_CPU_CLASS(oc); - acc->parent_realize = dc->realize; - dc->realize = hppa_cpu_realizefn; + device_class_set_parent_realize(dc, hppa_cpu_realizefn, + &acc->parent_realize); cc->class_by_name = hppa_cpu_class_by_name; cc->has_work = hppa_cpu_has_work; diff --git a/target/i386/Makefile.objs b/target/i386/Makefile.objs index 44103a693b..f5c6ef20a7 100644 --- a/target/i386/Makefile.objs +++ b/target/i386/Makefile.objs @@ -14,3 +14,4 @@ ifdef CONFIG_DARWIN obj-$(CONFIG_HAX) += hax-all.o hax-mem.o hax-darwin.o obj-$(CONFIG_HVF) += hvf/ endif +obj-$(CONFIG_WHPX) += whpx-all.o diff --git a/target/i386/cpu.c b/target/i386/cpu.c index a49d2221ad..d70954b8b7 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -4705,10 +4705,10 @@ static void x86_cpu_common_class_init(ObjectClass *oc, void *data) CPUClass *cc = CPU_CLASS(oc); DeviceClass *dc = DEVICE_CLASS(oc); - xcc->parent_realize = dc->realize; - xcc->parent_unrealize = dc->unrealize; - dc->realize = x86_cpu_realizefn; - dc->unrealize = x86_cpu_unrealizefn; + device_class_set_parent_realize(dc, x86_cpu_realizefn, + &xcc->parent_realize); + device_class_set_parent_unrealize(dc, x86_cpu_unrealizefn, + &xcc->parent_unrealize); dc->props = x86_cpu_properties; xcc->parent_reset = cc->reset; diff --git a/target/i386/helper.c b/target/i386/helper.c index f63eb3d3f4..9fba146b7f 100644 --- a/target/i386/helper.c +++ b/target/i386/helper.c @@ -986,7 +986,7 @@ void cpu_report_tpr_access(CPUX86State *env, TPRAccess access) X86CPU *cpu = x86_env_get_cpu(env); CPUState *cs = CPU(cpu); - if (kvm_enabled()) { + if (kvm_enabled() || whpx_enabled()) { env->tpr_access_type = access; cpu_interrupt(cs, CPU_INTERRUPT_TPR); diff --git a/target/i386/hvf/hvf.c b/target/i386/hvf/hvf.c index 010866ed22..85e5964365 100644 --- a/target/i386/hvf/hvf.c +++ b/target/i386/hvf/hvf.c @@ -17,6 +17,33 @@ * * You should have received a copy of the GNU Lesser General Public * License along with this program; if not, see <http://www.gnu.org/licenses/>. + * + * This file contain code under public domain from the hvdos project: + * https://github.com/mist64/hvdos + * + * Parts Copyright (c) 2011 NetApp, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. */ #include "qemu/osdep.h" #include "qemu-common.h" diff --git a/target/i386/hvf/vmx.h b/target/i386/hvf/vmx.h index 9dfcd2f2eb..162a7d51ae 100644 --- a/target/i386/hvf/vmx.h +++ b/target/i386/hvf/vmx.h @@ -17,6 +17,9 @@ * * You should have received a copy of the GNU Lesser General Public * License along with this program; if not, see <http://www.gnu.org/licenses/>. + * + * This file contain code under public domain from the hvdos project: + * https://github.com/mist64/hvdos */ #ifndef VMX_H diff --git a/target/i386/whpx-all.c b/target/i386/whpx-all.c new file mode 100644 index 0000000000..0015b27509 --- /dev/null +++ b/target/i386/whpx-all.c @@ -0,0 +1,1366 @@ +/* + * QEMU Windows Hypervisor Platform accelerator (WHPX) + * + * Copyright Microsoft Corp. 2017 + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + * + */ + +#include "qemu/osdep.h" +#include "cpu.h" +#include "exec/address-spaces.h" +#include "exec/exec-all.h" +#include "exec/ioport.h" +#include "qemu-common.h" +#include "strings.h" +#include "sysemu/accel.h" +#include "sysemu/whpx.h" +#include "sysemu/sysemu.h" +#include "sysemu/cpus.h" +#include "qemu/main-loop.h" +#include "hw/boards.h" +#include "qemu/error-report.h" +#include "qemu/queue.h" +#include "qapi/error.h" +#include "migration/blocker.h" + +#include <winhvplatform.h> +#include <winhvemulation.h> + +struct whpx_state { + uint64_t mem_quota; + WHV_PARTITION_HANDLE partition; + uint32_t exit_ctx_size; +}; + +static const WHV_REGISTER_NAME whpx_register_names[] = { + + /* X64 General purpose registers */ + WHvX64RegisterRax, + WHvX64RegisterRcx, + WHvX64RegisterRdx, + WHvX64RegisterRbx, + WHvX64RegisterRsp, + WHvX64RegisterRbp, + WHvX64RegisterRsi, + WHvX64RegisterRdi, + WHvX64RegisterR8, + WHvX64RegisterR9, + WHvX64RegisterR10, + WHvX64RegisterR11, + WHvX64RegisterR12, + WHvX64RegisterR13, + WHvX64RegisterR14, + WHvX64RegisterR15, + WHvX64RegisterRip, + WHvX64RegisterRflags, + + /* X64 Segment registers */ + WHvX64RegisterEs, + WHvX64RegisterCs, + WHvX64RegisterSs, + WHvX64RegisterDs, + WHvX64RegisterFs, + WHvX64RegisterGs, + WHvX64RegisterLdtr, + WHvX64RegisterTr, + + /* X64 Table registers */ + WHvX64RegisterIdtr, + WHvX64RegisterGdtr, + + /* X64 Control Registers */ + WHvX64RegisterCr0, + WHvX64RegisterCr2, + WHvX64RegisterCr3, + WHvX64RegisterCr4, + WHvX64RegisterCr8, + + /* X64 Debug Registers */ + /* + * WHvX64RegisterDr0, + * WHvX64RegisterDr1, + * WHvX64RegisterDr2, + * WHvX64RegisterDr3, + * WHvX64RegisterDr6, + * WHvX64RegisterDr7, + */ + + /* X64 Floating Point and Vector Registers */ + WHvX64RegisterXmm0, + WHvX64RegisterXmm1, + WHvX64RegisterXmm2, + WHvX64RegisterXmm3, + WHvX64RegisterXmm4, + WHvX64RegisterXmm5, + WHvX64RegisterXmm6, + WHvX64RegisterXmm7, + WHvX64RegisterXmm8, + WHvX64RegisterXmm9, + WHvX64RegisterXmm10, + WHvX64RegisterXmm11, + WHvX64RegisterXmm12, + WHvX64RegisterXmm13, + WHvX64RegisterXmm14, + WHvX64RegisterXmm15, + WHvX64RegisterFpMmx0, + WHvX64RegisterFpMmx1, + WHvX64RegisterFpMmx2, + WHvX64RegisterFpMmx3, + WHvX64RegisterFpMmx4, + WHvX64RegisterFpMmx5, + WHvX64RegisterFpMmx6, + WHvX64RegisterFpMmx7, + WHvX64RegisterFpControlStatus, + WHvX64RegisterXmmControlStatus, + + /* X64 MSRs */ + WHvX64RegisterTsc, + WHvX64RegisterEfer, +#ifdef TARGET_X86_64 + WHvX64RegisterKernelGsBase, +#endif + WHvX64RegisterApicBase, + /* WHvX64RegisterPat, */ + WHvX64RegisterSysenterCs, + WHvX64RegisterSysenterEip, + WHvX64RegisterSysenterEsp, + WHvX64RegisterStar, +#ifdef TARGET_X86_64 + WHvX64RegisterLstar, + WHvX64RegisterCstar, + WHvX64RegisterSfmask, +#endif + + /* Interrupt / Event Registers */ + /* + * WHvRegisterPendingInterruption, + * WHvRegisterInterruptState, + * WHvRegisterPendingEvent0, + * WHvRegisterPendingEvent1 + * WHvX64RegisterDeliverabilityNotifications, + */ +}; + +struct whpx_register_set { + WHV_REGISTER_VALUE values[RTL_NUMBER_OF(whpx_register_names)]; +}; + +struct whpx_vcpu { + WHV_EMULATOR_HANDLE emulator; + bool window_registered; + bool interruptable; + uint64_t tpr; + uint64_t apic_base; + WHV_X64_PENDING_INTERRUPTION_REGISTER interrupt_in_flight; + + /* Must be the last field as it may have a tail */ + WHV_RUN_VP_EXIT_CONTEXT exit_ctx; +}; + +static bool whpx_allowed; + +struct whpx_state whpx_global; + + +/* + * VP support + */ + +static struct whpx_vcpu *get_whpx_vcpu(CPUState *cpu) +{ + return (struct whpx_vcpu *)cpu->hax_vcpu; +} + +static WHV_X64_SEGMENT_REGISTER whpx_seg_q2h(const SegmentCache *qs, int v86, + int r86) +{ + WHV_X64_SEGMENT_REGISTER hs; + unsigned flags = qs->flags; + + hs.Base = qs->base; + hs.Limit = qs->limit; + hs.Selector = qs->selector; + + if (v86) { + hs.Attributes = 0; + hs.SegmentType = 3; + hs.Present = 1; + hs.DescriptorPrivilegeLevel = 3; + hs.NonSystemSegment = 1; + + } else { + hs.Attributes = (flags >> DESC_TYPE_SHIFT); + + if (r86) { + /* hs.Base &= 0xfffff; */ + } + } + + return hs; +} + +static SegmentCache whpx_seg_h2q(const WHV_X64_SEGMENT_REGISTER *hs) +{ + SegmentCache qs; + + qs.base = hs->Base; + qs.limit = hs->Limit; + qs.selector = hs->Selector; + + qs.flags = ((uint32_t)hs->Attributes) << DESC_TYPE_SHIFT; + + return qs; +} + +static void whpx_set_registers(CPUState *cpu) +{ + struct whpx_state *whpx = &whpx_global; + struct whpx_vcpu *vcpu = get_whpx_vcpu(cpu); + struct CPUX86State *env = (CPUArchState *)(cpu->env_ptr); + X86CPU *x86_cpu = X86_CPU(cpu); + struct whpx_register_set vcxt = {0}; + HRESULT hr; + int idx = 0; + int i; + int v86, r86; + + assert(cpu_is_stopped(cpu) || qemu_cpu_is_self(cpu)); + + v86 = (env->eflags & VM_MASK); + r86 = !(env->cr[0] & CR0_PE_MASK); + + vcpu->tpr = cpu_get_apic_tpr(x86_cpu->apic_state); + vcpu->apic_base = cpu_get_apic_base(x86_cpu->apic_state); + + /* Indexes for first 16 registers match between HV and QEMU definitions */ + for (idx = 0; idx < CPU_NB_REGS64; idx += 1) { + vcxt.values[idx].Reg64 = env->regs[idx]; + } + + /* Same goes for RIP and RFLAGS */ + assert(whpx_register_names[idx] == WHvX64RegisterRip); + vcxt.values[idx++].Reg64 = env->eip; + + assert(whpx_register_names[idx] == WHvX64RegisterRflags); + vcxt.values[idx++].Reg64 = env->eflags; + + /* Translate 6+4 segment registers. HV and QEMU order matches */ + assert(idx == WHvX64RegisterEs); + for (i = 0; i < 6; i += 1, idx += 1) { + vcxt.values[idx].Segment = whpx_seg_q2h(&env->segs[i], v86, r86); + } + + assert(idx == WHvX64RegisterLdtr); + vcxt.values[idx++].Segment = whpx_seg_q2h(&env->ldt, 0, 0); + + assert(idx == WHvX64RegisterTr); + vcxt.values[idx++].Segment = whpx_seg_q2h(&env->tr, 0, 0); + + assert(idx == WHvX64RegisterIdtr); + vcxt.values[idx].Table.Base = env->idt.base; + vcxt.values[idx].Table.Limit = env->idt.limit; + idx += 1; + + assert(idx == WHvX64RegisterGdtr); + vcxt.values[idx].Table.Base = env->gdt.base; + vcxt.values[idx].Table.Limit = env->gdt.limit; + idx += 1; + + /* CR0, 2, 3, 4, 8 */ + assert(whpx_register_names[idx] == WHvX64RegisterCr0); + vcxt.values[idx++].Reg64 = env->cr[0]; + assert(whpx_register_names[idx] == WHvX64RegisterCr2); + vcxt.values[idx++].Reg64 = env->cr[2]; + assert(whpx_register_names[idx] == WHvX64RegisterCr3); + vcxt.values[idx++].Reg64 = env->cr[3]; + assert(whpx_register_names[idx] == WHvX64RegisterCr4); + vcxt.values[idx++].Reg64 = env->cr[4]; + assert(whpx_register_names[idx] == WHvX64RegisterCr8); + vcxt.values[idx++].Reg64 = vcpu->tpr; + + /* 8 Debug Registers - Skipped */ + + /* 16 XMM registers */ + assert(whpx_register_names[idx] == WHvX64RegisterXmm0); + for (i = 0; i < 16; i += 1, idx += 1) { + vcxt.values[idx].Reg128.Low64 = env->xmm_regs[i].ZMM_Q(0); + vcxt.values[idx].Reg128.High64 = env->xmm_regs[i].ZMM_Q(1); + } + + /* 8 FP registers */ + assert(whpx_register_names[idx] == WHvX64RegisterFpMmx0); + for (i = 0; i < 8; i += 1, idx += 1) { + vcxt.values[idx].Fp.AsUINT128.Low64 = env->fpregs[i].mmx.MMX_Q(0); + /* vcxt.values[idx].Fp.AsUINT128.High64 = + env->fpregs[i].mmx.MMX_Q(1); + */ + } + + /* FP control status register */ + assert(whpx_register_names[idx] == WHvX64RegisterFpControlStatus); + vcxt.values[idx].FpControlStatus.FpControl = env->fpuc; + vcxt.values[idx].FpControlStatus.FpStatus = + (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11; + vcxt.values[idx].FpControlStatus.FpTag = 0; + for (i = 0; i < 8; ++i) { + vcxt.values[idx].FpControlStatus.FpTag |= (!env->fptags[i]) << i; + } + vcxt.values[idx].FpControlStatus.Reserved = 0; + vcxt.values[idx].FpControlStatus.LastFpOp = env->fpop; + vcxt.values[idx].FpControlStatus.LastFpRip = env->fpip; + idx += 1; + + /* XMM control status register */ + assert(whpx_register_names[idx] == WHvX64RegisterXmmControlStatus); + vcxt.values[idx].XmmControlStatus.LastFpRdp = 0; + vcxt.values[idx].XmmControlStatus.XmmStatusControl = env->mxcsr; + vcxt.values[idx].XmmControlStatus.XmmStatusControlMask = 0x0000ffff; + idx += 1; + + /* MSRs */ + assert(whpx_register_names[idx] == WHvX64RegisterTsc); + vcxt.values[idx++].Reg64 = env->tsc; + assert(whpx_register_names[idx] == WHvX64RegisterEfer); + vcxt.values[idx++].Reg64 = env->efer; +#ifdef TARGET_X86_64 + assert(whpx_register_names[idx] == WHvX64RegisterKernelGsBase); + vcxt.values[idx++].Reg64 = env->kernelgsbase; +#endif + + assert(whpx_register_names[idx] == WHvX64RegisterApicBase); + vcxt.values[idx++].Reg64 = vcpu->apic_base; + + /* WHvX64RegisterPat - Skipped */ + + assert(whpx_register_names[idx] == WHvX64RegisterSysenterCs); + vcxt.values[idx++].Reg64 = env->sysenter_cs; + assert(whpx_register_names[idx] == WHvX64RegisterSysenterEip); + vcxt.values[idx++].Reg64 = env->sysenter_eip; + assert(whpx_register_names[idx] == WHvX64RegisterSysenterEsp); + vcxt.values[idx++].Reg64 = env->sysenter_esp; + assert(whpx_register_names[idx] == WHvX64RegisterStar); + vcxt.values[idx++].Reg64 = env->star; +#ifdef TARGET_X86_64 + assert(whpx_register_names[idx] == WHvX64RegisterLstar); + vcxt.values[idx++].Reg64 = env->lstar; + assert(whpx_register_names[idx] == WHvX64RegisterCstar); + vcxt.values[idx++].Reg64 = env->cstar; + assert(whpx_register_names[idx] == WHvX64RegisterSfmask); + vcxt.values[idx++].Reg64 = env->fmask; +#endif + + /* Interrupt / Event Registers - Skipped */ + + assert(idx == RTL_NUMBER_OF(whpx_register_names)); + + hr = WHvSetVirtualProcessorRegisters(whpx->partition, cpu->cpu_index, + whpx_register_names, + RTL_NUMBER_OF(whpx_register_names), + &vcxt.values[0]); + + if (FAILED(hr)) { + error_report("WHPX: Failed to set virtual processor context, hr=%08lx", + hr); + __debugbreak(); + } + + return; +} + +static void whpx_get_registers(CPUState *cpu) +{ + struct whpx_state *whpx = &whpx_global; + struct whpx_vcpu *vcpu = get_whpx_vcpu(cpu); + struct CPUX86State *env = (CPUArchState *)(cpu->env_ptr); + X86CPU *x86_cpu = X86_CPU(cpu); + struct whpx_register_set vcxt; + uint64_t tpr, apic_base; + HRESULT hr; + int idx = 0; + int i; + + assert(cpu_is_stopped(cpu) || qemu_cpu_is_self(cpu)); + + hr = WHvGetVirtualProcessorRegisters(whpx->partition, cpu->cpu_index, + whpx_register_names, + RTL_NUMBER_OF(whpx_register_names), + &vcxt.values[0]); + if (FAILED(hr)) { + error_report("WHPX: Failed to get virtual processor context, hr=%08lx", + hr); + __debugbreak(); + } + + /* Indexes for first 16 registers match between HV and QEMU definitions */ + for (idx = 0; idx < CPU_NB_REGS64; idx += 1) { + env->regs[idx] = vcxt.values[idx].Reg64; + } + + /* Same goes for RIP and RFLAGS */ + assert(whpx_register_names[idx] == WHvX64RegisterRip); + env->eip = vcxt.values[idx++].Reg64; + assert(whpx_register_names[idx] == WHvX64RegisterRflags); + env->eflags = vcxt.values[idx++].Reg64; + + /* Translate 6+4 segment registers. HV and QEMU order matches */ + assert(idx == WHvX64RegisterEs); + for (i = 0; i < 6; i += 1, idx += 1) { + env->segs[i] = whpx_seg_h2q(&vcxt.values[idx].Segment); + } + + assert(idx == WHvX64RegisterLdtr); + env->ldt = whpx_seg_h2q(&vcxt.values[idx++].Segment); + assert(idx == WHvX64RegisterTr); + env->tr = whpx_seg_h2q(&vcxt.values[idx++].Segment); + assert(idx == WHvX64RegisterIdtr); + env->idt.base = vcxt.values[idx].Table.Base; + env->idt.limit = vcxt.values[idx].Table.Limit; + idx += 1; + assert(idx == WHvX64RegisterGdtr); + env->gdt.base = vcxt.values[idx].Table.Base; + env->gdt.limit = vcxt.values[idx].Table.Limit; + idx += 1; + + /* CR0, 2, 3, 4, 8 */ + assert(whpx_register_names[idx] == WHvX64RegisterCr0); + env->cr[0] = vcxt.values[idx++].Reg64; + assert(whpx_register_names[idx] == WHvX64RegisterCr2); + env->cr[2] = vcxt.values[idx++].Reg64; + assert(whpx_register_names[idx] == WHvX64RegisterCr3); + env->cr[3] = vcxt.values[idx++].Reg64; + assert(whpx_register_names[idx] == WHvX64RegisterCr4); + env->cr[4] = vcxt.values[idx++].Reg64; + assert(whpx_register_names[idx] == WHvX64RegisterCr8); + tpr = vcxt.values[idx++].Reg64; + if (tpr != vcpu->tpr) { + vcpu->tpr = tpr; + cpu_set_apic_tpr(x86_cpu->apic_state, tpr); + } + + /* 8 Debug Registers - Skipped */ + + /* 16 XMM registers */ + assert(whpx_register_names[idx] == WHvX64RegisterXmm0); + for (i = 0; i < 16; i += 1, idx += 1) { + env->xmm_regs[i].ZMM_Q(0) = vcxt.values[idx].Reg128.Low64; + env->xmm_regs[i].ZMM_Q(1) = vcxt.values[idx].Reg128.High64; + } + + /* 8 FP registers */ + assert(whpx_register_names[idx] == WHvX64RegisterFpMmx0); + for (i = 0; i < 8; i += 1, idx += 1) { + env->fpregs[i].mmx.MMX_Q(0) = vcxt.values[idx].Fp.AsUINT128.Low64; + /* env->fpregs[i].mmx.MMX_Q(1) = + vcxt.values[idx].Fp.AsUINT128.High64; + */ + } + + /* FP control status register */ + assert(whpx_register_names[idx] == WHvX64RegisterFpControlStatus); + env->fpuc = vcxt.values[idx].FpControlStatus.FpControl; + env->fpstt = (vcxt.values[idx].FpControlStatus.FpStatus >> 11) & 0x7; + env->fpus = vcxt.values[idx].FpControlStatus.FpStatus & ~0x3800; + for (i = 0; i < 8; ++i) { + env->fptags[i] = !((vcxt.values[idx].FpControlStatus.FpTag >> i) & 1); + } + env->fpop = vcxt.values[idx].FpControlStatus.LastFpOp; + env->fpip = vcxt.values[idx].FpControlStatus.LastFpRip; + idx += 1; + + /* XMM control status register */ + assert(whpx_register_names[idx] == WHvX64RegisterXmmControlStatus); + env->mxcsr = vcxt.values[idx].XmmControlStatus.XmmStatusControl; + idx += 1; + + /* MSRs */ + assert(whpx_register_names[idx] == WHvX64RegisterTsc); + env->tsc = vcxt.values[idx++].Reg64; + assert(whpx_register_names[idx] == WHvX64RegisterEfer); + env->efer = vcxt.values[idx++].Reg64; +#ifdef TARGET_X86_64 + assert(whpx_register_names[idx] == WHvX64RegisterKernelGsBase); + env->kernelgsbase = vcxt.values[idx++].Reg64; +#endif + + assert(whpx_register_names[idx] == WHvX64RegisterApicBase); + apic_base = vcxt.values[idx++].Reg64; + if (apic_base != vcpu->apic_base) { + vcpu->apic_base = apic_base; + cpu_set_apic_base(x86_cpu->apic_state, vcpu->apic_base); + } + + /* WHvX64RegisterPat - Skipped */ + + assert(whpx_register_names[idx] == WHvX64RegisterSysenterCs); + env->sysenter_cs = vcxt.values[idx++].Reg64;; + assert(whpx_register_names[idx] == WHvX64RegisterSysenterEip); + env->sysenter_eip = vcxt.values[idx++].Reg64; + assert(whpx_register_names[idx] == WHvX64RegisterSysenterEsp); + env->sysenter_esp = vcxt.values[idx++].Reg64; + assert(whpx_register_names[idx] == WHvX64RegisterStar); + env->star = vcxt.values[idx++].Reg64; +#ifdef TARGET_X86_64 + assert(whpx_register_names[idx] == WHvX64RegisterLstar); + env->lstar = vcxt.values[idx++].Reg64; + assert(whpx_register_names[idx] == WHvX64RegisterCstar); + env->cstar = vcxt.values[idx++].Reg64; + assert(whpx_register_names[idx] == WHvX64RegisterSfmask); + env->fmask = vcxt.values[idx++].Reg64; +#endif + + /* Interrupt / Event Registers - Skipped */ + + assert(idx == RTL_NUMBER_OF(whpx_register_names)); + + return; +} + +static HRESULT CALLBACK whpx_emu_ioport_callback( + void *ctx, + WHV_EMULATOR_IO_ACCESS_INFO *IoAccess) +{ + MemTxAttrs attrs = { 0 }; + address_space_rw(&address_space_io, IoAccess->Port, attrs, + (uint8_t *)&IoAccess->Data, IoAccess->AccessSize, + IoAccess->Direction); + return S_OK; +} + +static HRESULT CALLBACK whpx_emu_memio_callback( + void *ctx, + WHV_EMULATOR_MEMORY_ACCESS_INFO *ma) +{ + cpu_physical_memory_rw(ma->GpaAddress, ma->Data, ma->AccessSize, + ma->Direction); + return S_OK; +} + +static HRESULT CALLBACK whpx_emu_getreg_callback( + void *ctx, + const WHV_REGISTER_NAME *RegisterNames, + UINT32 RegisterCount, + WHV_REGISTER_VALUE *RegisterValues) +{ + HRESULT hr; + struct whpx_state *whpx = &whpx_global; + CPUState *cpu = (CPUState *)ctx; + + hr = WHvGetVirtualProcessorRegisters(whpx->partition, cpu->cpu_index, + RegisterNames, RegisterCount, + RegisterValues); + if (FAILED(hr)) { + error_report("WHPX: Failed to get virtual processor registers," + " hr=%08lx", hr); + __debugbreak(); + } + + return hr; +} + +static HRESULT CALLBACK whpx_emu_setreg_callback( + void *ctx, + const WHV_REGISTER_NAME *RegisterNames, + UINT32 RegisterCount, + const WHV_REGISTER_VALUE *RegisterValues) +{ + HRESULT hr; + struct whpx_state *whpx = &whpx_global; + CPUState *cpu = (CPUState *)ctx; + + hr = WHvSetVirtualProcessorRegisters(whpx->partition, cpu->cpu_index, + RegisterNames, RegisterCount, + RegisterValues); + if (FAILED(hr)) { + error_report("WHPX: Failed to set virtual processor registers," + " hr=%08lx", hr); + __debugbreak(); + } + + /* + * The emulator just successfully wrote the register state. We clear the + * dirty state so we avoid the double write on resume of the VP. + */ + cpu->vcpu_dirty = false; + + return hr; +} + +static HRESULT CALLBACK whpx_emu_translate_callback( + void *ctx, + WHV_GUEST_VIRTUAL_ADDRESS Gva, + WHV_TRANSLATE_GVA_FLAGS TranslateFlags, + WHV_TRANSLATE_GVA_RESULT_CODE *TranslationResult, + WHV_GUEST_PHYSICAL_ADDRESS *Gpa) +{ + HRESULT hr; + struct whpx_state *whpx = &whpx_global; + CPUState *cpu = (CPUState *)ctx; + WHV_TRANSLATE_GVA_RESULT res; + + hr = WHvTranslateGva(whpx->partition, cpu->cpu_index, + Gva, TranslateFlags, &res, Gpa); + if (FAILED(hr)) { + error_report("WHPX: Failed to translate GVA, hr=%08lx", hr); + __debugbreak(); + } else { + *TranslationResult = res.ResultCode; + } + + return hr; +} + +static const WHV_EMULATOR_CALLBACKS whpx_emu_callbacks = { + .WHvEmulatorIoPortCallback = whpx_emu_ioport_callback, + .WHvEmulatorMemoryCallback = whpx_emu_memio_callback, + .WHvEmulatorGetVirtualProcessorRegisters = whpx_emu_getreg_callback, + .WHvEmulatorSetVirtualProcessorRegisters = whpx_emu_setreg_callback, + .WHvEmulatorTranslateGvaPage = whpx_emu_translate_callback, +}; + +static int whpx_handle_mmio(CPUState *cpu, WHV_MEMORY_ACCESS_CONTEXT *ctx) +{ + HRESULT hr; + struct whpx_vcpu *vcpu = get_whpx_vcpu(cpu); + WHV_EMULATOR_STATUS emu_status; + + hr = WHvEmulatorTryMmioEmulation(vcpu->emulator, cpu, ctx, &emu_status); + if (FAILED(hr)) { + __debugbreak(); + error_report("WHPX: Failed to parse MMIO access, hr=%08lx", hr); + return -1; + } + + if (!emu_status.EmulationSuccessful) { + __debugbreak(); + error_report("WHPX: Failed to emulate MMIO access"); + return -1; + } + + return 0; +} + +static int whpx_handle_portio(CPUState *cpu, + WHV_X64_IO_PORT_ACCESS_CONTEXT *ctx) +{ + HRESULT hr; + struct whpx_vcpu *vcpu = get_whpx_vcpu(cpu); + WHV_EMULATOR_STATUS emu_status; + + hr = WHvEmulatorTryIoEmulation(vcpu->emulator, cpu, ctx, &emu_status); + if (FAILED(hr)) { + __debugbreak(); + error_report("WHPX: Failed to parse PortIO access, hr=%08lx", hr); + return -1; + } + + if (!emu_status.EmulationSuccessful) { + __debugbreak(); + error_report("WHPX: Failed to emulate PortMMIO access"); + return -1; + } + + return 0; +} + +static int whpx_handle_halt(CPUState *cpu) +{ + struct CPUX86State *env = (CPUArchState *)(cpu->env_ptr); + int ret = 0; + + qemu_mutex_lock_iothread(); + if (!((cpu->interrupt_request & CPU_INTERRUPT_HARD) && + (env->eflags & IF_MASK)) && + !(cpu->interrupt_request & CPU_INTERRUPT_NMI)) { + cpu->exception_index = EXCP_HLT; + cpu->halted = true; + ret = 1; + } + qemu_mutex_unlock_iothread(); + + return ret; +} + +static void whpx_vcpu_pre_run(CPUState *cpu) +{ + HRESULT hr; + struct whpx_state *whpx = &whpx_global; + struct whpx_vcpu *vcpu = get_whpx_vcpu(cpu); + struct CPUX86State *env = (CPUArchState *)(cpu->env_ptr); + X86CPU *x86_cpu = X86_CPU(cpu); + int irq; + WHV_X64_PENDING_INTERRUPTION_REGISTER new_int = {0}; + UINT32 reg_count = 0; + WHV_REGISTER_VALUE reg_values[3] = {0}; + WHV_REGISTER_NAME reg_names[3]; + + qemu_mutex_lock_iothread(); + + /* Inject NMI */ + if (!vcpu->interrupt_in_flight.InterruptionPending && + cpu->interrupt_request & (CPU_INTERRUPT_NMI | CPU_INTERRUPT_SMI)) { + if (cpu->interrupt_request & CPU_INTERRUPT_NMI) { + cpu->interrupt_request &= ~CPU_INTERRUPT_NMI; + vcpu->interruptable = false; + new_int.InterruptionType = WHvX64PendingNmi; + new_int.InterruptionPending = 1; + new_int.InterruptionVector = 2; + } + if (cpu->interrupt_request & CPU_INTERRUPT_SMI) { + qemu_mutex_lock_iothread(); + cpu->interrupt_request &= ~CPU_INTERRUPT_SMI; + __debugbreak(); + qemu_mutex_unlock_iothread(); + } + } + + /* + * Force the VCPU out of its inner loop to process any INIT requests or + * commit pending TPR access. + */ + if (cpu->interrupt_request & (CPU_INTERRUPT_INIT | CPU_INTERRUPT_TPR)) { + if ((cpu->interrupt_request & CPU_INTERRUPT_INIT) && + !(env->hflags & HF_SMM_MASK)) { + cpu->exit_request = 1; + } + if (cpu->interrupt_request & CPU_INTERRUPT_TPR) { + cpu->exit_request = 1; + } + } + + /* Get pending hard interruption or replay one that was overwritten */ + if (!vcpu->interrupt_in_flight.InterruptionPending && + vcpu->interruptable && (env->eflags & IF_MASK)) { + assert(!new_int.InterruptionPending); + if (cpu->interrupt_request & CPU_INTERRUPT_HARD) { + cpu->interrupt_request &= ~CPU_INTERRUPT_HARD; + irq = cpu_get_pic_interrupt(env); + if (irq >= 0) { + new_int.InterruptionType = WHvX64PendingInterrupt; + new_int.InterruptionPending = 1; + new_int.InterruptionVector = irq; + } + } + } + + /* Setup interrupt state if new one was prepared */ + if (new_int.InterruptionPending) { + reg_values[reg_count].PendingInterruption = new_int; + reg_names[reg_count] = WHvRegisterPendingInterruption; + reg_count += 1; + } + + /* Sync the TPR to the CR8 if was modified during the intercept */ + reg_values[reg_count].Reg64 = cpu_get_apic_tpr(x86_cpu->apic_state); + if (reg_values[reg_count].Reg64 != vcpu->tpr) { + vcpu->tpr = reg_values[reg_count].Reg64; + cpu->exit_request = 1; + reg_names[reg_count] = WHvX64RegisterCr8; + reg_count += 1; + } + + /* Update the state of the interrupt delivery notification */ + if (cpu->interrupt_request & CPU_INTERRUPT_HARD) { + reg_values[reg_count].DeliverabilityNotifications.InterruptNotification + = 1; + if (vcpu->window_registered != 1) { + vcpu->window_registered = 1; + } + reg_names[reg_count] = WHvX64RegisterDeliverabilityNotifications; + reg_count += 1; + } + + qemu_mutex_unlock_iothread(); + + if (reg_count) { + hr = WHvSetVirtualProcessorRegisters(whpx->partition, cpu->cpu_index, + reg_names, reg_count, reg_values); + if (FAILED(hr)) { + error_report("WHPX: Failed to set interrupt state registers," + " hr=%08lx", hr); + __debugbreak(); + } + } + + return; +} + +static void whpx_vcpu_post_run(CPUState *cpu) +{ + HRESULT hr; + struct whpx_state *whpx = &whpx_global; + struct whpx_vcpu *vcpu = get_whpx_vcpu(cpu); + struct CPUX86State *env = (CPUArchState *)(cpu->env_ptr); + X86CPU *x86_cpu = X86_CPU(cpu); + WHV_REGISTER_VALUE reg_values[4]; + const WHV_REGISTER_NAME reg_names[4] = { + WHvX64RegisterRflags, + WHvX64RegisterCr8, + WHvRegisterPendingInterruption, + WHvRegisterInterruptState, + }; + + hr = WHvGetVirtualProcessorRegisters(whpx->partition, cpu->cpu_index, + reg_names, 4, reg_values); + if (FAILED(hr)) { + error_report("WHPX: Failed to get interrupt state regusters," + " hr=%08lx", hr); + __debugbreak(); + vcpu->interruptable = false; + return; + } + + assert(reg_names[0] == WHvX64RegisterRflags); + env->eflags = reg_values[0].Reg64; + + assert(reg_names[1] == WHvX64RegisterCr8); + if (vcpu->tpr != reg_values[1].Reg64) { + vcpu->tpr = reg_values[1].Reg64; + qemu_mutex_lock_iothread(); + cpu_set_apic_tpr(x86_cpu->apic_state, vcpu->tpr); + qemu_mutex_unlock_iothread(); + } + + assert(reg_names[2] == WHvRegisterPendingInterruption); + vcpu->interrupt_in_flight = reg_values[2].PendingInterruption; + + assert(reg_names[3] == WHvRegisterInterruptState); + vcpu->interruptable = !reg_values[3].InterruptState.InterruptShadow; + + return; +} + +static void whpx_vcpu_process_async_events(CPUState *cpu) +{ + struct CPUX86State *env = (CPUArchState *)(cpu->env_ptr); + X86CPU *x86_cpu = X86_CPU(cpu); + struct whpx_vcpu *vcpu = get_whpx_vcpu(cpu); + + if ((cpu->interrupt_request & CPU_INTERRUPT_INIT) && + !(env->hflags & HF_SMM_MASK)) { + + do_cpu_init(x86_cpu); + cpu->vcpu_dirty = true; + vcpu->interruptable = true; + } + + if (cpu->interrupt_request & CPU_INTERRUPT_POLL) { + cpu->interrupt_request &= ~CPU_INTERRUPT_POLL; + apic_poll_irq(x86_cpu->apic_state); + } + + if (((cpu->interrupt_request & CPU_INTERRUPT_HARD) && + (env->eflags & IF_MASK)) || + (cpu->interrupt_request & CPU_INTERRUPT_NMI)) { + cpu->halted = false; + } + + if (cpu->interrupt_request & CPU_INTERRUPT_SIPI) { + if (!cpu->vcpu_dirty) { + whpx_get_registers(cpu); + } + do_cpu_sipi(x86_cpu); + } + + if (cpu->interrupt_request & CPU_INTERRUPT_TPR) { + cpu->interrupt_request &= ~CPU_INTERRUPT_TPR; + if (!cpu->vcpu_dirty) { + whpx_get_registers(cpu); + } + apic_handle_tpr_access_report(x86_cpu->apic_state, env->eip, + env->tpr_access_type); + } + + return; +} + +static int whpx_vcpu_run(CPUState *cpu) +{ + HRESULT hr; + struct whpx_state *whpx = &whpx_global; + struct whpx_vcpu *vcpu = get_whpx_vcpu(cpu); + int ret; + + whpx_vcpu_process_async_events(cpu); + if (cpu->halted) { + cpu->exception_index = EXCP_HLT; + atomic_set(&cpu->exit_request, false); + return 0; + } + + qemu_mutex_unlock_iothread(); + cpu_exec_start(cpu); + + do { + if (cpu->vcpu_dirty) { + whpx_set_registers(cpu); + cpu->vcpu_dirty = false; + } + + whpx_vcpu_pre_run(cpu); + + if (atomic_read(&cpu->exit_request)) { + whpx_vcpu_kick(cpu); + } + + for (;;) { + hr = WHvRunVirtualProcessor(whpx->partition, cpu->cpu_index, + &vcpu->exit_ctx, whpx->exit_ctx_size); + + if (SUCCEEDED(hr) && (vcpu->exit_ctx.ExitReason == + WHvRunVpExitReasonAlerted)) { + WHvCancelRunVirtualProcessor(whpx->partition, cpu->cpu_index, + 0); + } else { + break; + } + } + + if (FAILED(hr)) { + error_report("WHPX: Failed to exec a virtual processor," + " hr=%08lx", hr); + ret = -1; + break; + } + + whpx_vcpu_post_run(cpu); + + switch (vcpu->exit_ctx.ExitReason) { + case WHvRunVpExitReasonMemoryAccess: + ret = whpx_handle_mmio(cpu, &vcpu->exit_ctx.MemoryAccess); + break; + + case WHvRunVpExitReasonX64IoPortAccess: + ret = whpx_handle_portio(cpu, &vcpu->exit_ctx.IoPortAccess); + break; + + case WHvRunVpExitReasonX64InterruptWindow: + vcpu->window_registered = 0; + break; + + case WHvRunVpExitReasonX64Halt: + ret = whpx_handle_halt(cpu); + break; + + case WHvRunVpExitReasonCanceled: + cpu->exception_index = EXCP_INTERRUPT; + ret = 1; + break; + + case WHvRunVpExitReasonNone: + case WHvRunVpExitReasonUnrecoverableException: + case WHvRunVpExitReasonInvalidVpRegisterValue: + case WHvRunVpExitReasonUnsupportedFeature: + case WHvRunVpExitReasonX64MsrAccess: + case WHvRunVpExitReasonX64Cpuid: + case WHvRunVpExitReasonException: + case WHvRunVpExitReasonAlerted: + default: + error_report("WHPX: Unexpected VP exit code %d", + vcpu->exit_ctx.ExitReason); + whpx_get_registers(cpu); + qemu_mutex_lock_iothread(); + qemu_system_guest_panicked(cpu_get_crash_info(cpu)); + qemu_mutex_unlock_iothread(); + break; + } + + } while (!ret); + + cpu_exec_end(cpu); + qemu_mutex_lock_iothread(); + current_cpu = cpu; + + atomic_set(&cpu->exit_request, false); + + return ret < 0; +} + +static void do_whpx_cpu_synchronize_state(CPUState *cpu, run_on_cpu_data arg) +{ + whpx_get_registers(cpu); + cpu->vcpu_dirty = true; +} + +static void do_whpx_cpu_synchronize_post_reset(CPUState *cpu, + run_on_cpu_data arg) +{ + whpx_set_registers(cpu); + cpu->vcpu_dirty = false; +} + +static void do_whpx_cpu_synchronize_post_init(CPUState *cpu, + run_on_cpu_data arg) +{ + whpx_set_registers(cpu); + cpu->vcpu_dirty = false; +} + +static void do_whpx_cpu_synchronize_pre_loadvm(CPUState *cpu, + run_on_cpu_data arg) +{ + cpu->vcpu_dirty = true; +} + +/* + * CPU support. + */ + +void whpx_cpu_synchronize_state(CPUState *cpu) +{ + if (!cpu->vcpu_dirty) { + run_on_cpu(cpu, do_whpx_cpu_synchronize_state, RUN_ON_CPU_NULL); + } +} + +void whpx_cpu_synchronize_post_reset(CPUState *cpu) +{ + run_on_cpu(cpu, do_whpx_cpu_synchronize_post_reset, RUN_ON_CPU_NULL); +} + +void whpx_cpu_synchronize_post_init(CPUState *cpu) +{ + run_on_cpu(cpu, do_whpx_cpu_synchronize_post_init, RUN_ON_CPU_NULL); +} + +void whpx_cpu_synchronize_pre_loadvm(CPUState *cpu) +{ + run_on_cpu(cpu, do_whpx_cpu_synchronize_pre_loadvm, RUN_ON_CPU_NULL); +} + +/* + * Vcpu support. + */ + +static Error *whpx_migration_blocker; + +int whpx_init_vcpu(CPUState *cpu) +{ + HRESULT hr; + struct whpx_state *whpx = &whpx_global; + struct whpx_vcpu *vcpu; + Error *local_error = NULL; + + /* Add migration blockers for all unsupported features of the + * Windows Hypervisor Platform + */ + if (whpx_migration_blocker == NULL) { + error_setg(&whpx_migration_blocker, + "State blocked due to non-migratable CPUID feature support," + "dirty memory tracking support, and XSAVE/XRSTOR support"); + + (void)migrate_add_blocker(whpx_migration_blocker, &local_error); + if (local_error) { + error_report_err(local_error); + error_free(whpx_migration_blocker); + migrate_del_blocker(whpx_migration_blocker); + return -EINVAL; + } + } + + vcpu = g_malloc0(FIELD_OFFSET(struct whpx_vcpu, exit_ctx) + + whpx->exit_ctx_size); + + if (!vcpu) { + error_report("WHPX: Failed to allocte VCPU context."); + return -ENOMEM; + } + + hr = WHvEmulatorCreateEmulator(whpx_emu_callbacks, &vcpu->emulator); + if (FAILED(hr)) { + error_report("WHPX: Failed to setup instruction completion support," + " hr=%08lx", hr); + g_free(vcpu); + return -EINVAL; + } + + hr = WHvCreateVirtualProcessor(whpx->partition, cpu->cpu_index, 0); + if (FAILED(hr)) { + error_report("WHPX: Failed to create a virtual processor," + " hr=%08lx", hr); + WHvEmulatorDestroyEmulator(vcpu->emulator); + g_free(vcpu); + return -EINVAL; + } + + vcpu->interruptable = true; + + cpu->vcpu_dirty = true; + cpu->hax_vcpu = (struct hax_vcpu_state *)vcpu; + + return 0; +} + +int whpx_vcpu_exec(CPUState *cpu) +{ + int ret; + int fatal; + + for (;;) { + if (cpu->exception_index >= EXCP_INTERRUPT) { + ret = cpu->exception_index; + cpu->exception_index = -1; + break; + } + + fatal = whpx_vcpu_run(cpu); + + if (fatal) { + error_report("WHPX: Failed to exec a virtual processor"); + abort(); + } + } + + return ret; +} + +void whpx_destroy_vcpu(CPUState *cpu) +{ + struct whpx_state *whpx = &whpx_global; + struct whpx_vcpu *vcpu = get_whpx_vcpu(cpu); + + WHvDeleteVirtualProcessor(whpx->partition, cpu->cpu_index); + WHvEmulatorDestroyEmulator(vcpu->emulator); + g_free(cpu->hax_vcpu); + return; +} + +void whpx_vcpu_kick(CPUState *cpu) +{ + struct whpx_state *whpx = &whpx_global; + WHvCancelRunVirtualProcessor(whpx->partition, cpu->cpu_index, 0); +} + +/* + * Memory support. + */ + +static void whpx_update_mapping(hwaddr start_pa, ram_addr_t size, + void *host_va, int add, int rom, + const char *name) +{ + struct whpx_state *whpx = &whpx_global; + HRESULT hr; + + /* + if (add) { + printf("WHPX: ADD PA:%p Size:%p, Host:%p, %s, '%s'\n", + (void*)start_pa, (void*)size, host_va, + (rom ? "ROM" : "RAM"), name); + } else { + printf("WHPX: DEL PA:%p Size:%p, Host:%p, '%s'\n", + (void*)start_pa, (void*)size, host_va, name); + } + */ + + if (add) { + hr = WHvMapGpaRange(whpx->partition, + host_va, + start_pa, + size, + (WHvMapGpaRangeFlagRead | + WHvMapGpaRangeFlagExecute | + (rom ? 0 : WHvMapGpaRangeFlagWrite))); + } else { + hr = WHvUnmapGpaRange(whpx->partition, + start_pa, + size); + } + + if (FAILED(hr)) { + error_report("WHPX: Failed to %s GPA range '%s' PA:%p, Size:%p bytes," + " Host:%p, hr=%08lx", + (add ? "MAP" : "UNMAP"), name, + (void *)start_pa, (void *)size, host_va, hr); + } +} + +static void whpx_process_section(MemoryRegionSection *section, int add) +{ + MemoryRegion *mr = section->mr; + hwaddr start_pa = section->offset_within_address_space; + ram_addr_t size = int128_get64(section->size); + unsigned int delta; + uint64_t host_va; + + if (!memory_region_is_ram(mr)) { + return; + } + + delta = qemu_real_host_page_size - (start_pa & ~qemu_real_host_page_mask); + delta &= ~qemu_real_host_page_mask; + if (delta > size) { + return; + } + start_pa += delta; + size -= delta; + size &= qemu_real_host_page_mask; + if (!size || (start_pa & ~qemu_real_host_page_mask)) { + return; + } + + host_va = (uintptr_t)memory_region_get_ram_ptr(mr) + + section->offset_within_region + delta; + + whpx_update_mapping(start_pa, size, (void *)host_va, add, + memory_region_is_rom(mr), mr->name); +} + +static void whpx_region_add(MemoryListener *listener, + MemoryRegionSection *section) +{ + memory_region_ref(section->mr); + whpx_process_section(section, 1); +} + +static void whpx_region_del(MemoryListener *listener, + MemoryRegionSection *section) +{ + whpx_process_section(section, 0); + memory_region_unref(section->mr); +} + +static void whpx_transaction_begin(MemoryListener *listener) +{ +} + +static void whpx_transaction_commit(MemoryListener *listener) +{ +} + +static void whpx_log_sync(MemoryListener *listener, + MemoryRegionSection *section) +{ + MemoryRegion *mr = section->mr; + + if (!memory_region_is_ram(mr)) { + return; + } + + memory_region_set_dirty(mr, 0, int128_get64(section->size)); +} + +static MemoryListener whpx_memory_listener = { + .begin = whpx_transaction_begin, + .commit = whpx_transaction_commit, + .region_add = whpx_region_add, + .region_del = whpx_region_del, + .log_sync = whpx_log_sync, + .priority = 10, +}; + +static void whpx_memory_init(void) +{ + memory_listener_register(&whpx_memory_listener, &address_space_memory); +} + +static void whpx_handle_interrupt(CPUState *cpu, int mask) +{ + cpu->interrupt_request |= mask; + + if (!qemu_cpu_is_self(cpu)) { + qemu_cpu_kick(cpu); + } +} + +/* + * Partition support + */ + +static int whpx_accel_init(MachineState *ms) +{ + struct whpx_state *whpx; + int ret; + HRESULT hr; + WHV_CAPABILITY whpx_cap; + WHV_PARTITION_PROPERTY prop; + + whpx = &whpx_global; + + memset(whpx, 0, sizeof(struct whpx_state)); + whpx->mem_quota = ms->ram_size; + + hr = WHvGetCapability(WHvCapabilityCodeHypervisorPresent, &whpx_cap, + sizeof(whpx_cap)); + if (FAILED(hr) || !whpx_cap.HypervisorPresent) { + error_report("WHPX: No accelerator found, hr=%08lx", hr); + ret = -ENOSPC; + goto error; + } + + hr = WHvCreatePartition(&whpx->partition); + if (FAILED(hr)) { + error_report("WHPX: Failed to create partition, hr=%08lx", hr); + ret = -EINVAL; + goto error; + } + + memset(&prop, 0, sizeof(WHV_PARTITION_PROPERTY)); + prop.PropertyCode = WHvPartitionPropertyCodeProcessorCount; + prop.ProcessorCount = smp_cpus; + hr = WHvSetPartitionProperty(whpx->partition, + &prop, + sizeof(WHV_PARTITION_PROPERTY)); + + if (FAILED(hr)) { + error_report("WHPX: Failed to set partition core count to %d," + " hr=%08lx", smp_cores, hr); + ret = -EINVAL; + goto error; + } + + hr = WHvSetupPartition(whpx->partition); + if (FAILED(hr)) { + error_report("WHPX: Failed to setup partition, hr=%08lx", hr); + ret = -EINVAL; + goto error; + } + + whpx->exit_ctx_size = WHvGetRunExitContextSize(); + assert(whpx->exit_ctx_size); + + whpx_memory_init(); + + cpu_interrupt_handler = whpx_handle_interrupt; + + printf("Windows Hypervisor Platform accelerator is operational\n"); + return 0; + + error: + + if (NULL != whpx->partition) { + WHvDeletePartition(whpx->partition); + whpx->partition = NULL; + } + + + return ret; +} + +int whpx_enabled(void) +{ + return whpx_allowed; +} + +static void whpx_accel_class_init(ObjectClass *oc, void *data) +{ + AccelClass *ac = ACCEL_CLASS(oc); + ac->name = "WHPX"; + ac->init_machine = whpx_accel_init; + ac->allowed = &whpx_allowed; +} + +static const TypeInfo whpx_accel_type = { + .name = ACCEL_CLASS_NAME("whpx"), + .parent = TYPE_ACCEL, + .class_init = whpx_accel_class_init, +}; + +static void whpx_type_init(void) +{ + type_register_static(&whpx_accel_type); +} + +type_init(whpx_type_init); diff --git a/target/lm32/cpu.c b/target/lm32/cpu.c index 6f5c14767b..96c2499d0b 100644 --- a/target/lm32/cpu.c +++ b/target/lm32/cpu.c @@ -236,9 +236,8 @@ static void lm32_cpu_class_init(ObjectClass *oc, void *data) CPUClass *cc = CPU_CLASS(oc); DeviceClass *dc = DEVICE_CLASS(oc); - lcc->parent_realize = dc->realize; - dc->realize = lm32_cpu_realizefn; - + device_class_set_parent_realize(dc, lm32_cpu_realizefn, + &lcc->parent_realize); lcc->parent_reset = cc->reset; cc->reset = lm32_cpu_reset; diff --git a/target/m68k/cpu.c b/target/m68k/cpu.c index 98919b358b..6a80be009b 100644 --- a/target/m68k/cpu.c +++ b/target/m68k/cpu.c @@ -255,9 +255,8 @@ static void m68k_cpu_class_init(ObjectClass *c, void *data) CPUClass *cc = CPU_CLASS(c); DeviceClass *dc = DEVICE_CLASS(c); - mcc->parent_realize = dc->realize; - dc->realize = m68k_cpu_realizefn; - + device_class_set_parent_realize(dc, m68k_cpu_realizefn, + &mcc->parent_realize); mcc->parent_reset = cc->reset; cc->reset = m68k_cpu_reset; diff --git a/target/microblaze/cpu.c b/target/microblaze/cpu.c index 5700652e06..d8df2fb07e 100644 --- a/target/microblaze/cpu.c +++ b/target/microblaze/cpu.c @@ -258,9 +258,8 @@ static void mb_cpu_class_init(ObjectClass *oc, void *data) CPUClass *cc = CPU_CLASS(oc); MicroBlazeCPUClass *mcc = MICROBLAZE_CPU_CLASS(oc); - mcc->parent_realize = dc->realize; - dc->realize = mb_cpu_realizefn; - + device_class_set_parent_realize(dc, mb_cpu_realizefn, + &mcc->parent_realize); mcc->parent_reset = cc->reset; cc->reset = mb_cpu_reset; diff --git a/target/mips/cpu.c b/target/mips/cpu.c index 069f93560e..497706b669 100644 --- a/target/mips/cpu.c +++ b/target/mips/cpu.c @@ -174,9 +174,8 @@ static void mips_cpu_class_init(ObjectClass *c, void *data) CPUClass *cc = CPU_CLASS(c); DeviceClass *dc = DEVICE_CLASS(c); - mcc->parent_realize = dc->realize; - dc->realize = mips_cpu_realizefn; - + device_class_set_parent_realize(dc, mips_cpu_realizefn, + &mcc->parent_realize); mcc->parent_reset = cc->reset; cc->reset = mips_cpu_reset; diff --git a/target/moxie/cpu.c b/target/moxie/cpu.c index f1389e5097..4170284da6 100644 --- a/target/moxie/cpu.c +++ b/target/moxie/cpu.c @@ -102,9 +102,8 @@ static void moxie_cpu_class_init(ObjectClass *oc, void *data) CPUClass *cc = CPU_CLASS(oc); MoxieCPUClass *mcc = MOXIE_CPU_CLASS(oc); - mcc->parent_realize = dc->realize; - dc->realize = moxie_cpu_realizefn; - + device_class_set_parent_realize(dc, moxie_cpu_realizefn, + &mcc->parent_realize); mcc->parent_reset = cc->reset; cc->reset = moxie_cpu_reset; diff --git a/target/nios2/cpu.c b/target/nios2/cpu.c index 4742e52c78..fbfaa2ce26 100644 --- a/target/nios2/cpu.c +++ b/target/nios2/cpu.c @@ -187,8 +187,8 @@ static void nios2_cpu_class_init(ObjectClass *oc, void *data) CPUClass *cc = CPU_CLASS(oc); Nios2CPUClass *ncc = NIOS2_CPU_CLASS(oc); - ncc->parent_realize = dc->realize; - dc->realize = nios2_cpu_realizefn; + device_class_set_parent_realize(dc, nios2_cpu_realizefn, + &ncc->parent_realize); dc->props = nios2_properties; ncc->parent_reset = cc->reset; cc->reset = nios2_cpu_reset; diff --git a/target/openrisc/cpu.c b/target/openrisc/cpu.c index e0394b8b06..20b115afae 100644 --- a/target/openrisc/cpu.c +++ b/target/openrisc/cpu.c @@ -132,9 +132,8 @@ static void openrisc_cpu_class_init(ObjectClass *oc, void *data) CPUClass *cc = CPU_CLASS(occ); DeviceClass *dc = DEVICE_CLASS(oc); - occ->parent_realize = dc->realize; - dc->realize = openrisc_cpu_realizefn; - + device_class_set_parent_realize(dc, openrisc_cpu_realizefn, + &occ->parent_realize); occ->parent_reset = cc->reset; cc->reset = openrisc_cpu_reset; diff --git a/target/ppc/kvm.c b/target/ppc/kvm.c index 84284d5957..9842b3bb12 100644 --- a/target/ppc/kvm.c +++ b/target/ppc/kvm.c @@ -137,7 +137,7 @@ int kvm_arch_init(MachineState *ms, KVMState *s) cap_spapr_tce = kvm_check_extension(s, KVM_CAP_SPAPR_TCE); cap_spapr_tce_64 = kvm_check_extension(s, KVM_CAP_SPAPR_TCE_64); cap_spapr_multitce = kvm_check_extension(s, KVM_CAP_SPAPR_MULTITCE); - cap_spapr_vfio = false; + cap_spapr_vfio = kvm_vm_check_extension(s, KVM_CAP_SPAPR_TCE_VFIO); cap_one_reg = kvm_check_extension(s, KVM_CAP_ONE_REG); cap_hior = kvm_check_extension(s, KVM_CAP_PPC_HIOR); cap_epr = kvm_check_extension(s, KVM_CAP_PPC_EPR); @@ -2514,6 +2514,11 @@ int kvmppc_get_cap_safe_indirect_branch(void) return cap_ppc_safe_indirect_branch; } +bool kvmppc_has_cap_spapr_vfio(void) +{ + return cap_spapr_vfio; +} + PowerPCCPUClass *kvm_ppc_get_host_cpu_class(void) { uint32_t host_pvr = mfpvr(); diff --git a/target/ppc/kvm_ppc.h b/target/ppc/kvm_ppc.h index 39830baa77..4d2789eef6 100644 --- a/target/ppc/kvm_ppc.h +++ b/target/ppc/kvm_ppc.h @@ -46,6 +46,7 @@ void *kvmppc_create_spapr_tce(uint32_t liobn, uint32_t page_shift, int kvmppc_remove_spapr_tce(void *table, int pfd, uint32_t window_size); int kvmppc_reset_htab(int shift_hint); uint64_t kvmppc_rma_size(uint64_t current_size, unsigned int hash_shift); +bool kvmppc_has_cap_spapr_vfio(void); #endif /* !CONFIG_USER_ONLY */ bool kvmppc_has_cap_epr(void); int kvmppc_define_rtas_kernel_token(uint32_t token, const char *function); @@ -232,6 +233,11 @@ static inline bool kvmppc_is_mem_backend_page_size_ok(const char *obj_path) return true; } +static inline bool kvmppc_has_cap_spapr_vfio(void) +{ + return false; +} + #endif /* !CONFIG_USER_ONLY */ static inline bool kvmppc_has_cap_epr(void) diff --git a/target/ppc/translate_init.c b/target/ppc/translate_init.c index 55c99c97e3..e7b1044944 100644 --- a/target/ppc/translate_init.c +++ b/target/ppc/translate_init.c @@ -10556,12 +10556,12 @@ static void ppc_cpu_class_init(ObjectClass *oc, void *data) CPUClass *cc = CPU_CLASS(oc); DeviceClass *dc = DEVICE_CLASS(oc); - pcc->parent_realize = dc->realize; - pcc->parent_unrealize = dc->unrealize; + device_class_set_parent_realize(dc, ppc_cpu_realizefn, + &pcc->parent_realize); + device_class_set_parent_unrealize(dc, ppc_cpu_unrealizefn, + &pcc->parent_unrealize); pcc->pvr_match = ppc_pvr_match_default; pcc->interrupts_big_endian = ppc_cpu_interrupts_big_endian_always; - dc->realize = ppc_cpu_realizefn; - dc->unrealize = ppc_cpu_unrealizefn; dc->props = ppc_cpu_properties; pcc->parent_reset = cc->reset; diff --git a/target/s390x/cpu.c b/target/s390x/cpu.c index d2e6b9f5c7..979469dc3c 100644 --- a/target/s390x/cpu.c +++ b/target/s390x/cpu.c @@ -464,8 +464,8 @@ static void s390_cpu_class_init(ObjectClass *oc, void *data) CPUClass *cc = CPU_CLASS(scc); DeviceClass *dc = DEVICE_CLASS(oc); - scc->parent_realize = dc->realize; - dc->realize = s390_cpu_realizefn; + device_class_set_parent_realize(dc, s390_cpu_realizefn, + &scc->parent_realize); dc->props = s390x_cpu_properties; dc->user_creatable = true; diff --git a/target/sh4/cpu.c b/target/sh4/cpu.c index e0b99fbc89..e37c187ca2 100644 --- a/target/sh4/cpu.c +++ b/target/sh4/cpu.c @@ -236,8 +236,8 @@ static void superh_cpu_class_init(ObjectClass *oc, void *data) CPUClass *cc = CPU_CLASS(oc); SuperHCPUClass *scc = SUPERH_CPU_CLASS(oc); - scc->parent_realize = dc->realize; - dc->realize = superh_cpu_realizefn; + device_class_set_parent_realize(dc, superh_cpu_realizefn, + &scc->parent_realize); scc->parent_reset = cc->reset; cc->reset = superh_cpu_reset; diff --git a/target/sparc/cpu.c b/target/sparc/cpu.c index c7adc281de..ff6ed91f9a 100644 --- a/target/sparc/cpu.c +++ b/target/sparc/cpu.c @@ -858,8 +858,8 @@ static void sparc_cpu_class_init(ObjectClass *oc, void *data) CPUClass *cc = CPU_CLASS(oc); DeviceClass *dc = DEVICE_CLASS(oc); - scc->parent_realize = dc->realize; - dc->realize = sparc_cpu_realizefn; + device_class_set_parent_realize(dc, sparc_cpu_realizefn, + &scc->parent_realize); dc->props = sparc_cpu_properties; scc->parent_reset = cc->reset; diff --git a/target/tilegx/cpu.c b/target/tilegx/cpu.c index c140b461ac..b7451bdcf2 100644 --- a/target/tilegx/cpu.c +++ b/target/tilegx/cpu.c @@ -141,8 +141,8 @@ static void tilegx_cpu_class_init(ObjectClass *oc, void *data) CPUClass *cc = CPU_CLASS(oc); TileGXCPUClass *tcc = TILEGX_CPU_CLASS(oc); - tcc->parent_realize = dc->realize; - dc->realize = tilegx_cpu_realizefn; + device_class_set_parent_realize(dc, tilegx_cpu_realizefn, + &tcc->parent_realize); tcc->parent_reset = cc->reset; cc->reset = tilegx_cpu_reset; diff --git a/target/tricore/cpu.c b/target/tricore/cpu.c index 179c997aa4..2edaef1aef 100644 --- a/target/tricore/cpu.c +++ b/target/tricore/cpu.c @@ -153,8 +153,8 @@ static void tricore_cpu_class_init(ObjectClass *c, void *data) CPUClass *cc = CPU_CLASS(c); DeviceClass *dc = DEVICE_CLASS(c); - mcc->parent_realize = dc->realize; - dc->realize = tricore_cpu_realizefn; + device_class_set_parent_realize(dc, tricore_cpu_realizefn, + &mcc->parent_realize); mcc->parent_reset = cc->reset; cc->reset = tricore_cpu_reset; diff --git a/target/unicore32/cpu.c b/target/unicore32/cpu.c index 17dc1504d7..fb837aab4c 100644 --- a/target/unicore32/cpu.c +++ b/target/unicore32/cpu.c @@ -132,8 +132,8 @@ static void uc32_cpu_class_init(ObjectClass *oc, void *data) CPUClass *cc = CPU_CLASS(oc); UniCore32CPUClass *ucc = UNICORE32_CPU_CLASS(oc); - ucc->parent_realize = dc->realize; - dc->realize = uc32_cpu_realizefn; + device_class_set_parent_realize(dc, uc32_cpu_realizefn, + &ucc->parent_realize); cc->class_by_name = uc32_cpu_class_by_name; cc->has_work = uc32_cpu_has_work; diff --git a/target/xtensa/cpu.c b/target/xtensa/cpu.c index 1c982a0b2e..4573388a45 100644 --- a/target/xtensa/cpu.c +++ b/target/xtensa/cpu.c @@ -151,8 +151,8 @@ static void xtensa_cpu_class_init(ObjectClass *oc, void *data) CPUClass *cc = CPU_CLASS(oc); XtensaCPUClass *xcc = XTENSA_CPU_CLASS(cc); - xcc->parent_realize = dc->realize; - dc->realize = xtensa_cpu_realizefn; + device_class_set_parent_realize(dc, xtensa_cpu_realizefn, + &xcc->parent_realize); xcc->parent_reset = cc->reset; cc->reset = xtensa_cpu_reset; diff --git a/tests/ide-test.c b/tests/ide-test.c index aa9de065fc..be427e41d6 100644 --- a/tests/ide-test.c +++ b/tests/ide-test.c @@ -52,6 +52,7 @@ enum { reg_data = 0x0, reg_feature = 0x1, + reg_error = 0x1, reg_nsectors = 0x2, reg_lba_low = 0x3, reg_lba_middle = 0x4, @@ -69,6 +70,11 @@ enum { ERR = 0x01, }; +/* Error field */ +enum { + ABRT = 0x04, +}; + enum { DEV = 0x10, LBA = 0x40, @@ -81,6 +87,7 @@ enum { }; enum { + CMD_DSM = 0x06, CMD_READ_DMA = 0xc8, CMD_WRITE_DMA = 0xca, CMD_FLUSH_CACHE = 0xe7, @@ -179,6 +186,12 @@ typedef struct PrdtEntry { #define assert_bit_set(data, mask) g_assert_cmphex((data) & (mask), ==, (mask)) #define assert_bit_clear(data, mask) g_assert_cmphex((data) & (mask), ==, 0) +static uint64_t trim_range_le(uint64_t sector, uint16_t count) +{ + /* 2-byte range, 6-byte LBA */ + return cpu_to_le64(((uint64_t)count << 48) + sector); +} + static int send_dma_request(int cmd, uint64_t sector, int nb_sectors, PrdtEntry *prdt, int prdt_entries, void(*post_exec)(QPCIDevice *dev, QPCIBar ide_bar, @@ -204,6 +217,7 @@ static int send_dma_request(int cmd, uint64_t sector, int nb_sectors, * the SCSI command being sent in the packet, too. */ from_dev = true; break; + case CMD_DSM: case CMD_WRITE_DMA: from_dev = false; break; @@ -234,6 +248,10 @@ static int send_dma_request(int cmd, uint64_t sector, int nb_sectors, /* Enables ATAPI DMA; otherwise PIO is attempted */ qpci_io_writeb(dev, ide_bar, reg_feature, 0x01); } else { + if (cmd == CMD_DSM) { + /* trim bit */ + qpci_io_writeb(dev, ide_bar, reg_feature, 0x01); + } qpci_io_writeb(dev, ide_bar, reg_nsectors, nb_sectors); qpci_io_writeb(dev, ide_bar, reg_lba_low, sector & 0xff); qpci_io_writeb(dev, ide_bar, reg_lba_middle, (sector >> 8) & 0xff); @@ -344,6 +362,58 @@ static void test_bmdma_simple_rw(void) g_free(cmpbuf); } +static void test_bmdma_trim(void) +{ + QPCIDevice *dev; + QPCIBar bmdma_bar, ide_bar; + uint8_t status; + const uint64_t trim_range[] = { trim_range_le(0, 2), + trim_range_le(6, 8), + trim_range_le(10, 1), + }; + const uint64_t bad_range = trim_range_le(TEST_IMAGE_SIZE / 512 - 1, 2); + size_t len = 512; + uint8_t *buf; + uintptr_t guest_buf = guest_alloc(guest_malloc, len); + + PrdtEntry prdt[] = { + { + .addr = cpu_to_le32(guest_buf), + .size = cpu_to_le32(len | PRDT_EOT), + }, + }; + + dev = get_pci_device(&bmdma_bar, &ide_bar); + + buf = g_malloc(len); + + /* Normal request */ + *((uint64_t *)buf) = trim_range[0]; + *((uint64_t *)buf + 1) = trim_range[1]; + + memwrite(guest_buf, buf, 2 * sizeof(uint64_t)); + + status = send_dma_request(CMD_DSM, 0, 1, prdt, + ARRAY_SIZE(prdt), NULL); + g_assert_cmphex(status, ==, BM_STS_INTR); + assert_bit_clear(qpci_io_readb(dev, ide_bar, reg_status), DF | ERR); + + /* Request contains invalid range */ + *((uint64_t *)buf) = trim_range[2]; + *((uint64_t *)buf + 1) = bad_range; + + memwrite(guest_buf, buf, 2 * sizeof(uint64_t)); + + status = send_dma_request(CMD_DSM, 0, 1, prdt, + ARRAY_SIZE(prdt), NULL); + g_assert_cmphex(status, ==, BM_STS_INTR); + assert_bit_set(qpci_io_readb(dev, ide_bar, reg_status), ERR); + assert_bit_set(qpci_io_readb(dev, ide_bar, reg_error), ABRT); + + free_pci_device(dev); + g_free(buf); +} + static void test_bmdma_short_prdt(void) { QPCIDevice *dev; @@ -963,6 +1033,7 @@ int main(int argc, char **argv) qtest_add_func("/ide/bmdma/setup", test_bmdma_setup); qtest_add_func("/ide/bmdma/simple_rw", test_bmdma_simple_rw); + qtest_add_func("/ide/bmdma/trim", test_bmdma_trim); qtest_add_func("/ide/bmdma/short_prdt", test_bmdma_short_prdt); qtest_add_func("/ide/bmdma/one_sector_short_prdt", test_bmdma_one_sector_short_prdt); diff --git a/tests/test-filter-redirector.c b/tests/test-filter-redirector.c index f2566144cf..fbaf19bbd8 100644 --- a/tests/test-filter-redirector.c +++ b/tests/test-filter-redirector.c @@ -186,7 +186,6 @@ static void test_redirector_rx(void) ret = iov_send(send_sock, iov, 2, 0, sizeof(size) + sizeof(send_buf)); g_assert_cmpint(ret, ==, sizeof(send_buf) + sizeof(size)); - close(send_sock); ret = qemu_recv(backend_sock[0], &len, sizeof(len), 0); g_assert_cmpint(ret, ==, sizeof(len)); @@ -197,6 +196,7 @@ static void test_redirector_rx(void) ret = qemu_recv(backend_sock[0], recv_buf, len, 0); g_assert_cmpstr(recv_buf, ==, send_buf); + close(send_sock); g_free(recv_buf); unlink(sock_path0); unlink(sock_path1); diff --git a/tests/vhost-user-test.c b/tests/vhost-user-test.c index ec6ac9dc9e..95eb449cfc 100644 --- a/tests/vhost-user-test.c +++ b/tests/vhost-user-test.c @@ -17,6 +17,7 @@ #include "qemu/range.h" #include "qemu/sockets.h" #include "chardev/char-fe.h" +#include "qemu/memfd.h" #include "sysemu/sysemu.h" #include "libqos/libqos.h" #include "libqos/pci-pc.h" @@ -30,8 +31,6 @@ #include <linux/virtio_net.h> #include <sys/vfs.h> -#define VHOST_USER_NET_TESTS_WORKING 0 /* broken as of 2.10.0 */ - /* GLIB version compatibility flags */ #if !GLIB_CHECK_VERSION(2, 26, 0) #define G_TIME_SPAN_SECOND (G_GINT64_CONSTANT(1000000)) @@ -41,15 +40,14 @@ #define HAVE_MONOTONIC_TIME #endif -#define QEMU_CMD_MEM " -m %d -object memory-backend-file,id=mem,size=%dM,"\ +#define QEMU_CMD_MEM " -m %d -object memory-backend-file,id=mem,size=%dM," \ "mem-path=%s,share=on -numa node,memdev=mem" +#define QEMU_CMD_MEMFD " -m %d -object memory-backend-memfd,id=mem,size=%dM," \ + " -numa node,memdev=mem" #define QEMU_CMD_CHR " -chardev socket,id=%s,path=%s%s" #define QEMU_CMD_NETDEV " -netdev vhost-user,id=net0,chardev=%s,vhostforce" #define QEMU_CMD_NET " -device virtio-net-pci,netdev=net0" -#define QEMU_CMD QEMU_CMD_MEM QEMU_CMD_CHR \ - QEMU_CMD_NETDEV QEMU_CMD_NET - #define HUGETLBFS_MAGIC 0x958458f6 /*********** FROM hw/virtio/vhost-user.c *************************************/ @@ -161,9 +159,40 @@ typedef struct TestServer { QGuestAllocator *alloc; } TestServer; +static TestServer *test_server_new(const gchar *name); +static void test_server_free(TestServer *server); +static void test_server_listen(TestServer *server); + static const char *tmpfs; static const char *root; +enum test_memfd { + TEST_MEMFD_AUTO, + TEST_MEMFD_YES, + TEST_MEMFD_NO, +}; + +static char *get_qemu_cmd(TestServer *s, + int mem, enum test_memfd memfd, const char *mem_path, + const char *chr_opts, const char *extra) +{ + if (memfd == TEST_MEMFD_AUTO && qemu_memfd_check()) { + memfd = TEST_MEMFD_YES; + } + + if (memfd == TEST_MEMFD_YES) { + return g_strdup_printf(QEMU_CMD_MEMFD QEMU_CMD_CHR + QEMU_CMD_NETDEV QEMU_CMD_NET "%s", mem, mem, + s->chr_name, s->socket_path, + chr_opts, s->chr_name, extra); + } else { + return g_strdup_printf(QEMU_CMD_MEM QEMU_CMD_CHR + QEMU_CMD_NETDEV QEMU_CMD_NET "%s", mem, mem, + mem_path, s->chr_name, s->socket_path, + chr_opts, s->chr_name, extra); + } +} + static void init_virtio_dev(TestServer *s, uint32_t features_mask) { uint32_t features; @@ -227,9 +256,8 @@ static void wait_for_fds(TestServer *s) g_mutex_unlock(&s->data_mutex); } -static void read_guest_mem(const void *data) +static void read_guest_mem_server(TestServer *s) { - TestServer *s = (void *)data; uint32_t *guest_mem; int i, j; size_t size; @@ -494,14 +522,6 @@ static void test_server_listen(TestServer *server) test_server_create_chr(server, ",server,nowait"); } -#define GET_QEMU_CMD(s) \ - g_strdup_printf(QEMU_CMD, 512, 512, (root), (s)->chr_name, \ - (s)->socket_path, "", (s)->chr_name) - -#define GET_QEMU_CMDE(s, mem, chr_opts, extra, ...) \ - g_strdup_printf(QEMU_CMD extra, (mem), (mem), (root), (s)->chr_name, \ - (s)->socket_path, (chr_opts), (s)->chr_name, ##__VA_ARGS__) - static gboolean _test_server_free(TestServer *server) { int i; @@ -638,8 +658,9 @@ GSourceFuncs test_migrate_source_funcs = { .check = test_migrate_source_check, }; -static void test_read_guest_mem(void) +static void test_read_guest_mem(const void *arg) { + enum test_memfd memfd = GPOINTER_TO_INT(arg); TestServer *server = NULL; char *qemu_cmd = NULL; QTestState *s = NULL; @@ -647,14 +668,14 @@ static void test_read_guest_mem(void) server = test_server_new("test"); test_server_listen(server); - qemu_cmd = GET_QEMU_CMD(server); + qemu_cmd = get_qemu_cmd(server, 512, memfd, root, "", ""); s = qtest_start(qemu_cmd); g_free(qemu_cmd); init_virtio_dev(server, 1u << VIRTIO_NET_F_MAC); - read_guest_mem(server); + read_guest_mem_server(server); uninit_virtio_dev(server); @@ -669,7 +690,7 @@ static void test_migrate(void) char *uri = g_strdup_printf("%s%s", "unix:", dest->mig_path); QTestState *global = global_qtest, *from, *to; GSource *source; - gchar *cmd; + gchar *cmd, *tmp; QDict *rsp; guint8 *log; guint64 size; @@ -677,7 +698,7 @@ static void test_migrate(void) test_server_listen(s); test_server_listen(dest); - cmd = GET_QEMU_CMDE(s, 2, "", ""); + cmd = get_qemu_cmd(s, 2, TEST_MEMFD_AUTO, root, "", ""); from = qtest_start(cmd); g_free(cmd); @@ -686,7 +707,9 @@ static void test_migrate(void) size = get_log_size(s); g_assert_cmpint(size, ==, (2 * 1024 * 1024) / (VHOST_LOG_PAGE * 8)); - cmd = GET_QEMU_CMDE(dest, 2, "", " -incoming %s", uri); + tmp = g_strdup_printf(" -incoming %s", uri); + cmd = get_qemu_cmd(dest, 2, TEST_MEMFD_AUTO, root, "", tmp); + g_free(tmp); to = qtest_init(cmd); g_free(cmd); @@ -732,7 +755,7 @@ static void test_migrate(void) global_qtest = to; qmp_eventwait("RESUME"); - read_guest_mem(dest); + read_guest_mem_server(dest); uninit_virtio_dev(s); @@ -765,7 +788,7 @@ static void wait_for_rings_started(TestServer *s, size_t count) g_mutex_unlock(&s->data_mutex); } -#if VHOST_USER_NET_TESTS_WORKING && defined(CONFIG_HAS_GLIB_SUBPROCESS_TESTS) +#if defined(CONFIG_HAS_GLIB_SUBPROCESS_TESTS) static inline void test_server_connect(TestServer *server) { test_server_create_chr(server, ",reconnect=1"); @@ -799,7 +822,7 @@ static void test_reconnect_subprocess(void) char *cmd; g_thread_new("connect", connect_thread, s); - cmd = GET_QEMU_CMDE(s, 2, ",server", ""); + cmd = get_qemu_cmd(s, 2, TEST_MEMFD_AUTO, root, ",server", ""); qtest_start(cmd); g_free(cmd); @@ -837,7 +860,7 @@ static void test_connect_fail_subprocess(void) s->test_fail = true; g_thread_new("connect", connect_thread, s); - cmd = GET_QEMU_CMDE(s, 2, ",server", ""); + cmd = get_qemu_cmd(s, 2, TEST_MEMFD_AUTO, root, ",server", ""); qtest_start(cmd); g_free(cmd); @@ -867,7 +890,7 @@ static void test_flags_mismatch_subprocess(void) s->test_flags = TEST_FLAGS_DISCONNECT; g_thread_new("connect", connect_thread, s); - cmd = GET_QEMU_CMDE(s, 2, ",server", ""); + cmd = get_qemu_cmd(s, 2, TEST_MEMFD_AUTO, root, ",server", ""); qtest_start(cmd); g_free(cmd); @@ -902,11 +925,21 @@ static void test_multiqueue(void) s->queues = 2; test_server_listen(s); - cmd = g_strdup_printf(QEMU_CMD_MEM QEMU_CMD_CHR QEMU_CMD_NETDEV ",queues=%d " - "-device virtio-net-pci,netdev=net0,mq=on,vectors=%d", - 512, 512, root, s->chr_name, - s->socket_path, "", s->chr_name, - s->queues, s->queues * 2 + 2); + if (qemu_memfd_check()) { + cmd = g_strdup_printf( + QEMU_CMD_MEMFD QEMU_CMD_CHR QEMU_CMD_NETDEV ",queues=%d " + "-device virtio-net-pci,netdev=net0,mq=on,vectors=%d", + 512, 512, s->chr_name, + s->socket_path, "", s->chr_name, + s->queues, s->queues * 2 + 2); + } else { + cmd = g_strdup_printf( + QEMU_CMD_MEM QEMU_CMD_CHR QEMU_CMD_NETDEV ",queues=%d " + "-device virtio-net-pci,netdev=net0,mq=on,vectors=%d", + 512, 512, root, s->chr_name, + s->socket_path, "", s->chr_name, + s->queues, s->queues * 2 + 2); + } qtest_start(cmd); g_free(cmd); @@ -952,20 +985,29 @@ int main(int argc, char **argv) /* run the main loop thread so the chardev may operate */ thread = g_thread_new(NULL, thread_function, loop); - qtest_add_func("/vhost-user/read-guest-mem", test_read_guest_mem); + if (qemu_memfd_check()) { + qtest_add_data_func("/vhost-user/read-guest-mem/memfd", + GINT_TO_POINTER(TEST_MEMFD_YES), + test_read_guest_mem); + } + qtest_add_data_func("/vhost-user/read-guest-mem/memfile", + GINT_TO_POINTER(TEST_MEMFD_NO), test_read_guest_mem); qtest_add_func("/vhost-user/migrate", test_migrate); qtest_add_func("/vhost-user/multiqueue", test_multiqueue); -#if VHOST_USER_NET_TESTS_WORKING && defined(CONFIG_HAS_GLIB_SUBPROCESS_TESTS) - qtest_add_func("/vhost-user/reconnect/subprocess", - test_reconnect_subprocess); - qtest_add_func("/vhost-user/reconnect", test_reconnect); - qtest_add_func("/vhost-user/connect-fail/subprocess", - test_connect_fail_subprocess); - qtest_add_func("/vhost-user/connect-fail", test_connect_fail); - qtest_add_func("/vhost-user/flags-mismatch/subprocess", - test_flags_mismatch_subprocess); - qtest_add_func("/vhost-user/flags-mismatch", test_flags_mismatch); +#if defined(CONFIG_HAS_GLIB_SUBPROCESS_TESTS) + /* keeps failing on build-system since Aug 15 2017 */ + if (getenv("QTEST_VHOST_USER_FIXME")) { + qtest_add_func("/vhost-user/reconnect/subprocess", + test_reconnect_subprocess); + qtest_add_func("/vhost-user/reconnect", test_reconnect); + qtest_add_func("/vhost-user/connect-fail/subprocess", + test_connect_fail_subprocess); + qtest_add_func("/vhost-user/connect-fail", test_connect_fail); + qtest_add_func("/vhost-user/flags-mismatch/subprocess", + test_flags_mismatch_subprocess); + qtest_add_func("/vhost-user/flags-mismatch", test_flags_mismatch); + } #endif ret = g_test_run(); diff --git a/util/coroutine-ucontext.c b/util/coroutine-ucontext.c index 6621f3f692..926d3402e3 100644 --- a/util/coroutine-ucontext.c +++ b/util/coroutine-ucontext.c @@ -31,6 +31,13 @@ #include <valgrind/valgrind.h> #endif +#if defined(__SANITIZE_ADDRESS__) || __has_feature(address_sanitizer) +#ifdef CONFIG_ASAN_IFACE_FIBER +#define CONFIG_ASAN 1 +#include <sanitizer/asan_interface.h> +#endif +#endif + typedef struct { Coroutine base; void *stack; @@ -59,11 +66,37 @@ union cc_arg { int i[2]; }; +static void finish_switch_fiber(void *fake_stack_save) +{ +#ifdef CONFIG_ASAN + const void *bottom_old; + size_t size_old; + + __sanitizer_finish_switch_fiber(fake_stack_save, &bottom_old, &size_old); + + if (!leader.stack) { + leader.stack = (void *)bottom_old; + leader.stack_size = size_old; + } +#endif +} + +static void start_switch_fiber(void **fake_stack_save, + const void *bottom, size_t size) +{ +#ifdef CONFIG_ASAN + __sanitizer_start_switch_fiber(fake_stack_save, bottom, size); +#endif +} + static void coroutine_trampoline(int i0, int i1) { union cc_arg arg; CoroutineUContext *self; Coroutine *co; + void *fake_stack_save = NULL; + + finish_switch_fiber(NULL); arg.i[0] = i0; arg.i[1] = i1; @@ -72,9 +105,13 @@ static void coroutine_trampoline(int i0, int i1) /* Initialize longjmp environment and switch back the caller */ if (!sigsetjmp(self->env, 0)) { + start_switch_fiber(&fake_stack_save, + leader.stack, leader.stack_size); siglongjmp(*(sigjmp_buf *)co->entry_arg, 1); } + finish_switch_fiber(fake_stack_save); + while (true) { co->entry(co->entry_arg); qemu_coroutine_switch(co, co->caller, COROUTINE_TERMINATE); @@ -87,6 +124,7 @@ Coroutine *qemu_coroutine_new(void) ucontext_t old_uc, uc; sigjmp_buf old_env; union cc_arg arg = {0}; + void *fake_stack_save = NULL; /* The ucontext functions preserve signal masks which incurs a * system call overhead. sigsetjmp(buf, 0)/siglongjmp() does not @@ -122,8 +160,12 @@ Coroutine *qemu_coroutine_new(void) /* swapcontext() in, siglongjmp() back out */ if (!sigsetjmp(old_env, 0)) { + start_switch_fiber(&fake_stack_save, co->stack, co->stack_size); swapcontext(&old_uc, &uc); } + + finish_switch_fiber(fake_stack_save); + return &co->base; } @@ -169,13 +211,19 @@ qemu_coroutine_switch(Coroutine *from_, Coroutine *to_, CoroutineUContext *from = DO_UPCAST(CoroutineUContext, base, from_); CoroutineUContext *to = DO_UPCAST(CoroutineUContext, base, to_); int ret; + void *fake_stack_save = NULL; current = to_; ret = sigsetjmp(from->env, 0); if (ret == 0) { + start_switch_fiber(action == COROUTINE_TERMINATE ? + NULL : &fake_stack_save, to->stack, to->stack_size); siglongjmp(to->env, action); } + + finish_switch_fiber(fake_stack_save); + return ret; } diff --git a/util/memfd.c b/util/memfd.c index dce61f9d21..07d579ea7d 100644 --- a/util/memfd.c +++ b/util/memfd.c @@ -27,7 +27,9 @@ #include "qemu/osdep.h" +#include "qapi/error.h" #include "qemu/memfd.h" +#include "qemu/host-utils.h" #if defined CONFIG_LINUX && !defined CONFIG_MEMFD #include <sys/syscall.h> @@ -51,36 +53,59 @@ static int memfd_create(const char *name, unsigned int flags) #define MFD_ALLOW_SEALING 0x0002U #endif -int qemu_memfd_create(const char *name, size_t size, unsigned int seals) +#ifndef MFD_HUGETLB +#define MFD_HUGETLB 0x0004U +#endif + +#ifndef MFD_HUGE_SHIFT +#define MFD_HUGE_SHIFT 26 +#endif + +int qemu_memfd_create(const char *name, size_t size, bool hugetlb, + uint64_t hugetlbsize, unsigned int seals, Error **errp) { - int mfd = -1; + int htsize = hugetlbsize ? ctz64(hugetlbsize) : 0; + + if (htsize && 1 << htsize != hugetlbsize) { + error_setg(errp, "Hugepage size must be a power of 2"); + return -1; + } + + htsize = htsize << MFD_HUGE_SHIFT; #ifdef CONFIG_LINUX + int mfd = -1; unsigned int flags = MFD_CLOEXEC; if (seals) { flags |= MFD_ALLOW_SEALING; } - + if (hugetlb) { + flags |= MFD_HUGETLB; + flags |= htsize; + } mfd = memfd_create(name, flags); if (mfd < 0) { - return -1; + goto err; } if (ftruncate(mfd, size) == -1) { - perror("ftruncate"); - close(mfd); - return -1; + goto err; } if (seals && fcntl(mfd, F_ADD_SEALS, seals) == -1) { - perror("fcntl"); - close(mfd); - return -1; + goto err; } -#endif return mfd; + +err: + if (mfd >= 0) { + close(mfd); + } +#endif + error_setg_errno(errp, errno, "failed to create memfd"); + return -1; } /* @@ -90,14 +115,14 @@ int qemu_memfd_create(const char *name, size_t size, unsigned int seals) * sealing. */ void *qemu_memfd_alloc(const char *name, size_t size, unsigned int seals, - int *fd) + int *fd, Error **errp) { void *ptr; - int mfd = qemu_memfd_create(name, size, seals); + int mfd = qemu_memfd_create(name, size, false, 0, seals, NULL); /* some systems have memfd without sealing */ if (mfd == -1) { - mfd = qemu_memfd_create(name, size, 0); + mfd = qemu_memfd_create(name, size, false, 0, 0, NULL); } if (mfd == -1) { @@ -109,27 +134,26 @@ void *qemu_memfd_alloc(const char *name, size_t size, unsigned int seals, unlink(fname); g_free(fname); - if (mfd == -1) { - perror("mkstemp"); - return NULL; - } - - if (ftruncate(mfd, size) == -1) { - perror("ftruncate"); - close(mfd); - return NULL; + if (mfd == -1 || + ftruncate(mfd, size) == -1) { + goto err; } } ptr = mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, mfd, 0); if (ptr == MAP_FAILED) { - perror("mmap"); - close(mfd); - return NULL; + goto err; } *fd = mfd; return ptr; + +err: + error_setg_errno(errp, errno, "failed to allocate shared memory"); + if (mfd >= 0) { + close(mfd); + } + return NULL; } void qemu_memfd_free(void *ptr, size_t size, int fd) @@ -157,7 +181,7 @@ bool qemu_memfd_check(void) int fd; void *ptr; - ptr = qemu_memfd_alloc("test", 4096, 0, &fd); + ptr = qemu_memfd_alloc("test", 4096, 0, &fd, NULL); memfd_check = ptr ? MEMFD_OK : MEMFD_KO; qemu_memfd_free(ptr, 4096, fd); } diff --git a/util/qemu-sockets.c b/util/qemu-sockets.c index d6a1e1759e..fbbef69f62 100644 --- a/util/qemu-sockets.c +++ b/util/qemu-sockets.c @@ -554,6 +554,33 @@ err: } /* compatibility wrapper */ +static int inet_parse_flag(const char *flagname, const char *optstr, bool *val, + Error **errp) +{ + char *end; + size_t len; + + end = strstr(optstr, ","); + if (end) { + if (end[1] == ',') { /* Reject 'ipv6=on,,foo' */ + error_setg(errp, "error parsing '%s' flag '%s'", flagname, optstr); + return -1; + } + len = end - optstr; + } else { + len = strlen(optstr); + } + if (len == 0 || (len == 3 && strncmp(optstr, "=on", len) == 0)) { + *val = true; + } else if (len == 4 && strncmp(optstr, "=off", len) == 0) { + *val = false; + } else { + error_setg(errp, "error parsing '%s' flag '%s'", flagname, optstr); + return -1; + } + return 0; +} + int inet_parse(InetSocketAddress *addr, const char *str, Error **errp) { const char *optstr, *h; @@ -561,6 +588,7 @@ int inet_parse(InetSocketAddress *addr, const char *str, Error **errp) char port[33]; int to; int pos; + char *begin; memset(addr, 0, sizeof(*addr)); @@ -602,11 +630,19 @@ int inet_parse(InetSocketAddress *addr, const char *str, Error **errp) addr->has_to = true; addr->to = to; } - if (strstr(optstr, ",ipv4")) { - addr->ipv4 = addr->has_ipv4 = true; + begin = strstr(optstr, ",ipv4"); + if (begin) { + if (inet_parse_flag("ipv4", begin + 5, &addr->ipv4, errp) < 0) { + return -1; + } + addr->has_ipv4 = true; } - if (strstr(optstr, ",ipv6")) { - addr->ipv6 = addr->has_ipv6 = true; + begin = strstr(optstr, ",ipv6"); + if (begin) { + if (inet_parse_flag("ipv6", begin + 5, &addr->ipv6, errp) < 0) { + return -1; + } + addr->has_ipv6 = true; } return 0; } diff --git a/util/readline.c b/util/readline.c index 24ec839854..ec91ee0fea 100644 --- a/util/readline.c +++ b/util/readline.c @@ -510,9 +510,6 @@ void readline_free(ReadLineState *rs) for (i = 0; i < READLINE_MAX_CMDS; i++) { g_free(rs->history[i]); } - for (i = 0; i < READLINE_MAX_COMPLETIONS; i++) { - g_free(rs->completions[i]); - } g_free(rs); } @@ -2172,7 +2172,7 @@ static DisplayType select_display(const char *p) display_opengl = 1; display = DT_EGL; #else - fprintf(stderr, "egl support is disabled\n"); + error_report("egl support is disabled"); exit(1); #endif } else if (strstart(p, "curses", &opts)) { |