1ae1fae34SPekka Enberg #include "kvm/kvm.h" 2ae1fae34SPekka Enberg 3c78b8713SAsias He #include "kvm/cpufeature.h" 4ce79f1caSPekka Enberg #include "kvm/interrupt.h" 5b3594ec7SCyrill Gorcunov #include "kvm/boot-protocol.h" 6f3150089SPekka Enberg #include "kvm/util.h" 7*0c7c14a7SCyrill Gorcunov #include "kvm/mptable.h" 8eda03319SPekka Enberg 96c7d8514SPekka Enberg #include <linux/kvm.h> 10f5ab5f67SPekka Enberg 11f5ab5f67SPekka Enberg #include <asm/bootparam.h> 12f5ab5f67SPekka Enberg 13ae1fae34SPekka Enberg #include <sys/ioctl.h> 141f9cff23SPekka Enberg #include <inttypes.h> 151f9cff23SPekka Enberg #include <sys/mman.h> 16ce79f1caSPekka Enberg #include <sys/stat.h> 172da26a59SPekka Enberg #include <stdbool.h> 186e5e8b8dSPekka Enberg #include <assert.h> 1906e41eeaSPekka Enberg #include <limits.h> 20ce79f1caSPekka Enberg #include <signal.h> 21f5ab5f67SPekka Enberg #include <stdarg.h> 22b8f6afcdSPekka Enberg #include <stdlib.h> 23f5ab5f67SPekka Enberg #include <string.h> 240d1f17ecSPekka Enberg #include <unistd.h> 251f9cff23SPekka Enberg #include <stdio.h> 26b8f6afcdSPekka Enberg #include <fcntl.h> 27ce79f1caSPekka Enberg #include <time.h> 28b8f6afcdSPekka Enberg 29ae1fae34SPekka Enberg #define DEFINE_KVM_EXIT_REASON(reason) [reason] = #reason 300d1f17ecSPekka Enberg 31ae1fae34SPekka Enberg const char *kvm_exit_reasons[] = { 32ae1fae34SPekka Enberg DEFINE_KVM_EXIT_REASON(KVM_EXIT_UNKNOWN), 33ae1fae34SPekka Enberg DEFINE_KVM_EXIT_REASON(KVM_EXIT_EXCEPTION), 34ae1fae34SPekka Enberg DEFINE_KVM_EXIT_REASON(KVM_EXIT_IO), 35ae1fae34SPekka Enberg DEFINE_KVM_EXIT_REASON(KVM_EXIT_HYPERCALL), 36ae1fae34SPekka Enberg DEFINE_KVM_EXIT_REASON(KVM_EXIT_DEBUG), 37ae1fae34SPekka Enberg DEFINE_KVM_EXIT_REASON(KVM_EXIT_HLT), 38ae1fae34SPekka Enberg DEFINE_KVM_EXIT_REASON(KVM_EXIT_MMIO), 39ae1fae34SPekka Enberg DEFINE_KVM_EXIT_REASON(KVM_EXIT_IRQ_WINDOW_OPEN), 40ae1fae34SPekka Enberg DEFINE_KVM_EXIT_REASON(KVM_EXIT_SHUTDOWN), 41ae1fae34SPekka Enberg DEFINE_KVM_EXIT_REASON(KVM_EXIT_FAIL_ENTRY), 42ae1fae34SPekka Enberg DEFINE_KVM_EXIT_REASON(KVM_EXIT_INTR), 43ae1fae34SPekka Enberg DEFINE_KVM_EXIT_REASON(KVM_EXIT_SET_TPR), 44ae1fae34SPekka Enberg DEFINE_KVM_EXIT_REASON(KVM_EXIT_TPR_ACCESS), 45ae1fae34SPekka Enberg DEFINE_KVM_EXIT_REASON(KVM_EXIT_S390_SIEIC), 46ae1fae34SPekka Enberg DEFINE_KVM_EXIT_REASON(KVM_EXIT_S390_RESET), 47ae1fae34SPekka Enberg DEFINE_KVM_EXIT_REASON(KVM_EXIT_DCR), 48ae1fae34SPekka Enberg DEFINE_KVM_EXIT_REASON(KVM_EXIT_NMI), 49ae1fae34SPekka Enberg DEFINE_KVM_EXIT_REASON(KVM_EXIT_INTERNAL_ERROR), 509b1fb1c3SPekka Enberg }; 519b1fb1c3SPekka Enberg 5255e19624SCyrill Gorcunov #define DEFINE_KVM_EXT(ext) \ 5355e19624SCyrill Gorcunov .name = #ext, \ 5455e19624SCyrill Gorcunov .code = ext 5555e19624SCyrill Gorcunov 5655e19624SCyrill Gorcunov struct { 5755e19624SCyrill Gorcunov const char *name; 5855e19624SCyrill Gorcunov int code; 5955e19624SCyrill Gorcunov } kvm_req_ext[] = { 6055e19624SCyrill Gorcunov { DEFINE_KVM_EXT(KVM_CAP_COALESCED_MMIO) }, 6155e19624SCyrill Gorcunov { DEFINE_KVM_EXT(KVM_CAP_SET_TSS_ADDR) }, 6255e19624SCyrill Gorcunov { DEFINE_KVM_EXT(KVM_CAP_PIT2) }, 6355e19624SCyrill Gorcunov { DEFINE_KVM_EXT(KVM_CAP_USER_MEMORY) }, 6455e19624SCyrill Gorcunov { DEFINE_KVM_EXT(KVM_CAP_IRQ_ROUTING) }, 6555e19624SCyrill Gorcunov { DEFINE_KVM_EXT(KVM_CAP_IRQCHIP) }, 667c0ec28fSCyrill Gorcunov { DEFINE_KVM_EXT(KVM_CAP_HLT) }, 6755e19624SCyrill Gorcunov { DEFINE_KVM_EXT(KVM_CAP_IRQ_INJECT_STATUS) }, 68d38ad31aSCyrill Gorcunov { DEFINE_KVM_EXT(KVM_CAP_EXT_CPUID) }, 6955e19624SCyrill Gorcunov }; 7055e19624SCyrill Gorcunov 71ae1fae34SPekka Enberg static bool kvm__supports_extension(struct kvm *self, unsigned int extension) 72b8f6afcdSPekka Enberg { 7328fa19c0SPekka Enberg int ret; 74b8f6afcdSPekka Enberg 7573ac60e6SPekka Enberg ret = ioctl(self->sys_fd, KVM_CHECK_EXTENSION, extension); 764076b041SPekka Enberg if (ret < 0) 774076b041SPekka Enberg return false; 784076b041SPekka Enberg 794076b041SPekka Enberg return ret; 804076b041SPekka Enberg } 814076b041SPekka Enberg 8255e19624SCyrill Gorcunov static int kvm__check_extensions(struct kvm *self) 8355e19624SCyrill Gorcunov { 8455e19624SCyrill Gorcunov unsigned int i; 8555e19624SCyrill Gorcunov 8655e19624SCyrill Gorcunov for (i = 0; i < ARRAY_SIZE(kvm_req_ext); i++) { 8755e19624SCyrill Gorcunov if (!kvm__supports_extension(self, kvm_req_ext[i].code)) { 8855e19624SCyrill Gorcunov error("Unsuppored KVM extension detected: %s", 8955e19624SCyrill Gorcunov kvm_req_ext[i].name); 9055e19624SCyrill Gorcunov return (int)-i; 9155e19624SCyrill Gorcunov } 9255e19624SCyrill Gorcunov } 9355e19624SCyrill Gorcunov 9455e19624SCyrill Gorcunov return 0; 9555e19624SCyrill Gorcunov } 9655e19624SCyrill Gorcunov 974076b041SPekka Enberg static struct kvm *kvm__new(void) 984076b041SPekka Enberg { 994076b041SPekka Enberg struct kvm *self = calloc(1, sizeof *self); 1004076b041SPekka Enberg 1014076b041SPekka Enberg if (!self) 1024076b041SPekka Enberg die("out of memory"); 1034076b041SPekka Enberg 1044076b041SPekka Enberg return self; 1054076b041SPekka Enberg } 1064076b041SPekka Enberg 1079ef4c68eSPekka Enberg void kvm__delete(struct kvm *self) 1089ef4c68eSPekka Enberg { 109fbfe68b7SSasha Levin kvm__stop_timer(self); 110fbfe68b7SSasha Levin 111839051d9SSasha Levin munmap(self->ram_start, self->ram_size); 1129ef4c68eSPekka Enberg free(self); 1139ef4c68eSPekka Enberg } 1149ef4c68eSPekka Enberg 115c78b8713SAsias He static bool kvm__cpu_supports_vm(void) 116c78b8713SAsias He { 117c78b8713SAsias He struct cpuid_regs regs; 118831fbf23SPekka Enberg uint32_t eax_base; 119831fbf23SPekka Enberg int feature; 120c78b8713SAsias He 121c78b8713SAsias He regs = (struct cpuid_regs) { 122831fbf23SPekka Enberg .eax = 0x00, 123c78b8713SAsias He }; 124c78b8713SAsias He host_cpuid(®s); 125c78b8713SAsias He 126ae87afbfSCyrill Gorcunov switch (regs.ebx) { 127ae87afbfSCyrill Gorcunov case CPUID_VENDOR_INTEL_1: 128831fbf23SPekka Enberg eax_base = 0x00; 129831fbf23SPekka Enberg feature = KVM__X86_FEATURE_VMX; 130ae87afbfSCyrill Gorcunov break; 13134649df9SPekka Enberg 132ae87afbfSCyrill Gorcunov case CPUID_VENDOR_AMD_1: 133831fbf23SPekka Enberg eax_base = 0x80000000; 134831fbf23SPekka Enberg feature = KVM__X86_FEATURE_SVM; 135ae87afbfSCyrill Gorcunov break; 13634649df9SPekka Enberg 13734649df9SPekka Enberg default: 13834649df9SPekka Enberg return false; 139ae87afbfSCyrill Gorcunov } 140ae87afbfSCyrill Gorcunov 141831fbf23SPekka Enberg regs = (struct cpuid_regs) { 142831fbf23SPekka Enberg .eax = eax_base, 143831fbf23SPekka Enberg }; 144831fbf23SPekka Enberg host_cpuid(®s); 145831fbf23SPekka Enberg 146831fbf23SPekka Enberg if (regs.eax < eax_base + 0x01) 147831fbf23SPekka Enberg return false; 148831fbf23SPekka Enberg 149831fbf23SPekka Enberg regs = (struct cpuid_regs) { 150831fbf23SPekka Enberg .eax = eax_base + 0x01 151831fbf23SPekka Enberg }; 152831fbf23SPekka Enberg host_cpuid(®s); 153831fbf23SPekka Enberg 154831fbf23SPekka Enberg return regs.ecx & (1 << feature); 155c78b8713SAsias He } 156c78b8713SAsias He 157839051d9SSasha Levin void kvm__init_ram(struct kvm *self) 1584076b041SPekka Enberg { 1592b0e3342SPekka Enberg struct kvm_userspace_memory_region mem; 160839051d9SSasha Levin int ret; 161839051d9SSasha Levin 162839051d9SSasha Levin mem = (struct kvm_userspace_memory_region) { 163839051d9SSasha Levin .slot = 0, 164839051d9SSasha Levin .guest_phys_addr = 0x0UL, 165839051d9SSasha Levin .memory_size = self->ram_size, 166839051d9SSasha Levin .userspace_addr = (unsigned long) self->ram_start, 167839051d9SSasha Levin }; 168839051d9SSasha Levin 169839051d9SSasha Levin ret = ioctl(self->vm_fd, KVM_SET_USER_MEMORY_REGION, &mem); 170839051d9SSasha Levin if (ret < 0) 171839051d9SSasha Levin die_perror("KVM_SET_USER_MEMORY_REGION ioctl"); 172839051d9SSasha Levin } 173839051d9SSasha Levin 174839051d9SSasha Levin struct kvm *kvm__init(const char *kvm_dev, unsigned long ram_size) 175839051d9SSasha Levin { 1769687927dSAsias He struct kvm_pit_config pit_config = { .flags = 0, }; 1774076b041SPekka Enberg struct kvm *self; 1784076b041SPekka Enberg int ret; 1794076b041SPekka Enberg 180c78b8713SAsias He if (!kvm__cpu_supports_vm()) 181c78b8713SAsias He die("Your CPU does not support hardware virtualization"); 182c78b8713SAsias He 1834076b041SPekka Enberg self = kvm__new(); 1844076b041SPekka Enberg 1856d7c36ceSPekka Enberg self->sys_fd = open(kvm_dev, O_RDWR); 1866d7c36ceSPekka Enberg if (self->sys_fd < 0) { 1876d7c36ceSPekka Enberg if (errno == ENOENT) 188e907b83fSPekka Enberg die("'%s' not found. Please make sure your kernel has CONFIG_KVM enabled and that the KVM modules are loaded.", kvm_dev); 189f8334800SIngo Molnar if (errno == ENODEV) 190f8334800SIngo Molnar die("'%s' KVM driver not available.\n # (If the KVM module is loaded then 'dmesg' may offer further clues about the failure.)", kvm_dev); 1916d7c36ceSPekka Enberg 192f8334800SIngo Molnar fprintf(stderr, " Fatal, could not open %s: ", kvm_dev); 193f8334800SIngo Molnar perror(NULL); 194f8334800SIngo Molnar exit(1); 1956d7c36ceSPekka Enberg } 196b8f6afcdSPekka Enberg 19773ac60e6SPekka Enberg ret = ioctl(self->sys_fd, KVM_GET_API_VERSION, 0); 1986c7d8514SPekka Enberg if (ret != KVM_API_VERSION) 199f5ab5f67SPekka Enberg die_perror("KVM_API_VERSION ioctl"); 2006c7d8514SPekka Enberg 20173ac60e6SPekka Enberg self->vm_fd = ioctl(self->sys_fd, KVM_CREATE_VM, 0); 20273ac60e6SPekka Enberg if (self->vm_fd < 0) 203f5ab5f67SPekka Enberg die_perror("KVM_CREATE_VM ioctl"); 20428fa19c0SPekka Enberg 20555e19624SCyrill Gorcunov if (kvm__check_extensions(self)) 20655e19624SCyrill Gorcunov die("A required KVM extention is not supported by OS"); 2079687927dSAsias He 2089687927dSAsias He ret = ioctl(self->vm_fd, KVM_SET_TSS_ADDR, 0xfffbd000); 2099687927dSAsias He if (ret < 0) 2109687927dSAsias He die_perror("KVM_SET_TSS_ADDR ioctl"); 2119687927dSAsias He 2129687927dSAsias He ret = ioctl(self->vm_fd, KVM_CREATE_PIT2, &pit_config); 2139687927dSAsias He if (ret < 0) 2149687927dSAsias He die_perror("KVM_CREATE_PIT2 ioctl"); 2159687927dSAsias He 216192a99d1SCyrill Gorcunov self->ram_size = ram_size; 2170d1f17ecSPekka Enberg 218839051d9SSasha Levin self->ram_start = mmap(NULL, ram_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE, -1, 0); 219839051d9SSasha Levin if (self->ram_start == MAP_FAILED) 2200d1f17ecSPekka Enberg die("out of memory"); 2210d1f17ecSPekka Enberg 2229687927dSAsias He ret = ioctl(self->vm_fd, KVM_CREATE_IRQCHIP); 223895c2fefSPekka Enberg if (ret < 0) 2249687927dSAsias He die_perror("KVM_CREATE_IRQCHIP ioctl"); 2259687927dSAsias He 2264076b041SPekka Enberg return self; 2274076b041SPekka Enberg } 2284076b041SPekka Enberg 2295f6772b8SCyrill Gorcunov #define BOOT_LOADER_SELECTOR 0x1000 230b08e9ec4SPekka Enberg #define BOOT_LOADER_IP 0x0000 231dbdb74c2SPekka Enberg #define BOOT_LOADER_SP 0x8000 2322dd4a4edSCyrill Gorcunov #define BOOT_CMDLINE_OFFSET 0x20000 2332dd4a4edSCyrill Gorcunov 2349a4ecdc5SPekka Enberg #define BOOT_PROTOCOL_REQUIRED 0x206 235a43f6460SCyrill Gorcunov #define LOAD_HIGH 0x01 236009b0758SPekka Enberg 237edc8a14dSPekka Enberg static int load_flat_binary(struct kvm *self, int fd) 238009b0758SPekka Enberg { 239009b0758SPekka Enberg void *p; 240009b0758SPekka Enberg int nr; 241009b0758SPekka Enberg 242009b0758SPekka Enberg if (lseek(fd, 0, SEEK_SET) < 0) 243009b0758SPekka Enberg die_perror("lseek"); 244009b0758SPekka Enberg 2456753ed2fSPekka Enberg p = guest_real_to_host(self, BOOT_LOADER_SELECTOR, BOOT_LOADER_IP); 246009b0758SPekka Enberg 247009b0758SPekka Enberg while ((nr = read(fd, p, 65536)) > 0) 248009b0758SPekka Enberg p += nr; 249009b0758SPekka Enberg 250dbdb74c2SPekka Enberg self->boot_selector = BOOT_LOADER_SELECTOR; 251edc8a14dSPekka Enberg self->boot_ip = BOOT_LOADER_IP; 252dbdb74c2SPekka Enberg self->boot_sp = BOOT_LOADER_SP; 253edc8a14dSPekka Enberg 2547fb218bdSPekka Enberg return true; 255009b0758SPekka Enberg } 256009b0758SPekka Enberg 257ae1fae34SPekka Enberg static const char *BZIMAGE_MAGIC = "HdrS"; 258ae1fae34SPekka Enberg 2592065a6f7SCyrill Gorcunov static bool load_bzimage(struct kvm *self, int fd_kernel, 2602065a6f7SCyrill Gorcunov int fd_initrd, const char *kernel_cmdline) 261ae1fae34SPekka Enberg { 262b9271160SPekka Enberg struct boot_params *kern_boot; 2634b62331fSPekka Enberg unsigned long setup_sects; 264b9271160SPekka Enberg struct boot_params boot; 2652dd4a4edSCyrill Gorcunov size_t cmdline_size; 2667fb218bdSPekka Enberg ssize_t setup_size; 26722489bb0SCyrill Gorcunov void *p; 268ae1fae34SPekka Enberg int nr; 269ae1fae34SPekka Enberg 2705d67eaf6SPekka Enberg /* 2715d67eaf6SPekka Enberg * See Documentation/x86/boot.txt for details no bzImage on-disk and 2725d67eaf6SPekka Enberg * memory layout. 2735d67eaf6SPekka Enberg */ 2745d67eaf6SPekka Enberg 2752065a6f7SCyrill Gorcunov if (lseek(fd_kernel, 0, SEEK_SET) < 0) 276009b0758SPekka Enberg die_perror("lseek"); 277009b0758SPekka Enberg 2780b62d2bbSPekka Enberg if (read(fd_kernel, &boot, sizeof(boot)) != sizeof(boot)) 2792346d461SPekka Enberg return false; 280ae1fae34SPekka Enberg 2810b62d2bbSPekka Enberg if (memcmp(&boot.hdr.header, BZIMAGE_MAGIC, strlen(BZIMAGE_MAGIC))) 2827fb218bdSPekka Enberg return false; 283ae1fae34SPekka Enberg 2840ea58e5bSPekka Enberg if (boot.hdr.version < BOOT_PROTOCOL_REQUIRED) 2850b62d2bbSPekka Enberg die("Too old kernel"); 286ad681038SCyrill Gorcunov 2872065a6f7SCyrill Gorcunov if (lseek(fd_kernel, 0, SEEK_SET) < 0) 288e93ab78aSPekka Enberg die_perror("lseek"); 289e93ab78aSPekka Enberg 2904cf542bbSCyrill Gorcunov if (!boot.hdr.setup_sects) 2914cf542bbSCyrill Gorcunov boot.hdr.setup_sects = BZ_DEFAULT_SETUP_SECTS; 29210943d14SPekka Enberg setup_sects = boot.hdr.setup_sects + 1; 29310943d14SPekka Enberg 29454d4a626SPekka Enberg setup_size = setup_sects << 9; 2956753ed2fSPekka Enberg p = guest_real_to_host(self, BOOT_LOADER_SELECTOR, BOOT_LOADER_IP); 296ae1fae34SPekka Enberg 2972065a6f7SCyrill Gorcunov /* copy setup.bin to mem*/ 2982065a6f7SCyrill Gorcunov if (read(fd_kernel, p, setup_size) != setup_size) 2997fb218bdSPekka Enberg die_perror("read"); 3007fb218bdSPekka Enberg 3012065a6f7SCyrill Gorcunov /* copy vmlinux.bin to BZ_KERNEL_START*/ 3026753ed2fSPekka Enberg p = guest_flat_to_host(self, BZ_KERNEL_START); 303ae1fae34SPekka Enberg 3042065a6f7SCyrill Gorcunov while ((nr = read(fd_kernel, p, 65536)) > 0) 305ae1fae34SPekka Enberg p += nr; 306ae1fae34SPekka Enberg 307a43f6460SCyrill Gorcunov p = guest_flat_to_host(self, BOOT_CMDLINE_OFFSET); 308debcfac0SCyrill Gorcunov if (kernel_cmdline) { 309debcfac0SCyrill Gorcunov cmdline_size = strlen(kernel_cmdline) + 1; 310debcfac0SCyrill Gorcunov if (cmdline_size > boot.hdr.cmdline_size) 311debcfac0SCyrill Gorcunov cmdline_size = boot.hdr.cmdline_size; 312ad681038SCyrill Gorcunov 3132dd4a4edSCyrill Gorcunov memset(p, 0, boot.hdr.cmdline_size); 3142dd4a4edSCyrill Gorcunov memcpy(p, kernel_cmdline, cmdline_size - 1); 315debcfac0SCyrill Gorcunov } 316debcfac0SCyrill Gorcunov 317b9271160SPekka Enberg kern_boot = guest_real_to_host(self, BOOT_LOADER_SELECTOR, 0x00); 318a43f6460SCyrill Gorcunov 319b9271160SPekka Enberg kern_boot->hdr.cmd_line_ptr = BOOT_CMDLINE_OFFSET; 320b9271160SPekka Enberg kern_boot->hdr.type_of_loader = 0xff; 321b9271160SPekka Enberg kern_boot->hdr.heap_end_ptr = 0xfe00; 322b9271160SPekka Enberg kern_boot->hdr.loadflags |= CAN_USE_HEAP; 323a43f6460SCyrill Gorcunov 3242065a6f7SCyrill Gorcunov /* 3252065a6f7SCyrill Gorcunov * Read initrd image into guest memory 3262065a6f7SCyrill Gorcunov */ 3272065a6f7SCyrill Gorcunov if (fd_initrd >= 0) { 3282065a6f7SCyrill Gorcunov struct stat initrd_stat; 3292065a6f7SCyrill Gorcunov unsigned long addr; 3302065a6f7SCyrill Gorcunov 3312065a6f7SCyrill Gorcunov if (fstat(fd_initrd, &initrd_stat)) 3322065a6f7SCyrill Gorcunov die_perror("fstat"); 3332065a6f7SCyrill Gorcunov 3342065a6f7SCyrill Gorcunov addr = boot.hdr.initrd_addr_max & ~0xfffff; 3352065a6f7SCyrill Gorcunov for (;;) { 3362065a6f7SCyrill Gorcunov if (addr < BZ_KERNEL_START) 3372065a6f7SCyrill Gorcunov die("Not enough memory for initrd"); 3382065a6f7SCyrill Gorcunov else if (addr < (self->ram_size - initrd_stat.st_size)) 3392065a6f7SCyrill Gorcunov break; 3402065a6f7SCyrill Gorcunov addr -= 0x100000; 3412065a6f7SCyrill Gorcunov } 3422065a6f7SCyrill Gorcunov 3432065a6f7SCyrill Gorcunov p = guest_flat_to_host(self, addr); 3442065a6f7SCyrill Gorcunov nr = read(fd_initrd, p, initrd_stat.st_size); 3452065a6f7SCyrill Gorcunov if (nr != initrd_stat.st_size) 3462065a6f7SCyrill Gorcunov die("Failed to read initrd"); 3472065a6f7SCyrill Gorcunov 3482065a6f7SCyrill Gorcunov kern_boot->hdr.ramdisk_image = addr; 3492065a6f7SCyrill Gorcunov kern_boot->hdr.ramdisk_size = initrd_stat.st_size; 3502065a6f7SCyrill Gorcunov } 3512065a6f7SCyrill Gorcunov 352dbdb74c2SPekka Enberg self->boot_selector = BOOT_LOADER_SELECTOR; 353edc8a14dSPekka Enberg /* 354edc8a14dSPekka Enberg * The real-mode setup code starts at offset 0x200 of a bzImage. See 355edc8a14dSPekka Enberg * Documentation/x86/boot.txt for details. 356edc8a14dSPekka Enberg */ 357edc8a14dSPekka Enberg self->boot_ip = BOOT_LOADER_IP + 0x200; 358dbdb74c2SPekka Enberg self->boot_sp = BOOT_LOADER_SP; 359edc8a14dSPekka Enberg 3607fb218bdSPekka Enberg return true; 361ae1fae34SPekka Enberg } 362ae1fae34SPekka Enberg 3636d1f350dSCyrill Gorcunov bool kvm__load_kernel(struct kvm *kvm, const char *kernel_filename, 3642065a6f7SCyrill Gorcunov const char *initrd_filename, const char *kernel_cmdline) 365ae1fae34SPekka Enberg { 3667fb218bdSPekka Enberg bool ret; 3672065a6f7SCyrill Gorcunov int fd_kernel = -1, fd_initrd = -1; 368ae1fae34SPekka Enberg 3692065a6f7SCyrill Gorcunov fd_kernel = open(kernel_filename, O_RDONLY); 3702065a6f7SCyrill Gorcunov if (fd_kernel < 0) 3710b62d2bbSPekka Enberg die("Unable to open kernel %s", kernel_filename); 372ae1fae34SPekka Enberg 3732065a6f7SCyrill Gorcunov if (initrd_filename) { 3742065a6f7SCyrill Gorcunov fd_initrd = open(initrd_filename, O_RDONLY); 3752065a6f7SCyrill Gorcunov if (fd_initrd < 0) 3760b62d2bbSPekka Enberg die("Unable to open initrd %s", initrd_filename); 3772065a6f7SCyrill Gorcunov } 3782065a6f7SCyrill Gorcunov 3792065a6f7SCyrill Gorcunov ret = load_bzimage(kvm, fd_kernel, fd_initrd, kernel_cmdline); 38028972750SCyrill Gorcunov 38128972750SCyrill Gorcunov if (initrd_filename) 38228972750SCyrill Gorcunov close(fd_initrd); 38328972750SCyrill Gorcunov 384009b0758SPekka Enberg if (ret) 385009b0758SPekka Enberg goto found_kernel; 386ae1fae34SPekka Enberg 3870b62d2bbSPekka Enberg warning("%s is not a bzImage. Trying to load it as a flat binary...", kernel_filename); 3880b62d2bbSPekka Enberg 3892065a6f7SCyrill Gorcunov ret = load_flat_binary(kvm, fd_kernel); 390009b0758SPekka Enberg if (ret) 391009b0758SPekka Enberg goto found_kernel; 392009b0758SPekka Enberg 3935a6ac675SSasha Levin close(fd_kernel); 3945a6ac675SSasha Levin 395009b0758SPekka Enberg die("%s is not a valid bzImage or flat binary", kernel_filename); 396009b0758SPekka Enberg 397009b0758SPekka Enberg found_kernel: 3985a6ac675SSasha Levin close(fd_kernel); 3995a6ac675SSasha Levin 400ae1fae34SPekka Enberg return ret; 401ae1fae34SPekka Enberg } 402ae1fae34SPekka Enberg 403b3594ec7SCyrill Gorcunov /** 404b3594ec7SCyrill Gorcunov * kvm__setup_bios - inject BIOS into guest system memory 405b3594ec7SCyrill Gorcunov * @self - guest system descriptor 406b3594ec7SCyrill Gorcunov * 407b3594ec7SCyrill Gorcunov * This function is a main routine where we poke guest memory 408b3594ec7SCyrill Gorcunov * and install BIOS there. 409b3594ec7SCyrill Gorcunov */ 410b3594ec7SCyrill Gorcunov void kvm__setup_bios(struct kvm *self) 4112f3976eeSPekka Enberg { 412b3594ec7SCyrill Gorcunov /* standart minimal configuration */ 413b3594ec7SCyrill Gorcunov setup_bios(self); 4142f3976eeSPekka Enberg 415b3594ec7SCyrill Gorcunov /* FIXME: SMP, ACPI and friends here */ 416*0c7c14a7SCyrill Gorcunov 417*0c7c14a7SCyrill Gorcunov /* MP table */ 418*0c7c14a7SCyrill Gorcunov mptable_setup(self, self->nrcpus); 4192f3976eeSPekka Enberg } 4202f3976eeSPekka Enberg 421ce79f1caSPekka Enberg #define TIMER_INTERVAL_NS 1000000 /* 1 msec */ 422ce79f1caSPekka Enberg 423ce79f1caSPekka Enberg /* 424ce79f1caSPekka Enberg * This function sets up a timer that's used to inject interrupts from the 425ce79f1caSPekka Enberg * userspace hypervisor into the guest at periodical intervals. Please note 426ce79f1caSPekka Enberg * that clock interrupt, for example, is not handled here. 427ce79f1caSPekka Enberg */ 428ce79f1caSPekka Enberg void kvm__start_timer(struct kvm *self) 429ce79f1caSPekka Enberg { 430ce79f1caSPekka Enberg struct itimerspec its; 431ce79f1caSPekka Enberg struct sigevent sev; 432ce79f1caSPekka Enberg 433ce79f1caSPekka Enberg memset(&sev, 0, sizeof(struct sigevent)); 434ce79f1caSPekka Enberg sev.sigev_value.sival_int = 0; 435ce79f1caSPekka Enberg sev.sigev_notify = SIGEV_SIGNAL; 436ce79f1caSPekka Enberg sev.sigev_signo = SIGALRM; 437ce79f1caSPekka Enberg 438ce79f1caSPekka Enberg if (timer_create(CLOCK_REALTIME, &sev, &self->timerid) < 0) 439ce79f1caSPekka Enberg die("timer_create()"); 440ce79f1caSPekka Enberg 441ce79f1caSPekka Enberg its.it_value.tv_sec = TIMER_INTERVAL_NS / 1000000000; 442ce79f1caSPekka Enberg its.it_value.tv_nsec = TIMER_INTERVAL_NS % 1000000000; 443ce79f1caSPekka Enberg its.it_interval.tv_sec = its.it_value.tv_sec; 444ce79f1caSPekka Enberg its.it_interval.tv_nsec = its.it_value.tv_nsec; 445ce79f1caSPekka Enberg 446ce79f1caSPekka Enberg if (timer_settime(self->timerid, 0, &its, NULL) < 0) 447ce79f1caSPekka Enberg die("timer_settime()"); 448ce79f1caSPekka Enberg } 449ce79f1caSPekka Enberg 450fbfe68b7SSasha Levin void kvm__stop_timer(struct kvm *self) 451fbfe68b7SSasha Levin { 452fbfe68b7SSasha Levin if (self->timerid) 453fbfe68b7SSasha Levin if (timer_delete(self->timerid) < 0) 454fbfe68b7SSasha Levin die("timer_delete()"); 455fbfe68b7SSasha Levin 456fbfe68b7SSasha Levin self->timerid = 0; 457fbfe68b7SSasha Levin } 458fbfe68b7SSasha Levin 4598b1ff07eSPekka Enberg void kvm__irq_line(struct kvm *self, int irq, int level) 4608b1ff07eSPekka Enberg { 4618b1ff07eSPekka Enberg struct kvm_irq_level irq_level; 4628b1ff07eSPekka Enberg 4638b1ff07eSPekka Enberg irq_level = (struct kvm_irq_level) { 4648b1ff07eSPekka Enberg { 4658b1ff07eSPekka Enberg .irq = irq, 4668b1ff07eSPekka Enberg }, 4678b1ff07eSPekka Enberg .level = level, 4688b1ff07eSPekka Enberg }; 4698b1ff07eSPekka Enberg 4708b1ff07eSPekka Enberg if (ioctl(self->vm_fd, KVM_IRQ_LINE, &irq_level) < 0) 4718b1ff07eSPekka Enberg die_perror("KVM_IRQ_LINE failed"); 4728b1ff07eSPekka Enberg } 4738b1ff07eSPekka Enberg 474090f898eSCyrill Gorcunov void kvm__dump_mem(struct kvm *self, unsigned long addr, unsigned long size) 475090f898eSCyrill Gorcunov { 476090f898eSCyrill Gorcunov unsigned char *p; 477090f898eSCyrill Gorcunov unsigned long n; 478090f898eSCyrill Gorcunov 479090f898eSCyrill Gorcunov size &= ~7; /* mod 8 */ 480090f898eSCyrill Gorcunov if (!size) 481090f898eSCyrill Gorcunov return; 482090f898eSCyrill Gorcunov 4832a7d39a4SPekka Enberg p = guest_flat_to_host(self, addr); 484090f898eSCyrill Gorcunov 48548cf3877SPekka Enberg for (n = 0; n < size; n += 8) { 48648cf3877SPekka Enberg if (!host_ptr_in_ram(self, p + n)) 48748cf3877SPekka Enberg break; 48848cf3877SPekka Enberg 489090f898eSCyrill Gorcunov printf(" 0x%08lx: %02x %02x %02x %02x %02x %02x %02x %02x\n", 490090f898eSCyrill Gorcunov addr + n, p[n + 0], p[n + 1], p[n + 2], p[n + 3], 491090f898eSCyrill Gorcunov p[n + 4], p[n + 5], p[n + 6], p[n + 7]); 492090f898eSCyrill Gorcunov } 49348cf3877SPekka Enberg } 494