From 3a7a27cffb5ed50840e26a2567e187b17958cc64 Mon Sep 17 00:00:00 2001 From: Yang Weijiang Date: Tue, 17 May 2022 11:50:24 -0400 Subject: [PATCH 01/17] target/i386: Remove LBREn bit check when access Arch LBR MSRs Live migration can happen when Arch LBR LBREn bit is cleared, e.g., when migration happens after guest entered SMM mode. In this case, we still need to migrate Arch LBR MSRs. Signed-off-by: Yang Weijiang Message-Id: <20220517155024.33270-1-weijiang.yang@intel.com> Signed-off-by: Paolo Bonzini --- target/i386/kvm/kvm.c | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c index a9ee8eebd7..e2d675115b 100644 --- a/target/i386/kvm/kvm.c +++ b/target/i386/kvm/kvm.c @@ -3373,15 +3373,14 @@ static int kvm_put_msrs(X86CPU *cpu, int level) int i, ret; /* - * Only migrate Arch LBR states when: 1) Arch LBR is enabled - * for migrated vcpu. 2) the host Arch LBR depth equals that - * of source guest's, this is to avoid mismatch of guest/host - * config for the msr hence avoid unexpected misbehavior. + * Only migrate Arch LBR states when the host Arch LBR depth + * equals that of source guest's, this is to avoid mismatch + * of guest/host config for the msr hence avoid unexpected + * misbehavior. */ ret = kvm_get_one_msr(cpu, MSR_ARCH_LBR_DEPTH, &depth); - if (ret == 1 && (env->msr_lbr_ctl & 0x1) && !!depth && - depth == env->msr_lbr_depth) { + if (ret == 1 && !!depth && depth == env->msr_lbr_depth) { kvm_msr_entry_add(cpu, MSR_ARCH_LBR_CTL, env->msr_lbr_ctl); kvm_msr_entry_add(cpu, MSR_ARCH_LBR_DEPTH, env->msr_lbr_depth); @@ -3801,13 +3800,11 @@ static int kvm_get_msrs(X86CPU *cpu) if (kvm_enabled() && cpu->enable_pmu && (env->features[FEAT_7_0_EDX] & CPUID_7_0_EDX_ARCH_LBR)) { - uint64_t ctl, depth; - int i, ret2; + uint64_t depth; + int i, ret; - ret = kvm_get_one_msr(cpu, MSR_ARCH_LBR_CTL, &ctl); - ret2 = kvm_get_one_msr(cpu, MSR_ARCH_LBR_DEPTH, &depth); - if (ret == 1 && ret2 == 1 && (ctl & 0x1) && - depth == ARCH_LBR_NR_ENTRIES) { + ret = kvm_get_one_msr(cpu, MSR_ARCH_LBR_DEPTH, &depth); + if (ret == 1 && depth == ARCH_LBR_NR_ENTRIES) { kvm_msr_entry_add(cpu, MSR_ARCH_LBR_CTL, 0); kvm_msr_entry_add(cpu, MSR_ARCH_LBR_DEPTH, 0); From f8d426a6852c560fdd8648ae961c8189909a4b82 Mon Sep 17 00:00:00 2001 From: Jaroslav Jindrak Date: Tue, 17 May 2022 14:38:58 +0200 Subject: [PATCH 02/17] hostmem: default the amount of prealloc-threads to smp-cpus Prior to the introduction of the prealloc-threads property, the amount of threads used to preallocate memory was derived from the value of smp-cpus passed to qemu, the amount of physical cpus of the host and a hardcoded maximum value. When the prealloc-threads property was introduced, it included a default of 1 in backends/hostmem.c and a default of smp-cpus using the sugar API for the property itself. The latter default is not used when the property is not specified on qemu's command line, so guests that were not adjusted for this change suddenly started to use the default of 1 thread to preallocate memory, which resulted in observable slowdowns in guest boots for guests with large memory (e.g. when using libvirt <8.2.0 or managing guests manually). This commit restores the original behavior for these cases while not impacting guests started with the prealloc-threads property in any way. Fixes: 220c1fd864e9d ("hostmem: introduce "prealloc-threads" property") Signed-off-by: Jaroslav Jindrak Message-Id: <20220517123858.7933-1-dzejrou@gmail.com> Signed-off-by: Paolo Bonzini --- backends/hostmem.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backends/hostmem.c b/backends/hostmem.c index a7bae3d713..624bb7ecd3 100644 --- a/backends/hostmem.c +++ b/backends/hostmem.c @@ -274,7 +274,7 @@ static void host_memory_backend_init(Object *obj) backend->merge = machine_mem_merge(machine); backend->dump = machine_dump_guest_core(machine); backend->reserve = true; - backend->prealloc_threads = 1; + backend->prealloc_threads = machine->smp.cpus; } static void host_memory_backend_post_init(Object *obj) From 3c7b72ddca9ce85a9d1e8a98fd0996b74597b5ae Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Sat, 14 May 2022 08:50:10 +0200 Subject: [PATCH 03/17] thread-pool: optimize scheduling of completion bottom half The completion bottom half was scheduled within the pool->lock critical section. That actually results in worse performance, because the worker thread can run its own small critical section and go to sleep before the bottom half starts running. Note that this simple change does not produce an improvement without changing the thread pool QemuSemaphore to a condition variable. Reviewed-by: Stefan Hajnoczi Reviewed-by: Nicolas Saenz Julienne Message-Id: <20220514065012.1149539-2-pbonzini@redhat.com> Signed-off-by: Paolo Bonzini --- util/thread-pool.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/util/thread-pool.c b/util/thread-pool.c index 196835b4d3..4979f30ca3 100644 --- a/util/thread-pool.c +++ b/util/thread-pool.c @@ -127,9 +127,8 @@ static void *worker_thread(void *opaque) smp_wmb(); req->state = THREAD_DONE; - qemu_mutex_lock(&pool->lock); - qemu_bh_schedule(pool->completion_bh); + qemu_mutex_lock(&pool->lock); } pool->cur_threads--; From 900fa208f50623672a6f879374222a7fd4717791 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Sat, 14 May 2022 08:50:11 +0200 Subject: [PATCH 04/17] thread-pool: replace semaphore with condition variable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since commit f9fc8932b1 ("thread-posix: remove the posix semaphore support", 2022-04-06) QemuSemaphore has its own mutex and condition variable; this adds unnecessary overhead on I/O with small block sizes. Check the QTAILQ directly instead of adding the indirection of a semaphore's count. Using a semaphore has not been necessary since qemu_cond_timedwait was introduced; the new code has to be careful about spurious wakeups but it is simpler, for example thread_pool_cancel does not have to worry about synchronizing the semaphore count with the number of elements of pool->request_list. Note that the return value of qemu_cond_timedwait (0 for timeout, 1 for signal or spurious wakeup) is different from that of qemu_sem_timedwait (-1 for timeout, 0 for success). Reported-by: Lukáš Doktor Suggested-by: Stefan Hajnoczi Reviewed-by: Nicolas Saenz Julienne Message-Id: <20220514065012.1149539-3-pbonzini@redhat.com> Signed-off-by: Paolo Bonzini --- util/thread-pool.c | 68 +++++++++++++++++++--------------------------- 1 file changed, 28 insertions(+), 40 deletions(-) diff --git a/util/thread-pool.c b/util/thread-pool.c index 4979f30ca3..6e3d4e4a2f 100644 --- a/util/thread-pool.c +++ b/util/thread-pool.c @@ -57,7 +57,7 @@ struct ThreadPool { QEMUBH *completion_bh; QemuMutex lock; QemuCond worker_stopped; - QemuSemaphore sem; + QemuCond request_cond; QEMUBH *new_thread_bh; /* The following variables are only accessed from one AioContext. */ @@ -74,23 +74,6 @@ struct ThreadPool { int max_threads; }; -static inline bool back_to_sleep(ThreadPool *pool, int ret) -{ - /* - * The semaphore timed out, we should exit the loop except when: - * - There is work to do, we raced with the signal. - * - The max threads threshold just changed, we raced with the signal. - * - The thread pool forces a minimum number of readily available threads. - */ - if (ret == -1 && (!QTAILQ_EMPTY(&pool->request_list) || - pool->cur_threads > pool->max_threads || - pool->cur_threads <= pool->min_threads)) { - return true; - } - - return false; -} - static void *worker_thread(void *opaque) { ThreadPool *pool = opaque; @@ -99,20 +82,25 @@ static void *worker_thread(void *opaque) pool->pending_threads--; do_spawn_thread(pool); - while (!pool->stopping) { + while (!pool->stopping && pool->cur_threads <= pool->max_threads) { ThreadPoolElement *req; int ret; - do { + if (QTAILQ_EMPTY(&pool->request_list)) { pool->idle_threads++; - qemu_mutex_unlock(&pool->lock); - ret = qemu_sem_timedwait(&pool->sem, 10000); - qemu_mutex_lock(&pool->lock); + ret = qemu_cond_timedwait(&pool->request_cond, &pool->lock, 10000); pool->idle_threads--; - } while (back_to_sleep(pool, ret)); - if (ret == -1 || pool->stopping || - pool->cur_threads > pool->max_threads) { - break; + if (ret == 0 && + QTAILQ_EMPTY(&pool->request_list) && + pool->cur_threads > pool->min_threads) { + /* Timed out + no work to do + no need for warm threads = exit. */ + break; + } + /* + * Even if there was some work to do, check if there aren't + * too many worker threads before picking it up. + */ + continue; } req = QTAILQ_FIRST(&pool->request_list); @@ -134,6 +122,12 @@ static void *worker_thread(void *opaque) pool->cur_threads--; qemu_cond_signal(&pool->worker_stopped); qemu_mutex_unlock(&pool->lock); + + /* + * Wake up another thread, in case we got a wakeup but decided + * to exit due to pool->cur_threads > pool->max_threads. + */ + qemu_cond_signal(&pool->request_cond); return NULL; } @@ -229,13 +223,7 @@ static void thread_pool_cancel(BlockAIOCB *acb) trace_thread_pool_cancel(elem, elem->common.opaque); QEMU_LOCK_GUARD(&pool->lock); - if (elem->state == THREAD_QUEUED && - /* No thread has yet started working on elem. we can try to "steal" - * the item from the worker if we can get a signal from the - * semaphore. Because this is non-blocking, we can do it with - * the lock taken and ensure that elem will remain THREAD_QUEUED. - */ - qemu_sem_timedwait(&pool->sem, 0) == 0) { + if (elem->state == THREAD_QUEUED) { QTAILQ_REMOVE(&pool->request_list, elem, reqs); qemu_bh_schedule(pool->completion_bh); @@ -280,7 +268,7 @@ BlockAIOCB *thread_pool_submit_aio(ThreadPool *pool, } QTAILQ_INSERT_TAIL(&pool->request_list, req, reqs); qemu_mutex_unlock(&pool->lock); - qemu_sem_post(&pool->sem); + qemu_cond_signal(&pool->request_cond); return &req->common; } @@ -323,7 +311,7 @@ void thread_pool_update_params(ThreadPool *pool, AioContext *ctx) * We either have to: * - Increase the number available of threads until over the min_threads * threshold. - * - Decrease the number of available threads until under the max_threads + * - Bump the worker threads so that they exit, until under the max_threads * threshold. * - Do nothing. The current number of threads fall in between the min and * max thresholds. We'll let the pool manage itself. @@ -333,7 +321,7 @@ void thread_pool_update_params(ThreadPool *pool, AioContext *ctx) } for (int i = pool->cur_threads; i > pool->max_threads; i--) { - qemu_sem_post(&pool->sem); + qemu_cond_signal(&pool->request_cond); } qemu_mutex_unlock(&pool->lock); @@ -350,7 +338,7 @@ static void thread_pool_init_one(ThreadPool *pool, AioContext *ctx) pool->completion_bh = aio_bh_new(ctx, thread_pool_completion_bh, pool); qemu_mutex_init(&pool->lock); qemu_cond_init(&pool->worker_stopped); - qemu_sem_init(&pool->sem, 0); + qemu_cond_init(&pool->request_cond); pool->new_thread_bh = aio_bh_new(ctx, spawn_thread_bh_fn, pool); QLIST_INIT(&pool->head); @@ -383,15 +371,15 @@ void thread_pool_free(ThreadPool *pool) /* Wait for worker threads to terminate */ pool->stopping = true; + qemu_cond_broadcast(&pool->request_cond); while (pool->cur_threads > 0) { - qemu_sem_post(&pool->sem); qemu_cond_wait(&pool->worker_stopped, &pool->lock); } qemu_mutex_unlock(&pool->lock); qemu_bh_delete(pool->completion_bh); - qemu_sem_destroy(&pool->sem); + qemu_cond_destroy(&pool->request_cond); qemu_cond_destroy(&pool->worker_stopped); qemu_mutex_destroy(&pool->lock); g_free(pool); From 232e9255478f3849957d2f4b083d6e5d4736ab04 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Sat, 14 May 2022 08:50:12 +0200 Subject: [PATCH 05/17] thread-pool: remove stopping variable Just setting the max threads to 0 is enough to stop all workers. Message-Id: <20220514065012.1149539-4-pbonzini@redhat.com> Reviewed-by: Stefan Hajnoczi Reviewed-by: Nicolas Saenz Julienne Signed-off-by: Paolo Bonzini --- util/thread-pool.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/util/thread-pool.c b/util/thread-pool.c index 6e3d4e4a2f..31113b5860 100644 --- a/util/thread-pool.c +++ b/util/thread-pool.c @@ -69,7 +69,6 @@ struct ThreadPool { int idle_threads; int new_threads; /* backlog of threads we need to create */ int pending_threads; /* threads created but not running yet */ - bool stopping; int min_threads; int max_threads; }; @@ -82,7 +81,7 @@ static void *worker_thread(void *opaque) pool->pending_threads--; do_spawn_thread(pool); - while (!pool->stopping && pool->cur_threads <= pool->max_threads) { + while (pool->cur_threads <= pool->max_threads) { ThreadPoolElement *req; int ret; @@ -370,7 +369,7 @@ void thread_pool_free(ThreadPool *pool) pool->new_threads = 0; /* Wait for worker threads to terminate */ - pool->stopping = true; + pool->max_threads = 0; qemu_cond_broadcast(&pool->request_cond); while (pool->cur_threads > 0) { qemu_cond_wait(&pool->worker_stopped, &pool->lock); From c06ebc0f1b13b9b3802b35969c00e19a31cde484 Mon Sep 17 00:00:00 2001 From: Viktor Prutyanov Date: Fri, 20 May 2022 11:43:39 +0300 Subject: [PATCH 06/17] contrib/elf2dmp: add ELF dump header checking Add ELF header checking to prevent processing input file which is not QEMU x86_64 guest memory dump or even not ELF. Resolves: https://gitlab.com/qemu-project/qemu/-/issues/1013 Signed-off-by: Viktor Prutyanov Reviewed-by: Richard Henderson Message-Id: <20220520084339.171684-1-viktor.prutyanov@redhat.com> Signed-off-by: Paolo Bonzini --- contrib/elf2dmp/qemu_elf.c | 53 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/contrib/elf2dmp/qemu_elf.c b/contrib/elf2dmp/qemu_elf.c index b601b6d7ba..ebda60dcb8 100644 --- a/contrib/elf2dmp/qemu_elf.c +++ b/contrib/elf2dmp/qemu_elf.c @@ -118,6 +118,53 @@ static void exit_states(QEMU_Elf *qe) free(qe->state); } +static bool check_ehdr(QEMU_Elf *qe) +{ + Elf64_Ehdr *ehdr = qe->map; + + if (sizeof(Elf64_Ehdr) > qe->size) { + eprintf("Invalid input dump file size\n"); + return false; + } + + if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG)) { + eprintf("Invalid ELF signature, input file is not ELF\n"); + return false; + } + + if (ehdr->e_ident[EI_CLASS] != ELFCLASS64 || + ehdr->e_ident[EI_DATA] != ELFDATA2LSB) { + eprintf("Invalid ELF class or byte order, must be 64-bit LE\n"); + return false; + } + + if (ehdr->e_ident[EI_VERSION] != EV_CURRENT) { + eprintf("Invalid ELF version\n"); + return false; + } + + if (ehdr->e_machine != EM_X86_64) { + eprintf("Invalid input dump architecture, only x86_64 is supported\n"); + return false; + } + + if (ehdr->e_type != ET_CORE) { + eprintf("Invalid ELF type, must be core file\n"); + return false; + } + + /* + * ELF dump file must contain one PT_NOTE and at least one PT_LOAD to + * restore physical address space. + */ + if (ehdr->e_phnum < 2) { + eprintf("Invalid number of ELF program headers\n"); + return false; + } + + return true; +} + int QEMU_Elf_init(QEMU_Elf *qe, const char *filename) { GError *gerr = NULL; @@ -133,6 +180,12 @@ int QEMU_Elf_init(QEMU_Elf *qe, const char *filename) qe->map = g_mapped_file_get_contents(qe->gmf); qe->size = g_mapped_file_get_length(qe->gmf); + if (!check_ehdr(qe)) { + eprintf("Input file has the wrong format\n"); + err = 1; + goto out_unmap; + } + if (init_states(qe)) { eprintf("Failed to extract QEMU CPU states\n"); err = 1; From ab9f0f7d44d6795050187b3bb0fc28fe804a062b Mon Sep 17 00:00:00 2001 From: BALATON Zoltan Date: Sat, 23 Apr 2022 11:36:57 +0200 Subject: [PATCH 07/17] hw/audio/ac97: Coding style fixes to avoid checkpatch errors MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: BALATON Zoltan Reviewed-by: Víctor Colombo Message-Id: <62862a057e9c9ec0bb45248b2b9a3a1babb346a6.1650706617.git.balaton@eik.bme.hu> Signed-off-by: Paolo Bonzini --- hw/audio/ac97.c | 727 ++++++++++++++++++++++++------------------------ 1 file changed, 357 insertions(+), 370 deletions(-) diff --git a/hw/audio/ac97.c b/hw/audio/ac97.c index 3cb8131060..6b1c12bece 100644 --- a/hw/audio/ac97.c +++ b/hw/audio/ac97.c @@ -87,39 +87,39 @@ enum { #define GC_CR 2 /* rw */ #define GC_VALID_MASK ((1 << 6) - 1) -#define GS_MD3 (1<<17) /* rw */ -#define GS_AD3 (1<<16) /* rw */ -#define GS_RCS (1<<15) /* rwc */ -#define GS_B3S12 (1<<14) /* ro */ -#define GS_B2S12 (1<<13) /* ro */ -#define GS_B1S12 (1<<12) /* ro */ -#define GS_S1R1 (1<<11) /* rwc */ -#define GS_S0R1 (1<<10) /* rwc */ -#define GS_S1CR (1<<9) /* ro */ -#define GS_S0CR (1<<8) /* ro */ -#define GS_MINT (1<<7) /* ro */ -#define GS_POINT (1<<6) /* ro */ -#define GS_PIINT (1<<5) /* ro */ -#define GS_RSRVD ((1<<4)|(1<<3)) -#define GS_MOINT (1<<2) /* ro */ -#define GS_MIINT (1<<1) /* ro */ +#define GS_MD3 (1 << 17) /* rw */ +#define GS_AD3 (1 << 16) /* rw */ +#define GS_RCS (1 << 15) /* rwc */ +#define GS_B3S12 (1 << 14) /* ro */ +#define GS_B2S12 (1 << 13) /* ro */ +#define GS_B1S12 (1 << 12) /* ro */ +#define GS_S1R1 (1 << 11) /* rwc */ +#define GS_S0R1 (1 << 10) /* rwc */ +#define GS_S1CR (1 << 9) /* ro */ +#define GS_S0CR (1 << 8) /* ro */ +#define GS_MINT (1 << 7) /* ro */ +#define GS_POINT (1 << 6) /* ro */ +#define GS_PIINT (1 << 5) /* ro */ +#define GS_RSRVD ((1 << 4) | (1 << 3)) +#define GS_MOINT (1 << 2) /* ro */ +#define GS_MIINT (1 << 1) /* ro */ #define GS_GSCI 1 /* rwc */ -#define GS_RO_MASK (GS_B3S12| \ - GS_B2S12| \ - GS_B1S12| \ - GS_S1CR| \ - GS_S0CR| \ - GS_MINT| \ - GS_POINT| \ - GS_PIINT| \ - GS_RSRVD| \ - GS_MOINT| \ +#define GS_RO_MASK (GS_B3S12 | \ + GS_B2S12 | \ + GS_B1S12 | \ + GS_S1CR | \ + GS_S0CR | \ + GS_MINT | \ + GS_POINT | \ + GS_PIINT | \ + GS_RSRVD | \ + GS_MOINT | \ GS_MIINT) #define GS_VALID_MASK ((1 << 18) - 1) -#define GS_WCLEAR_MASK (GS_RCS|GS_S1R1|GS_S0R1|GS_GSCI) +#define GS_WCLEAR_MASK (GS_RCS | GS_S1R1 | GS_S0R1 | GS_GSCI) -#define BD_IOC (1<<31) -#define BD_BUP (1<<30) +#define BD_IOC (1 << 31) +#define BD_BUP (1 << 30) #define EACS_VRA 1 #define EACS_VRM 8 @@ -183,7 +183,7 @@ enum { }; #ifdef DEBUG_AC97 -#define dolog(...) AUD_log ("ac97", __VA_ARGS__) +#define dolog(...) AUD_log("ac97", __VA_ARGS__) #else #define dolog(...) #endif @@ -206,9 +206,9 @@ enum { LAST_INDEX }; -MKREGS (PI, PI_INDEX * 16); -MKREGS (PO, PO_INDEX * 16); -MKREGS (MC, MC_INDEX * 16); +MKREGS(PI, PI_INDEX * 16); +MKREGS(PO, PO_INDEX * 16); +MKREGS(MC, MC_INDEX * 16); enum { GLOB_CNT = 0x2c, @@ -218,36 +218,35 @@ enum { #define GET_BM(index) (((index) >> 4) & 3) -static void po_callback (void *opaque, int free); -static void pi_callback (void *opaque, int avail); -static void mc_callback (void *opaque, int avail); +static void po_callback(void *opaque, int free); +static void pi_callback(void *opaque, int avail); +static void mc_callback(void *opaque, int avail); -static void warm_reset (AC97LinkState *s) +static void warm_reset(AC97LinkState *s) { - (void) s; + (void)s; } -static void cold_reset (AC97LinkState * s) +static void cold_reset(AC97LinkState *s) { - (void) s; + (void)s; } -static void fetch_bd (AC97LinkState *s, AC97BusMasterRegs *r) +static void fetch_bd(AC97LinkState *s, AC97BusMasterRegs *r) { uint8_t b[8]; - pci_dma_read (&s->dev, r->bdbar + r->civ * 8, b, 8); + pci_dma_read(&s->dev, r->bdbar + r->civ * 8, b, 8); r->bd_valid = 1; - r->bd.addr = le32_to_cpu (*(uint32_t *) &b[0]) & ~3; - r->bd.ctl_len = le32_to_cpu (*(uint32_t *) &b[4]); + r->bd.addr = le32_to_cpu(*(uint32_t *) &b[0]) & ~3; + r->bd.ctl_len = le32_to_cpu(*(uint32_t *) &b[4]); r->picb = r->bd.ctl_len & 0xffff; - dolog ("bd %2d addr=%#x ctl=%#06x len=%#x(%d bytes)\n", - r->civ, r->bd.addr, r->bd.ctl_len >> 16, - r->bd.ctl_len & 0xffff, - (r->bd.ctl_len & 0xffff) << 1); + dolog("bd %2d addr=0x%x ctl=0x%06x len=0x%x(%d bytes)\n", + r->civ, r->bd.addr, r->bd.ctl_len >> 16, + r->bd.ctl_len & 0xffff, (r->bd.ctl_len & 0xffff) << 1); } -static void update_sr (AC97LinkState *s, AC97BusMasterRegs *r, uint32_t new_sr) +static void update_sr(AC97LinkState *s, AC97BusMasterRegs *r, uint32_t new_sr) { int event = 0; int level = 0; @@ -260,8 +259,7 @@ static void update_sr (AC97LinkState *s, AC97BusMasterRegs *r, uint32_t new_sr) if (!new_mask) { event = 1; level = 0; - } - else { + } else { if ((new_mask & SR_LVBCI) && (r->cr & CR_LVBIE)) { event = 1; level = 1; @@ -275,69 +273,67 @@ static void update_sr (AC97LinkState *s, AC97BusMasterRegs *r, uint32_t new_sr) r->sr = new_sr; - dolog ("IOC%d LVB%d sr=%#x event=%d level=%d\n", - r->sr & SR_BCIS, r->sr & SR_LVBCI, - r->sr, - event, level); + dolog("IOC%d LVB%d sr=0x%x event=%d level=%d\n", + r->sr & SR_BCIS, r->sr & SR_LVBCI, r->sr, event, level); - if (!event) + if (!event) { return; + } if (level) { s->glob_sta |= masks[r - s->bm_regs]; - dolog ("set irq level=1\n"); + dolog("set irq level=1\n"); pci_irq_assert(&s->dev); - } - else { + } else { s->glob_sta &= ~masks[r - s->bm_regs]; - dolog ("set irq level=0\n"); + dolog("set irq level=0\n"); pci_irq_deassert(&s->dev); } } -static void voice_set_active (AC97LinkState *s, int bm_index, int on) +static void voice_set_active(AC97LinkState *s, int bm_index, int on) { switch (bm_index) { case PI_INDEX: - AUD_set_active_in (s->voice_pi, on); + AUD_set_active_in(s->voice_pi, on); break; case PO_INDEX: - AUD_set_active_out (s->voice_po, on); + AUD_set_active_out(s->voice_po, on); break; case MC_INDEX: - AUD_set_active_in (s->voice_mc, on); + AUD_set_active_in(s->voice_mc, on); break; default: - AUD_log ("ac97", "invalid bm_index(%d) in voice_set_active", bm_index); + AUD_log("ac97", "invalid bm_index(%d) in voice_set_active", bm_index); break; } } -static void reset_bm_regs (AC97LinkState *s, AC97BusMasterRegs *r) +static void reset_bm_regs(AC97LinkState *s, AC97BusMasterRegs *r) { - dolog ("reset_bm_regs\n"); + dolog("reset_bm_regs\n"); r->bdbar = 0; r->civ = 0; r->lvi = 0; /** todo do we need to do that? */ - update_sr (s, r, SR_DCH); + update_sr(s, r, SR_DCH); r->picb = 0; r->piv = 0; r->cr = r->cr & CR_DONT_CLEAR_MASK; r->bd_valid = 0; - voice_set_active (s, r - s->bm_regs, 0); - memset (s->silence, 0, sizeof (s->silence)); + voice_set_active(s, r - s->bm_regs, 0); + memset(s->silence, 0, sizeof(s->silence)); } -static void mixer_store (AC97LinkState *s, uint32_t i, uint16_t v) +static void mixer_store(AC97LinkState *s, uint32_t i, uint16_t v) { - if (i + 2 > sizeof (s->mixer_data)) { - dolog ("mixer_store: index %d out of bounds %zd\n", - i, sizeof (s->mixer_data)); + if (i + 2 > sizeof(s->mixer_data)) { + dolog("mixer_store: index %d out of bounds %zd\n", + i, sizeof(s->mixer_data)); return; } @@ -345,22 +341,21 @@ static void mixer_store (AC97LinkState *s, uint32_t i, uint16_t v) s->mixer_data[i + 1] = v >> 8; } -static uint16_t mixer_load (AC97LinkState *s, uint32_t i) +static uint16_t mixer_load(AC97LinkState *s, uint32_t i) { uint16_t val = 0xffff; - if (i + 2 > sizeof (s->mixer_data)) { - dolog ("mixer_load: index %d out of bounds %zd\n", - i, sizeof (s->mixer_data)); - } - else { + if (i + 2 > sizeof(s->mixer_data)) { + dolog("mixer_load: index %d out of bounds %zd\n", + i, sizeof(s->mixer_data)); + } else { val = s->mixer_data[i + 0] | (s->mixer_data[i + 1] << 8); } return val; } -static void open_voice (AC97LinkState *s, int index, int freq) +static void open_voice(AC97LinkState *s, int index, int freq) { struct audsettings as; @@ -373,7 +368,7 @@ static void open_voice (AC97LinkState *s, int index, int freq) s->invalid_freq[index] = 0; switch (index) { case PI_INDEX: - s->voice_pi = AUD_open_in ( + s->voice_pi = AUD_open_in( &s->card, s->voice_pi, "ac97.pi", @@ -384,7 +379,7 @@ static void open_voice (AC97LinkState *s, int index, int freq) break; case PO_INDEX: - s->voice_po = AUD_open_out ( + s->voice_po = AUD_open_out( &s->card, s->voice_po, "ac97.po", @@ -395,7 +390,7 @@ static void open_voice (AC97LinkState *s, int index, int freq) break; case MC_INDEX: - s->voice_mc = AUD_open_in ( + s->voice_mc = AUD_open_in( &s->card, s->voice_mc, "ac97.mc", @@ -405,47 +400,46 @@ static void open_voice (AC97LinkState *s, int index, int freq) ); break; } - } - else { + } else { s->invalid_freq[index] = freq; switch (index) { case PI_INDEX: - AUD_close_in (&s->card, s->voice_pi); + AUD_close_in(&s->card, s->voice_pi); s->voice_pi = NULL; break; case PO_INDEX: - AUD_close_out (&s->card, s->voice_po); + AUD_close_out(&s->card, s->voice_po); s->voice_po = NULL; break; case MC_INDEX: - AUD_close_in (&s->card, s->voice_mc); + AUD_close_in(&s->card, s->voice_mc); s->voice_mc = NULL; break; } } } -static void reset_voices (AC97LinkState *s, uint8_t active[LAST_INDEX]) +static void reset_voices(AC97LinkState *s, uint8_t active[LAST_INDEX]) { uint16_t freq; - freq = mixer_load (s, AC97_PCM_LR_ADC_Rate); - open_voice (s, PI_INDEX, freq); - AUD_set_active_in (s->voice_pi, active[PI_INDEX]); + freq = mixer_load(s, AC97_PCM_LR_ADC_Rate); + open_voice(s, PI_INDEX, freq); + AUD_set_active_in(s->voice_pi, active[PI_INDEX]); - freq = mixer_load (s, AC97_PCM_Front_DAC_Rate); - open_voice (s, PO_INDEX, freq); - AUD_set_active_out (s->voice_po, active[PO_INDEX]); + freq = mixer_load(s, AC97_PCM_Front_DAC_Rate); + open_voice(s, PO_INDEX, freq); + AUD_set_active_out(s->voice_po, active[PO_INDEX]); - freq = mixer_load (s, AC97_MIC_ADC_Rate); - open_voice (s, MC_INDEX, freq); - AUD_set_active_in (s->voice_mc, active[MC_INDEX]); + freq = mixer_load(s, AC97_MIC_ADC_Rate); + open_voice(s, MC_INDEX, freq); + AUD_set_active_in(s->voice_mc, active[MC_INDEX]); } -static void get_volume (uint16_t vol, uint16_t mask, int inverse, - int *mute, uint8_t *lvol, uint8_t *rvol) +static void get_volume(uint16_t vol, uint16_t mask, int inverse, + int *mute, uint8_t *lvol, uint8_t *rvol) { *mute = (vol >> MUTE_SHIFT) & 1; *rvol = (255 * (vol & mask)) / mask; @@ -457,120 +451,120 @@ static void get_volume (uint16_t vol, uint16_t mask, int inverse, } } -static void update_combined_volume_out (AC97LinkState *s) +static void update_combined_volume_out(AC97LinkState *s) { uint8_t lvol, rvol, plvol, prvol; int mute, pmute; - get_volume (mixer_load (s, AC97_Master_Volume_Mute), 0x3f, 1, - &mute, &lvol, &rvol); - get_volume (mixer_load (s, AC97_PCM_Out_Volume_Mute), 0x1f, 1, - &pmute, &plvol, &prvol); + get_volume(mixer_load(s, AC97_Master_Volume_Mute), 0x3f, 1, + &mute, &lvol, &rvol); + get_volume(mixer_load(s, AC97_PCM_Out_Volume_Mute), 0x1f, 1, + &pmute, &plvol, &prvol); mute = mute | pmute; lvol = (lvol * plvol) / 255; rvol = (rvol * prvol) / 255; - AUD_set_volume_out (s->voice_po, mute, lvol, rvol); + AUD_set_volume_out(s->voice_po, mute, lvol, rvol); } -static void update_volume_in (AC97LinkState *s) +static void update_volume_in(AC97LinkState *s) { uint8_t lvol, rvol; int mute; - get_volume (mixer_load (s, AC97_Record_Gain_Mute), 0x0f, 0, - &mute, &lvol, &rvol); + get_volume(mixer_load(s, AC97_Record_Gain_Mute), 0x0f, 0, + &mute, &lvol, &rvol); - AUD_set_volume_in (s->voice_pi, mute, lvol, rvol); + AUD_set_volume_in(s->voice_pi, mute, lvol, rvol); } -static void set_volume (AC97LinkState *s, int index, uint32_t val) +static void set_volume(AC97LinkState *s, int index, uint32_t val) { switch (index) { case AC97_Master_Volume_Mute: val &= 0xbf3f; - mixer_store (s, index, val); - update_combined_volume_out (s); + mixer_store(s, index, val); + update_combined_volume_out(s); break; case AC97_PCM_Out_Volume_Mute: val &= 0x9f1f; - mixer_store (s, index, val); - update_combined_volume_out (s); + mixer_store(s, index, val); + update_combined_volume_out(s); break; case AC97_Record_Gain_Mute: val &= 0x8f0f; - mixer_store (s, index, val); - update_volume_in (s); + mixer_store(s, index, val); + update_volume_in(s); break; } } -static void record_select (AC97LinkState *s, uint32_t val) +static void record_select(AC97LinkState *s, uint32_t val) { uint8_t rs = val & REC_MASK; uint8_t ls = (val >> 8) & REC_MASK; - mixer_store (s, AC97_Record_Select, rs | (ls << 8)); + mixer_store(s, AC97_Record_Select, rs | (ls << 8)); } -static void mixer_reset (AC97LinkState *s) +static void mixer_reset(AC97LinkState *s) { uint8_t active[LAST_INDEX]; - dolog ("mixer_reset\n"); - memset (s->mixer_data, 0, sizeof (s->mixer_data)); - memset (active, 0, sizeof (active)); - mixer_store (s, AC97_Reset , 0x0000); /* 6940 */ - mixer_store (s, AC97_Headphone_Volume_Mute , 0x0000); - mixer_store (s, AC97_Master_Volume_Mono_Mute , 0x0000); - mixer_store (s, AC97_Master_Tone_RL, 0x0000); - mixer_store (s, AC97_PC_BEEP_Volume_Mute , 0x0000); - mixer_store (s, AC97_Phone_Volume_Mute , 0x0000); - mixer_store (s, AC97_Mic_Volume_Mute , 0x0000); - mixer_store (s, AC97_Line_In_Volume_Mute , 0x0000); - mixer_store (s, AC97_CD_Volume_Mute , 0x0000); - mixer_store (s, AC97_Video_Volume_Mute , 0x0000); - mixer_store (s, AC97_Aux_Volume_Mute , 0x0000); - mixer_store (s, AC97_Record_Gain_Mic_Mute , 0x0000); - mixer_store (s, AC97_General_Purpose , 0x0000); - mixer_store (s, AC97_3D_Control , 0x0000); - mixer_store (s, AC97_Powerdown_Ctrl_Stat , 0x000f); + dolog("mixer_reset\n"); + memset(s->mixer_data, 0, sizeof(s->mixer_data)); + memset(active, 0, sizeof(active)); + mixer_store(s, AC97_Reset, 0x0000); /* 6940 */ + mixer_store(s, AC97_Headphone_Volume_Mute, 0x0000); + mixer_store(s, AC97_Master_Volume_Mono_Mute, 0x0000); + mixer_store(s, AC97_Master_Tone_RL, 0x0000); + mixer_store(s, AC97_PC_BEEP_Volume_Mute, 0x0000); + mixer_store(s, AC97_Phone_Volume_Mute, 0x0000); + mixer_store(s, AC97_Mic_Volume_Mute, 0x0000); + mixer_store(s, AC97_Line_In_Volume_Mute, 0x0000); + mixer_store(s, AC97_CD_Volume_Mute, 0x0000); + mixer_store(s, AC97_Video_Volume_Mute, 0x0000); + mixer_store(s, AC97_Aux_Volume_Mute, 0x0000); + mixer_store(s, AC97_Record_Gain_Mic_Mute, 0x0000); + mixer_store(s, AC97_General_Purpose, 0x0000); + mixer_store(s, AC97_3D_Control, 0x0000); + mixer_store(s, AC97_Powerdown_Ctrl_Stat, 0x000f); /* * Sigmatel 9700 (STAC9700) */ - mixer_store (s, AC97_Vendor_ID1 , 0x8384); - mixer_store (s, AC97_Vendor_ID2 , 0x7600); /* 7608 */ + mixer_store(s, AC97_Vendor_ID1, 0x8384); + mixer_store(s, AC97_Vendor_ID2, 0x7600); /* 7608 */ - mixer_store (s, AC97_Extended_Audio_ID , 0x0809); - mixer_store (s, AC97_Extended_Audio_Ctrl_Stat, 0x0009); - mixer_store (s, AC97_PCM_Front_DAC_Rate , 0xbb80); - mixer_store (s, AC97_PCM_Surround_DAC_Rate , 0xbb80); - mixer_store (s, AC97_PCM_LFE_DAC_Rate , 0xbb80); - mixer_store (s, AC97_PCM_LR_ADC_Rate , 0xbb80); - mixer_store (s, AC97_MIC_ADC_Rate , 0xbb80); + mixer_store(s, AC97_Extended_Audio_ID, 0x0809); + mixer_store(s, AC97_Extended_Audio_Ctrl_Stat, 0x0009); + mixer_store(s, AC97_PCM_Front_DAC_Rate, 0xbb80); + mixer_store(s, AC97_PCM_Surround_DAC_Rate, 0xbb80); + mixer_store(s, AC97_PCM_LFE_DAC_Rate, 0xbb80); + mixer_store(s, AC97_PCM_LR_ADC_Rate, 0xbb80); + mixer_store(s, AC97_MIC_ADC_Rate, 0xbb80); - record_select (s, 0); - set_volume (s, AC97_Master_Volume_Mute, 0x8000); - set_volume (s, AC97_PCM_Out_Volume_Mute, 0x8808); - set_volume (s, AC97_Record_Gain_Mute, 0x8808); + record_select(s, 0); + set_volume(s, AC97_Master_Volume_Mute, 0x8000); + set_volume(s, AC97_PCM_Out_Volume_Mute, 0x8808); + set_volume(s, AC97_Record_Gain_Mute, 0x8808); - reset_voices (s, active); + reset_voices(s, active); } /** * Native audio mixer * I/O Reads */ -static uint32_t nam_readb (void *opaque, uint32_t addr) +static uint32_t nam_readb(void *opaque, uint32_t addr) { AC97LinkState *s = opaque; - dolog ("U nam readb %#x\n", addr); + dolog("U nam readb 0x%x\n", addr); s->cas = 0; return ~0U; } -static uint32_t nam_readw (void *opaque, uint32_t addr) +static uint32_t nam_readw(void *opaque, uint32_t addr) { AC97LinkState *s = opaque; uint32_t index = addr; @@ -578,10 +572,10 @@ static uint32_t nam_readw (void *opaque, uint32_t addr) return mixer_load(s, index); } -static uint32_t nam_readl (void *opaque, uint32_t addr) +static uint32_t nam_readl(void *opaque, uint32_t addr) { AC97LinkState *s = opaque; - dolog ("U nam readl %#x\n", addr); + dolog("U nam readl 0x%x\n", addr); s->cas = 0; return ~0U; } @@ -590,89 +584,84 @@ static uint32_t nam_readl (void *opaque, uint32_t addr) * Native audio mixer * I/O Writes */ -static void nam_writeb (void *opaque, uint32_t addr, uint32_t val) +static void nam_writeb(void *opaque, uint32_t addr, uint32_t val) { AC97LinkState *s = opaque; - dolog ("U nam writeb %#x <- %#x\n", addr, val); + dolog("U nam writeb 0x%x <- 0x%x\n", addr, val); s->cas = 0; } -static void nam_writew (void *opaque, uint32_t addr, uint32_t val) +static void nam_writew(void *opaque, uint32_t addr, uint32_t val) { AC97LinkState *s = opaque; uint32_t index = addr; s->cas = 0; switch (index) { case AC97_Reset: - mixer_reset (s); + mixer_reset(s); break; case AC97_Powerdown_Ctrl_Stat: val &= ~0x800f; - val |= mixer_load (s, index) & 0xf; - mixer_store (s, index, val); + val |= mixer_load(s, index) & 0xf; + mixer_store(s, index, val); break; case AC97_PCM_Out_Volume_Mute: case AC97_Master_Volume_Mute: case AC97_Record_Gain_Mute: - set_volume (s, index, val); + set_volume(s, index, val); break; case AC97_Record_Select: - record_select (s, val); + record_select(s, val); break; case AC97_Vendor_ID1: case AC97_Vendor_ID2: - dolog ("Attempt to write vendor ID to %#x\n", val); + dolog("Attempt to write vendor ID to 0x%x\n", val); break; case AC97_Extended_Audio_ID: - dolog ("Attempt to write extended audio ID to %#x\n", val); + dolog("Attempt to write extended audio ID to 0x%x\n", val); break; case AC97_Extended_Audio_Ctrl_Stat: if (!(val & EACS_VRA)) { - mixer_store (s, AC97_PCM_Front_DAC_Rate, 0xbb80); - mixer_store (s, AC97_PCM_LR_ADC_Rate, 0xbb80); - open_voice (s, PI_INDEX, 48000); - open_voice (s, PO_INDEX, 48000); + mixer_store(s, AC97_PCM_Front_DAC_Rate, 0xbb80); + mixer_store(s, AC97_PCM_LR_ADC_Rate, 0xbb80); + open_voice(s, PI_INDEX, 48000); + open_voice(s, PO_INDEX, 48000); } if (!(val & EACS_VRM)) { - mixer_store (s, AC97_MIC_ADC_Rate, 0xbb80); - open_voice (s, MC_INDEX, 48000); + mixer_store(s, AC97_MIC_ADC_Rate, 0xbb80); + open_voice(s, MC_INDEX, 48000); } - dolog ("Setting extended audio control to %#x\n", val); - mixer_store (s, AC97_Extended_Audio_Ctrl_Stat, val); + dolog("Setting extended audio control to 0x%x\n", val); + mixer_store(s, AC97_Extended_Audio_Ctrl_Stat, val); break; case AC97_PCM_Front_DAC_Rate: - if (mixer_load (s, AC97_Extended_Audio_Ctrl_Stat) & EACS_VRA) { - mixer_store (s, index, val); - dolog ("Set front DAC rate to %d\n", val); - open_voice (s, PO_INDEX, val); - } - else { - dolog ("Attempt to set front DAC rate to %d, " - "but VRA is not set\n", - val); + if (mixer_load(s, AC97_Extended_Audio_Ctrl_Stat) & EACS_VRA) { + mixer_store(s, index, val); + dolog("Set front DAC rate to %d\n", val); + open_voice(s, PO_INDEX, val); + } else { + dolog("Attempt to set front DAC rate to %d, but VRA is not set\n", + val); } break; case AC97_MIC_ADC_Rate: - if (mixer_load (s, AC97_Extended_Audio_Ctrl_Stat) & EACS_VRM) { - mixer_store (s, index, val); - dolog ("Set MIC ADC rate to %d\n", val); - open_voice (s, MC_INDEX, val); - } - else { - dolog ("Attempt to set MIC ADC rate to %d, " - "but VRM is not set\n", - val); + if (mixer_load(s, AC97_Extended_Audio_Ctrl_Stat) & EACS_VRM) { + mixer_store(s, index, val); + dolog("Set MIC ADC rate to %d\n", val); + open_voice(s, MC_INDEX, val); + } else { + dolog("Attempt to set MIC ADC rate to %d, but VRM is not set\n", + val); } break; case AC97_PCM_LR_ADC_Rate: - if (mixer_load (s, AC97_Extended_Audio_Ctrl_Stat) & EACS_VRA) { - mixer_store (s, index, val); - dolog ("Set front LR ADC rate to %d\n", val); - open_voice (s, PI_INDEX, val); - } - else { - dolog ("Attempt to set LR ADC rate to %d, but VRA is not set\n", - val); + if (mixer_load(s, AC97_Extended_Audio_Ctrl_Stat) & EACS_VRA) { + mixer_store(s, index, val); + dolog("Set front LR ADC rate to %d\n", val); + open_voice(s, PI_INDEX, val); + } else { + dolog("Attempt to set LR ADC rate to %d, but VRA is not set\n", + val); } break; case AC97_Headphone_Volume_Mute: @@ -693,16 +682,16 @@ static void nam_writew (void *opaque, uint32_t addr, uint32_t val) /* None of the features in these regs are emulated, so they are RO */ break; default: - dolog ("U nam writew %#x <- %#x\n", addr, val); - mixer_store (s, index, val); + dolog("U nam writew 0x%x <- 0x%x\n", addr, val); + mixer_store(s, index, val); break; } } -static void nam_writel (void *opaque, uint32_t addr, uint32_t val) +static void nam_writel(void *opaque, uint32_t addr, uint32_t val) { AC97LinkState *s = opaque; - dolog ("U nam writel %#x <- %#x\n", addr, val); + dolog("U nam writel 0x%x <- 0x%x\n", addr, val); s->cas = 0; } @@ -710,7 +699,7 @@ static void nam_writel (void *opaque, uint32_t addr, uint32_t val) * Native audio bus master * I/O Reads */ -static uint32_t nabm_readb (void *opaque, uint32_t addr) +static uint32_t nabm_readb(void *opaque, uint32_t addr) { AC97LinkState *s = opaque; AC97BusMasterRegs *r = NULL; @@ -719,53 +708,53 @@ static uint32_t nabm_readb (void *opaque, uint32_t addr) switch (index) { case CAS: - dolog ("CAS %d\n", s->cas); + dolog("CAS %d\n", s->cas); val = s->cas; s->cas = 1; break; case PI_CIV: case PO_CIV: case MC_CIV: - r = &s->bm_regs[GET_BM (index)]; + r = &s->bm_regs[GET_BM(index)]; val = r->civ; - dolog ("CIV[%d] -> %#x\n", GET_BM (index), val); + dolog("CIV[%d] -> 0x%x\n", GET_BM(index), val); break; case PI_LVI: case PO_LVI: case MC_LVI: - r = &s->bm_regs[GET_BM (index)]; + r = &s->bm_regs[GET_BM(index)]; val = r->lvi; - dolog ("LVI[%d] -> %#x\n", GET_BM (index), val); + dolog("LVI[%d] -> 0x%x\n", GET_BM(index), val); break; case PI_PIV: case PO_PIV: case MC_PIV: - r = &s->bm_regs[GET_BM (index)]; + r = &s->bm_regs[GET_BM(index)]; val = r->piv; - dolog ("PIV[%d] -> %#x\n", GET_BM (index), val); + dolog("PIV[%d] -> 0x%x\n", GET_BM(index), val); break; case PI_CR: case PO_CR: case MC_CR: - r = &s->bm_regs[GET_BM (index)]; + r = &s->bm_regs[GET_BM(index)]; val = r->cr; - dolog ("CR[%d] -> %#x\n", GET_BM (index), val); + dolog("CR[%d] -> 0x%x\n", GET_BM(index), val); break; case PI_SR: case PO_SR: case MC_SR: - r = &s->bm_regs[GET_BM (index)]; + r = &s->bm_regs[GET_BM(index)]; val = r->sr & 0xff; - dolog ("SRb[%d] -> %#x\n", GET_BM (index), val); + dolog("SRb[%d] -> 0x%x\n", GET_BM(index), val); break; default: - dolog ("U nabm readb %#x -> %#x\n", addr, val); + dolog("U nabm readb 0x%x -> 0x%x\n", addr, val); break; } return val; } -static uint32_t nabm_readw (void *opaque, uint32_t addr) +static uint32_t nabm_readw(void *opaque, uint32_t addr) { AC97LinkState *s = opaque; AC97BusMasterRegs *r = NULL; @@ -776,25 +765,25 @@ static uint32_t nabm_readw (void *opaque, uint32_t addr) case PI_SR: case PO_SR: case MC_SR: - r = &s->bm_regs[GET_BM (index)]; + r = &s->bm_regs[GET_BM(index)]; val = r->sr; - dolog ("SR[%d] -> %#x\n", GET_BM (index), val); + dolog("SR[%d] -> 0x%x\n", GET_BM(index), val); break; case PI_PICB: case PO_PICB: case MC_PICB: - r = &s->bm_regs[GET_BM (index)]; + r = &s->bm_regs[GET_BM(index)]; val = r->picb; - dolog ("PICB[%d] -> %#x\n", GET_BM (index), val); + dolog("PICB[%d] -> 0x%x\n", GET_BM(index), val); break; default: - dolog ("U nabm readw %#x -> %#x\n", addr, val); + dolog("U nabm readw 0x%x -> 0x%x\n", addr, val); break; } return val; } -static uint32_t nabm_readl (void *opaque, uint32_t addr) +static uint32_t nabm_readl(void *opaque, uint32_t addr) { AC97LinkState *s = opaque; AC97BusMasterRegs *r = NULL; @@ -805,36 +794,36 @@ static uint32_t nabm_readl (void *opaque, uint32_t addr) case PI_BDBAR: case PO_BDBAR: case MC_BDBAR: - r = &s->bm_regs[GET_BM (index)]; + r = &s->bm_regs[GET_BM(index)]; val = r->bdbar; - dolog ("BMADDR[%d] -> %#x\n", GET_BM (index), val); + dolog("BMADDR[%d] -> 0x%x\n", GET_BM(index), val); break; case PI_CIV: case PO_CIV: case MC_CIV: - r = &s->bm_regs[GET_BM (index)]; + r = &s->bm_regs[GET_BM(index)]; val = r->civ | (r->lvi << 8) | (r->sr << 16); - dolog ("CIV LVI SR[%d] -> %#x, %#x, %#x\n", GET_BM (index), + dolog("CIV LVI SR[%d] -> 0x%x, 0x%x, 0x%x\n", GET_BM(index), r->civ, r->lvi, r->sr); break; case PI_PICB: case PO_PICB: case MC_PICB: - r = &s->bm_regs[GET_BM (index)]; + r = &s->bm_regs[GET_BM(index)]; val = r->picb | (r->piv << 16) | (r->cr << 24); - dolog ("PICB PIV CR[%d] -> %#x %#x %#x %#x\n", GET_BM (index), + dolog("PICB PIV CR[%d] -> 0x%x 0x%x 0x%x 0x%x\n", GET_BM(index), val, r->picb, r->piv, r->cr); break; case GLOB_CNT: val = s->glob_cnt; - dolog ("glob_cnt -> %#x\n", val); + dolog("glob_cnt -> 0x%x\n", val); break; case GLOB_STA: val = s->glob_sta | GS_S0CR; - dolog ("glob_sta -> %#x\n", val); + dolog("glob_sta -> 0x%x\n", val); break; default: - dolog ("U nabm readl %#x -> %#x\n", addr, val); + dolog("U nabm readl 0x%x -> 0x%x\n", addr, val); break; } return val; @@ -844,7 +833,7 @@ static uint32_t nabm_readl (void *opaque, uint32_t addr) * Native audio bus master * I/O Writes */ -static void nabm_writeb (void *opaque, uint32_t addr, uint32_t val) +static void nabm_writeb(void *opaque, uint32_t addr, uint32_t val) { AC97LinkState *s = opaque; AC97BusMasterRegs *r = NULL; @@ -853,54 +842,52 @@ static void nabm_writeb (void *opaque, uint32_t addr, uint32_t val) case PI_LVI: case PO_LVI: case MC_LVI: - r = &s->bm_regs[GET_BM (index)]; + r = &s->bm_regs[GET_BM(index)]; if ((r->cr & CR_RPBM) && (r->sr & SR_DCH)) { r->sr &= ~(SR_DCH | SR_CELV); r->civ = r->piv; r->piv = (r->piv + 1) % 32; - fetch_bd (s, r); + fetch_bd(s, r); } r->lvi = val % 32; - dolog ("LVI[%d] <- %#x\n", GET_BM (index), val); + dolog("LVI[%d] <- 0x%x\n", GET_BM(index), val); break; case PI_CR: case PO_CR: case MC_CR: - r = &s->bm_regs[GET_BM (index)]; + r = &s->bm_regs[GET_BM(index)]; if (val & CR_RR) { - reset_bm_regs (s, r); - } - else { + reset_bm_regs(s, r); + } else { r->cr = val & CR_VALID_MASK; if (!(r->cr & CR_RPBM)) { - voice_set_active (s, r - s->bm_regs, 0); + voice_set_active(s, r - s->bm_regs, 0); r->sr |= SR_DCH; - } - else { + } else { r->civ = r->piv; r->piv = (r->piv + 1) % 32; - fetch_bd (s, r); + fetch_bd(s, r); r->sr &= ~SR_DCH; - voice_set_active (s, r - s->bm_regs, 1); + voice_set_active(s, r - s->bm_regs, 1); } } - dolog ("CR[%d] <- %#x (cr %#x)\n", GET_BM (index), val, r->cr); + dolog("CR[%d] <- 0x%x (cr 0x%x)\n", GET_BM(index), val, r->cr); break; case PI_SR: case PO_SR: case MC_SR: - r = &s->bm_regs[GET_BM (index)]; + r = &s->bm_regs[GET_BM(index)]; r->sr |= val & ~(SR_RO_MASK | SR_WCLEAR_MASK); - update_sr (s, r, r->sr & ~(val & SR_WCLEAR_MASK)); - dolog ("SR[%d] <- %#x (sr %#x)\n", GET_BM (index), val, r->sr); + update_sr(s, r, r->sr & ~(val & SR_WCLEAR_MASK)); + dolog("SR[%d] <- 0x%x (sr 0x%x)\n", GET_BM(index), val, r->sr); break; default: - dolog ("U nabm writeb %#x <- %#x\n", addr, val); + dolog("U nabm writeb 0x%x <- 0x%x\n", addr, val); break; } } -static void nabm_writew (void *opaque, uint32_t addr, uint32_t val) +static void nabm_writew(void *opaque, uint32_t addr, uint32_t val) { AC97LinkState *s = opaque; AC97BusMasterRegs *r = NULL; @@ -909,18 +896,18 @@ static void nabm_writew (void *opaque, uint32_t addr, uint32_t val) case PI_SR: case PO_SR: case MC_SR: - r = &s->bm_regs[GET_BM (index)]; + r = &s->bm_regs[GET_BM(index)]; r->sr |= val & ~(SR_RO_MASK | SR_WCLEAR_MASK); - update_sr (s, r, r->sr & ~(val & SR_WCLEAR_MASK)); - dolog ("SR[%d] <- %#x (sr %#x)\n", GET_BM (index), val, r->sr); + update_sr(s, r, r->sr & ~(val & SR_WCLEAR_MASK)); + dolog("SR[%d] <- 0x%x (sr 0x%x)\n", GET_BM(index), val, r->sr); break; default: - dolog ("U nabm writew %#x <- %#x\n", addr, val); + dolog("U nabm writew 0x%x <- 0x%x\n", addr, val); break; } } -static void nabm_writel (void *opaque, uint32_t addr, uint32_t val) +static void nabm_writel(void *opaque, uint32_t addr, uint32_t val) { AC97LinkState *s = opaque; AC97BusMasterRegs *r = NULL; @@ -929,40 +916,42 @@ static void nabm_writel (void *opaque, uint32_t addr, uint32_t val) case PI_BDBAR: case PO_BDBAR: case MC_BDBAR: - r = &s->bm_regs[GET_BM (index)]; + r = &s->bm_regs[GET_BM(index)]; r->bdbar = val & ~3; - dolog ("BDBAR[%d] <- %#x (bdbar %#x)\n", - GET_BM (index), val, r->bdbar); + dolog("BDBAR[%d] <- 0x%x (bdbar 0x%x)\n", GET_BM(index), val, r->bdbar); break; case GLOB_CNT: - if (val & GC_WR) - warm_reset (s); - if (val & GC_CR) - cold_reset (s); - if (!(val & (GC_WR | GC_CR))) + if (val & GC_WR) { + warm_reset(s); + } + if (val & GC_CR) { + cold_reset(s); + } + if (!(val & (GC_WR | GC_CR))) { s->glob_cnt = val & GC_VALID_MASK; - dolog ("glob_cnt <- %#x (glob_cnt %#x)\n", val, s->glob_cnt); + } + dolog("glob_cnt <- 0x%x (glob_cnt 0x%x)\n", val, s->glob_cnt); break; case GLOB_STA: s->glob_sta &= ~(val & GS_WCLEAR_MASK); s->glob_sta |= (val & ~(GS_WCLEAR_MASK | GS_RO_MASK)) & GS_VALID_MASK; - dolog ("glob_sta <- %#x (glob_sta %#x)\n", val, s->glob_sta); + dolog("glob_sta <- 0x%x (glob_sta 0x%x)\n", val, s->glob_sta); break; default: - dolog ("U nabm writel %#x <- %#x\n", addr, val); + dolog("U nabm writel 0x%x <- 0x%x\n", addr, val); break; } } -static int write_audio (AC97LinkState *s, AC97BusMasterRegs *r, - int max, int *stop) +static int write_audio(AC97LinkState *s, AC97BusMasterRegs *r, + int max, int *stop) { uint8_t tmpbuf[4096]; uint32_t addr = r->bd.addr; uint32_t temp = r->picb << 1; uint32_t written = 0; int to_copy = 0; - temp = MIN (temp, max); + temp = MIN(temp, max); if (!temp) { *stop = 1; @@ -971,11 +960,11 @@ static int write_audio (AC97LinkState *s, AC97BusMasterRegs *r, while (temp) { int copied; - to_copy = MIN (temp, sizeof (tmpbuf)); - pci_dma_read (&s->dev, addr, tmpbuf, to_copy); - copied = AUD_write (s->voice_po, tmpbuf, to_copy); - dolog ("write_audio max=%x to_copy=%x copied=%x\n", - max, to_copy, copied); + to_copy = MIN(temp, sizeof(tmpbuf)); + pci_dma_read(&s->dev, addr, tmpbuf, to_copy); + copied = AUD_write(s->voice_po, tmpbuf, to_copy); + dolog("write_audio max=%x to_copy=%x copied=%x\n", + max, to_copy, copied); if (!copied) { *stop = 1; break; @@ -987,11 +976,10 @@ static int write_audio (AC97LinkState *s, AC97BusMasterRegs *r, if (!temp) { if (to_copy < 4) { - dolog ("whoops\n"); + dolog("whoops\n"); s->last_samp = 0; - } - else { - s->last_samp = *(uint32_t *) &tmpbuf[to_copy - 4]; + } else { + s->last_samp = *(uint32_t *)&tmpbuf[to_copy - 4]; } } @@ -999,37 +987,37 @@ static int write_audio (AC97LinkState *s, AC97BusMasterRegs *r, return written; } -static void write_bup (AC97LinkState *s, int elapsed) +static void write_bup(AC97LinkState *s, int elapsed) { - dolog ("write_bup\n"); + dolog("write_bup\n"); if (!(s->bup_flag & BUP_SET)) { if (s->bup_flag & BUP_LAST) { int i; uint8_t *p = s->silence; - for (i = 0; i < sizeof (s->silence) / 4; i++, p += 4) { + for (i = 0; i < sizeof(s->silence) / 4; i++, p += 4) { *(uint32_t *) p = s->last_samp; } - } - else { - memset (s->silence, 0, sizeof (s->silence)); + } else { + memset(s->silence, 0, sizeof(s->silence)); } s->bup_flag |= BUP_SET; } while (elapsed) { - int temp = MIN (elapsed, sizeof (s->silence)); + int temp = MIN(elapsed, sizeof(s->silence)); while (temp) { - int copied = AUD_write (s->voice_po, s->silence, temp); - if (!copied) + int copied = AUD_write(s->voice_po, s->silence, temp); + if (!copied) { return; + } temp -= copied; elapsed -= copied; } } } -static int read_audio (AC97LinkState *s, AC97BusMasterRegs *r, - int max, int *stop) +static int read_audio(AC97LinkState *s, AC97BusMasterRegs *r, + int max, int *stop) { uint8_t tmpbuf[4096]; uint32_t addr = r->bd.addr; @@ -1038,7 +1026,7 @@ static int read_audio (AC97LinkState *s, AC97BusMasterRegs *r, int to_copy = 0; SWVoiceIn *voice = (r - s->bm_regs) == MC_INDEX ? s->voice_mc : s->voice_pi; - temp = MIN (temp, max); + temp = MIN(temp, max); if (!temp) { *stop = 1; @@ -1047,13 +1035,13 @@ static int read_audio (AC97LinkState *s, AC97BusMasterRegs *r, while (temp) { int acquired; - to_copy = MIN (temp, sizeof (tmpbuf)); - acquired = AUD_read (voice, tmpbuf, to_copy); + to_copy = MIN(temp, sizeof(tmpbuf)); + acquired = AUD_read(voice, tmpbuf, to_copy); if (!acquired) { *stop = 1; break; } - pci_dma_write (&s->dev, addr, tmpbuf, acquired); + pci_dma_write(&s->dev, addr, tmpbuf, acquired); temp -= acquired; addr += acquired; nread += acquired; @@ -1063,14 +1051,14 @@ static int read_audio (AC97LinkState *s, AC97BusMasterRegs *r, return nread; } -static void transfer_audio (AC97LinkState *s, int index, int elapsed) +static void transfer_audio(AC97LinkState *s, int index, int elapsed) { AC97BusMasterRegs *r = &s->bm_regs[index]; int stop = 0; if (s->invalid_freq[index]) { - AUD_log ("ac97", "attempt to use voice %d with invalid frequency %d\n", - index, s->invalid_freq[index]); + AUD_log("ac97", "attempt to use voice %d with invalid frequency %d\n", + index, s->invalid_freq[index]); return; } @@ -1078,7 +1066,7 @@ static void transfer_audio (AC97LinkState *s, int index, int elapsed) if (r->cr & CR_RPBM) { switch (index) { case PO_INDEX: - write_bup (s, elapsed); + write_bup(s, elapsed); break; } } @@ -1089,13 +1077,13 @@ static void transfer_audio (AC97LinkState *s, int index, int elapsed) int temp; if (!r->bd_valid) { - dolog ("invalid bd\n"); - fetch_bd (s, r); + dolog("invalid bd\n"); + fetch_bd(s, r); } if (!r->picb) { - dolog ("fresh bd %d is empty %#x %#x\n", - r->civ, r->bd.addr, r->bd.ctl_len); + dolog("fresh bd %d is empty 0x%x 0x%x\n", + r->civ, r->bd.addr, r->bd.ctl_len); if (r->civ == r->lvi) { r->sr |= SR_DCH; /* CELV? */ s->bup_flag = 0; @@ -1104,20 +1092,20 @@ static void transfer_audio (AC97LinkState *s, int index, int elapsed) r->sr &= ~SR_CELV; r->civ = r->piv; r->piv = (r->piv + 1) % 32; - fetch_bd (s, r); + fetch_bd(s, r); return; } switch (index) { case PO_INDEX: - temp = write_audio (s, r, elapsed, &stop); + temp = write_audio(s, r, elapsed, &stop); elapsed -= temp; r->picb -= (temp >> 1); break; case PI_INDEX: case MC_INDEX: - temp = read_audio (s, r, elapsed, &stop); + temp = read_audio(s, r, elapsed, &stop); elapsed -= temp; r->picb -= (temp >> 1); break; @@ -1131,36 +1119,35 @@ static void transfer_audio (AC97LinkState *s, int index, int elapsed) } if (r->civ == r->lvi) { - dolog ("Underrun civ (%d) == lvi (%d)\n", r->civ, r->lvi); + dolog("Underrun civ (%d) == lvi (%d)\n", r->civ, r->lvi); new_sr |= SR_LVBCI | SR_DCH | SR_CELV; stop = 1; s->bup_flag = (r->bd.ctl_len & BD_BUP) ? BUP_LAST : 0; - } - else { + } else { r->civ = r->piv; r->piv = (r->piv + 1) % 32; - fetch_bd (s, r); + fetch_bd(s, r); } - update_sr (s, r, new_sr); + update_sr(s, r, new_sr); } } } -static void pi_callback (void *opaque, int avail) +static void pi_callback(void *opaque, int avail) { - transfer_audio (opaque, PI_INDEX, avail); + transfer_audio(opaque, PI_INDEX, avail); } -static void mc_callback (void *opaque, int avail) +static void mc_callback(void *opaque, int avail) { - transfer_audio (opaque, MC_INDEX, avail); + transfer_audio(opaque, MC_INDEX, avail); } -static void po_callback (void *opaque, int free) +static void po_callback(void *opaque, int free) { - transfer_audio (opaque, PO_INDEX, free); + transfer_audio(opaque, PO_INDEX, free); } static const VMStateDescription vmstate_ac97_bm_regs = { @@ -1168,44 +1155,44 @@ static const VMStateDescription vmstate_ac97_bm_regs = { .version_id = 1, .minimum_version_id = 1, .fields = (VMStateField[]) { - VMSTATE_UINT32 (bdbar, AC97BusMasterRegs), - VMSTATE_UINT8 (civ, AC97BusMasterRegs), - VMSTATE_UINT8 (lvi, AC97BusMasterRegs), - VMSTATE_UINT16 (sr, AC97BusMasterRegs), - VMSTATE_UINT16 (picb, AC97BusMasterRegs), - VMSTATE_UINT8 (piv, AC97BusMasterRegs), - VMSTATE_UINT8 (cr, AC97BusMasterRegs), - VMSTATE_UINT32 (bd_valid, AC97BusMasterRegs), - VMSTATE_UINT32 (bd.addr, AC97BusMasterRegs), - VMSTATE_UINT32 (bd.ctl_len, AC97BusMasterRegs), - VMSTATE_END_OF_LIST () + VMSTATE_UINT32(bdbar, AC97BusMasterRegs), + VMSTATE_UINT8(civ, AC97BusMasterRegs), + VMSTATE_UINT8(lvi, AC97BusMasterRegs), + VMSTATE_UINT16(sr, AC97BusMasterRegs), + VMSTATE_UINT16(picb, AC97BusMasterRegs), + VMSTATE_UINT8(piv, AC97BusMasterRegs), + VMSTATE_UINT8(cr, AC97BusMasterRegs), + VMSTATE_UINT32(bd_valid, AC97BusMasterRegs), + VMSTATE_UINT32(bd.addr, AC97BusMasterRegs), + VMSTATE_UINT32(bd.ctl_len, AC97BusMasterRegs), + VMSTATE_END_OF_LIST() } }; -static int ac97_post_load (void *opaque, int version_id) +static int ac97_post_load(void *opaque, int version_id) { uint8_t active[LAST_INDEX]; AC97LinkState *s = opaque; - record_select (s, mixer_load (s, AC97_Record_Select)); - set_volume (s, AC97_Master_Volume_Mute, - mixer_load (s, AC97_Master_Volume_Mute)); - set_volume (s, AC97_PCM_Out_Volume_Mute, - mixer_load (s, AC97_PCM_Out_Volume_Mute)); - set_volume (s, AC97_Record_Gain_Mute, - mixer_load (s, AC97_Record_Gain_Mute)); + record_select(s, mixer_load(s, AC97_Record_Select)); + set_volume(s, AC97_Master_Volume_Mute, + mixer_load(s, AC97_Master_Volume_Mute)); + set_volume(s, AC97_PCM_Out_Volume_Mute, + mixer_load(s, AC97_PCM_Out_Volume_Mute)); + set_volume(s, AC97_Record_Gain_Mute, + mixer_load(s, AC97_Record_Gain_Mute)); active[PI_INDEX] = !!(s->bm_regs[PI_INDEX].cr & CR_RPBM); active[PO_INDEX] = !!(s->bm_regs[PO_INDEX].cr & CR_RPBM); active[MC_INDEX] = !!(s->bm_regs[MC_INDEX].cr & CR_RPBM); - reset_voices (s, active); + reset_voices(s, active); s->bup_flag = 0; s->last_samp = 0; return 0; } -static bool is_version_2 (void *opaque, int version_id) +static bool is_version_2(void *opaque, int version_id) { return version_id == 2; } @@ -1216,15 +1203,15 @@ static const VMStateDescription vmstate_ac97 = { .minimum_version_id = 2, .post_load = ac97_post_load, .fields = (VMStateField[]) { - VMSTATE_PCI_DEVICE (dev, AC97LinkState), - VMSTATE_UINT32 (glob_cnt, AC97LinkState), - VMSTATE_UINT32 (glob_sta, AC97LinkState), - VMSTATE_UINT32 (cas, AC97LinkState), - VMSTATE_STRUCT_ARRAY (bm_regs, AC97LinkState, 3, 1, - vmstate_ac97_bm_regs, AC97BusMasterRegs), - VMSTATE_BUFFER (mixer_data, AC97LinkState), - VMSTATE_UNUSED_TEST (is_version_2, 3), - VMSTATE_END_OF_LIST () + VMSTATE_PCI_DEVICE(dev, AC97LinkState), + VMSTATE_UINT32(glob_cnt, AC97LinkState), + VMSTATE_UINT32(glob_sta, AC97LinkState), + VMSTATE_UINT32(cas, AC97LinkState), + VMSTATE_STRUCT_ARRAY(bm_regs, AC97LinkState, 3, 1, + vmstate_ac97_bm_regs, AC97BusMasterRegs), + VMSTATE_BUFFER(mixer_data, AC97LinkState), + VMSTATE_UNUSED_TEST(is_version_2, 3), + VMSTATE_END_OF_LIST() } }; @@ -1295,7 +1282,7 @@ static uint64_t nabm_read(void *opaque, hwaddr addr, unsigned size) } static void nabm_write(void *opaque, hwaddr addr, uint64_t val, - unsigned size) + unsigned size) { if ((addr / size) > 64) { return; @@ -1325,20 +1312,20 @@ static const MemoryRegionOps ac97_io_nabm_ops = { .endianness = DEVICE_LITTLE_ENDIAN, }; -static void ac97_on_reset (DeviceState *dev) +static void ac97_on_reset(DeviceState *dev) { AC97LinkState *s = container_of(dev, AC97LinkState, dev.qdev); - reset_bm_regs (s, &s->bm_regs[0]); - reset_bm_regs (s, &s->bm_regs[1]); - reset_bm_regs (s, &s->bm_regs[2]); + reset_bm_regs(s, &s->bm_regs[0]); + reset_bm_regs(s, &s->bm_regs[1]); + reset_bm_regs(s, &s->bm_regs[2]); /* * Reset the mixer too. The Windows XP driver seems to rely on * this. At least it wants to read the vendor id before it resets * the codec manually. */ - mixer_reset (s); + mixer_reset(s); } static void ac97_realize(PCIDevice *dev, Error **errp) @@ -1373,13 +1360,13 @@ static void ac97_realize(PCIDevice *dev, Error **errp) c[PCI_INTERRUPT_LINE] = 0x00; /* intr_ln interrupt line rw */ c[PCI_INTERRUPT_PIN] = 0x01; /* intr_pn interrupt pin ro */ - memory_region_init_io (&s->io_nam, OBJECT(s), &ac97_io_nam_ops, s, - "ac97-nam", 1024); - memory_region_init_io (&s->io_nabm, OBJECT(s), &ac97_io_nabm_ops, s, - "ac97-nabm", 256); - pci_register_bar (&s->dev, 0, PCI_BASE_ADDRESS_SPACE_IO, &s->io_nam); - pci_register_bar (&s->dev, 1, PCI_BASE_ADDRESS_SPACE_IO, &s->io_nabm); - AUD_register_card ("ac97", &s->card); + memory_region_init_io(&s->io_nam, OBJECT(s), &ac97_io_nam_ops, s, + "ac97-nam", 1024); + memory_region_init_io(&s->io_nabm, OBJECT(s), &ac97_io_nabm_ops, s, + "ac97-nabm", 256); + pci_register_bar(&s->dev, 0, PCI_BASE_ADDRESS_SPACE_IO, &s->io_nam); + pci_register_bar(&s->dev, 1, PCI_BASE_ADDRESS_SPACE_IO, &s->io_nabm); + AUD_register_card("ac97", &s->card); ac97_on_reset(DEVICE(s)); } @@ -1395,13 +1382,13 @@ static void ac97_exit(PCIDevice *dev) static Property ac97_properties[] = { DEFINE_AUDIO_PROPERTIES(AC97LinkState, card), - DEFINE_PROP_END_OF_LIST (), + DEFINE_PROP_END_OF_LIST(), }; -static void ac97_class_init (ObjectClass *klass, void *data) +static void ac97_class_init(ObjectClass *klass, void *data) { - DeviceClass *dc = DEVICE_CLASS (klass); - PCIDeviceClass *k = PCI_DEVICE_CLASS (klass); + DeviceClass *dc = DEVICE_CLASS(klass); + PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); k->realize = ac97_realize; k->exit = ac97_exit; @@ -1419,7 +1406,7 @@ static void ac97_class_init (ObjectClass *klass, void *data) static const TypeInfo ac97_info = { .name = TYPE_AC97, .parent = TYPE_PCI_DEVICE, - .instance_size = sizeof (AC97LinkState), + .instance_size = sizeof(AC97LinkState), .class_init = ac97_class_init, .interfaces = (InterfaceInfo[]) { { INTERFACE_CONVENTIONAL_PCI_DEVICE }, @@ -1427,11 +1414,11 @@ static const TypeInfo ac97_info = { }, }; -static void ac97_register_types (void) +static void ac97_register_types(void) { - type_register_static (&ac97_info); + type_register_static(&ac97_info); deprecated_register_soundhw("ac97", "Intel 82801AA AC97 Audio", 0, TYPE_AC97); } -type_init (ac97_register_types) +type_init(ac97_register_types) From dafea9e2868a5349bb0f1650dd18fa1aac806ee4 Mon Sep 17 00:00:00 2001 From: BALATON Zoltan Date: Sat, 23 Apr 2022 11:36:57 +0200 Subject: [PATCH 08/17] hw/audio/ac97: Remove unimplemented reset functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The warm_reset() and cold_reset() functions are not implemented and do nothing so no point in calling them or keep around as dead code. Therefore remove them for now. Signed-off-by: BALATON Zoltan Reviewed-by: Víctor Colombo Message-Id: Signed-off-by: Paolo Bonzini --- hw/audio/ac97.c | 17 +---------------- 1 file changed, 1 insertion(+), 16 deletions(-) diff --git a/hw/audio/ac97.c b/hw/audio/ac97.c index 6b1c12bece..6584aa749e 100644 --- a/hw/audio/ac97.c +++ b/hw/audio/ac97.c @@ -222,16 +222,6 @@ static void po_callback(void *opaque, int free); static void pi_callback(void *opaque, int avail); static void mc_callback(void *opaque, int avail); -static void warm_reset(AC97LinkState *s) -{ - (void)s; -} - -static void cold_reset(AC97LinkState *s) -{ - (void)s; -} - static void fetch_bd(AC97LinkState *s, AC97BusMasterRegs *r) { uint8_t b[8]; @@ -921,12 +911,7 @@ static void nabm_writel(void *opaque, uint32_t addr, uint32_t val) dolog("BDBAR[%d] <- 0x%x (bdbar 0x%x)\n", GET_BM(index), val, r->bdbar); break; case GLOB_CNT: - if (val & GC_WR) { - warm_reset(s); - } - if (val & GC_CR) { - cold_reset(s); - } + /* TODO: Handle WR or CR being set (warm/cold reset requests) */ if (!(val & (GC_WR | GC_CR))) { s->glob_cnt = val & GC_VALID_MASK; } From dba2b2941ca2ebd5275b3b2c6e72678f98f83a8a Mon Sep 17 00:00:00 2001 From: BALATON Zoltan Date: Sat, 23 Apr 2022 11:36:57 +0200 Subject: [PATCH 09/17] hw/audio/ac97: Remove unneeded local variables Several functions have a local variable that is just a copy of one of the function parameters. This is unneeded complication so just get rid of these. Signed-off-by: BALATON Zoltan Reviewed-by: Peter Maydell Message-Id: Signed-off-by: Paolo Bonzini --- hw/audio/ac97.c | 102 +++++++++++++++++++++++------------------------- 1 file changed, 49 insertions(+), 53 deletions(-) diff --git a/hw/audio/ac97.c b/hw/audio/ac97.c index 6584aa749e..be2dd701a4 100644 --- a/hw/audio/ac97.c +++ b/hw/audio/ac97.c @@ -557,9 +557,8 @@ static uint32_t nam_readb(void *opaque, uint32_t addr) static uint32_t nam_readw(void *opaque, uint32_t addr) { AC97LinkState *s = opaque; - uint32_t index = addr; s->cas = 0; - return mixer_load(s, index); + return mixer_load(s, addr); } static uint32_t nam_readl(void *opaque, uint32_t addr) @@ -584,21 +583,21 @@ static void nam_writeb(void *opaque, uint32_t addr, uint32_t val) static void nam_writew(void *opaque, uint32_t addr, uint32_t val) { AC97LinkState *s = opaque; - uint32_t index = addr; + s->cas = 0; - switch (index) { + switch (addr) { case AC97_Reset: mixer_reset(s); break; case AC97_Powerdown_Ctrl_Stat: val &= ~0x800f; - val |= mixer_load(s, index) & 0xf; - mixer_store(s, index, val); + val |= mixer_load(s, addr) & 0xf; + mixer_store(s, addr, val); break; case AC97_PCM_Out_Volume_Mute: case AC97_Master_Volume_Mute: case AC97_Record_Gain_Mute: - set_volume(s, index, val); + set_volume(s, addr, val); break; case AC97_Record_Select: record_select(s, val); @@ -626,7 +625,7 @@ static void nam_writew(void *opaque, uint32_t addr, uint32_t val) break; case AC97_PCM_Front_DAC_Rate: if (mixer_load(s, AC97_Extended_Audio_Ctrl_Stat) & EACS_VRA) { - mixer_store(s, index, val); + mixer_store(s, addr, val); dolog("Set front DAC rate to %d\n", val); open_voice(s, PO_INDEX, val); } else { @@ -636,7 +635,7 @@ static void nam_writew(void *opaque, uint32_t addr, uint32_t val) break; case AC97_MIC_ADC_Rate: if (mixer_load(s, AC97_Extended_Audio_Ctrl_Stat) & EACS_VRM) { - mixer_store(s, index, val); + mixer_store(s, addr, val); dolog("Set MIC ADC rate to %d\n", val); open_voice(s, MC_INDEX, val); } else { @@ -646,7 +645,7 @@ static void nam_writew(void *opaque, uint32_t addr, uint32_t val) break; case AC97_PCM_LR_ADC_Rate: if (mixer_load(s, AC97_Extended_Audio_Ctrl_Stat) & EACS_VRA) { - mixer_store(s, index, val); + mixer_store(s, addr, val); dolog("Set front LR ADC rate to %d\n", val); open_voice(s, PI_INDEX, val); } else { @@ -673,7 +672,7 @@ static void nam_writew(void *opaque, uint32_t addr, uint32_t val) break; default: dolog("U nam writew 0x%x <- 0x%x\n", addr, val); - mixer_store(s, index, val); + mixer_store(s, addr, val); break; } } @@ -693,10 +692,9 @@ static uint32_t nabm_readb(void *opaque, uint32_t addr) { AC97LinkState *s = opaque; AC97BusMasterRegs *r = NULL; - uint32_t index = addr; uint32_t val = ~0U; - switch (index) { + switch (addr) { case CAS: dolog("CAS %d\n", s->cas); val = s->cas; @@ -705,37 +703,37 @@ static uint32_t nabm_readb(void *opaque, uint32_t addr) case PI_CIV: case PO_CIV: case MC_CIV: - r = &s->bm_regs[GET_BM(index)]; + r = &s->bm_regs[GET_BM(addr)]; val = r->civ; - dolog("CIV[%d] -> 0x%x\n", GET_BM(index), val); + dolog("CIV[%d] -> 0x%x\n", GET_BM(addr), val); break; case PI_LVI: case PO_LVI: case MC_LVI: - r = &s->bm_regs[GET_BM(index)]; + r = &s->bm_regs[GET_BM(addr)]; val = r->lvi; - dolog("LVI[%d] -> 0x%x\n", GET_BM(index), val); + dolog("LVI[%d] -> 0x%x\n", GET_BM(addr), val); break; case PI_PIV: case PO_PIV: case MC_PIV: - r = &s->bm_regs[GET_BM(index)]; + r = &s->bm_regs[GET_BM(addr)]; val = r->piv; - dolog("PIV[%d] -> 0x%x\n", GET_BM(index), val); + dolog("PIV[%d] -> 0x%x\n", GET_BM(addr), val); break; case PI_CR: case PO_CR: case MC_CR: - r = &s->bm_regs[GET_BM(index)]; + r = &s->bm_regs[GET_BM(addr)]; val = r->cr; - dolog("CR[%d] -> 0x%x\n", GET_BM(index), val); + dolog("CR[%d] -> 0x%x\n", GET_BM(addr), val); break; case PI_SR: case PO_SR: case MC_SR: - r = &s->bm_regs[GET_BM(index)]; + r = &s->bm_regs[GET_BM(addr)]; val = r->sr & 0xff; - dolog("SRb[%d] -> 0x%x\n", GET_BM(index), val); + dolog("SRb[%d] -> 0x%x\n", GET_BM(addr), val); break; default: dolog("U nabm readb 0x%x -> 0x%x\n", addr, val); @@ -748,23 +746,22 @@ static uint32_t nabm_readw(void *opaque, uint32_t addr) { AC97LinkState *s = opaque; AC97BusMasterRegs *r = NULL; - uint32_t index = addr; uint32_t val = ~0U; - switch (index) { + switch (addr) { case PI_SR: case PO_SR: case MC_SR: - r = &s->bm_regs[GET_BM(index)]; + r = &s->bm_regs[GET_BM(addr)]; val = r->sr; - dolog("SR[%d] -> 0x%x\n", GET_BM(index), val); + dolog("SR[%d] -> 0x%x\n", GET_BM(addr), val); break; case PI_PICB: case PO_PICB: case MC_PICB: - r = &s->bm_regs[GET_BM(index)]; + r = &s->bm_regs[GET_BM(addr)]; val = r->picb; - dolog("PICB[%d] -> 0x%x\n", GET_BM(index), val); + dolog("PICB[%d] -> 0x%x\n", GET_BM(addr), val); break; default: dolog("U nabm readw 0x%x -> 0x%x\n", addr, val); @@ -777,31 +774,30 @@ static uint32_t nabm_readl(void *opaque, uint32_t addr) { AC97LinkState *s = opaque; AC97BusMasterRegs *r = NULL; - uint32_t index = addr; uint32_t val = ~0U; - switch (index) { + switch (addr) { case PI_BDBAR: case PO_BDBAR: case MC_BDBAR: - r = &s->bm_regs[GET_BM(index)]; + r = &s->bm_regs[GET_BM(addr)]; val = r->bdbar; - dolog("BMADDR[%d] -> 0x%x\n", GET_BM(index), val); + dolog("BMADDR[%d] -> 0x%x\n", GET_BM(addr), val); break; case PI_CIV: case PO_CIV: case MC_CIV: - r = &s->bm_regs[GET_BM(index)]; + r = &s->bm_regs[GET_BM(addr)]; val = r->civ | (r->lvi << 8) | (r->sr << 16); - dolog("CIV LVI SR[%d] -> 0x%x, 0x%x, 0x%x\n", GET_BM(index), + dolog("CIV LVI SR[%d] -> 0x%x, 0x%x, 0x%x\n", GET_BM(addr), r->civ, r->lvi, r->sr); break; case PI_PICB: case PO_PICB: case MC_PICB: - r = &s->bm_regs[GET_BM(index)]; + r = &s->bm_regs[GET_BM(addr)]; val = r->picb | (r->piv << 16) | (r->cr << 24); - dolog("PICB PIV CR[%d] -> 0x%x 0x%x 0x%x 0x%x\n", GET_BM(index), + dolog("PICB PIV CR[%d] -> 0x%x 0x%x 0x%x 0x%x\n", GET_BM(addr), val, r->picb, r->piv, r->cr); break; case GLOB_CNT: @@ -827,12 +823,12 @@ static void nabm_writeb(void *opaque, uint32_t addr, uint32_t val) { AC97LinkState *s = opaque; AC97BusMasterRegs *r = NULL; - uint32_t index = addr; - switch (index) { + + switch (addr) { case PI_LVI: case PO_LVI: case MC_LVI: - r = &s->bm_regs[GET_BM(index)]; + r = &s->bm_regs[GET_BM(addr)]; if ((r->cr & CR_RPBM) && (r->sr & SR_DCH)) { r->sr &= ~(SR_DCH | SR_CELV); r->civ = r->piv; @@ -840,12 +836,12 @@ static void nabm_writeb(void *opaque, uint32_t addr, uint32_t val) fetch_bd(s, r); } r->lvi = val % 32; - dolog("LVI[%d] <- 0x%x\n", GET_BM(index), val); + dolog("LVI[%d] <- 0x%x\n", GET_BM(addr), val); break; case PI_CR: case PO_CR: case MC_CR: - r = &s->bm_regs[GET_BM(index)]; + r = &s->bm_regs[GET_BM(addr)]; if (val & CR_RR) { reset_bm_regs(s, r); } else { @@ -861,15 +857,15 @@ static void nabm_writeb(void *opaque, uint32_t addr, uint32_t val) voice_set_active(s, r - s->bm_regs, 1); } } - dolog("CR[%d] <- 0x%x (cr 0x%x)\n", GET_BM(index), val, r->cr); + dolog("CR[%d] <- 0x%x (cr 0x%x)\n", GET_BM(addr), val, r->cr); break; case PI_SR: case PO_SR: case MC_SR: - r = &s->bm_regs[GET_BM(index)]; + r = &s->bm_regs[GET_BM(addr)]; r->sr |= val & ~(SR_RO_MASK | SR_WCLEAR_MASK); update_sr(s, r, r->sr & ~(val & SR_WCLEAR_MASK)); - dolog("SR[%d] <- 0x%x (sr 0x%x)\n", GET_BM(index), val, r->sr); + dolog("SR[%d] <- 0x%x (sr 0x%x)\n", GET_BM(addr), val, r->sr); break; default: dolog("U nabm writeb 0x%x <- 0x%x\n", addr, val); @@ -881,15 +877,15 @@ static void nabm_writew(void *opaque, uint32_t addr, uint32_t val) { AC97LinkState *s = opaque; AC97BusMasterRegs *r = NULL; - uint32_t index = addr; - switch (index) { + + switch (addr) { case PI_SR: case PO_SR: case MC_SR: - r = &s->bm_regs[GET_BM(index)]; + r = &s->bm_regs[GET_BM(addr)]; r->sr |= val & ~(SR_RO_MASK | SR_WCLEAR_MASK); update_sr(s, r, r->sr & ~(val & SR_WCLEAR_MASK)); - dolog("SR[%d] <- 0x%x (sr 0x%x)\n", GET_BM(index), val, r->sr); + dolog("SR[%d] <- 0x%x (sr 0x%x)\n", GET_BM(addr), val, r->sr); break; default: dolog("U nabm writew 0x%x <- 0x%x\n", addr, val); @@ -901,14 +897,14 @@ static void nabm_writel(void *opaque, uint32_t addr, uint32_t val) { AC97LinkState *s = opaque; AC97BusMasterRegs *r = NULL; - uint32_t index = addr; - switch (index) { + + switch (addr) { case PI_BDBAR: case PO_BDBAR: case MC_BDBAR: - r = &s->bm_regs[GET_BM(index)]; + r = &s->bm_regs[GET_BM(addr)]; r->bdbar = val & ~3; - dolog("BDBAR[%d] <- 0x%x (bdbar 0x%x)\n", GET_BM(index), val, r->bdbar); + dolog("BDBAR[%d] <- 0x%x (bdbar 0x%x)\n", GET_BM(addr), val, r->bdbar); break; case GLOB_CNT: /* TODO: Handle WR or CR being set (warm/cold reset requests) */ From 267b5e7e378afd260004cb37a66a6fcd641e3b53 Mon Sep 17 00:00:00 2001 From: "Maciej S. Szmigiero" Date: Mon, 23 May 2022 18:26:58 +0200 Subject: [PATCH 10/17] target/i386/kvm: Fix disabling MPX on "-cpu host" with MPX-capable host Since KVM commit 5f76f6f5ff96 ("KVM: nVMX: Do not expose MPX VMX controls when guest MPX disabled") it is not possible to disable MPX on a "-cpu host" just by adding "-mpx" there if the host CPU does indeed support MPX. QEMU will fail to set MSR_IA32_VMX_TRUE_{EXIT,ENTRY}_CTLS MSRs in this case and so trigger an assertion failure. Instead, besides "-mpx" one has to explicitly add also "-vmx-exit-clear-bndcfgs" and "-vmx-entry-load-bndcfgs" to QEMU command line to make it work, which is a bit convoluted. Make the MPX-related bits in FEAT_VMX_{EXIT,ENTRY}_CTLS dependent on MPX being actually enabled so such workarounds are no longer necessary. Signed-off-by: Maciej S. Szmigiero Message-Id: <51aa2125c76363204cc23c27165e778097c33f0b.1653323077.git.maciej.szmigiero@oracle.com> Cc: qemu-stable@nongnu.org Signed-off-by: Paolo Bonzini --- target/i386/cpu.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/target/i386/cpu.c b/target/i386/cpu.c index 35c3475e6c..385691458f 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -1355,6 +1355,14 @@ static FeatureDep feature_dependencies[] = { .from = { FEAT_7_0_EBX, CPUID_7_0_EBX_INVPCID }, .to = { FEAT_VMX_SECONDARY_CTLS, VMX_SECONDARY_EXEC_ENABLE_INVPCID }, }, + { + .from = { FEAT_7_0_EBX, CPUID_7_0_EBX_MPX }, + .to = { FEAT_VMX_EXIT_CTLS, VMX_VM_EXIT_CLEAR_BNDCFGS }, + }, + { + .from = { FEAT_7_0_EBX, CPUID_7_0_EBX_MPX }, + .to = { FEAT_VMX_ENTRY_CTLS, VMX_VM_ENTRY_LOAD_BNDCFGS }, + }, { .from = { FEAT_7_0_EBX, CPUID_7_0_EBX_RDSEED }, .to = { FEAT_VMX_SECONDARY_CTLS, VMX_SECONDARY_EXEC_RDSEED_EXITING }, From 758c925ee04ecd9d2d543a60f3c389e4e814c6aa Mon Sep 17 00:00:00 2001 From: Lev Kujawski Date: Fri, 20 May 2022 23:52:00 +0000 Subject: [PATCH 11/17] ide_ioport_read: Return lower octet of data register instead of 0xFF Prior to this patch, the pre-GRUB Solaris x86 bootloader would fail to load on QEMU with the following screen output: SunOS Secondary Boot version 3.00 prom_panic: Could not mount filesystem. Entering boot debugger: [136419]: _ This occurs because the bootloader issues an ATA IDENTIFY DEVICE command, and then reads the resulting 256 words of parameter information using inb rather than the correct inw. As the previous behavior of QEMU was to return 0xFF and not advance the drive's sector buffer, DRQ would never be cleared and the bootloader would be blocked from selecting a secondary ATA device, such as an optical drive. Resolves: * [Bug 1639394] Unable to boot Solaris 8/9 x86 under Fedora 24 Signed-off-by: Lev Kujawski Message-Id: <20220520235200.1138450-1-lkujaw@member.fsf.org> Signed-off-by: Paolo Bonzini --- hw/ide/core.c | 6 +++++- hw/ide/macio.c | 4 +++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/hw/ide/core.c b/hw/ide/core.c index 3a5afff5d7..c2caa54285 100644 --- a/hw/ide/core.c +++ b/hw/ide/core.c @@ -2166,7 +2166,11 @@ uint32_t ide_ioport_read(void *opaque, uint32_t addr) hob = bus->cmd & (IDE_CTRL_HOB); switch (reg_num) { case ATA_IOPORT_RR_DATA: - ret = 0xff; + /* + * The pre-GRUB Solaris x86 bootloader relies upon inb + * consuming a word from the drive's sector buffer. + */ + ret = ide_data_readw(bus, addr) & 0xff; break; case ATA_IOPORT_RR_ERROR: if ((!bus->ifs[0].blk && !bus->ifs[1].blk) || diff --git a/hw/ide/macio.c b/hw/ide/macio.c index f08318cf97..1c15c37ec5 100644 --- a/hw/ide/macio.c +++ b/hw/ide/macio.c @@ -267,7 +267,9 @@ static uint64_t pmac_ide_read(void *opaque, hwaddr addr, unsigned size) switch (reg) { case 0x0: - if (size == 2) { + if (size == 1) { + retval = ide_data_readw(&d->bus, 0) & 0xFF; + } else if (size == 2) { retval = ide_data_readw(&d->bus, 0); } else if (size == 4) { retval = ide_data_readl(&d->bus, 0); From 7110fe56c1f69b9e1bdf838558fdcb75d1568964 Mon Sep 17 00:00:00 2001 From: Vitaly Kuznetsov Date: Wed, 25 May 2022 13:59:44 +0200 Subject: [PATCH 12/17] i386: Use hv_build_cpuid_leaf() for HV_CPUID_NESTED_FEATURES Previously, HV_CPUID_NESTED_FEATURES.EAX CPUID leaf was handled differently as it was only used to encode the supported eVMCS version range. In fact, there are also feature (e.g. Enlightened MSR-Bitmap) bits there. In preparation to adding these features, move HV_CPUID_NESTED_FEATURES leaf handling to hv_build_cpuid_leaf() and drop now-unneeded 'hyperv_nested'. No functional change intended. Signed-off-by: Vitaly Kuznetsov Message-Id: <20220525115949.1294004-2-vkuznets@redhat.com> Signed-off-by: Paolo Bonzini --- target/i386/cpu.h | 1 - target/i386/kvm/kvm.c | 25 +++++++++++++++---------- 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/target/i386/cpu.h b/target/i386/cpu.h index 0d528ac58f..2e918daf6b 100644 --- a/target/i386/cpu.h +++ b/target/i386/cpu.h @@ -1804,7 +1804,6 @@ struct ArchCPU { uint32_t hyperv_vendor_id[3]; uint32_t hyperv_interface_id[4]; uint32_t hyperv_limits[3]; - uint32_t hyperv_nested[4]; bool hyperv_enforce_cpuid; uint32_t hyperv_ver_id_build; uint16_t hyperv_ver_id_major; diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c index e2d675115b..38af0e4f04 100644 --- a/target/i386/kvm/kvm.c +++ b/target/i386/kvm/kvm.c @@ -831,6 +831,8 @@ static bool tsc_is_stable_and_known(CPUX86State *env) || env->user_tsc_khz; } +#define DEFAULT_EVMCS_VERSION ((1 << 8) | 1) + static struct { const char *desc; struct { @@ -1254,6 +1256,13 @@ static uint32_t hv_build_cpuid_leaf(CPUState *cs, uint32_t func, int reg) } } + /* HV_CPUID_NESTED_FEATURES.EAX also encodes the supported eVMCS range */ + if (func == HV_CPUID_NESTED_FEATURES && reg == R_EAX) { + if (hyperv_feat_enabled(cpu, HYPERV_FEAT_EVMCS)) { + r |= DEFAULT_EVMCS_VERSION; + } + } + return r; } @@ -1384,11 +1393,11 @@ static int hyperv_fill_cpuids(CPUState *cs, struct kvm_cpuid_entry2 *c; uint32_t signature[3]; uint32_t cpuid_i = 0, max_cpuid_leaf = 0; + uint32_t nested_eax = + hv_build_cpuid_leaf(cs, HV_CPUID_NESTED_FEATURES, R_EAX); - max_cpuid_leaf = HV_CPUID_IMPLEMENT_LIMITS; - if (hyperv_feat_enabled(cpu, HYPERV_FEAT_EVMCS)) { - max_cpuid_leaf = MAX(max_cpuid_leaf, HV_CPUID_NESTED_FEATURES); - } + max_cpuid_leaf = nested_eax ? HV_CPUID_NESTED_FEATURES : + HV_CPUID_IMPLEMENT_LIMITS; if (hyperv_feat_enabled(cpu, HYPERV_FEAT_SYNDBG)) { max_cpuid_leaf = @@ -1461,7 +1470,7 @@ static int hyperv_fill_cpuids(CPUState *cs, c->ecx = cpu->hyperv_limits[1]; c->edx = cpu->hyperv_limits[2]; - if (hyperv_feat_enabled(cpu, HYPERV_FEAT_EVMCS)) { + if (nested_eax) { uint32_t function; /* Create zeroed 0x40000006..0x40000009 leaves */ @@ -1473,7 +1482,7 @@ static int hyperv_fill_cpuids(CPUState *cs, c = &cpuid_ent[cpuid_i++]; c->function = HV_CPUID_NESTED_FEATURES; - c->eax = cpu->hyperv_nested[0]; + c->eax = nested_eax; } if (hyperv_feat_enabled(cpu, HYPERV_FEAT_SYNDBG)) { @@ -1522,8 +1531,6 @@ static bool evmcs_version_supported(uint16_t evmcs_version, (max_version <= max_supported_version); } -#define DEFAULT_EVMCS_VERSION ((1 << 8) | 1) - static int hyperv_init_vcpu(X86CPU *cpu) { CPUState *cs = CPU(cpu); @@ -1620,8 +1627,6 @@ static int hyperv_init_vcpu(X86CPU *cpu) supported_evmcs_version >> 8); return -ENOTSUP; } - - cpu->hyperv_nested[0] = evmcs_version; } if (cpu->hyperv_enforce_cpuid) { From 869840d26c929b99694e31b1a18e83bdea6e97ca Mon Sep 17 00:00:00 2001 From: Vitaly Kuznetsov Date: Wed, 25 May 2022 13:59:45 +0200 Subject: [PATCH 13/17] i386: Hyper-V Enlightened MSR bitmap feature The newly introduced enlightenment allow L0 (KVM) and L1 (Hyper-V) hypervisors to collaborate to avoid unnecessary updates to L2 MSR-Bitmap upon vmexits. Signed-off-by: Vitaly Kuznetsov Message-Id: <20220525115949.1294004-3-vkuznets@redhat.com> Signed-off-by: Paolo Bonzini --- docs/hyperv.txt | 9 +++++++++ target/i386/cpu.c | 2 ++ target/i386/cpu.h | 1 + target/i386/kvm/hyperv-proto.h | 5 +++++ target/i386/kvm/kvm.c | 7 +++++++ 5 files changed, 24 insertions(+) diff --git a/docs/hyperv.txt b/docs/hyperv.txt index 33588a0396..5d85569b99 100644 --- a/docs/hyperv.txt +++ b/docs/hyperv.txt @@ -239,6 +239,15 @@ This enlightenment requires a VMBus device (-device vmbus-bridge,irq=15) and the follow enlightenments to work: hv-relaxed,hv_time,hv-vapic,hv-vpindex,hv-synic,hv-runtime,hv-stimer +3.22. hv-emsr-bitmap +===================== +The enlightenment is nested specific, it targets Hyper-V on KVM guests. When +enabled, it allows L0 (KVM) and L1 (Hyper-V) hypervisors to collaborate to +avoid unnecessary updates to L2 MSR-Bitmap upon vmexits. While the protocol is +supported for both VMX (Intel) and SVM (AMD), the VMX implementation requires +Enlightened VMCS ('hv-evmcs') feature to also be enabled. + +Recommended: hv-evmcs (Intel) 4. Supplementary features ========================= diff --git a/target/i386/cpu.c b/target/i386/cpu.c index 385691458f..474e9b582e 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -6968,6 +6968,8 @@ static Property x86_cpu_properties[] = { HYPERV_FEAT_STIMER_DIRECT, 0), DEFINE_PROP_BIT64("hv-avic", X86CPU, hyperv_features, HYPERV_FEAT_AVIC, 0), + DEFINE_PROP_BIT64("hv-emsr-bitmap", X86CPU, hyperv_features, + HYPERV_FEAT_MSR_BITMAP, 0), DEFINE_PROP_ON_OFF_AUTO("hv-no-nonarch-coresharing", X86CPU, hyperv_no_nonarch_cs, ON_OFF_AUTO_OFF), DEFINE_PROP_BIT64("hv-syndbg", X86CPU, hyperv_features, diff --git a/target/i386/cpu.h b/target/i386/cpu.h index 2e918daf6b..c788285736 100644 --- a/target/i386/cpu.h +++ b/target/i386/cpu.h @@ -1106,6 +1106,7 @@ uint64_t x86_cpu_get_supported_feature_word(FeatureWord w, #define HYPERV_FEAT_STIMER_DIRECT 14 #define HYPERV_FEAT_AVIC 15 #define HYPERV_FEAT_SYNDBG 16 +#define HYPERV_FEAT_MSR_BITMAP 17 #ifndef HYPERV_SPINLOCK_NEVER_NOTIFY #define HYPERV_SPINLOCK_NEVER_NOTIFY 0xFFFFFFFF diff --git a/target/i386/kvm/hyperv-proto.h b/target/i386/kvm/hyperv-proto.h index e40e59411c..cea18dbc0e 100644 --- a/target/i386/kvm/hyperv-proto.h +++ b/target/i386/kvm/hyperv-proto.h @@ -86,6 +86,11 @@ */ #define HV_SYNDBG_CAP_ALLOW_KERNEL_DEBUGGING (1u << 1) +/* + * HV_CPUID_NESTED_FEATURES.EAX bits + */ +#define HV_NESTED_MSR_BITMAP (1u << 19) + /* * Basic virtualized MSRs */ diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c index 38af0e4f04..f389bbedf2 100644 --- a/target/i386/kvm/kvm.c +++ b/target/i386/kvm/kvm.c @@ -973,6 +973,13 @@ static struct { .dependencies = BIT(HYPERV_FEAT_SYNIC) | BIT(HYPERV_FEAT_RELAXED) }, #endif + [HYPERV_FEAT_MSR_BITMAP] = { + .desc = "enlightened MSR-Bitmap (hv-emsr-bitmap)", + .flags = { + {.func = HV_CPUID_NESTED_FEATURES, .reg = R_EAX, + .bits = HV_NESTED_MSR_BITMAP} + } + }, }; static struct kvm_cpuid2 *try_get_hv_cpuid(CPUState *cs, int max, From 9411e8b6faeb1d88d4441c63c5ec072a01b2914e Mon Sep 17 00:00:00 2001 From: Vitaly Kuznetsov Date: Wed, 25 May 2022 13:59:46 +0200 Subject: [PATCH 14/17] i386: Hyper-V XMM fast hypercall input feature Hyper-V specification allows to pass parameters for certain hypercalls using XMM registers ("XMM Fast Hypercall Input"). When the feature is in use, it allows for faster hypercalls processing as KVM can avoid reading guest's memory. KVM supports the feature since v5.14. Rename HV_HYPERCALL_{PARAMS_XMM_AVAILABLE -> XMM_INPUT_AVAILABLE} to comply with KVM. Signed-off-by: Vitaly Kuznetsov Message-Id: <20220525115949.1294004-4-vkuznets@redhat.com> Signed-off-by: Paolo Bonzini --- docs/hyperv.txt | 6 ++++++ target/i386/cpu.c | 2 ++ target/i386/cpu.h | 1 + target/i386/kvm/hyperv-proto.h | 2 +- target/i386/kvm/kvm.c | 7 +++++++ 5 files changed, 17 insertions(+), 1 deletion(-) diff --git a/docs/hyperv.txt b/docs/hyperv.txt index 5d85569b99..af1b10c0b3 100644 --- a/docs/hyperv.txt +++ b/docs/hyperv.txt @@ -249,6 +249,12 @@ Enlightened VMCS ('hv-evmcs') feature to also be enabled. Recommended: hv-evmcs (Intel) +3.23. hv-xmm-input +=================== +Hyper-V specification allows to pass parameters for certain hypercalls using XMM +registers ("XMM Fast Hypercall Input"). When the feature is in use, it allows +for faster hypercalls processing as KVM can avoid reading guest's memory. + 4. Supplementary features ========================= diff --git a/target/i386/cpu.c b/target/i386/cpu.c index 474e9b582e..63cec0ea68 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -6970,6 +6970,8 @@ static Property x86_cpu_properties[] = { HYPERV_FEAT_AVIC, 0), DEFINE_PROP_BIT64("hv-emsr-bitmap", X86CPU, hyperv_features, HYPERV_FEAT_MSR_BITMAP, 0), + DEFINE_PROP_BIT64("hv-xmm-input", X86CPU, hyperv_features, + HYPERV_FEAT_XMM_INPUT, 0), DEFINE_PROP_ON_OFF_AUTO("hv-no-nonarch-coresharing", X86CPU, hyperv_no_nonarch_cs, ON_OFF_AUTO_OFF), DEFINE_PROP_BIT64("hv-syndbg", X86CPU, hyperv_features, diff --git a/target/i386/cpu.h b/target/i386/cpu.h index c788285736..37e9553584 100644 --- a/target/i386/cpu.h +++ b/target/i386/cpu.h @@ -1107,6 +1107,7 @@ uint64_t x86_cpu_get_supported_feature_word(FeatureWord w, #define HYPERV_FEAT_AVIC 15 #define HYPERV_FEAT_SYNDBG 16 #define HYPERV_FEAT_MSR_BITMAP 17 +#define HYPERV_FEAT_XMM_INPUT 18 #ifndef HYPERV_SPINLOCK_NEVER_NOTIFY #define HYPERV_SPINLOCK_NEVER_NOTIFY 0xFFFFFFFF diff --git a/target/i386/kvm/hyperv-proto.h b/target/i386/kvm/hyperv-proto.h index cea18dbc0e..f5f16474fa 100644 --- a/target/i386/kvm/hyperv-proto.h +++ b/target/i386/kvm/hyperv-proto.h @@ -54,7 +54,7 @@ #define HV_GUEST_DEBUGGING_AVAILABLE (1u << 1) #define HV_PERF_MONITOR_AVAILABLE (1u << 2) #define HV_CPU_DYNAMIC_PARTITIONING_AVAILABLE (1u << 3) -#define HV_HYPERCALL_PARAMS_XMM_AVAILABLE (1u << 4) +#define HV_HYPERCALL_XMM_INPUT_AVAILABLE (1u << 4) #define HV_GUEST_IDLE_STATE_AVAILABLE (1u << 5) #define HV_FREQUENCY_MSRS_AVAILABLE (1u << 8) #define HV_GUEST_CRASH_MSR_AVAILABLE (1u << 10) diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c index f389bbedf2..7e6f934eda 100644 --- a/target/i386/kvm/kvm.c +++ b/target/i386/kvm/kvm.c @@ -980,6 +980,13 @@ static struct { .bits = HV_NESTED_MSR_BITMAP} } }, + [HYPERV_FEAT_XMM_INPUT] = { + .desc = "XMM fast hypercall input (hv-xmm-input)", + .flags = { + {.func = HV_CPUID_FEATURES, .reg = R_EDX, + .bits = HV_HYPERCALL_XMM_INPUT_AVAILABLE} + } + }, }; static struct kvm_cpuid2 *try_get_hv_cpuid(CPUState *cs, int max, From aa6bb5fad58d049c6ea97448d4caba4499d60634 Mon Sep 17 00:00:00 2001 From: Vitaly Kuznetsov Date: Wed, 25 May 2022 13:59:47 +0200 Subject: [PATCH 15/17] i386: Hyper-V Support extended GVA ranges for TLB flush hypercalls KVM kind of supported "extended GVA ranges" (up to 4095 additional GFNs per hypercall) since the implementation of Hyper-V PV TLB flush feature (Linux-4.18) as regardless of the request, full TLB flush was always performed. "Extended GVA ranges for TLB flush hypercalls" feature bit wasn't exposed then. Now, as KVM gains support for fine-grained TLB flush handling, exposing this feature starts making sense. Signed-off-by: Vitaly Kuznetsov Message-Id: <20220525115949.1294004-5-vkuznets@redhat.com> Signed-off-by: Paolo Bonzini --- docs/hyperv.txt | 7 +++++++ target/i386/cpu.c | 2 ++ target/i386/cpu.h | 1 + target/i386/kvm/hyperv-proto.h | 1 + target/i386/kvm/kvm.c | 8 ++++++++ 5 files changed, 19 insertions(+) diff --git a/docs/hyperv.txt b/docs/hyperv.txt index af1b10c0b3..4b132b1c94 100644 --- a/docs/hyperv.txt +++ b/docs/hyperv.txt @@ -255,6 +255,13 @@ Hyper-V specification allows to pass parameters for certain hypercalls using XMM registers ("XMM Fast Hypercall Input"). When the feature is in use, it allows for faster hypercalls processing as KVM can avoid reading guest's memory. +3.24. hv-tlbflush-ext +===================== +Allow for extended GVA ranges to be passed to Hyper-V TLB flush hypercalls +(HvFlushVirtualAddressList/HvFlushVirtualAddressListEx). + +Requires: hv-tlbflush + 4. Supplementary features ========================= diff --git a/target/i386/cpu.c b/target/i386/cpu.c index 63cec0ea68..3429a4e455 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -6972,6 +6972,8 @@ static Property x86_cpu_properties[] = { HYPERV_FEAT_MSR_BITMAP, 0), DEFINE_PROP_BIT64("hv-xmm-input", X86CPU, hyperv_features, HYPERV_FEAT_XMM_INPUT, 0), + DEFINE_PROP_BIT64("hv-tlbflush-ext", X86CPU, hyperv_features, + HYPERV_FEAT_TLBFLUSH_EXT, 0), DEFINE_PROP_ON_OFF_AUTO("hv-no-nonarch-coresharing", X86CPU, hyperv_no_nonarch_cs, ON_OFF_AUTO_OFF), DEFINE_PROP_BIT64("hv-syndbg", X86CPU, hyperv_features, diff --git a/target/i386/cpu.h b/target/i386/cpu.h index 37e9553584..5ff48257e5 100644 --- a/target/i386/cpu.h +++ b/target/i386/cpu.h @@ -1108,6 +1108,7 @@ uint64_t x86_cpu_get_supported_feature_word(FeatureWord w, #define HYPERV_FEAT_SYNDBG 16 #define HYPERV_FEAT_MSR_BITMAP 17 #define HYPERV_FEAT_XMM_INPUT 18 +#define HYPERV_FEAT_TLBFLUSH_EXT 19 #ifndef HYPERV_SPINLOCK_NEVER_NOTIFY #define HYPERV_SPINLOCK_NEVER_NOTIFY 0xFFFFFFFF diff --git a/target/i386/kvm/hyperv-proto.h b/target/i386/kvm/hyperv-proto.h index f5f16474fa..c7854ed6d3 100644 --- a/target/i386/kvm/hyperv-proto.h +++ b/target/i386/kvm/hyperv-proto.h @@ -59,6 +59,7 @@ #define HV_FREQUENCY_MSRS_AVAILABLE (1u << 8) #define HV_GUEST_CRASH_MSR_AVAILABLE (1u << 10) #define HV_FEATURE_DEBUG_MSRS_AVAILABLE (1u << 11) +#define HV_EXT_GVA_RANGES_FLUSH_AVAILABLE (1u << 14) #define HV_STIMER_DIRECT_MODE_AVAILABLE (1u << 19) /* diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c index 7e6f934eda..a11c8e88f6 100644 --- a/target/i386/kvm/kvm.c +++ b/target/i386/kvm/kvm.c @@ -987,6 +987,14 @@ static struct { .bits = HV_HYPERCALL_XMM_INPUT_AVAILABLE} } }, + [HYPERV_FEAT_TLBFLUSH_EXT] = { + .desc = "Extended gva ranges for TLB flush hypercalls (hv-tlbflush-ext)", + .flags = { + {.func = HV_CPUID_FEATURES, .reg = R_EDX, + .bits = HV_EXT_GVA_RANGES_FLUSH_AVAILABLE} + }, + .dependencies = BIT(HYPERV_FEAT_TLBFLUSH) + }, }; static struct kvm_cpuid2 *try_get_hv_cpuid(CPUState *cs, int max, From 3aae0854b26aff303202c6f9542445f58b2539fe Mon Sep 17 00:00:00 2001 From: Vitaly Kuznetsov Date: Wed, 25 May 2022 13:59:48 +0200 Subject: [PATCH 16/17] i386: Hyper-V Direct TLB flush hypercall Hyper-V TLFS allows for L0 and L1 hypervisors to collaborate on L2's TLB flush hypercalls handling. With the correct setup, L2's TLB flush hypercalls can be handled by L0 directly, without the need to exit to L1. Signed-off-by: Vitaly Kuznetsov Message-Id: <20220525115949.1294004-6-vkuznets@redhat.com> Signed-off-by: Paolo Bonzini --- docs/hyperv.txt | 11 +++++++++++ target/i386/cpu.c | 2 ++ target/i386/cpu.h | 1 + target/i386/kvm/hyperv-proto.h | 1 + target/i386/kvm/kvm.c | 8 ++++++++ 5 files changed, 23 insertions(+) diff --git a/docs/hyperv.txt b/docs/hyperv.txt index 4b132b1c94..14a7f449ea 100644 --- a/docs/hyperv.txt +++ b/docs/hyperv.txt @@ -262,6 +262,17 @@ Allow for extended GVA ranges to be passed to Hyper-V TLB flush hypercalls Requires: hv-tlbflush +3.25. hv-tlbflush-direct +========================= +The enlightenment is nested specific, it targets Hyper-V on KVM guests. When +enabled, it allows L0 (KVM) to directly handle TLB flush hypercalls from L2 +guest without the need to exit to L1 (Hyper-V) hypervisor. While the feature is +supported for both VMX (Intel) and SVM (AMD), the VMX implementation requires +Enlightened VMCS ('hv-evmcs') feature to also be enabled. + +Requires: hv-vapic +Recommended: hv-evmcs (Intel) + 4. Supplementary features ========================= diff --git a/target/i386/cpu.c b/target/i386/cpu.c index 3429a4e455..bb6a5dd498 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -6974,6 +6974,8 @@ static Property x86_cpu_properties[] = { HYPERV_FEAT_XMM_INPUT, 0), DEFINE_PROP_BIT64("hv-tlbflush-ext", X86CPU, hyperv_features, HYPERV_FEAT_TLBFLUSH_EXT, 0), + DEFINE_PROP_BIT64("hv-tlbflush-direct", X86CPU, hyperv_features, + HYPERV_FEAT_TLBFLUSH_DIRECT, 0), DEFINE_PROP_ON_OFF_AUTO("hv-no-nonarch-coresharing", X86CPU, hyperv_no_nonarch_cs, ON_OFF_AUTO_OFF), DEFINE_PROP_BIT64("hv-syndbg", X86CPU, hyperv_features, diff --git a/target/i386/cpu.h b/target/i386/cpu.h index 5ff48257e5..82004b65b9 100644 --- a/target/i386/cpu.h +++ b/target/i386/cpu.h @@ -1109,6 +1109,7 @@ uint64_t x86_cpu_get_supported_feature_word(FeatureWord w, #define HYPERV_FEAT_MSR_BITMAP 17 #define HYPERV_FEAT_XMM_INPUT 18 #define HYPERV_FEAT_TLBFLUSH_EXT 19 +#define HYPERV_FEAT_TLBFLUSH_DIRECT 20 #ifndef HYPERV_SPINLOCK_NEVER_NOTIFY #define HYPERV_SPINLOCK_NEVER_NOTIFY 0xFFFFFFFF diff --git a/target/i386/kvm/hyperv-proto.h b/target/i386/kvm/hyperv-proto.h index c7854ed6d3..464fbf09e3 100644 --- a/target/i386/kvm/hyperv-proto.h +++ b/target/i386/kvm/hyperv-proto.h @@ -90,6 +90,7 @@ /* * HV_CPUID_NESTED_FEATURES.EAX bits */ +#define HV_NESTED_DIRECT_FLUSH (1u << 17) #define HV_NESTED_MSR_BITMAP (1u << 19) /* diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c index a11c8e88f6..f148a6d52f 100644 --- a/target/i386/kvm/kvm.c +++ b/target/i386/kvm/kvm.c @@ -995,6 +995,14 @@ static struct { }, .dependencies = BIT(HYPERV_FEAT_TLBFLUSH) }, + [HYPERV_FEAT_TLBFLUSH_DIRECT] = { + .desc = "direct TLB flush (hv-tlbflush-direct)", + .flags = { + {.func = HV_CPUID_NESTED_FEATURES, .reg = R_EAX, + .bits = HV_NESTED_DIRECT_FLUSH} + }, + .dependencies = BIT(HYPERV_FEAT_VAPIC) + }, }; static struct kvm_cpuid2 *try_get_hv_cpuid(CPUState *cs, int max, From 9ad6634ec956bcf3558059aae8c6b2b5ee985307 Mon Sep 17 00:00:00 2001 From: Vitaly Kuznetsov Date: Wed, 25 May 2022 13:59:49 +0200 Subject: [PATCH 17/17] i386: docs: Convert hyperv.txt to rST rSTify docs/hyperv.txt and link it from docs/system/target-i386.rst. Signed-off-by: Vitaly Kuznetsov Message-Id: <20220525115949.1294004-7-vkuznets@redhat.com> Signed-off-by: Paolo Bonzini --- docs/hyperv.txt | 303 ------------------------------------ docs/system/i386/hyperv.rst | 288 ++++++++++++++++++++++++++++++++++ docs/system/target-i386.rst | 1 + 3 files changed, 289 insertions(+), 303 deletions(-) delete mode 100644 docs/hyperv.txt create mode 100644 docs/system/i386/hyperv.rst diff --git a/docs/hyperv.txt b/docs/hyperv.txt deleted file mode 100644 index 14a7f449ea..0000000000 --- a/docs/hyperv.txt +++ /dev/null @@ -1,303 +0,0 @@ -Hyper-V Enlightenments -====================== - - -1. Description -=============== -In some cases when implementing a hardware interface in software is slow, KVM -implements its own paravirtualized interfaces. This works well for Linux as -guest support for such features is added simultaneously with the feature itself. -It may, however, be hard-to-impossible to add support for these interfaces to -proprietary OSes, namely, Microsoft Windows. - -KVM on x86 implements Hyper-V Enlightenments for Windows guests. These features -make Windows and Hyper-V guests think they're running on top of a Hyper-V -compatible hypervisor and use Hyper-V specific features. - - -2. Setup -========= -No Hyper-V enlightenments are enabled by default by either KVM or QEMU. In -QEMU, individual enlightenments can be enabled through CPU flags, e.g: - - qemu-system-x86_64 --enable-kvm --cpu host,hv_relaxed,hv_vpindex,hv_time, ... - -Sometimes there are dependencies between enlightenments, QEMU is supposed to -check that the supplied configuration is sane. - -When any set of the Hyper-V enlightenments is enabled, QEMU changes hypervisor -identification (CPUID 0x40000000..0x4000000A) to Hyper-V. KVM identification -and features are kept in leaves 0x40000100..0x40000101. - - -3. Existing enlightenments -=========================== - -3.1. hv-relaxed -================ -This feature tells guest OS to disable watchdog timeouts as it is running on a -hypervisor. It is known that some Windows versions will do this even when they -see 'hypervisor' CPU flag. - -3.2. hv-vapic -============== -Provides so-called VP Assist page MSR to guest allowing it to work with APIC -more efficiently. In particular, this enlightenment allows paravirtualized -(exit-less) EOI processing. - -3.3. hv-spinlocks=xxx -====================== -Enables paravirtualized spinlocks. The parameter indicates how many times -spinlock acquisition should be attempted before indicating the situation to the -hypervisor. A special value 0xffffffff indicates "never notify". - -3.4. hv-vpindex -================ -Provides HV_X64_MSR_VP_INDEX (0x40000002) MSR to the guest which has Virtual -processor index information. This enlightenment makes sense in conjunction with -hv-synic, hv-stimer and other enlightenments which require the guest to know its -Virtual Processor indices (e.g. when VP index needs to be passed in a -hypercall). - -3.5. hv-runtime -================ -Provides HV_X64_MSR_VP_RUNTIME (0x40000010) MSR to the guest. The MSR keeps the -virtual processor run time in 100ns units. This gives guest operating system an -idea of how much time was 'stolen' from it (when the virtual CPU was preempted -to perform some other work). - -3.6. hv-crash -============== -Provides HV_X64_MSR_CRASH_P0..HV_X64_MSR_CRASH_P5 (0x40000100..0x40000105) and -HV_X64_MSR_CRASH_CTL (0x40000105) MSRs to the guest. These MSRs are written to -by the guest when it crashes, HV_X64_MSR_CRASH_P0..HV_X64_MSR_CRASH_P5 MSRs -contain additional crash information. This information is outputted in QEMU log -and through QAPI. -Note: unlike under genuine Hyper-V, write to HV_X64_MSR_CRASH_CTL causes guest -to shutdown. This effectively blocks crash dump generation by Windows. - -3.7. hv-time -============= -Enables two Hyper-V-specific clocksources available to the guest: MSR-based -Hyper-V clocksource (HV_X64_MSR_TIME_REF_COUNT, 0x40000020) and Reference TSC -page (enabled via MSR HV_X64_MSR_REFERENCE_TSC, 0x40000021). Both clocksources -are per-guest, Reference TSC page clocksource allows for exit-less time stamp -readings. Using this enlightenment leads to significant speedup of all timestamp -related operations. - -3.8. hv-synic -============== -Enables Hyper-V Synthetic interrupt controller - an extension of a local APIC. -When enabled, this enlightenment provides additional communication facilities -to the guest: SynIC messages and Events. This is a pre-requisite for -implementing VMBus devices (not yet in QEMU). Additionally, this enlightenment -is needed to enable Hyper-V synthetic timers. SynIC is controlled through MSRs -HV_X64_MSR_SCONTROL..HV_X64_MSR_EOM (0x40000080..0x40000084) and -HV_X64_MSR_SINT0..HV_X64_MSR_SINT15 (0x40000090..0x4000009F) - -Requires: hv-vpindex - -3.9. hv-stimer -=============== -Enables Hyper-V synthetic timers. There are four synthetic timers per virtual -CPU controlled through HV_X64_MSR_STIMER0_CONFIG..HV_X64_MSR_STIMER3_COUNT -(0x400000B0..0x400000B7) MSRs. These timers can work either in single-shot or -periodic mode. It is known that certain Windows versions revert to using HPET -(or even RTC when HPET is unavailable) extensively when this enlightenment is -not provided; this can lead to significant CPU consumption, even when virtual -CPU is idle. - -Requires: hv-vpindex, hv-synic, hv-time - -3.10. hv-tlbflush -================== -Enables paravirtualized TLB shoot-down mechanism. On x86 architecture, remote -TLB flush procedure requires sending IPIs and waiting for other CPUs to perform -local TLB flush. In virtualized environment some virtual CPUs may not even be -scheduled at the time of the call and may not require flushing (or, flushing -may be postponed until the virtual CPU is scheduled). hv-tlbflush enlightenment -implements TLB shoot-down through hypervisor enabling the optimization. - -Requires: hv-vpindex - -3.11. hv-ipi -============= -Enables paravirtualized IPI send mechanism. HvCallSendSyntheticClusterIpi -hypercall may target more than 64 virtual CPUs simultaneously, doing the same -through APIC requires more than one access (and thus exit to the hypervisor). - -Requires: hv-vpindex - -3.12. hv-vendor-id=xxx -======================= -This changes Hyper-V identification in CPUID 0x40000000.EBX-EDX from the default -"Microsoft Hv". The parameter should be no longer than 12 characters. According -to the specification, guests shouldn't use this information and it is unknown -if there is a Windows version which acts differently. -Note: hv-vendor-id is not an enlightenment and thus doesn't enable Hyper-V -identification when specified without some other enlightenment. - -3.13. hv-reset -=============== -Provides HV_X64_MSR_RESET (0x40000003) MSR to the guest allowing it to reset -itself by writing to it. Even when this MSR is enabled, it is not a recommended -way for Windows to perform system reboot and thus it may not be used. - -3.14. hv-frequencies -============================================ -Provides HV_X64_MSR_TSC_FREQUENCY (0x40000022) and HV_X64_MSR_APIC_FREQUENCY -(0x40000023) allowing the guest to get its TSC/APIC frequencies without doing -measurements. - -3.15 hv-reenlightenment -======================== -The enlightenment is nested specific, it targets Hyper-V on KVM guests. When -enabled, it provides HV_X64_MSR_REENLIGHTENMENT_CONTROL (0x40000106), -HV_X64_MSR_TSC_EMULATION_CONTROL (0x40000107)and HV_X64_MSR_TSC_EMULATION_STATUS -(0x40000108) MSRs allowing the guest to get notified when TSC frequency changes -(only happens on migration) and keep using old frequency (through emulation in -the hypervisor) until it is ready to switch to the new one. This, in conjunction -with hv-frequencies, allows Hyper-V on KVM to pass stable clocksource (Reference -TSC page) to its own guests. - -Note, KVM doesn't fully support re-enlightenment notifications and doesn't -emulate TSC accesses after migration so 'tsc-frequency=' CPU option also has to -be specified to make migration succeed. The destination host has to either have -the same TSC frequency or support TSC scaling CPU feature. - -Recommended: hv-frequencies - -3.16. hv-evmcs -=============== -The enlightenment is nested specific, it targets Hyper-V on KVM guests. When -enabled, it provides Enlightened VMCS version 1 feature to the guest. The feature -implements paravirtualized protocol between L0 (KVM) and L1 (Hyper-V) -hypervisors making L2 exits to the hypervisor faster. The feature is Intel-only. -Note: some virtualization features (e.g. Posted Interrupts) are disabled when -hv-evmcs is enabled. It may make sense to measure your nested workload with and -without the feature to find out if enabling it is beneficial. - -Requires: hv-vapic - -3.17. hv-stimer-direct -======================= -Hyper-V specification allows synthetic timer operation in two modes: "classic", -when expiration event is delivered as SynIC message and "direct", when the event -is delivered via normal interrupt. It is known that nested Hyper-V can only -use synthetic timers in direct mode and thus 'hv-stimer-direct' needs to be -enabled. - -Requires: hv-vpindex, hv-synic, hv-time, hv-stimer - -3.18. hv-avic (hv-apicv) -======================= -The enlightenment allows to use Hyper-V SynIC with hardware APICv/AVIC enabled. -Normally, Hyper-V SynIC disables these hardware feature and suggests the guest -to use paravirtualized AutoEOI feature. -Note: enabling this feature on old hardware (without APICv/AVIC support) may -have negative effect on guest's performance. - -3.19. hv-no-nonarch-coresharing=on/off/auto -=========================================== -This enlightenment tells guest OS that virtual processors will never share a -physical core unless they are reported as sibling SMT threads. This information -is required by Windows and Hyper-V guests to properly mitigate SMT related CPU -vulnerabilities. -When the option is set to 'auto' QEMU will enable the feature only when KVM -reports that non-architectural coresharing is impossible, this means that -hyper-threading is not supported or completely disabled on the host. This -setting also prevents migration as SMT settings on the destination may differ. -When the option is set to 'on' QEMU will always enable the feature, regardless -of host setup. To keep guests secure, this can only be used in conjunction with -exposing correct vCPU topology and vCPU pinning. - -3.20. hv-version-id-{build,major,minor,spack,sbranch,snumber} -============================================================= -This changes Hyper-V version identification in CPUID 0x40000002.EAX-EDX from the -default (WS2016). -- hv-version-id-build sets 'Build Number' (32 bits) -- hv-version-id-major sets 'Major Version' (16 bits) -- hv-version-id-minor sets 'Minor Version' (16 bits) -- hv-version-id-spack sets 'Service Pack' (32 bits) -- hv-version-id-sbranch sets 'Service Branch' (8 bits) -- hv-version-id-snumber sets 'Service Number' (24 bits) - -Note: hv-version-id-* are not enlightenments and thus don't enable Hyper-V -identification when specified without any other enlightenments. - -3.21. hv-syndbg -=============== -Enables Hyper-V synthetic debugger interface, this is a special interface used -by Windows Kernel debugger to send the packets through, rather than sending -them via serial/network . -When enabled, this enlightenment provides additional communication facilities -to the guest: SynDbg messages. -This new communication is used by Windows Kernel debugger rather than sending -packets via serial/network, adding significant performance boost over the other -comm channels. -This enlightenment requires a VMBus device (-device vmbus-bridge,irq=15) -and the follow enlightenments to work: -hv-relaxed,hv_time,hv-vapic,hv-vpindex,hv-synic,hv-runtime,hv-stimer - -3.22. hv-emsr-bitmap -===================== -The enlightenment is nested specific, it targets Hyper-V on KVM guests. When -enabled, it allows L0 (KVM) and L1 (Hyper-V) hypervisors to collaborate to -avoid unnecessary updates to L2 MSR-Bitmap upon vmexits. While the protocol is -supported for both VMX (Intel) and SVM (AMD), the VMX implementation requires -Enlightened VMCS ('hv-evmcs') feature to also be enabled. - -Recommended: hv-evmcs (Intel) - -3.23. hv-xmm-input -=================== -Hyper-V specification allows to pass parameters for certain hypercalls using XMM -registers ("XMM Fast Hypercall Input"). When the feature is in use, it allows -for faster hypercalls processing as KVM can avoid reading guest's memory. - -3.24. hv-tlbflush-ext -===================== -Allow for extended GVA ranges to be passed to Hyper-V TLB flush hypercalls -(HvFlushVirtualAddressList/HvFlushVirtualAddressListEx). - -Requires: hv-tlbflush - -3.25. hv-tlbflush-direct -========================= -The enlightenment is nested specific, it targets Hyper-V on KVM guests. When -enabled, it allows L0 (KVM) to directly handle TLB flush hypercalls from L2 -guest without the need to exit to L1 (Hyper-V) hypervisor. While the feature is -supported for both VMX (Intel) and SVM (AMD), the VMX implementation requires -Enlightened VMCS ('hv-evmcs') feature to also be enabled. - -Requires: hv-vapic -Recommended: hv-evmcs (Intel) - -4. Supplementary features -========================= - -4.1. hv-passthrough -=================== -In some cases (e.g. during development) it may make sense to use QEMU in -'pass-through' mode and give Windows guests all enlightenments currently -supported by KVM. This pass-through mode is enabled by "hv-passthrough" CPU -flag. -Note: "hv-passthrough" flag only enables enlightenments which are known to QEMU -(have corresponding "hv-*" flag) and copies "hv-spinlocks="/"hv-vendor-id=" -values from KVM to QEMU. "hv-passthrough" overrides all other "hv-*" settings on -the command line. Also, enabling this flag effectively prevents migration as the -list of enabled enlightenments may differ between target and destination hosts. - -4.2. hv-enforce-cpuid -===================== -By default, KVM allows the guest to use all currently supported Hyper-V -enlightenments when Hyper-V CPUID interface was exposed, regardless of if -some features were not announced in guest visible CPUIDs. 'hv-enforce-cpuid' -feature alters this behavior and only allows the guest to use exposed Hyper-V -enlightenments. - - -5. Useful links -================ -Hyper-V Top Level Functional specification and other information: -https://github.com/MicrosoftDocs/Virtualization-Documentation diff --git a/docs/system/i386/hyperv.rst b/docs/system/i386/hyperv.rst new file mode 100644 index 0000000000..2505dc4c86 --- /dev/null +++ b/docs/system/i386/hyperv.rst @@ -0,0 +1,288 @@ +Hyper-V Enlightenments +====================== + + +Description +----------- + +In some cases when implementing a hardware interface in software is slow, KVM +implements its own paravirtualized interfaces. This works well for Linux as +guest support for such features is added simultaneously with the feature itself. +It may, however, be hard-to-impossible to add support for these interfaces to +proprietary OSes, namely, Microsoft Windows. + +KVM on x86 implements Hyper-V Enlightenments for Windows guests. These features +make Windows and Hyper-V guests think they're running on top of a Hyper-V +compatible hypervisor and use Hyper-V specific features. + + +Setup +----- + +No Hyper-V enlightenments are enabled by default by either KVM or QEMU. In +QEMU, individual enlightenments can be enabled through CPU flags, e.g: + +.. parsed-literal:: + + |qemu_system| --enable-kvm --cpu host,hv_relaxed,hv_vpindex,hv_time, ... + +Sometimes there are dependencies between enlightenments, QEMU is supposed to +check that the supplied configuration is sane. + +When any set of the Hyper-V enlightenments is enabled, QEMU changes hypervisor +identification (CPUID 0x40000000..0x4000000A) to Hyper-V. KVM identification +and features are kept in leaves 0x40000100..0x40000101. + + +Existing enlightenments +----------------------- + +``hv-relaxed`` + This feature tells guest OS to disable watchdog timeouts as it is running on a + hypervisor. It is known that some Windows versions will do this even when they + see 'hypervisor' CPU flag. + +``hv-vapic`` + Provides so-called VP Assist page MSR to guest allowing it to work with APIC + more efficiently. In particular, this enlightenment allows paravirtualized + (exit-less) EOI processing. + +``hv-spinlocks`` = xxx + Enables paravirtualized spinlocks. The parameter indicates how many times + spinlock acquisition should be attempted before indicating the situation to the + hypervisor. A special value 0xffffffff indicates "never notify". + +``hv-vpindex`` + Provides HV_X64_MSR_VP_INDEX (0x40000002) MSR to the guest which has Virtual + processor index information. This enlightenment makes sense in conjunction with + hv-synic, hv-stimer and other enlightenments which require the guest to know its + Virtual Processor indices (e.g. when VP index needs to be passed in a + hypercall). + +``hv-runtime`` + Provides HV_X64_MSR_VP_RUNTIME (0x40000010) MSR to the guest. The MSR keeps the + virtual processor run time in 100ns units. This gives guest operating system an + idea of how much time was 'stolen' from it (when the virtual CPU was preempted + to perform some other work). + +``hv-crash`` + Provides HV_X64_MSR_CRASH_P0..HV_X64_MSR_CRASH_P5 (0x40000100..0x40000105) and + HV_X64_MSR_CRASH_CTL (0x40000105) MSRs to the guest. These MSRs are written to + by the guest when it crashes, HV_X64_MSR_CRASH_P0..HV_X64_MSR_CRASH_P5 MSRs + contain additional crash information. This information is outputted in QEMU log + and through QAPI. + Note: unlike under genuine Hyper-V, write to HV_X64_MSR_CRASH_CTL causes guest + to shutdown. This effectively blocks crash dump generation by Windows. + +``hv-time`` + Enables two Hyper-V-specific clocksources available to the guest: MSR-based + Hyper-V clocksource (HV_X64_MSR_TIME_REF_COUNT, 0x40000020) and Reference TSC + page (enabled via MSR HV_X64_MSR_REFERENCE_TSC, 0x40000021). Both clocksources + are per-guest, Reference TSC page clocksource allows for exit-less time stamp + readings. Using this enlightenment leads to significant speedup of all timestamp + related operations. + +``hv-synic`` + Enables Hyper-V Synthetic interrupt controller - an extension of a local APIC. + When enabled, this enlightenment provides additional communication facilities + to the guest: SynIC messages and Events. This is a pre-requisite for + implementing VMBus devices (not yet in QEMU). Additionally, this enlightenment + is needed to enable Hyper-V synthetic timers. SynIC is controlled through MSRs + HV_X64_MSR_SCONTROL..HV_X64_MSR_EOM (0x40000080..0x40000084) and + HV_X64_MSR_SINT0..HV_X64_MSR_SINT15 (0x40000090..0x4000009F) + + Requires: ``hv-vpindex`` + +``hv-stimer`` + Enables Hyper-V synthetic timers. There are four synthetic timers per virtual + CPU controlled through HV_X64_MSR_STIMER0_CONFIG..HV_X64_MSR_STIMER3_COUNT + (0x400000B0..0x400000B7) MSRs. These timers can work either in single-shot or + periodic mode. It is known that certain Windows versions revert to using HPET + (or even RTC when HPET is unavailable) extensively when this enlightenment is + not provided; this can lead to significant CPU consumption, even when virtual + CPU is idle. + + Requires: ``hv-vpindex``, ``hv-synic``, ``hv-time`` + +``hv-tlbflush`` + Enables paravirtualized TLB shoot-down mechanism. On x86 architecture, remote + TLB flush procedure requires sending IPIs and waiting for other CPUs to perform + local TLB flush. In virtualized environment some virtual CPUs may not even be + scheduled at the time of the call and may not require flushing (or, flushing + may be postponed until the virtual CPU is scheduled). hv-tlbflush enlightenment + implements TLB shoot-down through hypervisor enabling the optimization. + + Requires: ``hv-vpindex`` + +``hv-ipi`` + Enables paravirtualized IPI send mechanism. HvCallSendSyntheticClusterIpi + hypercall may target more than 64 virtual CPUs simultaneously, doing the same + through APIC requires more than one access (and thus exit to the hypervisor). + + Requires: ``hv-vpindex`` + +``hv-vendor-id`` = xxx + This changes Hyper-V identification in CPUID 0x40000000.EBX-EDX from the default + "Microsoft Hv". The parameter should be no longer than 12 characters. According + to the specification, guests shouldn't use this information and it is unknown + if there is a Windows version which acts differently. + Note: hv-vendor-id is not an enlightenment and thus doesn't enable Hyper-V + identification when specified without some other enlightenment. + +``hv-reset`` + Provides HV_X64_MSR_RESET (0x40000003) MSR to the guest allowing it to reset + itself by writing to it. Even when this MSR is enabled, it is not a recommended + way for Windows to perform system reboot and thus it may not be used. + +``hv-frequencies`` + Provides HV_X64_MSR_TSC_FREQUENCY (0x40000022) and HV_X64_MSR_APIC_FREQUENCY + (0x40000023) allowing the guest to get its TSC/APIC frequencies without doing + measurements. + +``hv-reenlightenment`` + The enlightenment is nested specific, it targets Hyper-V on KVM guests. When + enabled, it provides HV_X64_MSR_REENLIGHTENMENT_CONTROL (0x40000106), + HV_X64_MSR_TSC_EMULATION_CONTROL (0x40000107)and HV_X64_MSR_TSC_EMULATION_STATUS + (0x40000108) MSRs allowing the guest to get notified when TSC frequency changes + (only happens on migration) and keep using old frequency (through emulation in + the hypervisor) until it is ready to switch to the new one. This, in conjunction + with ``hv-frequencies``, allows Hyper-V on KVM to pass stable clocksource + (Reference TSC page) to its own guests. + + Note, KVM doesn't fully support re-enlightenment notifications and doesn't + emulate TSC accesses after migration so 'tsc-frequency=' CPU option also has to + be specified to make migration succeed. The destination host has to either have + the same TSC frequency or support TSC scaling CPU feature. + + Recommended: ``hv-frequencies`` + +``hv-evmcs`` + The enlightenment is nested specific, it targets Hyper-V on KVM guests. When + enabled, it provides Enlightened VMCS version 1 feature to the guest. The feature + implements paravirtualized protocol between L0 (KVM) and L1 (Hyper-V) + hypervisors making L2 exits to the hypervisor faster. The feature is Intel-only. + + Note: some virtualization features (e.g. Posted Interrupts) are disabled when + hv-evmcs is enabled. It may make sense to measure your nested workload with and + without the feature to find out if enabling it is beneficial. + + Requires: ``hv-vapic`` + +``hv-stimer-direct`` + Hyper-V specification allows synthetic timer operation in two modes: "classic", + when expiration event is delivered as SynIC message and "direct", when the event + is delivered via normal interrupt. It is known that nested Hyper-V can only + use synthetic timers in direct mode and thus ``hv-stimer-direct`` needs to be + enabled. + + Requires: ``hv-vpindex``, ``hv-synic``, ``hv-time``, ``hv-stimer`` + +``hv-avic`` (``hv-apicv``) + The enlightenment allows to use Hyper-V SynIC with hardware APICv/AVIC enabled. + Normally, Hyper-V SynIC disables these hardware feature and suggests the guest + to use paravirtualized AutoEOI feature. + Note: enabling this feature on old hardware (without APICv/AVIC support) may + have negative effect on guest's performance. + +``hv-no-nonarch-coresharing`` = on/off/auto + This enlightenment tells guest OS that virtual processors will never share a + physical core unless they are reported as sibling SMT threads. This information + is required by Windows and Hyper-V guests to properly mitigate SMT related CPU + vulnerabilities. + + When the option is set to 'auto' QEMU will enable the feature only when KVM + reports that non-architectural coresharing is impossible, this means that + hyper-threading is not supported or completely disabled on the host. This + setting also prevents migration as SMT settings on the destination may differ. + When the option is set to 'on' QEMU will always enable the feature, regardless + of host setup. To keep guests secure, this can only be used in conjunction with + exposing correct vCPU topology and vCPU pinning. + +``hv-version-id-build``, ``hv-version-id-major``, ``hv-version-id-minor``, ``hv-version-id-spack``, ``hv-version-id-sbranch``, ``hv-version-id-snumber`` + This changes Hyper-V version identification in CPUID 0x40000002.EAX-EDX from the + default (WS2016). + + - ``hv-version-id-build`` sets 'Build Number' (32 bits) + - ``hv-version-id-major`` sets 'Major Version' (16 bits) + - ``hv-version-id-minor`` sets 'Minor Version' (16 bits) + - ``hv-version-id-spack`` sets 'Service Pack' (32 bits) + - ``hv-version-id-sbranch`` sets 'Service Branch' (8 bits) + - ``hv-version-id-snumber`` sets 'Service Number' (24 bits) + + Note: hv-version-id-* are not enlightenments and thus don't enable Hyper-V + identification when specified without any other enlightenments. + +``hv-syndbg`` + Enables Hyper-V synthetic debugger interface, this is a special interface used + by Windows Kernel debugger to send the packets through, rather than sending + them via serial/network . + When enabled, this enlightenment provides additional communication facilities + to the guest: SynDbg messages. + This new communication is used by Windows Kernel debugger rather than sending + packets via serial/network, adding significant performance boost over the other + comm channels. + This enlightenment requires a VMBus device (-device vmbus-bridge,irq=15). + + Requires: ``hv-relaxed``, ``hv_time``, ``hv-vapic``, ``hv-vpindex``, ``hv-synic``, ``hv-runtime``, ``hv-stimer`` + +``hv-emsr-bitmap`` + The enlightenment is nested specific, it targets Hyper-V on KVM guests. When + enabled, it allows L0 (KVM) and L1 (Hyper-V) hypervisors to collaborate to + avoid unnecessary updates to L2 MSR-Bitmap upon vmexits. While the protocol is + supported for both VMX (Intel) and SVM (AMD), the VMX implementation requires + Enlightened VMCS (``hv-evmcs``) feature to also be enabled. + + Recommended: ``hv-evmcs`` (Intel) + +``hv-xmm-input`` + Hyper-V specification allows to pass parameters for certain hypercalls using XMM + registers ("XMM Fast Hypercall Input"). When the feature is in use, it allows + for faster hypercalls processing as KVM can avoid reading guest's memory. + +``hv-tlbflush-ext`` + Allow for extended GVA ranges to be passed to Hyper-V TLB flush hypercalls + (HvFlushVirtualAddressList/HvFlushVirtualAddressListEx). + + Requires: ``hv-tlbflush`` + +``hv-tlbflush-direct`` + The enlightenment is nested specific, it targets Hyper-V on KVM guests. When + enabled, it allows L0 (KVM) to directly handle TLB flush hypercalls from L2 + guest without the need to exit to L1 (Hyper-V) hypervisor. While the feature is + supported for both VMX (Intel) and SVM (AMD), the VMX implementation requires + Enlightened VMCS (``hv-evmcs``) feature to also be enabled. + + Requires: ``hv-vapic`` + + Recommended: ``hv-evmcs`` (Intel) + +Supplementary features +---------------------- + +``hv-passthrough`` + In some cases (e.g. during development) it may make sense to use QEMU in + 'pass-through' mode and give Windows guests all enlightenments currently + supported by KVM. This pass-through mode is enabled by "hv-passthrough" CPU + flag. + + Note: ``hv-passthrough`` flag only enables enlightenments which are known to QEMU + (have corresponding 'hv-' flag) and copies ``hv-spinlocks`` and ``hv-vendor-id`` + values from KVM to QEMU. ``hv-passthrough`` overrides all other 'hv-' settings on + the command line. Also, enabling this flag effectively prevents migration as the + list of enabled enlightenments may differ between target and destination hosts. + +``hv-enforce-cpuid`` + By default, KVM allows the guest to use all currently supported Hyper-V + enlightenments when Hyper-V CPUID interface was exposed, regardless of if + some features were not announced in guest visible CPUIDs. ``hv-enforce-cpuid`` + feature alters this behavior and only allows the guest to use exposed Hyper-V + enlightenments. + + +Useful links +------------ +Hyper-V Top Level Functional specification and other information: + +- https://github.com/MicrosoftDocs/Virtualization-Documentation +- https://docs.microsoft.com/en-us/virtualization/hyper-v-on-windows/tlfs/tlfs + diff --git a/docs/system/target-i386.rst b/docs/system/target-i386.rst index 96bf54889a..e64c013077 100644 --- a/docs/system/target-i386.rst +++ b/docs/system/target-i386.rst @@ -26,6 +26,7 @@ Architectural features :maxdepth: 1 i386/cpu + i386/hyperv i386/kvm-pv i386/sgx i386/amd-memory-encryption