17281a8dbSDavid Daney #include "kvm/kvm.h" 27281a8dbSDavid Daney #include "kvm/ioport.h" 37281a8dbSDavid Daney #include "kvm/virtio-console.h" 47281a8dbSDavid Daney 57281a8dbSDavid Daney #include <linux/kvm.h> 67281a8dbSDavid Daney 77281a8dbSDavid Daney #include <ctype.h> 87281a8dbSDavid Daney #include <unistd.h> 9*1ade2d7dSDavid Daney #include <elf.h> 107281a8dbSDavid Daney 117281a8dbSDavid Daney struct kvm_ext kvm_req_ext[] = { 127281a8dbSDavid Daney { 0, 0 } 137281a8dbSDavid Daney }; 147281a8dbSDavid Daney 157281a8dbSDavid Daney void kvm__arch_read_term(struct kvm *kvm) 167281a8dbSDavid Daney { 177281a8dbSDavid Daney virtio_console__inject_interrupt(kvm); 187281a8dbSDavid Daney } 197281a8dbSDavid Daney 207281a8dbSDavid Daney void kvm__init_ram(struct kvm *kvm) 217281a8dbSDavid Daney { 227281a8dbSDavid Daney u64 phys_start, phys_size; 237281a8dbSDavid Daney void *host_mem; 247281a8dbSDavid Daney 257281a8dbSDavid Daney phys_start = 0; 267281a8dbSDavid Daney phys_size = kvm->ram_size; 277281a8dbSDavid Daney host_mem = kvm->ram_start; 287281a8dbSDavid Daney 297281a8dbSDavid Daney kvm__register_mem(kvm, phys_start, phys_size, host_mem); 307281a8dbSDavid Daney } 317281a8dbSDavid Daney 327281a8dbSDavid Daney void kvm__arch_delete_ram(struct kvm *kvm) 337281a8dbSDavid Daney { 347281a8dbSDavid Daney munmap(kvm->ram_start, kvm->ram_size); 357281a8dbSDavid Daney } 367281a8dbSDavid Daney 377281a8dbSDavid Daney void kvm__arch_set_cmdline(char *cmdline, bool video) 387281a8dbSDavid Daney { 397281a8dbSDavid Daney 407281a8dbSDavid Daney } 417281a8dbSDavid Daney 427281a8dbSDavid Daney /* Architecture-specific KVM init */ 437281a8dbSDavid Daney void kvm__arch_init(struct kvm *kvm, const char *hugetlbfs_path, u64 ram_size) 447281a8dbSDavid Daney { 457281a8dbSDavid Daney int ret; 467281a8dbSDavid Daney 477281a8dbSDavid Daney kvm->ram_start = mmap_anon_or_hugetlbfs(kvm, hugetlbfs_path, ram_size); 487281a8dbSDavid Daney kvm->ram_size = ram_size; 497281a8dbSDavid Daney 507281a8dbSDavid Daney if (kvm->ram_start == MAP_FAILED) 517281a8dbSDavid Daney die("out of memory"); 527281a8dbSDavid Daney 537281a8dbSDavid Daney madvise(kvm->ram_start, kvm->ram_size, MADV_MERGEABLE); 547281a8dbSDavid Daney 557281a8dbSDavid Daney ret = ioctl(kvm->vm_fd, KVM_CREATE_IRQCHIP); 567281a8dbSDavid Daney if (ret < 0) 577281a8dbSDavid Daney die_perror("KVM_CREATE_IRQCHIP ioctl"); 587281a8dbSDavid Daney } 597281a8dbSDavid Daney 607281a8dbSDavid Daney void kvm__irq_line(struct kvm *kvm, int irq, int level) 617281a8dbSDavid Daney { 627281a8dbSDavid Daney struct kvm_irq_level irq_level; 637281a8dbSDavid Daney int ret; 647281a8dbSDavid Daney 657281a8dbSDavid Daney irq_level.irq = irq; 667281a8dbSDavid Daney irq_level.level = level ? 1 : 0; 677281a8dbSDavid Daney 687281a8dbSDavid Daney ret = ioctl(kvm->vm_fd, KVM_IRQ_LINE, &irq_level); 697281a8dbSDavid Daney if (ret < 0) 707281a8dbSDavid Daney die_perror("KVM_IRQ_LINE ioctl"); 717281a8dbSDavid Daney } 727281a8dbSDavid Daney 737281a8dbSDavid Daney void kvm__irq_trigger(struct kvm *kvm, int irq) 747281a8dbSDavid Daney { 757281a8dbSDavid Daney struct kvm_irq_level irq_level; 767281a8dbSDavid Daney int ret; 777281a8dbSDavid Daney 787281a8dbSDavid Daney irq_level.irq = irq; 797281a8dbSDavid Daney irq_level.level = 1; 807281a8dbSDavid Daney 817281a8dbSDavid Daney ret = ioctl(kvm->vm_fd, KVM_IRQ_LINE, &irq_level); 827281a8dbSDavid Daney if (ret < 0) 837281a8dbSDavid Daney die_perror("KVM_IRQ_LINE ioctl"); 847281a8dbSDavid Daney } 857281a8dbSDavid Daney 867281a8dbSDavid Daney void ioport__setup_arch(struct kvm *kvm) 877281a8dbSDavid Daney { 887281a8dbSDavid Daney } 897281a8dbSDavid Daney 907281a8dbSDavid Daney bool kvm__arch_cpu_supports_vm(void) 917281a8dbSDavid Daney { 927281a8dbSDavid Daney return true; 937281a8dbSDavid Daney } 947281a8dbSDavid Daney bool kvm__load_firmware(struct kvm *kvm, const char *firmware_filename) 957281a8dbSDavid Daney { 967281a8dbSDavid Daney return false; 977281a8dbSDavid Daney } 987281a8dbSDavid Daney int kvm__arch_setup_firmware(struct kvm *kvm) 997281a8dbSDavid Daney { 1007281a8dbSDavid Daney return 0; 1017281a8dbSDavid Daney } 1027281a8dbSDavid Daney 103*1ade2d7dSDavid Daney static void kvm__mips_install_cmdline(struct kvm *kvm) 104*1ade2d7dSDavid Daney { 105*1ade2d7dSDavid Daney char *p = kvm->ram_start; 106*1ade2d7dSDavid Daney u64 cmdline_offset = 0x2000; 107*1ade2d7dSDavid Daney u64 argv_start = 0x3000; 108*1ade2d7dSDavid Daney u64 argv_offset = argv_start; 109*1ade2d7dSDavid Daney u64 argc = 0; 110*1ade2d7dSDavid Daney 111*1ade2d7dSDavid Daney sprintf(p + cmdline_offset, "mem=0x%llx@0 ", 112*1ade2d7dSDavid Daney (unsigned long long)kvm->ram_size); 113*1ade2d7dSDavid Daney 114*1ade2d7dSDavid Daney strcat(p + cmdline_offset, kvm->cfg.real_cmdline); /* maximum size is 2K */ 115*1ade2d7dSDavid Daney 116*1ade2d7dSDavid Daney while (p[cmdline_offset]) { 117*1ade2d7dSDavid Daney if (!isspace(p[cmdline_offset])) { 118*1ade2d7dSDavid Daney if (kvm->arch.is64bit) { 119*1ade2d7dSDavid Daney *(u64 *)(p + argv_offset) = 0xffffffff80000000ull + cmdline_offset; 120*1ade2d7dSDavid Daney argv_offset += sizeof(u64); 121*1ade2d7dSDavid Daney } else { 122*1ade2d7dSDavid Daney *(u32 *)(p + argv_offset) = 0x80000000u + cmdline_offset; 123*1ade2d7dSDavid Daney argv_offset += sizeof(u32); 124*1ade2d7dSDavid Daney } 125*1ade2d7dSDavid Daney argc++; 126*1ade2d7dSDavid Daney while(p[cmdline_offset] && !isspace(p[cmdline_offset])) 127*1ade2d7dSDavid Daney cmdline_offset++; 128*1ade2d7dSDavid Daney continue; 129*1ade2d7dSDavid Daney } 130*1ade2d7dSDavid Daney /* Must be a space character skip over these*/ 131*1ade2d7dSDavid Daney while(p[cmdline_offset] && isspace(p[cmdline_offset])) { 132*1ade2d7dSDavid Daney p[cmdline_offset] = 0; 133*1ade2d7dSDavid Daney cmdline_offset++; 134*1ade2d7dSDavid Daney } 135*1ade2d7dSDavid Daney } 136*1ade2d7dSDavid Daney kvm->arch.argc = argc; 137*1ade2d7dSDavid Daney kvm->arch.argv = 0xffffffff80000000ull + argv_start; 138*1ade2d7dSDavid Daney } 139*1ade2d7dSDavid Daney 1407281a8dbSDavid Daney /* Load at the 1M point. */ 1417281a8dbSDavid Daney #define KERNEL_LOAD_ADDR 0x1000000 1427281a8dbSDavid Daney int load_flat_binary(struct kvm *kvm, int fd_kernel, int fd_initrd, const char *kernel_cmdline) 1437281a8dbSDavid Daney { 1447281a8dbSDavid Daney void *p; 1457281a8dbSDavid Daney void *k_start; 1467281a8dbSDavid Daney int nr; 1477281a8dbSDavid Daney 1487281a8dbSDavid Daney if (lseek(fd_kernel, 0, SEEK_SET) < 0) 1497281a8dbSDavid Daney die_perror("lseek"); 1507281a8dbSDavid Daney 1517281a8dbSDavid Daney p = k_start = guest_flat_to_host(kvm, KERNEL_LOAD_ADDR); 1527281a8dbSDavid Daney 1537281a8dbSDavid Daney while ((nr = read(fd_kernel, p, 65536)) > 0) 1547281a8dbSDavid Daney p += nr; 1557281a8dbSDavid Daney 1567281a8dbSDavid Daney kvm->arch.is64bit = true; 1577281a8dbSDavid Daney kvm->arch.entry_point = 0xffffffff81000000ull; 1587281a8dbSDavid Daney 1597281a8dbSDavid Daney pr_info("Loaded kernel to 0x%x (%ld bytes)", KERNEL_LOAD_ADDR, (long int)(p - k_start)); 1607281a8dbSDavid Daney 1617281a8dbSDavid Daney return true; 1627281a8dbSDavid Daney } 1637281a8dbSDavid Daney 164*1ade2d7dSDavid Daney struct kvm__arch_elf_info { 165*1ade2d7dSDavid Daney u64 load_addr; 166*1ade2d7dSDavid Daney u64 entry_point; 167*1ade2d7dSDavid Daney size_t len; 168*1ade2d7dSDavid Daney size_t offset; 169*1ade2d7dSDavid Daney }; 170*1ade2d7dSDavid Daney 171*1ade2d7dSDavid Daney static bool kvm__arch_get_elf_64_info(Elf64_Ehdr *ehdr, int fd_kernel, 172*1ade2d7dSDavid Daney struct kvm__arch_elf_info *ei) 173*1ade2d7dSDavid Daney { 174*1ade2d7dSDavid Daney int i; 175*1ade2d7dSDavid Daney size_t nr; 176*1ade2d7dSDavid Daney Elf64_Phdr phdr; 177*1ade2d7dSDavid Daney 178*1ade2d7dSDavid Daney if (ehdr->e_phentsize != sizeof(phdr)) { 179*1ade2d7dSDavid Daney pr_info("Incompatible ELF PHENTSIZE %d", ehdr->e_phentsize); 180*1ade2d7dSDavid Daney return false; 181*1ade2d7dSDavid Daney } 182*1ade2d7dSDavid Daney 183*1ade2d7dSDavid Daney ei->entry_point = ehdr->e_entry; 184*1ade2d7dSDavid Daney 185*1ade2d7dSDavid Daney if (lseek(fd_kernel, ehdr->e_phoff, SEEK_SET) < 0) 186*1ade2d7dSDavid Daney die_perror("lseek"); 187*1ade2d7dSDavid Daney 188*1ade2d7dSDavid Daney phdr.p_type = PT_NULL; 189*1ade2d7dSDavid Daney for (i = 0; i < ehdr->e_phnum; i++) { 190*1ade2d7dSDavid Daney nr = read(fd_kernel, &phdr, sizeof(phdr)); 191*1ade2d7dSDavid Daney if (nr != sizeof(phdr)) { 192*1ade2d7dSDavid Daney pr_info("Couldn't read %d bytes for ELF PHDR.", (int)sizeof(phdr)); 193*1ade2d7dSDavid Daney return false; 194*1ade2d7dSDavid Daney } 195*1ade2d7dSDavid Daney if (phdr.p_type == PT_LOAD) 196*1ade2d7dSDavid Daney break; 197*1ade2d7dSDavid Daney } 198*1ade2d7dSDavid Daney if (phdr.p_type != PT_LOAD) { 199*1ade2d7dSDavid Daney pr_info("No PT_LOAD Program Header found."); 200*1ade2d7dSDavid Daney return false; 201*1ade2d7dSDavid Daney } 202*1ade2d7dSDavid Daney 203*1ade2d7dSDavid Daney ei->load_addr = phdr.p_paddr; 204*1ade2d7dSDavid Daney 205*1ade2d7dSDavid Daney if ((ei->load_addr & 0xffffffffc0000000ull) == 0xffffffff80000000ull) 206*1ade2d7dSDavid Daney ei->load_addr &= 0x1ffffffful; /* Convert KSEG{0,1} to physical. */ 207*1ade2d7dSDavid Daney if ((ei->load_addr & 0xc000000000000000ull) == 0x8000000000000000ull) 208*1ade2d7dSDavid Daney ei->load_addr &= 0x07ffffffffffffffull; /* Convert XKPHYS to pysical */ 209*1ade2d7dSDavid Daney 210*1ade2d7dSDavid Daney 211*1ade2d7dSDavid Daney ei->len = phdr.p_filesz; 212*1ade2d7dSDavid Daney ei->offset = phdr.p_offset; 213*1ade2d7dSDavid Daney 214*1ade2d7dSDavid Daney return true; 215*1ade2d7dSDavid Daney } 216*1ade2d7dSDavid Daney 217*1ade2d7dSDavid Daney static bool kvm__arch_get_elf_32_info(Elf32_Ehdr *ehdr, int fd_kernel, 218*1ade2d7dSDavid Daney struct kvm__arch_elf_info *ei) 219*1ade2d7dSDavid Daney { 220*1ade2d7dSDavid Daney int i; 221*1ade2d7dSDavid Daney size_t nr; 222*1ade2d7dSDavid Daney Elf32_Phdr phdr; 223*1ade2d7dSDavid Daney 224*1ade2d7dSDavid Daney if (ehdr->e_phentsize != sizeof(phdr)) { 225*1ade2d7dSDavid Daney pr_info("Incompatible ELF PHENTSIZE %d", ehdr->e_phentsize); 226*1ade2d7dSDavid Daney return false; 227*1ade2d7dSDavid Daney } 228*1ade2d7dSDavid Daney 229*1ade2d7dSDavid Daney ei->entry_point = (s64)((s32)ehdr->e_entry); 230*1ade2d7dSDavid Daney 231*1ade2d7dSDavid Daney if (lseek(fd_kernel, ehdr->e_phoff, SEEK_SET) < 0) 232*1ade2d7dSDavid Daney die_perror("lseek"); 233*1ade2d7dSDavid Daney 234*1ade2d7dSDavid Daney phdr.p_type = PT_NULL; 235*1ade2d7dSDavid Daney for (i = 0; i < ehdr->e_phnum; i++) { 236*1ade2d7dSDavid Daney nr = read(fd_kernel, &phdr, sizeof(phdr)); 237*1ade2d7dSDavid Daney if (nr != sizeof(phdr)) { 238*1ade2d7dSDavid Daney pr_info("Couldn't read %d bytes for ELF PHDR.", (int)sizeof(phdr)); 239*1ade2d7dSDavid Daney return false; 240*1ade2d7dSDavid Daney } 241*1ade2d7dSDavid Daney if (phdr.p_type == PT_LOAD) 242*1ade2d7dSDavid Daney break; 243*1ade2d7dSDavid Daney } 244*1ade2d7dSDavid Daney if (phdr.p_type != PT_LOAD) { 245*1ade2d7dSDavid Daney pr_info("No PT_LOAD Program Header found."); 246*1ade2d7dSDavid Daney return false; 247*1ade2d7dSDavid Daney } 248*1ade2d7dSDavid Daney 249*1ade2d7dSDavid Daney ei->load_addr = (s64)((s32)phdr.p_paddr); 250*1ade2d7dSDavid Daney 251*1ade2d7dSDavid Daney if ((ei->load_addr & 0xffffffffc0000000ull) == 0xffffffff80000000ull) 252*1ade2d7dSDavid Daney ei->load_addr &= 0x1fffffffull; /* Convert KSEG{0,1} to physical. */ 253*1ade2d7dSDavid Daney 254*1ade2d7dSDavid Daney ei->len = phdr.p_filesz; 255*1ade2d7dSDavid Daney ei->offset = phdr.p_offset; 256*1ade2d7dSDavid Daney 257*1ade2d7dSDavid Daney return true; 258*1ade2d7dSDavid Daney } 259*1ade2d7dSDavid Daney 260*1ade2d7dSDavid Daney int load_elf_binary(struct kvm *kvm, int fd_kernel, int fd_initrd, const char *kernel_cmdline) 261*1ade2d7dSDavid Daney { 262*1ade2d7dSDavid Daney union { 263*1ade2d7dSDavid Daney Elf64_Ehdr ehdr; 264*1ade2d7dSDavid Daney Elf32_Ehdr ehdr32; 265*1ade2d7dSDavid Daney } eh; 266*1ade2d7dSDavid Daney 267*1ade2d7dSDavid Daney size_t nr; 268*1ade2d7dSDavid Daney char *p; 269*1ade2d7dSDavid Daney struct kvm__arch_elf_info ei; 270*1ade2d7dSDavid Daney 271*1ade2d7dSDavid Daney if (lseek(fd_kernel, 0, SEEK_SET) < 0) 272*1ade2d7dSDavid Daney die_perror("lseek"); 273*1ade2d7dSDavid Daney 274*1ade2d7dSDavid Daney nr = read(fd_kernel, &eh, sizeof(eh)); 275*1ade2d7dSDavid Daney if (nr != sizeof(eh)) { 276*1ade2d7dSDavid Daney pr_info("Couldn't read %d bytes for ELF header.", (int)sizeof(eh)); 277*1ade2d7dSDavid Daney return false; 278*1ade2d7dSDavid Daney } 279*1ade2d7dSDavid Daney 280*1ade2d7dSDavid Daney if (eh.ehdr.e_ident[EI_MAG0] != ELFMAG0 || 281*1ade2d7dSDavid Daney eh.ehdr.e_ident[EI_MAG1] != ELFMAG1 || 282*1ade2d7dSDavid Daney eh.ehdr.e_ident[EI_MAG2] != ELFMAG2 || 283*1ade2d7dSDavid Daney eh.ehdr.e_ident[EI_MAG3] != ELFMAG3 || 284*1ade2d7dSDavid Daney (eh.ehdr.e_ident[EI_CLASS] != ELFCLASS64 && eh.ehdr.e_ident[EI_CLASS] != ELFCLASS32) || 285*1ade2d7dSDavid Daney eh.ehdr.e_ident[EI_VERSION] != EV_CURRENT) { 286*1ade2d7dSDavid Daney pr_info("Incompatible ELF header."); 287*1ade2d7dSDavid Daney return false; 288*1ade2d7dSDavid Daney } 289*1ade2d7dSDavid Daney if (eh.ehdr.e_type != ET_EXEC || eh.ehdr.e_machine != EM_MIPS) { 290*1ade2d7dSDavid Daney pr_info("Incompatible ELF not MIPS EXEC."); 291*1ade2d7dSDavid Daney return false; 292*1ade2d7dSDavid Daney } 293*1ade2d7dSDavid Daney 294*1ade2d7dSDavid Daney if (eh.ehdr.e_ident[EI_CLASS] == ELFCLASS64) { 295*1ade2d7dSDavid Daney if (!kvm__arch_get_elf_64_info(&eh.ehdr, fd_kernel, &ei)) 296*1ade2d7dSDavid Daney return false; 297*1ade2d7dSDavid Daney kvm->arch.is64bit = true; 298*1ade2d7dSDavid Daney } else { 299*1ade2d7dSDavid Daney if (!kvm__arch_get_elf_32_info(&eh.ehdr32, fd_kernel, &ei)) 300*1ade2d7dSDavid Daney return false; 301*1ade2d7dSDavid Daney kvm->arch.is64bit = false; 302*1ade2d7dSDavid Daney } 303*1ade2d7dSDavid Daney 304*1ade2d7dSDavid Daney kvm->arch.entry_point = ei.entry_point; 305*1ade2d7dSDavid Daney 306*1ade2d7dSDavid Daney if (lseek(fd_kernel, ei.offset, SEEK_SET) < 0) 307*1ade2d7dSDavid Daney die_perror("lseek"); 308*1ade2d7dSDavid Daney 309*1ade2d7dSDavid Daney p = guest_flat_to_host(kvm, ei.load_addr); 310*1ade2d7dSDavid Daney 311*1ade2d7dSDavid Daney pr_info("ELF Loading 0x%lx bytes from 0x%llx to 0x%llx", 312*1ade2d7dSDavid Daney (unsigned long)ei.len, (unsigned long long)ei.offset, (unsigned long long)ei.load_addr); 313*1ade2d7dSDavid Daney do { 314*1ade2d7dSDavid Daney nr = read(fd_kernel, p, ei.len); 315*1ade2d7dSDavid Daney if (nr < 0) 316*1ade2d7dSDavid Daney die_perror("read"); 317*1ade2d7dSDavid Daney p += nr; 318*1ade2d7dSDavid Daney ei.len -= nr; 319*1ade2d7dSDavid Daney } while (ei.len); 320*1ade2d7dSDavid Daney 321*1ade2d7dSDavid Daney kvm__mips_install_cmdline(kvm); 322*1ade2d7dSDavid Daney 323*1ade2d7dSDavid Daney return true; 324*1ade2d7dSDavid Daney } 325*1ade2d7dSDavid Daney 3267281a8dbSDavid Daney void ioport__map_irq(u8 *irq) 3277281a8dbSDavid Daney { 3287281a8dbSDavid Daney } 329