1ece09f8fSPekka Enberg #include "kvm/builtin-run.h" 2ece09f8fSPekka Enberg 3c8675741SSasha Levin #include "kvm/builtin-setup.h" 4ece09f8fSPekka Enberg #include "kvm/virtio-balloon.h" 5ece09f8fSPekka Enberg #include "kvm/virtio-console.h" 6ece09f8fSPekka Enberg #include "kvm/parse-options.h" 7ece09f8fSPekka Enberg #include "kvm/8250-serial.h" 8ece09f8fSPekka Enberg #include "kvm/framebuffer.h" 9ece09f8fSPekka Enberg #include "kvm/disk-image.h" 10ece09f8fSPekka Enberg #include "kvm/threadpool.h" 11a67da3beSAsias He #include "kvm/virtio-scsi.h" 12ece09f8fSPekka Enberg #include "kvm/virtio-blk.h" 13ece09f8fSPekka Enberg #include "kvm/virtio-net.h" 14ece09f8fSPekka Enberg #include "kvm/virtio-rng.h" 15ece09f8fSPekka Enberg #include "kvm/ioeventfd.h" 16ece09f8fSPekka Enberg #include "kvm/virtio-9p.h" 17ece09f8fSPekka Enberg #include "kvm/barrier.h" 18ece09f8fSPekka Enberg #include "kvm/kvm-cpu.h" 19ece09f8fSPekka Enberg #include "kvm/ioport.h" 20ece09f8fSPekka Enberg #include "kvm/symbol.h" 21ece09f8fSPekka Enberg #include "kvm/i8042.h" 22ece09f8fSPekka Enberg #include "kvm/mutex.h" 23ece09f8fSPekka Enberg #include "kvm/term.h" 24ece09f8fSPekka Enberg #include "kvm/util.h" 25ec52d504SLai Jiangshan #include "kvm/strbuf.h" 26ece09f8fSPekka Enberg #include "kvm/vesa.h" 27ece09f8fSPekka Enberg #include "kvm/irq.h" 28ece09f8fSPekka Enberg #include "kvm/kvm.h" 29ece09f8fSPekka Enberg #include "kvm/pci.h" 30ece09f8fSPekka Enberg #include "kvm/rtc.h" 31ece09f8fSPekka Enberg #include "kvm/sdl.h" 32ece09f8fSPekka Enberg #include "kvm/vnc.h" 33e6694207SSasha Levin #include "kvm/guest_compat.h" 344b1addaeSSasha Levin #include "kvm/kvm-ipc.h" 354b1c6f6eSSasha Levin #include "kvm/builtin-debug.h" 36ece09f8fSPekka Enberg 37ece09f8fSPekka Enberg #include <linux/types.h> 3848d9e01aSSasha Levin #include <linux/err.h> 399d655190SAlexandru Elisei #include <linux/sizes.h> 40ece09f8fSPekka Enberg 418329f30bSPekka Enberg #include <sys/utsname.h> 428329f30bSPekka Enberg #include <sys/types.h> 438329f30bSPekka Enberg #include <sys/stat.h> 44ece09f8fSPekka Enberg #include <termios.h> 45ece09f8fSPekka Enberg #include <signal.h> 46ece09f8fSPekka Enberg #include <stdlib.h> 47ece09f8fSPekka Enberg #include <string.h> 48ece09f8fSPekka Enberg #include <unistd.h> 4926c853e4SPrasad Joshi #include <ctype.h> 50ece09f8fSPekka Enberg #include <stdio.h> 51f967c427SPrasad Joshi 5295d13a52SSasha Levin #define KB_SHIFT (10) 53*a9c24ec7SSuzuki K Poulose #define MB_SHIFT (20) 5495d13a52SSasha Levin #define GB_SHIFT (30) 55*a9c24ec7SSuzuki K Poulose #define TB_SHIFT (40) 56*a9c24ec7SSuzuki K Poulose #define PB_SHIFT (50) 57f967c427SPrasad Joshi 58656be1b8SSasha Levin __thread struct kvm_cpu *current_kvm_cpu; 59f967c427SPrasad Joshi 603c29e2aaSSasha Levin static int kvm_run_wrapper; 61f967c427SPrasad Joshi 62ed036f03SCyrill Gorcunov bool do_debug_print = false; 63ed036f03SCyrill Gorcunov 64f967c427SPrasad Joshi static const char * const run_usage[] = { 658d2ff5daSWanlong Gao "lkvm run [<options>] [<kernel image>]", 66f967c427SPrasad Joshi NULL 67f967c427SPrasad Joshi }; 68f967c427SPrasad Joshi 693c29e2aaSSasha Levin enum { 70e0747665SSasha Levin KVM_RUN_DEFAULT, 713c29e2aaSSasha Levin KVM_RUN_SANDBOX, 723c29e2aaSSasha Levin }; 733c29e2aaSSasha Levin 74a33979d8SSasha Levin static int img_name_parser(const struct option *opt, const char *arg, int unset) 75a33979d8SSasha Levin { 7682d65b5eSSasha Levin char path[PATH_MAX]; 775236b505SAsias He struct stat st; 78a33979d8SSasha Levin 799667701cSPekka Enberg snprintf(path, PATH_MAX, "%s%s", kvm__get_dir(), arg); 8082d65b5eSSasha Levin 81cac9e8fdSSasha Levin if ((stat(arg, &st) == 0 && S_ISDIR(st.st_mode)) || 82cac9e8fdSSasha Levin (stat(path, &st) == 0 && S_ISDIR(st.st_mode))) 83cac9e8fdSSasha Levin return virtio_9p_img_name_parser(opt, arg, unset); 843b55dcdeSSasha Levin return disk_img_name_parser(opt, arg, unset); 85a67da3beSAsias He } 86a67da3beSAsias He 873b55dcdeSSasha Levin void kvm_run_set_wrapper_sandbox(void) 883b55dcdeSSasha Levin { 893b55dcdeSSasha Levin kvm_run_wrapper = KVM_RUN_SANDBOX; 90a33979d8SSasha Levin } 91a33979d8SSasha Levin 92*a9c24ec7SSuzuki K Poulose static int parse_mem_unit(char **next) 93*a9c24ec7SSuzuki K Poulose { 94*a9c24ec7SSuzuki K Poulose switch (**next) { 95*a9c24ec7SSuzuki K Poulose case 'B': case 'b': (*next)++; return 0; 96*a9c24ec7SSuzuki K Poulose case 'K': case 'k': (*next)++; return KB_SHIFT; 97*a9c24ec7SSuzuki K Poulose case 'M': case 'm': (*next)++; return MB_SHIFT; 98*a9c24ec7SSuzuki K Poulose case 'G': case 'g': (*next)++; return GB_SHIFT; 99*a9c24ec7SSuzuki K Poulose case 'T': case 't': (*next)++; return TB_SHIFT; 100*a9c24ec7SSuzuki K Poulose case 'P': case 'p': (*next)++; return PB_SHIFT; 101*a9c24ec7SSuzuki K Poulose } 102*a9c24ec7SSuzuki K Poulose 103*a9c24ec7SSuzuki K Poulose return MB_SHIFT; 104*a9c24ec7SSuzuki K Poulose } 105*a9c24ec7SSuzuki K Poulose 106*a9c24ec7SSuzuki K Poulose static u64 parse_mem_option(const char *nptr, char **next) 107*a9c24ec7SSuzuki K Poulose { 108*a9c24ec7SSuzuki K Poulose u64 shift; 109*a9c24ec7SSuzuki K Poulose u64 val; 110*a9c24ec7SSuzuki K Poulose 111*a9c24ec7SSuzuki K Poulose errno = 0; 112*a9c24ec7SSuzuki K Poulose val = strtoull(nptr, next, 10); 113*a9c24ec7SSuzuki K Poulose if (errno == ERANGE) 114*a9c24ec7SSuzuki K Poulose die("Memory too large: %s", nptr); 115*a9c24ec7SSuzuki K Poulose if (*next == nptr) 116*a9c24ec7SSuzuki K Poulose die("Invalid memory specifier: %s", nptr); 117*a9c24ec7SSuzuki K Poulose 118*a9c24ec7SSuzuki K Poulose shift = parse_mem_unit(next); 119*a9c24ec7SSuzuki K Poulose if ((val << shift) < val) 120*a9c24ec7SSuzuki K Poulose die("Memory too large: %s", nptr); 121*a9c24ec7SSuzuki K Poulose 122*a9c24ec7SSuzuki K Poulose return val << shift; 123*a9c24ec7SSuzuki K Poulose } 124*a9c24ec7SSuzuki K Poulose 125*a9c24ec7SSuzuki K Poulose static int mem_parser(const struct option *opt, const char *arg, int unset) 126*a9c24ec7SSuzuki K Poulose { 127*a9c24ec7SSuzuki K Poulose struct kvm *kvm = opt->ptr; 128*a9c24ec7SSuzuki K Poulose char *next; 129*a9c24ec7SSuzuki K Poulose 130*a9c24ec7SSuzuki K Poulose kvm->cfg.ram_size = parse_mem_option(arg, &next); 131*a9c24ec7SSuzuki K Poulose if (kvm->cfg.ram_size == 0) 132*a9c24ec7SSuzuki K Poulose die("Invalid RAM size: %s", arg); 133*a9c24ec7SSuzuki K Poulose 134*a9c24ec7SSuzuki K Poulose if (*next != '\0') 135*a9c24ec7SSuzuki K Poulose die("Invalid memory specifier: %s", arg); 136*a9c24ec7SSuzuki K Poulose 137*a9c24ec7SSuzuki K Poulose return 0; 138*a9c24ec7SSuzuki K Poulose } 139*a9c24ec7SSuzuki K Poulose 140ff7ba6faSWill Deacon #ifndef OPT_ARCH_RUN 141ff7ba6faSWill Deacon #define OPT_ARCH_RUN(...) 142ff7ba6faSWill Deacon #endif 143ff7ba6faSWill Deacon 1443b55dcdeSSasha Levin #define BUILD_OPTIONS(name, cfg, kvm) \ 145b816364aSSasha Levin struct option name[] = { \ 146b816364aSSasha Levin OPT_GROUP("Basic options:"), \ 147b816364aSSasha Levin OPT_STRING('\0', "name", &(cfg)->guest_name, "guest name", \ 148b816364aSSasha Levin "A name for the guest"), \ 14900ebbe96SSasha Levin OPT_INTEGER('c', "cpus", &(cfg)->nrcpus, "Number of CPUs"), \ 150*a9c24ec7SSuzuki K Poulose OPT_CALLBACK('m', "mem", NULL, "size[BKMGTP]", \ 151*a9c24ec7SSuzuki K Poulose "Virtual machine memory size, by default measured" \ 152*a9c24ec7SSuzuki K Poulose " in megabytes (M)", mem_parser, kvm), \ 153b5e56fa3SWilliam Dauchy OPT_CALLBACK('d', "disk", kvm, "image or rootfs_dir", "Disk " \ 154b5e56fa3SWilliam Dauchy " image or rootfs directory", img_name_parser, \ 1553b55dcdeSSasha Levin kvm), \ 156b5e56fa3SWilliam Dauchy OPT_BOOLEAN('\0', "balloon", &(cfg)->balloon, "Enable virtio" \ 157b5e56fa3SWilliam Dauchy " balloon"), \ 158b816364aSSasha Levin OPT_BOOLEAN('\0', "vnc", &(cfg)->vnc, "Enable VNC framebuffer"),\ 1597bcceb95SPekka Enberg OPT_BOOLEAN('\0', "gtk", &(cfg)->gtk, "Enable GTK framebuffer"),\ 160b816364aSSasha Levin OPT_BOOLEAN('\0', "sdl", &(cfg)->sdl, "Enable SDL framebuffer"),\ 161b5e56fa3SWilliam Dauchy OPT_BOOLEAN('\0', "rng", &(cfg)->virtio_rng, "Enable virtio" \ 162b5e56fa3SWilliam Dauchy " Random Number Generator"), \ 1635613ae26SAlexandru Elisei OPT_BOOLEAN('\0', "nodefaults", &(cfg)->nodefaults, "Disable" \ 1645613ae26SAlexandru Elisei " implicit configuration that cannot be" \ 1655613ae26SAlexandru Elisei " disabled otherwise"), \ 166b816364aSSasha Levin OPT_CALLBACK('\0', "9p", NULL, "dir_to_share,tag_name", \ 167b5e56fa3SWilliam Dauchy "Enable virtio 9p to share files between host and" \ 168b5e56fa3SWilliam Dauchy " guest", virtio_9p_rootdir_parser, kvm), \ 169b5e56fa3SWilliam Dauchy OPT_STRING('\0', "console", &(cfg)->console, "serial, virtio or"\ 170b5e56fa3SWilliam Dauchy " hv", "Console to use"), \ 171117d6495STianjia Zhang OPT_U64('\0', "vsock", &(cfg)->vsock_cid, \ 172117d6495STianjia Zhang "Guest virtio socket CID"), \ 173b816364aSSasha Levin OPT_STRING('\0', "dev", &(cfg)->dev, "device_file", \ 174b816364aSSasha Levin "KVM device file"), \ 175b816364aSSasha Levin OPT_CALLBACK('\0', "tty", NULL, "tty id", \ 176b816364aSSasha Levin "Remap guest TTY into a pty on the host", \ 1771dc24dccSSasha Levin tty_parser, NULL), \ 178b816364aSSasha Levin OPT_STRING('\0', "sandbox", &(cfg)->sandbox, "script", \ 179b5e56fa3SWilliam Dauchy "Run this script when booting into custom" \ 180b5e56fa3SWilliam Dauchy " rootfs"), \ 181b816364aSSasha Levin OPT_STRING('\0', "hugetlbfs", &(cfg)->hugetlbfs_path, "path", \ 182b816364aSSasha Levin "Hugetlbfs path"), \ 183b816364aSSasha Levin \ 184b816364aSSasha Levin OPT_GROUP("Kernel options:"), \ 185b816364aSSasha Levin OPT_STRING('k', "kernel", &(cfg)->kernel_filename, "kernel", \ 186b816364aSSasha Levin "Kernel to boot in virtual machine"), \ 187b816364aSSasha Levin OPT_STRING('i', "initrd", &(cfg)->initrd_filename, "initrd", \ 188b816364aSSasha Levin "Initial RAM disk image"), \ 189b816364aSSasha Levin OPT_STRING('p', "params", &(cfg)->kernel_cmdline, "params", \ 190b816364aSSasha Levin "Kernel command line arguments"), \ 191b816364aSSasha Levin OPT_STRING('f', "firmware", &(cfg)->firmware_filename, "firmware",\ 192b816364aSSasha Levin "Firmware image to boot in virtual machine"), \ 19325cf3198SRaphael Gault OPT_STRING('F', "flash", &(cfg)->flash_filename, "flash",\ 19425cf3198SRaphael Gault "Flash image to present to virtual machine"), \ 195b816364aSSasha Levin \ 196b816364aSSasha Levin OPT_GROUP("Networking options:"), \ 197b816364aSSasha Levin OPT_CALLBACK_DEFAULT('n', "network", NULL, "network params", \ 198b816364aSSasha Levin "Create a new guest NIC", \ 1995f225124SSasha Levin netdev_parser, NULL, kvm), \ 200b5e56fa3SWilliam Dauchy OPT_BOOLEAN('\0', "no-dhcp", &(cfg)->no_dhcp, "Disable kernel" \ 201b5e56fa3SWilliam Dauchy " DHCP in rootfs mode"), \ 202b816364aSSasha Levin \ 2036078a454SJean-Philippe Brucker OPT_GROUP("VFIO options:"), \ 2046078a454SJean-Philippe Brucker OPT_CALLBACK('\0', "vfio-pci", NULL, "[domain:]bus:dev.fn", \ 2056078a454SJean-Philippe Brucker "Assign a PCI device to the virtual machine", \ 2066078a454SJean-Philippe Brucker vfio_device_parser, kvm), \ 2076078a454SJean-Philippe Brucker \ 208b816364aSSasha Levin OPT_GROUP("Debug options:"), \ 209b816364aSSasha Levin OPT_BOOLEAN('\0', "debug", &do_debug_print, \ 210b816364aSSasha Levin "Enable debug messages"), \ 211b816364aSSasha Levin OPT_BOOLEAN('\0', "debug-single-step", &(cfg)->single_step, \ 212b816364aSSasha Levin "Enable single stepping"), \ 2135765977dSSasha Levin OPT_BOOLEAN('\0', "debug-ioport", &(cfg)->ioport_debug, \ 214b816364aSSasha Levin "Enable ioport debugging"), \ 215e830cce7SSasha Levin OPT_BOOLEAN('\0', "debug-mmio", &(cfg)->mmio_debug, \ 216b816364aSSasha Levin "Enable MMIO debugging"), \ 2173b55dcdeSSasha Levin OPT_INTEGER('\0', "debug-iodelay", &(cfg)->debug_iodelay, \ 218b816364aSSasha Levin "Delay IO by millisecond"), \ 219ff7ba6faSWill Deacon \ 220ff7ba6faSWill Deacon OPT_ARCH(RUN, cfg) \ 221b816364aSSasha Levin OPT_END() \ 222f967c427SPrasad Joshi }; 223f967c427SPrasad Joshi 2245ee154d1SPekka Enberg static void *kvm_cpu_thread(void *arg) 2255ee154d1SPekka Enberg { 226a4d8c55eSSasha Levin char name[16]; 227a4d8c55eSSasha Levin 228d77a9efaSCyrill Gorcunov current_kvm_cpu = arg; 2295ee154d1SPekka Enberg 230a4d8c55eSSasha Levin sprintf(name, "kvm-vcpu-%lu", current_kvm_cpu->cpu_id); 231a4d8c55eSSasha Levin kvm__set_thread_name(name); 232a4d8c55eSSasha Levin 233d77a9efaSCyrill Gorcunov if (kvm_cpu__start(current_kvm_cpu)) 2345ee154d1SPekka Enberg goto panic_kvm; 2355ee154d1SPekka Enberg 2365ee154d1SPekka Enberg return (void *) (intptr_t) 0; 2375ee154d1SPekka Enberg 2385ee154d1SPekka Enberg panic_kvm: 2393fdf659dSSasha Levin fprintf(stderr, "KVM exit reason: %u (\"%s\")\n", 240d77a9efaSCyrill Gorcunov current_kvm_cpu->kvm_run->exit_reason, 241d77a9efaSCyrill Gorcunov kvm_exit_reasons[current_kvm_cpu->kvm_run->exit_reason]); 242d77a9efaSCyrill Gorcunov if (current_kvm_cpu->kvm_run->exit_reason == KVM_EXIT_UNKNOWN) 24369f50425SAndreas Herrmann fprintf(stderr, "KVM exit code: 0x%llu\n", 24469f50425SAndreas Herrmann (unsigned long long)current_kvm_cpu->kvm_run->hw.hardware_exit_reason); 2458e5accedSPekka Enberg 246b7d2f013SSasha Levin kvm_cpu__set_debug_fd(STDOUT_FILENO); 247d77a9efaSCyrill Gorcunov kvm_cpu__show_registers(current_kvm_cpu); 248d77a9efaSCyrill Gorcunov kvm_cpu__show_code(current_kvm_cpu); 249d77a9efaSCyrill Gorcunov kvm_cpu__show_page_tables(current_kvm_cpu); 2505ee154d1SPekka Enberg 2515ee154d1SPekka Enberg return (void *) (intptr_t) 1; 2525ee154d1SPekka Enberg } 2535ee154d1SPekka Enberg 254e08c0896SPrasad Joshi static char kernel[PATH_MAX]; 255b0b42ba0SPekka Enberg 256b0b42ba0SPekka Enberg static const char *host_kernels[] = { 257e08c0896SPrasad Joshi "/boot/vmlinuz", 258e08c0896SPrasad Joshi "/boot/bzImage", 259e08c0896SPrasad Joshi NULL 260e08c0896SPrasad Joshi }; 261b0b42ba0SPekka Enberg 262b0b42ba0SPekka Enberg static const char *default_kernels[] = { 263e08c0896SPrasad Joshi "./bzImage", 264b03af790SKonstantin Khlebnikov "arch/" BUILD_ARCH "/boot/bzImage", 265af7b0868SMatt Evans "../../arch/" BUILD_ARCH "/boot/bzImage", 266e08c0896SPrasad Joshi NULL 267e08c0896SPrasad Joshi }; 2688329f30bSPekka Enberg 269b0b42ba0SPekka Enberg static const char *default_vmlinux[] = { 270b03af790SKonstantin Khlebnikov "vmlinux", 271b0b42ba0SPekka Enberg "../../../vmlinux", 272b0b42ba0SPekka Enberg "../../vmlinux", 273b0b42ba0SPekka Enberg NULL 274b0b42ba0SPekka Enberg }; 275b0b42ba0SPekka Enberg 276e08c0896SPrasad Joshi static void kernel_usage_with_options(void) 2778329f30bSPekka Enberg { 278e08c0896SPrasad Joshi const char **k; 2798329f30bSPekka Enberg struct utsname uts; 280e08c0896SPrasad Joshi 281e08c0896SPrasad Joshi fprintf(stderr, "Fatal: could not find default kernel image in:\n"); 28265182f37SPrasad Joshi k = &default_kernels[0]; 283e08c0896SPrasad Joshi while (*k) { 284e08c0896SPrasad Joshi fprintf(stderr, "\t%s\n", *k); 285e08c0896SPrasad Joshi k++; 286e08c0896SPrasad Joshi } 287e08c0896SPrasad Joshi 288e08c0896SPrasad Joshi if (uname(&uts) < 0) 289e08c0896SPrasad Joshi return; 290e08c0896SPrasad Joshi 291e08c0896SPrasad Joshi k = &host_kernels[0]; 292e08c0896SPrasad Joshi while (*k) { 293e08c0896SPrasad Joshi if (snprintf(kernel, PATH_MAX, "%s-%s", *k, uts.release) < 0) 294e08c0896SPrasad Joshi return; 295e08c0896SPrasad Joshi fprintf(stderr, "\t%s\n", kernel); 296e08c0896SPrasad Joshi k++; 297e08c0896SPrasad Joshi } 298ee8b1456SWanlong Gao fprintf(stderr, "\nPlease see '%s run --help' for more options.\n\n", 299ee8b1456SWanlong Gao KVM_BINARY_NAME); 300e08c0896SPrasad Joshi } 301e08c0896SPrasad Joshi 30260ded003SPekka Enberg static u64 host_ram_size(void) 30360ded003SPekka Enberg { 30460ded003SPekka Enberg long page_size; 30560ded003SPekka Enberg long nr_pages; 30660ded003SPekka Enberg 30760ded003SPekka Enberg nr_pages = sysconf(_SC_PHYS_PAGES); 308d63c5ce6SPekka Enberg if (nr_pages < 0) { 3094542f276SCyrill Gorcunov pr_warning("sysconf(_SC_PHYS_PAGES) failed"); 310d63c5ce6SPekka Enberg return 0; 311d63c5ce6SPekka Enberg } 31260ded003SPekka Enberg 31360ded003SPekka Enberg page_size = sysconf(_SC_PAGE_SIZE); 314d63c5ce6SPekka Enberg if (page_size < 0) { 3154542f276SCyrill Gorcunov pr_warning("sysconf(_SC_PAGE_SIZE) failed"); 316d63c5ce6SPekka Enberg return 0; 317d63c5ce6SPekka Enberg } 31860ded003SPekka Enberg 3199d655190SAlexandru Elisei return (u64)nr_pages * page_size; 32060ded003SPekka Enberg } 32160ded003SPekka Enberg 32218bd8c3bSPekka Enberg /* 32318bd8c3bSPekka Enberg * If user didn't specify how much memory it wants to allocate for the guest, 32418bd8c3bSPekka Enberg * avoid filling the whole host RAM. 32518bd8c3bSPekka Enberg */ 32618bd8c3bSPekka Enberg #define RAM_SIZE_RATIO 0.8 32718bd8c3bSPekka Enberg 328fd834defSPekka Enberg static u64 get_ram_size(int nr_cpus) 329fd834defSPekka Enberg { 33006761c76SPekka Enberg u64 available; 33106761c76SPekka Enberg u64 ram_size; 332fd834defSPekka Enberg 3339d655190SAlexandru Elisei ram_size = (u64)SZ_64M * (nr_cpus + 3); 334fd834defSPekka Enberg 33560ded003SPekka Enberg available = host_ram_size() * RAM_SIZE_RATIO; 336d63c5ce6SPekka Enberg if (!available) 3379d655190SAlexandru Elisei available = MIN_RAM_SIZE; 338fd834defSPekka Enberg 339fd834defSPekka Enberg if (ram_size > available) 340fd834defSPekka Enberg ram_size = available; 341fd834defSPekka Enberg 342fd834defSPekka Enberg return ram_size; 343fd834defSPekka Enberg } 344fd834defSPekka Enberg 345e08c0896SPrasad Joshi static const char *find_kernel(void) 346e08c0896SPrasad Joshi { 347e08c0896SPrasad Joshi const char **k; 3488329f30bSPekka Enberg struct stat st; 349e08c0896SPrasad Joshi struct utsname uts; 350e08c0896SPrasad Joshi 35165182f37SPrasad Joshi k = &default_kernels[0]; 352e08c0896SPrasad Joshi while (*k) { 353e08c0896SPrasad Joshi if (stat(*k, &st) < 0 || !S_ISREG(st.st_mode)) { 354e08c0896SPrasad Joshi k++; 355e08c0896SPrasad Joshi continue; 356e08c0896SPrasad Joshi } 357266a0ed4SAndre Przywara strlcpy(kernel, *k, PATH_MAX); 358e08c0896SPrasad Joshi return kernel; 359e08c0896SPrasad Joshi } 3608329f30bSPekka Enberg 3618329f30bSPekka Enberg if (uname(&uts) < 0) 3628329f30bSPekka Enberg return NULL; 3638329f30bSPekka Enberg 364e08c0896SPrasad Joshi k = &host_kernels[0]; 365e08c0896SPrasad Joshi while (*k) { 366e08c0896SPrasad Joshi if (snprintf(kernel, PATH_MAX, "%s-%s", *k, uts.release) < 0) 3678329f30bSPekka Enberg return NULL; 3688329f30bSPekka Enberg 369e08c0896SPrasad Joshi if (stat(kernel, &st) < 0 || !S_ISREG(st.st_mode)) { 370e08c0896SPrasad Joshi k++; 371e08c0896SPrasad Joshi continue; 372e08c0896SPrasad Joshi } 373e08c0896SPrasad Joshi return kernel; 3748329f30bSPekka Enberg 375e08c0896SPrasad Joshi } 3768329f30bSPekka Enberg return NULL; 3778329f30bSPekka Enberg } 3788329f30bSPekka Enberg 379b0b42ba0SPekka Enberg static const char *find_vmlinux(void) 380b0b42ba0SPekka Enberg { 381b0b42ba0SPekka Enberg const char **vmlinux; 382b0b42ba0SPekka Enberg 383b0b42ba0SPekka Enberg vmlinux = &default_vmlinux[0]; 384b0b42ba0SPekka Enberg while (*vmlinux) { 385b0b42ba0SPekka Enberg struct stat st; 386b0b42ba0SPekka Enberg 387b0b42ba0SPekka Enberg if (stat(*vmlinux, &st) < 0 || !S_ISREG(st.st_mode)) { 388b0b42ba0SPekka Enberg vmlinux++; 389b0b42ba0SPekka Enberg continue; 390b0b42ba0SPekka Enberg } 391b0b42ba0SPekka Enberg return *vmlinux; 392b0b42ba0SPekka Enberg } 393b0b42ba0SPekka Enberg return NULL; 394b0b42ba0SPekka Enberg } 395b0b42ba0SPekka Enberg 396f6677a1dSAmerigo Wang void kvm_run_help(void) 397f6677a1dSAmerigo Wang { 3984346fd8fSSasha Levin struct kvm *kvm = NULL; 3994346fd8fSSasha Levin 4003b55dcdeSSasha Levin BUILD_OPTIONS(options, &kvm->cfg, kvm); 401f6677a1dSAmerigo Wang usage_with_options(run_usage, options); 402f6677a1dSAmerigo Wang } 403f6677a1dSAmerigo Wang 4044346fd8fSSasha Levin static int kvm_run_set_sandbox(struct kvm *kvm) 405d50fe489SSasha Levin { 40647621338SSasha Levin const char *guestfs_name = kvm->cfg.custom_rootfs_name; 407d50fe489SSasha Levin char path[PATH_MAX], script[PATH_MAX], *tmp; 408d50fe489SSasha Levin 409d50fe489SSasha Levin snprintf(path, PATH_MAX, "%s%s/virt/sandbox.sh", kvm__get_dir(), guestfs_name); 410d50fe489SSasha Levin 411d50fe489SSasha Levin remove(path); 412d50fe489SSasha Levin 41347621338SSasha Levin if (kvm->cfg.sandbox == NULL) 414d50fe489SSasha Levin return 0; 415d50fe489SSasha Levin 41647621338SSasha Levin tmp = realpath(kvm->cfg.sandbox, NULL); 417d50fe489SSasha Levin if (tmp == NULL) 418d50fe489SSasha Levin return -ENOMEM; 419d50fe489SSasha Levin 420d50fe489SSasha Levin snprintf(script, PATH_MAX, "/host/%s", tmp); 421d50fe489SSasha Levin free(tmp); 422d50fe489SSasha Levin 423d50fe489SSasha Levin return symlink(script, path); 424d50fe489SSasha Levin } 425d50fe489SSasha Levin 4265173b4afSLai Jiangshan static void kvm_write_sandbox_cmd_exactly(int fd, const char *arg) 4275173b4afSLai Jiangshan { 4285173b4afSLai Jiangshan const char *single_quote; 4295173b4afSLai Jiangshan 4305173b4afSLai Jiangshan if (!*arg) { /* zero length string */ 4315173b4afSLai Jiangshan if (write(fd, "''", 2) <= 0) 4325173b4afSLai Jiangshan die("Failed writing sandbox script"); 4335173b4afSLai Jiangshan return; 4345173b4afSLai Jiangshan } 4355173b4afSLai Jiangshan 4365173b4afSLai Jiangshan while (*arg) { 4375173b4afSLai Jiangshan single_quote = strchrnul(arg, '\''); 4385173b4afSLai Jiangshan 4395173b4afSLai Jiangshan /* write non-single-quote string as #('string') */ 4405173b4afSLai Jiangshan if (arg != single_quote) { 4415173b4afSLai Jiangshan if (write(fd, "'", 1) <= 0 || 4425173b4afSLai Jiangshan write(fd, arg, single_quote - arg) <= 0 || 4435173b4afSLai Jiangshan write(fd, "'", 1) <= 0) 4445173b4afSLai Jiangshan die("Failed writing sandbox script"); 4455173b4afSLai Jiangshan } 4465173b4afSLai Jiangshan 4475173b4afSLai Jiangshan /* write single quote as #("'") */ 4485173b4afSLai Jiangshan if (*single_quote) { 4495173b4afSLai Jiangshan if (write(fd, "\"'\"", 3) <= 0) 4505173b4afSLai Jiangshan die("Failed writing sandbox script"); 4515173b4afSLai Jiangshan } else 4525173b4afSLai Jiangshan break; 4535173b4afSLai Jiangshan 4545173b4afSLai Jiangshan arg = single_quote + 1; 4555173b4afSLai Jiangshan } 4565173b4afSLai Jiangshan } 4575173b4afSLai Jiangshan 4585cd19aa0SPekka Enberg static void resolve_program(const char *src, char *dst, size_t len) 4595cd19aa0SPekka Enberg { 4605cd19aa0SPekka Enberg struct stat st; 461c2c742d9SPekka Enberg int err; 4625cd19aa0SPekka Enberg 463c2c742d9SPekka Enberg err = stat(src, &st); 4645cd19aa0SPekka Enberg 465c2c742d9SPekka Enberg if (!err && S_ISREG(st.st_mode)) { 4665cd19aa0SPekka Enberg char resolved_path[PATH_MAX]; 4675cd19aa0SPekka Enberg 468de3f75c9SPekka Enberg if (!realpath(src, resolved_path)) 469de3f75c9SPekka Enberg die("Unable to resolve program %s: %s\n", src, strerror(errno)); 4705cd19aa0SPekka Enberg 47196eda741SAnisse Astier if (snprintf(dst, len, "/host%s", resolved_path) >= (int)len) 47296eda741SAnisse Astier die("Pathname too long: %s -> %s\n", src, resolved_path); 47396eda741SAnisse Astier 4745cd19aa0SPekka Enberg } else 475266a0ed4SAndre Przywara strlcpy(dst, src, len); 4765cd19aa0SPekka Enberg } 4775cd19aa0SPekka Enberg 4784346fd8fSSasha Levin static void kvm_run_write_sandbox_cmd(struct kvm *kvm, const char **argv, int argc) 4793c29e2aaSSasha Levin { 4803c29e2aaSSasha Levin const char script_hdr[] = "#! /bin/bash\n\n"; 4815cd19aa0SPekka Enberg char program[PATH_MAX]; 4823c29e2aaSSasha Levin int fd; 4833c29e2aaSSasha Levin 48447621338SSasha Levin remove(kvm->cfg.sandbox); 4853c29e2aaSSasha Levin 48647621338SSasha Levin fd = open(kvm->cfg.sandbox, O_RDWR | O_CREAT, 0777); 4873c29e2aaSSasha Levin if (fd < 0) 4883c29e2aaSSasha Levin die("Failed creating sandbox script"); 4893c29e2aaSSasha Levin 4903c29e2aaSSasha Levin if (write(fd, script_hdr, sizeof(script_hdr) - 1) <= 0) 4913c29e2aaSSasha Levin die("Failed writing sandbox script"); 4923c29e2aaSSasha Levin 4935cd19aa0SPekka Enberg resolve_program(argv[0], program, PATH_MAX); 4945cd19aa0SPekka Enberg kvm_write_sandbox_cmd_exactly(fd, program); 4955cd19aa0SPekka Enberg 4965cd19aa0SPekka Enberg argv++; 4975cd19aa0SPekka Enberg argc--; 4985cd19aa0SPekka Enberg 4993c29e2aaSSasha Levin while (argc) { 5003c29e2aaSSasha Levin if (write(fd, " ", 1) <= 0) 5013c29e2aaSSasha Levin die("Failed writing sandbox script"); 5025cd19aa0SPekka Enberg 5035cd19aa0SPekka Enberg kvm_write_sandbox_cmd_exactly(fd, argv[0]); 5043c29e2aaSSasha Levin argv++; 5053c29e2aaSSasha Levin argc--; 5063c29e2aaSSasha Levin } 5073c29e2aaSSasha Levin if (write(fd, "\n", 1) <= 0) 5083c29e2aaSSasha Levin die("Failed writing sandbox script"); 5093c29e2aaSSasha Levin 5103c29e2aaSSasha Levin close(fd); 5113c29e2aaSSasha Levin } 5123c29e2aaSSasha Levin 513a5253f7cSAlexandru Elisei static void kvm_run_set_real_cmdline(struct kvm *kvm) 514a5253f7cSAlexandru Elisei { 515a5253f7cSAlexandru Elisei static char real_cmdline[2048]; 516a5253f7cSAlexandru Elisei bool video; 517a5253f7cSAlexandru Elisei 518a5253f7cSAlexandru Elisei video = kvm->cfg.vnc || kvm->cfg.sdl || kvm->cfg.gtk; 519a5253f7cSAlexandru Elisei 520a5253f7cSAlexandru Elisei memset(real_cmdline, 0, sizeof(real_cmdline)); 521a5253f7cSAlexandru Elisei kvm__arch_set_cmdline(real_cmdline, video); 522a5253f7cSAlexandru Elisei 523a5253f7cSAlexandru Elisei if (video) { 524a5253f7cSAlexandru Elisei strcat(real_cmdline, " console=tty0"); 525a5253f7cSAlexandru Elisei } else { 526a5253f7cSAlexandru Elisei switch (kvm->cfg.active_console) { 527a5253f7cSAlexandru Elisei case CONSOLE_HV: 528a5253f7cSAlexandru Elisei /* Fallthrough */ 529a5253f7cSAlexandru Elisei case CONSOLE_VIRTIO: 530a5253f7cSAlexandru Elisei strcat(real_cmdline, " console=hvc0"); 531a5253f7cSAlexandru Elisei break; 532a5253f7cSAlexandru Elisei case CONSOLE_8250: 533a5253f7cSAlexandru Elisei strcat(real_cmdline, " console=ttyS0"); 534a5253f7cSAlexandru Elisei break; 535a5253f7cSAlexandru Elisei } 536a5253f7cSAlexandru Elisei } 537a5253f7cSAlexandru Elisei 538a5253f7cSAlexandru Elisei if (kvm->cfg.using_rootfs) { 539a5253f7cSAlexandru Elisei strcat(real_cmdline, " rw rootflags=trans=virtio,version=9p2000.L,cache=loose rootfstype=9p"); 540a5253f7cSAlexandru Elisei if (kvm->cfg.custom_rootfs) { 541a5253f7cSAlexandru Elisei #ifdef CONFIG_GUEST_PRE_INIT 542a5253f7cSAlexandru Elisei strcat(real_cmdline, " init=/virt/pre_init"); 543a5253f7cSAlexandru Elisei #else 544a5253f7cSAlexandru Elisei strcat(real_cmdline, " init=/virt/init"); 545a5253f7cSAlexandru Elisei #endif 546a5253f7cSAlexandru Elisei if (!kvm->cfg.no_dhcp) 547a5253f7cSAlexandru Elisei strcat(real_cmdline, " ip=dhcp"); 548a5253f7cSAlexandru Elisei } 549a5253f7cSAlexandru Elisei } else if (!kvm->cfg.kernel_cmdline || !strstr(kvm->cfg.kernel_cmdline, "root=")) { 550a5253f7cSAlexandru Elisei strlcat(real_cmdline, " root=/dev/vda rw ", sizeof(real_cmdline)); 551a5253f7cSAlexandru Elisei } 552a5253f7cSAlexandru Elisei 553a5253f7cSAlexandru Elisei if (kvm->cfg.kernel_cmdline) { 554a5253f7cSAlexandru Elisei strcat(real_cmdline, " "); 555a5253f7cSAlexandru Elisei strlcat(real_cmdline, kvm->cfg.kernel_cmdline, sizeof(real_cmdline)); 556a5253f7cSAlexandru Elisei } 557a5253f7cSAlexandru Elisei 558a5253f7cSAlexandru Elisei kvm->cfg.real_cmdline = real_cmdline; 559a5253f7cSAlexandru Elisei } 560a5253f7cSAlexandru Elisei 561cce96164SAlexandru Elisei static void kvm_run_validate_cfg(struct kvm *kvm) 562cce96164SAlexandru Elisei { 56328b96259SAlexandru Elisei u64 available_ram; 56428b96259SAlexandru Elisei 565cce96164SAlexandru Elisei if (kvm->cfg.kernel_filename && kvm->cfg.firmware_filename) 566cce96164SAlexandru Elisei die("Only one of --kernel or --firmware can be specified"); 567cce96164SAlexandru Elisei 568cce96164SAlexandru Elisei if ((kvm->cfg.vnc && (kvm->cfg.sdl || kvm->cfg.gtk)) || 569cce96164SAlexandru Elisei (kvm->cfg.sdl && kvm->cfg.gtk)) 570cce96164SAlexandru Elisei die("Only one of --vnc, --sdl or --gtk can be specified"); 571cce96164SAlexandru Elisei 572cce96164SAlexandru Elisei if (kvm->cfg.firmware_filename && kvm->cfg.initrd_filename) 573cce96164SAlexandru Elisei pr_warning("Ignoring initrd file when loading a firmware image"); 57428b96259SAlexandru Elisei 57528b96259SAlexandru Elisei if (kvm->cfg.ram_size) { 57628b96259SAlexandru Elisei available_ram = host_ram_size(); 57728b96259SAlexandru Elisei if (available_ram && kvm->cfg.ram_size > available_ram) { 57828b96259SAlexandru Elisei pr_warning("Guest memory size %lluMB exceeds host physical RAM size %lluMB", 57928b96259SAlexandru Elisei (unsigned long long)kvm->cfg.ram_size >> MB_SHIFT, 58028b96259SAlexandru Elisei (unsigned long long)available_ram >> MB_SHIFT); 58128b96259SAlexandru Elisei } 58228b96259SAlexandru Elisei } 583abe3f28aSAlexandru Elisei 584abe3f28aSAlexandru Elisei kvm__arch_validate_cfg(kvm); 585cce96164SAlexandru Elisei } 586cce96164SAlexandru Elisei 5874346fd8fSSasha Levin static struct kvm *kvm_cmd_run_init(int argc, const char **argv) 588f967c427SPrasad Joshi { 589a5253f7cSAlexandru Elisei static char default_name[20]; 590384922b3SPekka Enberg unsigned int nr_online_cpus; 5914346fd8fSSasha Levin struct kvm *kvm = kvm__new(); 59247621338SSasha Levin 59347621338SSasha Levin if (IS_ERR(kvm)) 5944346fd8fSSasha Levin return kvm; 595f967c427SPrasad Joshi 596cfd63bbbSSasha Levin nr_online_cpus = sysconf(_SC_NPROCESSORS_ONLN); 59747621338SSasha Levin kvm->cfg.custom_rootfs_name = "default"; 598cfd63bbbSSasha Levin 599f967c427SPrasad Joshi while (argc != 0) { 6003b55dcdeSSasha Levin BUILD_OPTIONS(options, &kvm->cfg, kvm); 601f967c427SPrasad Joshi argc = parse_options(argc, argv, options, run_usage, 6021a007c82SSasha Levin PARSE_OPT_STOP_AT_NON_OPTION | 6031a007c82SSasha Levin PARSE_OPT_KEEP_DASHDASH); 604f967c427SPrasad Joshi if (argc != 0) { 6051a007c82SSasha Levin /* Cusrom options, should have been handled elsewhere */ 6063c29e2aaSSasha Levin if (strcmp(argv[0], "--") == 0) { 6073c29e2aaSSasha Levin if (kvm_run_wrapper == KVM_RUN_SANDBOX) { 60847621338SSasha Levin kvm->cfg.sandbox = DEFAULT_SANDBOX_FILENAME; 6094346fd8fSSasha Levin kvm_run_write_sandbox_cmd(kvm, argv+1, argc-1); 6101a007c82SSasha Levin break; 6113c29e2aaSSasha Levin } 6123c29e2aaSSasha Levin } 6131a007c82SSasha Levin 61447621338SSasha Levin if ((kvm_run_wrapper == KVM_RUN_DEFAULT && kvm->cfg.kernel_filename) || 61547621338SSasha Levin (kvm_run_wrapper == KVM_RUN_SANDBOX && kvm->cfg.sandbox)) { 616f967c427SPrasad Joshi fprintf(stderr, "Cannot handle parameter: " 617f967c427SPrasad Joshi "%s\n", argv[0]); 618f967c427SPrasad Joshi usage_with_options(run_usage, options); 61947621338SSasha Levin free(kvm); 6204346fd8fSSasha Levin return ERR_PTR(-EINVAL); 621f967c427SPrasad Joshi } 622e0747665SSasha Levin if (kvm_run_wrapper == KVM_RUN_SANDBOX) { 623e0747665SSasha Levin /* 624e0747665SSasha Levin * first unhandled parameter is treated as 625e0747665SSasha Levin * sandbox command 626e0747665SSasha Levin */ 62747621338SSasha Levin kvm->cfg.sandbox = DEFAULT_SANDBOX_FILENAME; 6284346fd8fSSasha Levin kvm_run_write_sandbox_cmd(kvm, argv, argc); 629e0747665SSasha Levin } else { 630e0747665SSasha Levin /* 631e0747665SSasha Levin * first unhandled parameter is treated as a kernel 632e0747665SSasha Levin * image 633f967c427SPrasad Joshi */ 63447621338SSasha Levin kvm->cfg.kernel_filename = argv[0]; 635e0747665SSasha Levin } 636f967c427SPrasad Joshi argv++; 637f967c427SPrasad Joshi argc--; 638f967c427SPrasad Joshi } 639f967c427SPrasad Joshi 640f967c427SPrasad Joshi } 641f967c427SPrasad Joshi 642cce96164SAlexandru Elisei kvm_run_validate_cfg(kvm); 643cce96164SAlexandru Elisei 64413498576SJulien Thierry if (!kvm->cfg.kernel_filename && !kvm->cfg.firmware_filename) { 64547621338SSasha Levin kvm->cfg.kernel_filename = find_kernel(); 6468329f30bSPekka Enberg 64747621338SSasha Levin if (!kvm->cfg.kernel_filename) { 648e08c0896SPrasad Joshi kernel_usage_with_options(); 6494346fd8fSSasha Levin return ERR_PTR(-EINVAL); 6508329f30bSPekka Enberg } 65113498576SJulien Thierry } 6528329f30bSPekka Enberg 653638630c9SAlexandru Elisei if (kvm->cfg.kernel_filename) { 65447621338SSasha Levin kvm->cfg.vmlinux_filename = find_vmlinux(); 655084a1356SSasha Levin kvm->vmlinux = kvm->cfg.vmlinux_filename; 656638630c9SAlexandru Elisei } 657b0b42ba0SPekka Enberg 65800ebbe96SSasha Levin if (kvm->cfg.nrcpus == 0) 65900ebbe96SSasha Levin kvm->cfg.nrcpus = nr_online_cpus; 660d77a9efaSCyrill Gorcunov 66147621338SSasha Levin if (!kvm->cfg.ram_size) 66200ebbe96SSasha Levin kvm->cfg.ram_size = get_ram_size(kvm->cfg.nrcpus); 663f967c427SPrasad Joshi 66447621338SSasha Levin if (!kvm->cfg.dev) 66547621338SSasha Levin kvm->cfg.dev = DEFAULT_KVM_DEV; 666f967c427SPrasad Joshi 66747621338SSasha Levin if (!kvm->cfg.console) 66847621338SSasha Levin kvm->cfg.console = DEFAULT_CONSOLE; 6699aa4a0ebSAsias He 67047621338SSasha Levin if (!strncmp(kvm->cfg.console, "virtio", 6)) 6712651ea58SSasha Levin kvm->cfg.active_console = CONSOLE_VIRTIO; 67247621338SSasha Levin else if (!strncmp(kvm->cfg.console, "serial", 6)) 6732651ea58SSasha Levin kvm->cfg.active_console = CONSOLE_8250; 67447621338SSasha Levin else if (!strncmp(kvm->cfg.console, "hv", 2)) 6752651ea58SSasha Levin kvm->cfg.active_console = CONSOLE_HV; 6763bbc49b6SMatt Evans else 6773bbc49b6SMatt Evans pr_warning("No console!"); 678f967c427SPrasad Joshi 67947621338SSasha Levin if (!kvm->cfg.host_ip) 68047621338SSasha Levin kvm->cfg.host_ip = DEFAULT_HOST_ADDR; 6814d67c820SSasha Levin 68247621338SSasha Levin if (!kvm->cfg.guest_ip) 68347621338SSasha Levin kvm->cfg.guest_ip = DEFAULT_GUEST_ADDR; 684bb8ffd2fSAsias He 68547621338SSasha Levin if (!kvm->cfg.guest_mac) 68647621338SSasha Levin kvm->cfg.guest_mac = DEFAULT_GUEST_MAC; 687a4e724ddSSasha Levin 68847621338SSasha Levin if (!kvm->cfg.host_mac) 68947621338SSasha Levin kvm->cfg.host_mac = DEFAULT_HOST_MAC; 690d7098b9bSAsias He 69147621338SSasha Levin if (!kvm->cfg.script) 69247621338SSasha Levin kvm->cfg.script = DEFAULT_SCRIPT; 69373b7d038SAmos Kong 694cf5323a3SSasha Levin if (!kvm->cfg.network) 695cf5323a3SSasha Levin kvm->cfg.network = DEFAULT_NETWORK; 696cf5323a3SSasha Levin 69747621338SSasha Levin if (!kvm->cfg.guest_name) { 69847621338SSasha Levin if (kvm->cfg.custom_rootfs) { 69947621338SSasha Levin kvm->cfg.guest_name = kvm->cfg.custom_rootfs_name; 700587a4d17SLai Jiangshan } else { 7012d96f6b6SSasha Levin sprintf(default_name, "guest-%u", getpid()); 70247621338SSasha Levin kvm->cfg.guest_name = default_name; 7032d96f6b6SSasha Levin } 704587a4d17SLai Jiangshan } 7052d96f6b6SSasha Levin 7065613ae26SAlexandru Elisei if (!kvm->cfg.nodefaults && 7075613ae26SAlexandru Elisei !kvm->cfg.using_rootfs && 7085613ae26SAlexandru Elisei !kvm->cfg.disk_image[0].filename && 7095613ae26SAlexandru Elisei !kvm->cfg.initrd_filename) { 710c8675741SSasha Levin char tmp[PATH_MAX]; 7116df1471eSPekka Enberg 71247621338SSasha Levin kvm_setup_create_new(kvm->cfg.custom_rootfs_name); 71347621338SSasha Levin kvm_setup_resolv(kvm->cfg.custom_rootfs_name); 714c8675741SSasha Levin 7159667701cSPekka Enberg snprintf(tmp, PATH_MAX, "%s%s", kvm__get_dir(), "default"); 716c8675741SSasha Levin if (virtio_9p__register(kvm, tmp, "/dev/root") < 0) 717c8675741SSasha Levin die("Unable to initialize virtio 9p"); 718c8675741SSasha Levin if (virtio_9p__register(kvm, "/", "hostfs") < 0) 719c8675741SSasha Levin die("Unable to initialize virtio 9p"); 72047621338SSasha Levin kvm->cfg.using_rootfs = kvm->cfg.custom_rootfs = 1; 72126c853e4SPrasad Joshi } 72226c853e4SPrasad Joshi 72347621338SSasha Levin if (kvm->cfg.custom_rootfs) { 7244346fd8fSSasha Levin kvm_run_set_sandbox(kvm); 725cdce942cSDimitri John Ledkov if (kvm_setup_guest_init(kvm->cfg.custom_rootfs_name)) 726afc2c7c0SAsias He die("Failed to setup init for guest."); 727a8e6b4b9SSasha Levin } 72859aa2d30SSasha Levin 7295613ae26SAlexandru Elisei if (kvm->cfg.nodefaults) 7305613ae26SAlexandru Elisei kvm->cfg.real_cmdline = kvm->cfg.kernel_cmdline; 7315613ae26SAlexandru Elisei else 732a5253f7cSAlexandru Elisei kvm_run_set_real_cmdline(kvm); 733084a1356SSasha Levin 73413498576SJulien Thierry if (kvm->cfg.kernel_filename) { 735084a1356SSasha Levin printf(" # %s run -k %s -m %Lu -c %d --name %s\n", KVM_BINARY_NAME, 73669f50425SAndreas Herrmann kvm->cfg.kernel_filename, 7379d655190SAlexandru Elisei (unsigned long long)kvm->cfg.ram_size >> MB_SHIFT, 73869f50425SAndreas Herrmann kvm->cfg.nrcpus, kvm->cfg.guest_name); 73913498576SJulien Thierry } else if (kvm->cfg.firmware_filename) { 74013498576SJulien Thierry printf(" # %s run --firmware %s -m %Lu -c %d --name %s\n", KVM_BINARY_NAME, 74113498576SJulien Thierry kvm->cfg.firmware_filename, 7429d655190SAlexandru Elisei (unsigned long long)kvm->cfg.ram_size >> MB_SHIFT, 74313498576SJulien Thierry kvm->cfg.nrcpus, kvm->cfg.guest_name); 74413498576SJulien Thierry } 745084a1356SSasha Levin 7465b403dbfSWill Deacon if (init_list__init(kvm) < 0) 7475b403dbfSWill Deacon die ("Initialisation failed"); 7484346fd8fSSasha Levin 7494346fd8fSSasha Levin return kvm; 750e1e46fe6SSasha Levin } 751e1e46fe6SSasha Levin 7524346fd8fSSasha Levin static int kvm_cmd_run_work(struct kvm *kvm) 753e1e46fe6SSasha Levin { 754df4239fbSSasha Levin int i; 755e1e46fe6SSasha Levin 75600ebbe96SSasha Levin for (i = 0; i < kvm->nrcpus; i++) { 757df4239fbSSasha Levin if (pthread_create(&kvm->cpus[i]->thread, NULL, kvm_cpu_thread, kvm->cpus[i]) != 0) 7585ee154d1SPekka Enberg die("unable to create KVM VCPU thread"); 7595ee154d1SPekka Enberg } 7605ee154d1SPekka Enberg 76149e5227dSSasha Levin /* Only VCPU #0 is going to exit by itself when shutting down */ 762e8cb90fbSWill Deacon if (pthread_join(kvm->cpus[0]->thread, NULL) != 0) 763e8cb90fbSWill Deacon die("unable to join with vcpu 0"); 764e8cb90fbSWill Deacon 765e8cb90fbSWill Deacon return kvm_cpu__exit(kvm); 766e1e46fe6SSasha Levin } 767e1e46fe6SSasha Levin 7684346fd8fSSasha Levin static void kvm_cmd_run_exit(struct kvm *kvm, int guest_ret) 769e1e46fe6SSasha Levin { 770e6694207SSasha Levin compat__print_all_messages(); 771e6694207SSasha Levin 77249a8afd1SSasha Levin init_list__exit(kvm); 773f967c427SPrasad Joshi 774e1e46fe6SSasha Levin if (guest_ret == 0) 775f967c427SPrasad Joshi printf("\n # KVM session ended normally.\n"); 776e1e46fe6SSasha Levin } 777e1e46fe6SSasha Levin 778e1e46fe6SSasha Levin int kvm_cmd_run(int argc, const char **argv, const char *prefix) 779e1e46fe6SSasha Levin { 7804346fd8fSSasha Levin int ret = -EFAULT; 7814346fd8fSSasha Levin struct kvm *kvm; 782e1e46fe6SSasha Levin 7834346fd8fSSasha Levin kvm = kvm_cmd_run_init(argc, argv); 7844346fd8fSSasha Levin if (IS_ERR(kvm)) 7854346fd8fSSasha Levin return PTR_ERR(kvm); 786e1e46fe6SSasha Levin 7874346fd8fSSasha Levin ret = kvm_cmd_run_work(kvm); 7884346fd8fSSasha Levin kvm_cmd_run_exit(kvm, ret); 789e1e46fe6SSasha Levin 790e1e46fe6SSasha Levin return ret; 791f967c427SPrasad Joshi } 792