From patchwork Mon Jun 15 19:27:18 2009 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Glauber Costa X-Patchwork-Id: 30426 Received: from vger.kernel.org (vger.kernel.org [209.132.176.167]) by demeter.kernel.org (8.14.2/8.14.2) with ESMTP id n5FJRV3O027879 for ; Mon, 15 Jun 2009 19:27:31 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752348AbZFOT10 (ORCPT ); Mon, 15 Jun 2009 15:27:26 -0400 Received: (majordomo@vger.kernel.org) by vger.kernel.org id S1752391AbZFOT10 (ORCPT ); Mon, 15 Jun 2009 15:27:26 -0400 Received: from mx2.redhat.com ([66.187.237.31]:55721 "EHLO mx2.redhat.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752295AbZFOT1Y (ORCPT ); Mon, 15 Jun 2009 15:27:24 -0400 Received: from int-mx2.corp.redhat.com (int-mx2.corp.redhat.com [172.16.27.26]) by mx2.redhat.com (8.13.8/8.13.8) with ESMTP id n5FJRPS7003197 for ; Mon, 15 Jun 2009 15:27:25 -0400 Received: from ns3.rdu.redhat.com (ns3.rdu.redhat.com [10.11.255.199]) by int-mx2.corp.redhat.com (8.13.1/8.13.1) with ESMTP id n5FJROWr019559; Mon, 15 Jun 2009 15:27:24 -0400 Received: from localhost.localdomain (virtlab1.virt.bos.redhat.com [10.16.72.21]) by ns3.rdu.redhat.com (8.13.8/8.13.8) with ESMTP id n5FJRNaX032535; Mon, 15 Jun 2009 15:27:23 -0400 From: Glauber Costa To: kvm@vger.kernel.org Cc: avi@redhat.com Subject: [PATCH] get rid of target-i386/libkvm.c Date: Mon, 15 Jun 2009 15:27:18 -0400 Message-Id: <1245094038-4542-1-git-send-email-glommer@redhat.com> X-Scanned-By: MIMEDefang 2.58 on 172.16.27.26 Sender: kvm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org Same spirit of what has already been done for the generic code. Fold libkvm.c into qemu-kvm-x86.c. handle_tpr_access becomes kvm_handle_tpr_access, to avoid name clash. Signed-off-by: Glauber Costa --- Makefile.target | 2 +- qemu-kvm-x86.c | 652 ++++++++++++++++++++++++++++++++++++++++++++++++ target-i386/libkvm.c | 666 -------------------------------------------------- 3 files changed, 653 insertions(+), 667 deletions(-) delete mode 100644 target-i386/libkvm.c diff --git a/Makefile.target b/Makefile.target index ca8d54d..4dfd5b3 100644 --- a/Makefile.target +++ b/Makefile.target @@ -162,7 +162,7 @@ CPPFLAGS+=-I$(SRC_PATH)/tcg/sparc endif ifeq ($(USE_KVM), 1) -LIBOBJS+=qemu-kvm.o libkvm.o +LIBOBJS+=qemu-kvm.o endif ifdef CONFIG_SOFTFLOAT LIBOBJS+=fpu/softfloat.o diff --git a/qemu-kvm-x86.c b/qemu-kvm-x86.c index 729d600..43bbdfa 100644 --- a/qemu-kvm-x86.c +++ b/qemu-kvm-x86.c @@ -16,9 +16,11 @@ #include "qemu-kvm.h" #include "libkvm-all.h" +#include "libkvm.h" #include #include #include +#include #include "kvm.h" @@ -31,6 +33,656 @@ static int kvm_has_vm_hsave_pa; static int lm_capable_kernel; +int kvm_set_tss_addr(kvm_context_t kvm, unsigned long addr) +{ +#ifdef KVM_CAP_SET_TSS_ADDR + int r; + + r = ioctl(kvm->fd, KVM_CHECK_EXTENSION, KVM_CAP_SET_TSS_ADDR); + if (r > 0) { + r = ioctl(kvm->vm_fd, KVM_SET_TSS_ADDR, addr); + if (r == -1) { + fprintf(stderr, "kvm_set_tss_addr: %m\n"); + return -errno; + } + return 0; + } +#endif + return -ENOSYS; +} + +static int kvm_init_tss(kvm_context_t kvm) +{ +#ifdef KVM_CAP_SET_TSS_ADDR + int r; + + r = ioctl(kvm->fd, KVM_CHECK_EXTENSION, KVM_CAP_SET_TSS_ADDR); + if (r > 0) { + /* + * this address is 3 pages before the bios, and the bios should present + * as unavaible memory + */ + r = kvm_set_tss_addr(kvm, 0xfffbd000); + if (r < 0) { + fprintf(stderr, "kvm_init_tss: unable to set tss addr\n"); + return r; + } + + } +#endif + return 0; +} + +static int kvm_create_pit(kvm_context_t kvm) +{ +#ifdef KVM_CAP_PIT + int r; + + kvm->pit_in_kernel = 0; + if (!kvm->no_pit_creation) { + r = ioctl(kvm->fd, KVM_CHECK_EXTENSION, KVM_CAP_PIT); + if (r > 0) { + r = ioctl(kvm->vm_fd, KVM_CREATE_PIT); + if (r >= 0) + kvm->pit_in_kernel = 1; + else { + fprintf(stderr, "Create kernel PIC irqchip failed\n"); + return r; + } + } + } +#endif + return 0; +} + +int kvm_arch_create(kvm_context_t kvm, unsigned long phys_mem_bytes, + void **vm_mem) +{ + int r = 0; + + r = kvm_init_tss(kvm); + if (r < 0) + return r; + + r = kvm_create_pit(kvm); + if (r < 0) + return r; + + r = kvm_init_coalesced_mmio(kvm); + if (r < 0) + return r; + + return 0; +} + +#ifdef KVM_EXIT_TPR_ACCESS + +static int kvm_handle_tpr_access(kvm_vcpu_context_t vcpu) +{ + struct kvm_run *run = vcpu->run; + return vcpu->kvm->callbacks->tpr_access(vcpu->kvm->opaque, vcpu, + run->tpr_access.rip, + run->tpr_access.is_write); +} + + +int kvm_enable_vapic(kvm_vcpu_context_t vcpu, uint64_t vapic) +{ + int r; + struct kvm_vapic_addr va = { + .vapic_addr = vapic, + }; + + r = ioctl(vcpu->fd, KVM_SET_VAPIC_ADDR, &va); + if (r == -1) { + r = -errno; + perror("kvm_enable_vapic"); + return r; + } + return 0; +} + +#endif + +int kvm_arch_run(kvm_vcpu_context_t vcpu) +{ + int r = 0; + struct kvm_run *run = vcpu->run; + + + switch (run->exit_reason) { +#ifdef KVM_EXIT_SET_TPR + case KVM_EXIT_SET_TPR: + break; +#endif +#ifdef KVM_EXIT_TPR_ACCESS + case KVM_EXIT_TPR_ACCESS: + r = kvm_handle_tpr_access(vcpu); + break; +#endif + default: + r = 1; + break; + } + + return r; +} + +#define MAX_ALIAS_SLOTS 4 +static struct { + uint64_t start; + uint64_t len; +} kvm_aliases[MAX_ALIAS_SLOTS]; + +static int get_alias_slot(uint64_t start) +{ + int i; + + for (i=0; ivm_fd; + int r; + int slot; + + slot = get_alias_slot(phys_start); + if (slot < 0) + slot = get_free_alias_slot(); + if (slot < 0) + return -EBUSY; + alias.slot = slot; + + r = ioctl(fd, KVM_SET_MEMORY_ALIAS, &alias); + if (r == -1) + return -errno; + + register_alias(slot, phys_start, len); + return 0; +} + +int kvm_destroy_memory_alias(kvm_context_t kvm, uint64_t phys_start) +{ + return kvm_create_memory_alias(kvm, phys_start, 0, 0); +} + +#ifdef KVM_CAP_IRQCHIP + +int kvm_get_lapic(kvm_vcpu_context_t vcpu, struct kvm_lapic_state *s) +{ + int r; + if (!kvm_irqchip_in_kernel(vcpu->kvm)) + return 0; + r = ioctl(vcpu->fd, KVM_GET_LAPIC, s); + if (r == -1) { + r = -errno; + perror("kvm_get_lapic"); + } + return r; +} + +int kvm_set_lapic(kvm_vcpu_context_t vcpu, struct kvm_lapic_state *s) +{ + int r; + if (!kvm_irqchip_in_kernel(vcpu->kvm)) + return 0; + r = ioctl(vcpu->fd, KVM_SET_LAPIC, s); + if (r == -1) { + r = -errno; + perror("kvm_set_lapic"); + } + return r; +} + +#endif + +#ifdef KVM_CAP_PIT + +int kvm_get_pit(kvm_context_t kvm, struct kvm_pit_state *s) +{ + int r; + if (!kvm->pit_in_kernel) + return 0; + r = ioctl(kvm->vm_fd, KVM_GET_PIT, s); + if (r == -1) { + r = -errno; + perror("kvm_get_pit"); + } + return r; +} + +int kvm_set_pit(kvm_context_t kvm, struct kvm_pit_state *s) +{ + int r; + if (!kvm->pit_in_kernel) + return 0; + r = ioctl(kvm->vm_fd, KVM_SET_PIT, s); + if (r == -1) { + r = -errno; + perror("kvm_set_pit"); + } + return r; +} + +#endif + +void kvm_show_code(kvm_vcpu_context_t vcpu) +{ +#define SHOW_CODE_LEN 50 + int fd = vcpu->fd; + struct kvm_regs regs; + struct kvm_sregs sregs; + int r, n; + int back_offset; + unsigned char code; + char code_str[SHOW_CODE_LEN * 3 + 1]; + unsigned long rip; + kvm_context_t kvm = vcpu->kvm; + + r = ioctl(fd, KVM_GET_SREGS, &sregs); + if (r == -1) { + perror("KVM_GET_SREGS"); + return; + } + r = ioctl(fd, KVM_GET_REGS, ®s); + if (r == -1) { + perror("KVM_GET_REGS"); + return; + } + rip = sregs.cs.base + regs.rip; + back_offset = regs.rip; + if (back_offset > 20) + back_offset = 20; + *code_str = 0; + for (n = -back_offset; n < SHOW_CODE_LEN-back_offset; ++n) { + if (n == 0) + strcat(code_str, " -->"); + r = kvm->callbacks->mmio_read(kvm->opaque, rip + n, &code, 1); + if (r < 0) { + strcat(code_str, " xx"); + continue; + } + sprintf(code_str + strlen(code_str), " %02x", code); + } + fprintf(stderr, "code:%s\n", code_str); +} + + +/* + * Returns available msr list. User must free. + */ +struct kvm_msr_list *kvm_get_msr_list(kvm_context_t kvm) +{ + struct kvm_msr_list sizer, *msrs; + int r, e; + + sizer.nmsrs = 0; + r = ioctl(kvm->fd, KVM_GET_MSR_INDEX_LIST, &sizer); + if (r == -1 && errno != E2BIG) + return NULL; + msrs = malloc(sizeof *msrs + sizer.nmsrs * sizeof *msrs->indices); + if (!msrs) { + errno = ENOMEM; + return NULL; + } + msrs->nmsrs = sizer.nmsrs; + r = ioctl(kvm->fd, KVM_GET_MSR_INDEX_LIST, msrs); + if (r == -1) { + e = errno; + free(msrs); + errno = e; + return NULL; + } + return msrs; +} + +int kvm_get_msrs(kvm_vcpu_context_t vcpu, struct kvm_msr_entry *msrs, int n) +{ + struct kvm_msrs *kmsrs = malloc(sizeof *kmsrs + n * sizeof *msrs); + int r, e; + + if (!kmsrs) { + errno = ENOMEM; + return -1; + } + kmsrs->nmsrs = n; + memcpy(kmsrs->entries, msrs, n * sizeof *msrs); + r = ioctl(vcpu->fd, KVM_GET_MSRS, kmsrs); + e = errno; + memcpy(msrs, kmsrs->entries, n * sizeof *msrs); + free(kmsrs); + errno = e; + return r; +} + +int kvm_set_msrs(kvm_vcpu_context_t vcpu, struct kvm_msr_entry *msrs, int n) +{ + struct kvm_msrs *kmsrs = malloc(sizeof *kmsrs + n * sizeof *msrs); + int r, e; + + if (!kmsrs) { + errno = ENOMEM; + return -1; + } + kmsrs->nmsrs = n; + memcpy(kmsrs->entries, msrs, n * sizeof *msrs); + r = ioctl(vcpu->fd, KVM_SET_MSRS, kmsrs); + e = errno; + free(kmsrs); + errno = e; + return r; +} + +static void print_seg(FILE *file, const char *name, struct kvm_segment *seg) +{ + fprintf(stderr, + "%s %04x (%08llx/%08x p %d dpl %d db %d s %d type %x l %d" + " g %d avl %d)\n", + name, seg->selector, seg->base, seg->limit, seg->present, + seg->dpl, seg->db, seg->s, seg->type, seg->l, seg->g, + seg->avl); +} + +static void print_dt(FILE *file, const char *name, struct kvm_dtable *dt) +{ + fprintf(stderr, "%s %llx/%x\n", name, dt->base, dt->limit); +} + +void kvm_show_regs(kvm_vcpu_context_t vcpu) +{ + int fd = vcpu->fd; + struct kvm_regs regs; + struct kvm_sregs sregs; + int r; + + r = ioctl(fd, KVM_GET_REGS, ®s); + if (r == -1) { + perror("KVM_GET_REGS"); + return; + } + fprintf(stderr, + "rax %016llx rbx %016llx rcx %016llx rdx %016llx\n" + "rsi %016llx rdi %016llx rsp %016llx rbp %016llx\n" + "r8 %016llx r9 %016llx r10 %016llx r11 %016llx\n" + "r12 %016llx r13 %016llx r14 %016llx r15 %016llx\n" + "rip %016llx rflags %08llx\n", + regs.rax, regs.rbx, regs.rcx, regs.rdx, + regs.rsi, regs.rdi, regs.rsp, regs.rbp, + regs.r8, regs.r9, regs.r10, regs.r11, + regs.r12, regs.r13, regs.r14, regs.r15, + regs.rip, regs.rflags); + r = ioctl(fd, KVM_GET_SREGS, &sregs); + if (r == -1) { + perror("KVM_GET_SREGS"); + return; + } + print_seg(stderr, "cs", &sregs.cs); + print_seg(stderr, "ds", &sregs.ds); + print_seg(stderr, "es", &sregs.es); + print_seg(stderr, "ss", &sregs.ss); + print_seg(stderr, "fs", &sregs.fs); + print_seg(stderr, "gs", &sregs.gs); + print_seg(stderr, "tr", &sregs.tr); + print_seg(stderr, "ldt", &sregs.ldt); + print_dt(stderr, "gdt", &sregs.gdt); + print_dt(stderr, "idt", &sregs.idt); + fprintf(stderr, "cr0 %llx cr2 %llx cr3 %llx cr4 %llx cr8 %llx" + " efer %llx\n", + sregs.cr0, sregs.cr2, sregs.cr3, sregs.cr4, sregs.cr8, + sregs.efer); +} + +uint64_t kvm_get_apic_base(kvm_vcpu_context_t vcpu) +{ + return vcpu->run->apic_base; +} + +void kvm_set_cr8(kvm_vcpu_context_t vcpu, uint64_t cr8) +{ + vcpu->run->cr8 = cr8; +} + +__u64 kvm_get_cr8(kvm_vcpu_context_t vcpu) +{ + return vcpu->run->cr8; +} + +int kvm_setup_cpuid(kvm_vcpu_context_t vcpu, int nent, + struct kvm_cpuid_entry *entries) +{ + struct kvm_cpuid *cpuid; + int r; + + cpuid = malloc(sizeof(*cpuid) + nent * sizeof(*entries)); + if (!cpuid) + return -ENOMEM; + + cpuid->nent = nent; + memcpy(cpuid->entries, entries, nent * sizeof(*entries)); + r = ioctl(vcpu->fd, KVM_SET_CPUID, cpuid); + + free(cpuid); + return r; +} + +int kvm_setup_cpuid2(kvm_vcpu_context_t vcpu, int nent, + struct kvm_cpuid_entry2 *entries) +{ + struct kvm_cpuid2 *cpuid; + int r; + + cpuid = malloc(sizeof(*cpuid) + nent * sizeof(*entries)); + if (!cpuid) + return -ENOMEM; + + cpuid->nent = nent; + memcpy(cpuid->entries, entries, nent * sizeof(*entries)); + r = ioctl(vcpu->fd, KVM_SET_CPUID2, cpuid); + if (r == -1) { + fprintf(stderr, "kvm_setup_cpuid2: %m\n"); + return -errno; + } + free(cpuid); + return r; +} + +int kvm_set_shadow_pages(kvm_context_t kvm, unsigned int nrshadow_pages) +{ +#ifdef KVM_CAP_MMU_SHADOW_CACHE_CONTROL + int r; + + r = ioctl(kvm->fd, KVM_CHECK_EXTENSION, + KVM_CAP_MMU_SHADOW_CACHE_CONTROL); + if (r > 0) { + r = ioctl(kvm->vm_fd, KVM_SET_NR_MMU_PAGES, nrshadow_pages); + if (r == -1) { + fprintf(stderr, "kvm_set_shadow_pages: %m\n"); + return -errno; + } + return 0; + } +#endif + return -1; +} + +int kvm_get_shadow_pages(kvm_context_t kvm, unsigned int *nrshadow_pages) +{ +#ifdef KVM_CAP_MMU_SHADOW_CACHE_CONTROL + int r; + + r = ioctl(kvm->fd, KVM_CHECK_EXTENSION, + KVM_CAP_MMU_SHADOW_CACHE_CONTROL); + if (r > 0) { + *nrshadow_pages = ioctl(kvm->vm_fd, KVM_GET_NR_MMU_PAGES); + return 0; + } +#endif + return -1; +} + +#ifdef KVM_CAP_VAPIC + +static int tpr_access_reporting(kvm_vcpu_context_t vcpu, int enabled) +{ + int r; + struct kvm_tpr_access_ctl tac = { + .enabled = enabled, + }; + + r = ioctl(vcpu->kvm->fd, KVM_CHECK_EXTENSION, KVM_CAP_VAPIC); + if (r == -1 || r == 0) + return -ENOSYS; + r = ioctl(vcpu->fd, KVM_TPR_ACCESS_REPORTING, &tac); + if (r == -1) { + r = -errno; + perror("KVM_TPR_ACCESS_REPORTING"); + return r; + } + return 0; +} + +int kvm_enable_tpr_access_reporting(kvm_vcpu_context_t vcpu) +{ + return tpr_access_reporting(vcpu, 1); +} + +int kvm_disable_tpr_access_reporting(kvm_vcpu_context_t vcpu) +{ + return tpr_access_reporting(vcpu, 0); +} + +#endif + +#ifdef KVM_CAP_EXT_CPUID + +static struct kvm_cpuid2 *try_get_cpuid(kvm_context_t kvm, int max) +{ + struct kvm_cpuid2 *cpuid; + int r, size; + + size = sizeof(*cpuid) + max * sizeof(*cpuid->entries); + cpuid = (struct kvm_cpuid2 *)malloc(size); + cpuid->nent = max; + r = ioctl(kvm->fd, KVM_GET_SUPPORTED_CPUID, cpuid); + if (r == -1) + r = -errno; + else if (r == 0 && cpuid->nent >= max) + r = -E2BIG; + if (r < 0) { + if (r == -E2BIG) { + free(cpuid); + return NULL; + } else { + fprintf(stderr, "KVM_GET_SUPPORTED_CPUID failed: %s\n", + strerror(-r)); + exit(1); + } + } + return cpuid; +} + +#define R_EAX 0 +#define R_ECX 1 +#define R_EDX 2 +#define R_EBX 3 +#define R_ESP 4 +#define R_EBP 5 +#define R_ESI 6 +#define R_EDI 7 + +uint32_t kvm_get_supported_cpuid(kvm_context_t kvm, uint32_t function, int reg) +{ + struct kvm_cpuid2 *cpuid; + int i, max; + uint32_t ret = 0; + uint32_t cpuid_1_edx; + + if (!kvm_check_extension(kvm, KVM_CAP_EXT_CPUID)) { + return -1U; + } + + max = 1; + while ((cpuid = try_get_cpuid(kvm, max)) == NULL) { + max *= 2; + } + + for (i = 0; i < cpuid->nent; ++i) { + if (cpuid->entries[i].function == function) { + switch (reg) { + case R_EAX: + ret = cpuid->entries[i].eax; + break; + case R_EBX: + ret = cpuid->entries[i].ebx; + break; + case R_ECX: + ret = cpuid->entries[i].ecx; + break; + case R_EDX: + ret = cpuid->entries[i].edx; + if (function == 1) { + /* kvm misreports the following features + */ + ret |= 1 << 12; /* MTRR */ + ret |= 1 << 16; /* PAT */ + ret |= 1 << 7; /* MCE */ + ret |= 1 << 14; /* MCA */ + } + + /* On Intel, kvm returns cpuid according to + * the Intel spec, so add missing bits + * according to the AMD spec: + */ + if (function == 0x80000001) { + cpuid_1_edx = kvm_get_supported_cpuid(kvm, 1, R_EDX); + ret |= cpuid_1_edx & 0xdfeff7ff; + } + break; + } + } + } + + free(cpuid); + + return ret; +} + +#else + +uint32_t kvm_get_supported_cpuid(kvm_context_t kvm, uint32_t function, int reg) +{ + return -1U; +} + +#endif int kvm_qemu_create_memory_alias(uint64_t phys_start, uint64_t len, uint64_t target_phys) diff --git a/target-i386/libkvm.c b/target-i386/libkvm.c deleted file mode 100644 index 0f4e009..0000000 --- a/target-i386/libkvm.c +++ /dev/null @@ -1,666 +0,0 @@ -#include "sysemu.h" - -#include "libkvm-all.h" -#include "libkvm.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -int kvm_set_tss_addr(kvm_context_t kvm, unsigned long addr) -{ -#ifdef KVM_CAP_SET_TSS_ADDR - int r; - - r = ioctl(kvm->fd, KVM_CHECK_EXTENSION, KVM_CAP_SET_TSS_ADDR); - if (r > 0) { - r = ioctl(kvm->vm_fd, KVM_SET_TSS_ADDR, addr); - if (r == -1) { - fprintf(stderr, "kvm_set_tss_addr: %m\n"); - return -errno; - } - return 0; - } -#endif - return -ENOSYS; -} - -static int kvm_init_tss(kvm_context_t kvm) -{ -#ifdef KVM_CAP_SET_TSS_ADDR - int r; - - r = ioctl(kvm->fd, KVM_CHECK_EXTENSION, KVM_CAP_SET_TSS_ADDR); - if (r > 0) { - /* - * this address is 3 pages before the bios, and the bios should present - * as unavaible memory - */ - r = kvm_set_tss_addr(kvm, 0xfffbd000); - if (r < 0) { - fprintf(stderr, "kvm_init_tss: unable to set tss addr\n"); - return r; - } - - } -#endif - return 0; -} - -static int kvm_create_pit(kvm_context_t kvm) -{ -#ifdef KVM_CAP_PIT - int r; - - kvm->pit_in_kernel = 0; - if (!kvm->no_pit_creation) { - r = ioctl(kvm->fd, KVM_CHECK_EXTENSION, KVM_CAP_PIT); - if (r > 0) { - r = ioctl(kvm->vm_fd, KVM_CREATE_PIT); - if (r >= 0) - kvm->pit_in_kernel = 1; - else { - fprintf(stderr, "Create kernel PIC irqchip failed\n"); - return r; - } - } - } -#endif - return 0; -} - -int kvm_arch_create(kvm_context_t kvm, unsigned long phys_mem_bytes, - void **vm_mem) -{ - int r = 0; - - r = kvm_init_tss(kvm); - if (r < 0) - return r; - - r = kvm_create_pit(kvm); - if (r < 0) - return r; - - r = kvm_init_coalesced_mmio(kvm); - if (r < 0) - return r; - - return 0; -} - -#ifdef KVM_EXIT_TPR_ACCESS - -static int handle_tpr_access(kvm_vcpu_context_t vcpu) -{ - struct kvm_run *run = vcpu->run; - return vcpu->kvm->callbacks->tpr_access(vcpu->kvm->opaque, vcpu, - run->tpr_access.rip, - run->tpr_access.is_write); -} - - -int kvm_enable_vapic(kvm_vcpu_context_t vcpu, uint64_t vapic) -{ - int r; - struct kvm_vapic_addr va = { - .vapic_addr = vapic, - }; - - r = ioctl(vcpu->fd, KVM_SET_VAPIC_ADDR, &va); - if (r == -1) { - r = -errno; - perror("kvm_enable_vapic"); - return r; - } - return 0; -} - -#endif - -int kvm_arch_run(kvm_vcpu_context_t vcpu) -{ - int r = 0; - struct kvm_run *run = vcpu->run; - - - switch (run->exit_reason) { -#ifdef KVM_EXIT_SET_TPR - case KVM_EXIT_SET_TPR: - break; -#endif -#ifdef KVM_EXIT_TPR_ACCESS - case KVM_EXIT_TPR_ACCESS: - r = handle_tpr_access(vcpu); - break; -#endif - default: - r = 1; - break; - } - - return r; -} - -#define MAX_ALIAS_SLOTS 4 -static struct { - uint64_t start; - uint64_t len; -} kvm_aliases[MAX_ALIAS_SLOTS]; - -static int get_alias_slot(uint64_t start) -{ - int i; - - for (i=0; ivm_fd; - int r; - int slot; - - slot = get_alias_slot(phys_start); - if (slot < 0) - slot = get_free_alias_slot(); - if (slot < 0) - return -EBUSY; - alias.slot = slot; - - r = ioctl(fd, KVM_SET_MEMORY_ALIAS, &alias); - if (r == -1) - return -errno; - - register_alias(slot, phys_start, len); - return 0; -} - -int kvm_destroy_memory_alias(kvm_context_t kvm, uint64_t phys_start) -{ - return kvm_create_memory_alias(kvm, phys_start, 0, 0); -} - -#ifdef KVM_CAP_IRQCHIP - -int kvm_get_lapic(kvm_vcpu_context_t vcpu, struct kvm_lapic_state *s) -{ - int r; - if (!kvm_irqchip_in_kernel(vcpu->kvm)) - return 0; - r = ioctl(vcpu->fd, KVM_GET_LAPIC, s); - if (r == -1) { - r = -errno; - perror("kvm_get_lapic"); - } - return r; -} - -int kvm_set_lapic(kvm_vcpu_context_t vcpu, struct kvm_lapic_state *s) -{ - int r; - if (!kvm_irqchip_in_kernel(vcpu->kvm)) - return 0; - r = ioctl(vcpu->fd, KVM_SET_LAPIC, s); - if (r == -1) { - r = -errno; - perror("kvm_set_lapic"); - } - return r; -} - -#endif - -#ifdef KVM_CAP_PIT - -int kvm_get_pit(kvm_context_t kvm, struct kvm_pit_state *s) -{ - int r; - if (!kvm->pit_in_kernel) - return 0; - r = ioctl(kvm->vm_fd, KVM_GET_PIT, s); - if (r == -1) { - r = -errno; - perror("kvm_get_pit"); - } - return r; -} - -int kvm_set_pit(kvm_context_t kvm, struct kvm_pit_state *s) -{ - int r; - if (!kvm->pit_in_kernel) - return 0; - r = ioctl(kvm->vm_fd, KVM_SET_PIT, s); - if (r == -1) { - r = -errno; - perror("kvm_set_pit"); - } - return r; -} - -#endif - -void kvm_show_code(kvm_vcpu_context_t vcpu) -{ -#define SHOW_CODE_LEN 50 - int fd = vcpu->fd; - struct kvm_regs regs; - struct kvm_sregs sregs; - int r, n; - int back_offset; - unsigned char code; - char code_str[SHOW_CODE_LEN * 3 + 1]; - unsigned long rip; - kvm_context_t kvm = vcpu->kvm; - - r = ioctl(fd, KVM_GET_SREGS, &sregs); - if (r == -1) { - perror("KVM_GET_SREGS"); - return; - } - r = ioctl(fd, KVM_GET_REGS, ®s); - if (r == -1) { - perror("KVM_GET_REGS"); - return; - } - rip = sregs.cs.base + regs.rip; - back_offset = regs.rip; - if (back_offset > 20) - back_offset = 20; - *code_str = 0; - for (n = -back_offset; n < SHOW_CODE_LEN-back_offset; ++n) { - if (n == 0) - strcat(code_str, " -->"); - r = kvm->callbacks->mmio_read(kvm->opaque, rip + n, &code, 1); - if (r < 0) { - strcat(code_str, " xx"); - continue; - } - sprintf(code_str + strlen(code_str), " %02x", code); - } - fprintf(stderr, "code:%s\n", code_str); -} - - -/* - * Returns available msr list. User must free. - */ -struct kvm_msr_list *kvm_get_msr_list(kvm_context_t kvm) -{ - struct kvm_msr_list sizer, *msrs; - int r, e; - - sizer.nmsrs = 0; - r = ioctl(kvm->fd, KVM_GET_MSR_INDEX_LIST, &sizer); - if (r == -1 && errno != E2BIG) - return NULL; - msrs = malloc(sizeof *msrs + sizer.nmsrs * sizeof *msrs->indices); - if (!msrs) { - errno = ENOMEM; - return NULL; - } - msrs->nmsrs = sizer.nmsrs; - r = ioctl(kvm->fd, KVM_GET_MSR_INDEX_LIST, msrs); - if (r == -1) { - e = errno; - free(msrs); - errno = e; - return NULL; - } - return msrs; -} - -int kvm_get_msrs(kvm_vcpu_context_t vcpu, struct kvm_msr_entry *msrs, int n) -{ - struct kvm_msrs *kmsrs = malloc(sizeof *kmsrs + n * sizeof *msrs); - int r, e; - - if (!kmsrs) { - errno = ENOMEM; - return -1; - } - kmsrs->nmsrs = n; - memcpy(kmsrs->entries, msrs, n * sizeof *msrs); - r = ioctl(vcpu->fd, KVM_GET_MSRS, kmsrs); - e = errno; - memcpy(msrs, kmsrs->entries, n * sizeof *msrs); - free(kmsrs); - errno = e; - return r; -} - -int kvm_set_msrs(kvm_vcpu_context_t vcpu, struct kvm_msr_entry *msrs, int n) -{ - struct kvm_msrs *kmsrs = malloc(sizeof *kmsrs + n * sizeof *msrs); - int r, e; - - if (!kmsrs) { - errno = ENOMEM; - return -1; - } - kmsrs->nmsrs = n; - memcpy(kmsrs->entries, msrs, n * sizeof *msrs); - r = ioctl(vcpu->fd, KVM_SET_MSRS, kmsrs); - e = errno; - free(kmsrs); - errno = e; - return r; -} - -static void print_seg(FILE *file, const char *name, struct kvm_segment *seg) -{ - fprintf(stderr, - "%s %04x (%08llx/%08x p %d dpl %d db %d s %d type %x l %d" - " g %d avl %d)\n", - name, seg->selector, seg->base, seg->limit, seg->present, - seg->dpl, seg->db, seg->s, seg->type, seg->l, seg->g, - seg->avl); -} - -static void print_dt(FILE *file, const char *name, struct kvm_dtable *dt) -{ - fprintf(stderr, "%s %llx/%x\n", name, dt->base, dt->limit); -} - -void kvm_show_regs(kvm_vcpu_context_t vcpu) -{ - int fd = vcpu->fd; - struct kvm_regs regs; - struct kvm_sregs sregs; - int r; - - r = ioctl(fd, KVM_GET_REGS, ®s); - if (r == -1) { - perror("KVM_GET_REGS"); - return; - } - fprintf(stderr, - "rax %016llx rbx %016llx rcx %016llx rdx %016llx\n" - "rsi %016llx rdi %016llx rsp %016llx rbp %016llx\n" - "r8 %016llx r9 %016llx r10 %016llx r11 %016llx\n" - "r12 %016llx r13 %016llx r14 %016llx r15 %016llx\n" - "rip %016llx rflags %08llx\n", - regs.rax, regs.rbx, regs.rcx, regs.rdx, - regs.rsi, regs.rdi, regs.rsp, regs.rbp, - regs.r8, regs.r9, regs.r10, regs.r11, - regs.r12, regs.r13, regs.r14, regs.r15, - regs.rip, regs.rflags); - r = ioctl(fd, KVM_GET_SREGS, &sregs); - if (r == -1) { - perror("KVM_GET_SREGS"); - return; - } - print_seg(stderr, "cs", &sregs.cs); - print_seg(stderr, "ds", &sregs.ds); - print_seg(stderr, "es", &sregs.es); - print_seg(stderr, "ss", &sregs.ss); - print_seg(stderr, "fs", &sregs.fs); - print_seg(stderr, "gs", &sregs.gs); - print_seg(stderr, "tr", &sregs.tr); - print_seg(stderr, "ldt", &sregs.ldt); - print_dt(stderr, "gdt", &sregs.gdt); - print_dt(stderr, "idt", &sregs.idt); - fprintf(stderr, "cr0 %llx cr2 %llx cr3 %llx cr4 %llx cr8 %llx" - " efer %llx\n", - sregs.cr0, sregs.cr2, sregs.cr3, sregs.cr4, sregs.cr8, - sregs.efer); -} - -uint64_t kvm_get_apic_base(kvm_vcpu_context_t vcpu) -{ - return vcpu->run->apic_base; -} - -void kvm_set_cr8(kvm_vcpu_context_t vcpu, uint64_t cr8) -{ - vcpu->run->cr8 = cr8; -} - -__u64 kvm_get_cr8(kvm_vcpu_context_t vcpu) -{ - return vcpu->run->cr8; -} - -int kvm_setup_cpuid(kvm_vcpu_context_t vcpu, int nent, - struct kvm_cpuid_entry *entries) -{ - struct kvm_cpuid *cpuid; - int r; - - cpuid = malloc(sizeof(*cpuid) + nent * sizeof(*entries)); - if (!cpuid) - return -ENOMEM; - - cpuid->nent = nent; - memcpy(cpuid->entries, entries, nent * sizeof(*entries)); - r = ioctl(vcpu->fd, KVM_SET_CPUID, cpuid); - - free(cpuid); - return r; -} - -int kvm_setup_cpuid2(kvm_vcpu_context_t vcpu, int nent, - struct kvm_cpuid_entry2 *entries) -{ - struct kvm_cpuid2 *cpuid; - int r; - - cpuid = malloc(sizeof(*cpuid) + nent * sizeof(*entries)); - if (!cpuid) - return -ENOMEM; - - cpuid->nent = nent; - memcpy(cpuid->entries, entries, nent * sizeof(*entries)); - r = ioctl(vcpu->fd, KVM_SET_CPUID2, cpuid); - if (r == -1) { - fprintf(stderr, "kvm_setup_cpuid2: %m\n"); - return -errno; - } - free(cpuid); - return r; -} - -int kvm_set_shadow_pages(kvm_context_t kvm, unsigned int nrshadow_pages) -{ -#ifdef KVM_CAP_MMU_SHADOW_CACHE_CONTROL - int r; - - r = ioctl(kvm->fd, KVM_CHECK_EXTENSION, - KVM_CAP_MMU_SHADOW_CACHE_CONTROL); - if (r > 0) { - r = ioctl(kvm->vm_fd, KVM_SET_NR_MMU_PAGES, nrshadow_pages); - if (r == -1) { - fprintf(stderr, "kvm_set_shadow_pages: %m\n"); - return -errno; - } - return 0; - } -#endif - return -1; -} - -int kvm_get_shadow_pages(kvm_context_t kvm, unsigned int *nrshadow_pages) -{ -#ifdef KVM_CAP_MMU_SHADOW_CACHE_CONTROL - int r; - - r = ioctl(kvm->fd, KVM_CHECK_EXTENSION, - KVM_CAP_MMU_SHADOW_CACHE_CONTROL); - if (r > 0) { - *nrshadow_pages = ioctl(kvm->vm_fd, KVM_GET_NR_MMU_PAGES); - return 0; - } -#endif - return -1; -} - -#ifdef KVM_CAP_VAPIC - -static int tpr_access_reporting(kvm_vcpu_context_t vcpu, int enabled) -{ - int r; - struct kvm_tpr_access_ctl tac = { - .enabled = enabled, - }; - - r = ioctl(vcpu->kvm->fd, KVM_CHECK_EXTENSION, KVM_CAP_VAPIC); - if (r == -1 || r == 0) - return -ENOSYS; - r = ioctl(vcpu->fd, KVM_TPR_ACCESS_REPORTING, &tac); - if (r == -1) { - r = -errno; - perror("KVM_TPR_ACCESS_REPORTING"); - return r; - } - return 0; -} - -int kvm_enable_tpr_access_reporting(kvm_vcpu_context_t vcpu) -{ - return tpr_access_reporting(vcpu, 1); -} - -int kvm_disable_tpr_access_reporting(kvm_vcpu_context_t vcpu) -{ - return tpr_access_reporting(vcpu, 0); -} - -#endif - -#ifdef KVM_CAP_EXT_CPUID - -static struct kvm_cpuid2 *try_get_cpuid(kvm_context_t kvm, int max) -{ - struct kvm_cpuid2 *cpuid; - int r, size; - - size = sizeof(*cpuid) + max * sizeof(*cpuid->entries); - cpuid = (struct kvm_cpuid2 *)malloc(size); - cpuid->nent = max; - r = ioctl(kvm->fd, KVM_GET_SUPPORTED_CPUID, cpuid); - if (r == -1) - r = -errno; - else if (r == 0 && cpuid->nent >= max) - r = -E2BIG; - if (r < 0) { - if (r == -E2BIG) { - free(cpuid); - return NULL; - } else { - fprintf(stderr, "KVM_GET_SUPPORTED_CPUID failed: %s\n", - strerror(-r)); - exit(1); - } - } - return cpuid; -} - -#define R_EAX 0 -#define R_ECX 1 -#define R_EDX 2 -#define R_EBX 3 -#define R_ESP 4 -#define R_EBP 5 -#define R_ESI 6 -#define R_EDI 7 - -uint32_t kvm_get_supported_cpuid(kvm_context_t kvm, uint32_t function, int reg) -{ - struct kvm_cpuid2 *cpuid; - int i, max; - uint32_t ret = 0; - uint32_t cpuid_1_edx; - - if (!kvm_check_extension(kvm, KVM_CAP_EXT_CPUID)) { - return -1U; - } - - max = 1; - while ((cpuid = try_get_cpuid(kvm, max)) == NULL) { - max *= 2; - } - - for (i = 0; i < cpuid->nent; ++i) { - if (cpuid->entries[i].function == function) { - switch (reg) { - case R_EAX: - ret = cpuid->entries[i].eax; - break; - case R_EBX: - ret = cpuid->entries[i].ebx; - break; - case R_ECX: - ret = cpuid->entries[i].ecx; - break; - case R_EDX: - ret = cpuid->entries[i].edx; - if (function == 1) { - /* kvm misreports the following features - */ - ret |= 1 << 12; /* MTRR */ - ret |= 1 << 16; /* PAT */ - ret |= 1 << 7; /* MCE */ - ret |= 1 << 14; /* MCA */ - } - - /* On Intel, kvm returns cpuid according to - * the Intel spec, so add missing bits - * according to the AMD spec: - */ - if (function == 0x80000001) { - cpuid_1_edx = kvm_get_supported_cpuid(kvm, 1, R_EDX); - ret |= cpuid_1_edx & 0xdfeff7ff; - } - break; - } - } - } - - free(cpuid); - - return ret; -} - -#else - -uint32_t kvm_get_supported_cpuid(kvm_context_t kvm, uint32_t function, int reg) -{ - return -1U; -} - -#endif