int kvm_create_memory_alias(kvm_context_t kvm, uint64_t phys_start, uint64_t len, uint64_t target_phys) { struct kvm_memory_alias alias = { .flags = 0, .guest_phys_addr = phys_start, .memory_size = len, .target_phys_addr = target_phys, }; int fd = kvm->vm_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_context_t kvm, int vcpu, struct kvm_lapic_state *s) { int r; if (!kvm->irqchip_in_kernel) return 0; r = ioctl(kvm->vcpu_fd[vcpu], KVM_GET_LAPIC, s); if (r == -1) { r = -errno; perror("kvm_get_lapic"); } return r; }
int kvm_create(kvm_context_t kvm, unsigned long phys_mem_bytes, void **vm_mem) { unsigned long dosmem = 0xa0000; unsigned long exmem = 0xc0000; unsigned long pcimem = 0xf0000000; unsigned long memory = (phys_mem_bytes + PAGE_SIZE - 1) & PAGE_MASK; int fd = kvm->fd; int zfd; int r; struct kvm_userspace_memory_region low_memory = { .slot = 3, .memory_size = memory < dosmem ? memory : dosmem, .guest_phys_addr = 0, }; struct kvm_userspace_memory_region extended_memory = { .slot = 0, .memory_size = memory < exmem ? 0 : memory - exmem, .guest_phys_addr = exmem, }; struct kvm_userspace_memory_region above_4g_memory = { .slot = 4, .memory_size = memory < pcimem ? 0 : memory - pcimem, .guest_phys_addr = 0x100000000, }; if (memory >= pcimem) extended_memory.memory_size = pcimem - exmem; kvm->vcpu_fd[0] = -1; fd = ioctl(fd, KVM_CREATE_VM, 0); if (fd == -1) { fprintf(stderr, "kvm_create_vm: %m\n"); return -1; } kvm->vm_fd = fd; kvm->physical_memory = mmap(NULL, extended_memory.memory_size + exmem, 7, MAP_ANON|MAP_SHARED, -1, 0); /* 640K should be enough. */ low_memory.userspace_addr = kvm->physical_memory; r = ioctl(fd, KVM_SET_USER_MEMORY_REGION, &low_memory); if (r == -1) { fprintf(stderr, "kvm_create_memory_region: %m\n"); return -1; } if (extended_memory.memory_size) { extended_memory.userspace_addr = kvm->physical_memory + exmem; r = ioctl(fd, KVM_SET_USER_MEMORY_REGION, &extended_memory); if (r == -1) { fprintf(stderr, "kvm_create_memory_region: %m\n"); return -1; } } *vm_mem = kvm->physical_memory; /*if (above_4g_memory.memory_size) { above_4g_memory.userspace_addr = mmap(NULL, above_4g_memory.memory_size, 7, MAP_ANON|MAP_SHARED, -1, 0); r = ioctl(fd, KVM_SET_USER_MEMORY_REGION, &above_4g_memory); if (r == -1) { fprintf(stderr, "kvm_create_memory_region: %m\n"); return -1; } }*/ /*kvm_memory_region_save_params(kvm, &low_memory); kvm_memory_region_save_params(kvm, &extended_memory); kvm_memory_region_save_params(kvm, &above_4g_memory);*/ /**vm_mem = mmap(NULL, memory, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); if (*vm_mem == MAP_FAILED) { fprintf(stderr, "mmap: %m\n"); return -1; } kvm->physical_memory = *vm_mem;*/ /*zfd = open("/dev/zero", O_RDONLY); mmap(*vm_mem + 0xa8000, 0x8000, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED, zfd, 0); close(zfd);*/ //kvm->physical_memory = low_memory.userspace_addr; kvm->irqchip_in_kernel = 0; if (!kvm->no_irqchip_creation) { r = ioctl(kvm->fd, KVM_CHECK_EXTENSION, KVM_CAP_IRQCHIP); if (r > 0) { /* kernel irqchip supported */ r = ioctl(fd, KVM_CREATE_IRQCHIP, NULL); if (r >= 0) kvm->irqchip_in_kernel = 1; else printf("Create kernel PIC irqchip failed\n"); } } r = kvm_create_vcpu(kvm, 0); if (r < 0) return r; return 0; } void *kvm_create_phys_mem(kvm_context_t kvm, unsigned long phys_start, unsigned long len, int slot, int log, int writable) { void *ptr; int r; int fd = kvm->vm_fd; int prot = PROT_READ; struct kvm_memory_region memory = { .slot = slot, .memory_size = len, .guest_phys_addr = phys_start, .flags = log ? KVM_MEM_LOG_DIRTY_PAGES : 0, }; r = ioctl(fd, KVM_SET_MEMORY_REGION, &memory); if (r == -1) return 0; kvm_memory_region_save_params(kvm, &memory); if (writable) prot |= PROT_WRITE; ptr = mmap(NULL, len, prot, MAP_SHARED, fd, phys_start); if (ptr == MAP_FAILED) return 0; return ptr; } /* destroy/free a whole slot. * phys_start, len and slot are the params passed to kvm_create_phys_mem() */ void kvm_destroy_phys_mem(kvm_context_t kvm, unsigned long phys_start, unsigned long len, int slot) { struct kvm_memory_region *mem; if (slot >= KVM_MAX_NUM_MEM_REGIONS) { fprintf(stderr, "BUG: %s: invalid parameters (slot=%d)\n", __FUNCTION__, slot); return; } mem = &kvm->mem_regions[slot]; if (phys_start != mem->guest_phys_addr) { fprintf(stderr, "WARNING: %s: phys_start is 0x%lx expecting 0x%llx\n", __FUNCTION__, phys_start, mem->guest_phys_addr); phys_start = mem->guest_phys_addr; } kvm_create_phys_mem(kvm, phys_start, 0, slot, 0, 0); } int kvm_create_memory_alias(kvm_context_t kvm, int slot, uint64_t phys_start, uint64_t len, uint64_t target_phys) { struct kvm_memory_alias alias = { .slot = slot, .flags = 0, .guest_phys_addr = phys_start, .memory_size = len, .target_phys_addr = target_phys, }; int fd = kvm->vm_fd; int r; r = ioctl(fd, KVM_SET_MEMORY_ALIAS, &alias); if (r == -1) return -errno; return 0; } int kvm_destroy_memory_alias(kvm_context_t kvm, int slot) { return kvm_create_memory_alias(kvm, slot, 0, 0, 0); } static int kvm_get_map(kvm_context_t kvm, int ioctl_num, int slot, void *buf) { int r; struct kvm_dirty_log log = { .slot = slot, }; log.dirty_bitmap = buf; r = ioctl(kvm->vm_fd, ioctl_num, &log); if (r == -1) return -errno; return 0; } int kvm_get_dirty_pages(kvm_context_t kvm, int slot, void *buf) { return kvm_get_map(kvm, KVM_GET_DIRTY_LOG, slot, buf); } int kvm_get_mem_map(kvm_context_t kvm, int slot, void *buf) { #ifdef KVM_GET_MEM_MAP return kvm_get_map(kvm, KVM_GET_MEM_MAP, slot, buf); #else /* not KVM_GET_MEM_MAP ==> fake it: all pages exist */ unsigned long i, n, m, npages; unsigned char v; if (slot >= KVM_MAX_NUM_MEM_REGIONS) { errno = -EINVAL; return -1; } npages = kvm->mem_regions[slot].memory_size / PAGE_SIZE; n = npages / 8; m = npages % 8; memset(buf, 0xff, n); /* all pages exist */ v = 0; for (i=0; i<=m; i++) /* last byte may not be "aligned" */ v |= 1<<(7-i); if (v) *(unsigned char*)(buf+n) = v; return 0; #endif /* KVM_GET_MEM_MAP */ } int kvm_set_irq_level(kvm_context_t kvm, int irq, int level) { struct kvm_irq_level event; int r; if (!kvm->irqchip_in_kernel) return 0; event.level = level; event.irq = irq; r = ioctl(kvm->vm_fd, KVM_IRQ_LINE, &event); if (r == -1) perror("kvm_set_irq_level"); return 1; } int kvm_get_irqchip(kvm_context_t kvm, struct kvm_irqchip *chip) { int r; if (!kvm->irqchip_in_kernel) return 0; r = ioctl(kvm->vm_fd, KVM_GET_IRQCHIP, chip); if (r == -1) { r = -errno; perror("kvm_get_irqchip\n"); } return r; } int kvm_set_irqchip(kvm_context_t kvm, struct kvm_irqchip *chip) { int r; if (!kvm->irqchip_in_kernel) return 0; r = ioctl(kvm->vm_fd, KVM_SET_IRQCHIP, chip); if (r == -1) { r = -errno; perror("kvm_set_irqchip\n"); } return r; } int kvm_get_lapic(kvm_context_t kvm, int vcpu, struct kvm_lapic_state *s) { int r; if (!kvm->irqchip_in_kernel) return 0; r = ioctl(kvm->vcpu_fd[vcpu], KVM_GET_LAPIC, s); if (r == -1) { r = -errno; perror("kvm_get_lapic"); } return r; }