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) 53a9c24ec7SSuzuki K Poulose #define MB_SHIFT (20) 5495d13a52SSasha Levin #define GB_SHIFT (30) 55a9c24ec7SSuzuki K Poulose #define TB_SHIFT (40) 56a9c24ec7SSuzuki 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 92a9c24ec7SSuzuki K Poulose static int parse_mem_unit(char **next) 93a9c24ec7SSuzuki K Poulose { 94a9c24ec7SSuzuki K Poulose switch (**next) { 95a9c24ec7SSuzuki K Poulose case 'B': case 'b': (*next)++; return 0; 96a9c24ec7SSuzuki K Poulose case 'K': case 'k': (*next)++; return KB_SHIFT; 97a9c24ec7SSuzuki K Poulose case 'M': case 'm': (*next)++; return MB_SHIFT; 98a9c24ec7SSuzuki K Poulose case 'G': case 'g': (*next)++; return GB_SHIFT; 99a9c24ec7SSuzuki K Poulose case 'T': case 't': (*next)++; return TB_SHIFT; 100a9c24ec7SSuzuki K Poulose case 'P': case 'p': (*next)++; return PB_SHIFT; 101a9c24ec7SSuzuki K Poulose } 102a9c24ec7SSuzuki K Poulose 103a9c24ec7SSuzuki K Poulose return MB_SHIFT; 104a9c24ec7SSuzuki K Poulose } 105a9c24ec7SSuzuki K Poulose 106a9c24ec7SSuzuki K Poulose static u64 parse_mem_option(const char *nptr, char **next) 107a9c24ec7SSuzuki K Poulose { 108a9c24ec7SSuzuki K Poulose u64 shift; 109a9c24ec7SSuzuki K Poulose u64 val; 110a9c24ec7SSuzuki K Poulose 111a9c24ec7SSuzuki K Poulose errno = 0; 112a9c24ec7SSuzuki K Poulose val = strtoull(nptr, next, 10); 113a9c24ec7SSuzuki K Poulose if (errno == ERANGE) 114a9c24ec7SSuzuki K Poulose die("Memory too large: %s", nptr); 115a9c24ec7SSuzuki K Poulose if (*next == nptr) 116a9c24ec7SSuzuki K Poulose die("Invalid memory specifier: %s", nptr); 117a9c24ec7SSuzuki K Poulose 118a9c24ec7SSuzuki K Poulose shift = parse_mem_unit(next); 119a9c24ec7SSuzuki K Poulose if ((val << shift) < val) 120a9c24ec7SSuzuki K Poulose die("Memory too large: %s", nptr); 121a9c24ec7SSuzuki K Poulose 122a9c24ec7SSuzuki K Poulose return val << shift; 123a9c24ec7SSuzuki K Poulose } 124a9c24ec7SSuzuki K Poulose 125a9c24ec7SSuzuki K Poulose static int mem_parser(const struct option *opt, const char *arg, int unset) 126a9c24ec7SSuzuki K Poulose { 127a9c24ec7SSuzuki K Poulose struct kvm *kvm = opt->ptr; 128*8b91a182SAlexandru Elisei char *next, *nptr; 129a9c24ec7SSuzuki K Poulose 130a9c24ec7SSuzuki K Poulose kvm->cfg.ram_size = parse_mem_option(arg, &next); 131a9c24ec7SSuzuki K Poulose if (kvm->cfg.ram_size == 0) 132a9c24ec7SSuzuki K Poulose die("Invalid RAM size: %s", arg); 133a9c24ec7SSuzuki K Poulose 134*8b91a182SAlexandru Elisei if (kvm__arch_has_cfg_ram_address() && *next == '@') { 135*8b91a182SAlexandru Elisei next++; 136*8b91a182SAlexandru Elisei if (*next == '\0') 137*8b91a182SAlexandru Elisei die("Missing memory address: %s", arg); 138*8b91a182SAlexandru Elisei 139*8b91a182SAlexandru Elisei nptr = next; 140*8b91a182SAlexandru Elisei kvm->cfg.ram_addr = parse_mem_option(nptr, &next); 141*8b91a182SAlexandru Elisei } 142*8b91a182SAlexandru Elisei 143a9c24ec7SSuzuki K Poulose if (*next != '\0') 144a9c24ec7SSuzuki K Poulose die("Invalid memory specifier: %s", arg); 145a9c24ec7SSuzuki K Poulose 146a9c24ec7SSuzuki K Poulose return 0; 147a9c24ec7SSuzuki K Poulose } 148a9c24ec7SSuzuki K Poulose 149ff7ba6faSWill Deacon #ifndef OPT_ARCH_RUN 150ff7ba6faSWill Deacon #define OPT_ARCH_RUN(...) 151ff7ba6faSWill Deacon #endif 152ff7ba6faSWill Deacon 153*8b91a182SAlexandru Elisei #ifdef ARCH_HAS_CFG_RAM_ADDRESS 154*8b91a182SAlexandru Elisei #define MEM_OPT_HELP_SHORT "size[BKMGTP][@addr[BKMGTP]]" 155*8b91a182SAlexandru Elisei #define MEM_OPT_HELP_LONG \ 156*8b91a182SAlexandru Elisei "Virtual machine memory size and optional base address, both" \ 157*8b91a182SAlexandru Elisei " measured by default in megabytes (M)" 158*8b91a182SAlexandru Elisei #else 159*8b91a182SAlexandru Elisei #define MEM_OPT_HELP_SHORT "size[BKMGTP]" 160*8b91a182SAlexandru Elisei #define MEM_OPT_HELP_LONG \ 161*8b91a182SAlexandru Elisei "Virtual machine memory size, by default measured in" \ 162*8b91a182SAlexandru Elisei " in megabytes (M)" 163*8b91a182SAlexandru Elisei #endif 164*8b91a182SAlexandru Elisei 1653b55dcdeSSasha Levin #define BUILD_OPTIONS(name, cfg, kvm) \ 166b816364aSSasha Levin struct option name[] = { \ 167b816364aSSasha Levin OPT_GROUP("Basic options:"), \ 168b816364aSSasha Levin OPT_STRING('\0', "name", &(cfg)->guest_name, "guest name", \ 169b816364aSSasha Levin "A name for the guest"), \ 17000ebbe96SSasha Levin OPT_INTEGER('c', "cpus", &(cfg)->nrcpus, "Number of CPUs"), \ 171*8b91a182SAlexandru Elisei OPT_CALLBACK('m', "mem", NULL, MEM_OPT_HELP_SHORT, \ 172*8b91a182SAlexandru Elisei MEM_OPT_HELP_LONG, mem_parser, kvm), \ 173b5e56fa3SWilliam Dauchy OPT_CALLBACK('d', "disk", kvm, "image or rootfs_dir", "Disk " \ 174b5e56fa3SWilliam Dauchy " image or rootfs directory", img_name_parser, \ 1753b55dcdeSSasha Levin kvm), \ 176b5e56fa3SWilliam Dauchy OPT_BOOLEAN('\0', "balloon", &(cfg)->balloon, "Enable virtio" \ 177b5e56fa3SWilliam Dauchy " balloon"), \ 178b816364aSSasha Levin OPT_BOOLEAN('\0', "vnc", &(cfg)->vnc, "Enable VNC framebuffer"),\ 1797bcceb95SPekka Enberg OPT_BOOLEAN('\0', "gtk", &(cfg)->gtk, "Enable GTK framebuffer"),\ 180b816364aSSasha Levin OPT_BOOLEAN('\0', "sdl", &(cfg)->sdl, "Enable SDL framebuffer"),\ 181b5e56fa3SWilliam Dauchy OPT_BOOLEAN('\0', "rng", &(cfg)->virtio_rng, "Enable virtio" \ 182b5e56fa3SWilliam Dauchy " Random Number Generator"), \ 1835613ae26SAlexandru Elisei OPT_BOOLEAN('\0', "nodefaults", &(cfg)->nodefaults, "Disable" \ 1845613ae26SAlexandru Elisei " implicit configuration that cannot be" \ 1855613ae26SAlexandru Elisei " disabled otherwise"), \ 186b816364aSSasha Levin OPT_CALLBACK('\0', "9p", NULL, "dir_to_share,tag_name", \ 187b5e56fa3SWilliam Dauchy "Enable virtio 9p to share files between host and" \ 188b5e56fa3SWilliam Dauchy " guest", virtio_9p_rootdir_parser, kvm), \ 189b5e56fa3SWilliam Dauchy OPT_STRING('\0', "console", &(cfg)->console, "serial, virtio or"\ 190b5e56fa3SWilliam Dauchy " hv", "Console to use"), \ 191117d6495STianjia Zhang OPT_U64('\0', "vsock", &(cfg)->vsock_cid, \ 192117d6495STianjia Zhang "Guest virtio socket CID"), \ 193b816364aSSasha Levin OPT_STRING('\0', "dev", &(cfg)->dev, "device_file", \ 194b816364aSSasha Levin "KVM device file"), \ 195b816364aSSasha Levin OPT_CALLBACK('\0', "tty", NULL, "tty id", \ 196b816364aSSasha Levin "Remap guest TTY into a pty on the host", \ 1971dc24dccSSasha Levin tty_parser, NULL), \ 198b816364aSSasha Levin OPT_STRING('\0', "sandbox", &(cfg)->sandbox, "script", \ 199b5e56fa3SWilliam Dauchy "Run this script when booting into custom" \ 200b5e56fa3SWilliam Dauchy " rootfs"), \ 201b816364aSSasha Levin OPT_STRING('\0', "hugetlbfs", &(cfg)->hugetlbfs_path, "path", \ 202b816364aSSasha Levin "Hugetlbfs path"), \ 203b816364aSSasha Levin \ 204b816364aSSasha Levin OPT_GROUP("Kernel options:"), \ 205b816364aSSasha Levin OPT_STRING('k', "kernel", &(cfg)->kernel_filename, "kernel", \ 206b816364aSSasha Levin "Kernel to boot in virtual machine"), \ 207b816364aSSasha Levin OPT_STRING('i', "initrd", &(cfg)->initrd_filename, "initrd", \ 208b816364aSSasha Levin "Initial RAM disk image"), \ 209b816364aSSasha Levin OPT_STRING('p', "params", &(cfg)->kernel_cmdline, "params", \ 210b816364aSSasha Levin "Kernel command line arguments"), \ 211b816364aSSasha Levin OPT_STRING('f', "firmware", &(cfg)->firmware_filename, "firmware",\ 212b816364aSSasha Levin "Firmware image to boot in virtual machine"), \ 21325cf3198SRaphael Gault OPT_STRING('F', "flash", &(cfg)->flash_filename, "flash",\ 21425cf3198SRaphael Gault "Flash image to present to virtual machine"), \ 215b816364aSSasha Levin \ 216b816364aSSasha Levin OPT_GROUP("Networking options:"), \ 217b816364aSSasha Levin OPT_CALLBACK_DEFAULT('n', "network", NULL, "network params", \ 218b816364aSSasha Levin "Create a new guest NIC", \ 2195f225124SSasha Levin netdev_parser, NULL, kvm), \ 220b5e56fa3SWilliam Dauchy OPT_BOOLEAN('\0', "no-dhcp", &(cfg)->no_dhcp, "Disable kernel" \ 221b5e56fa3SWilliam Dauchy " DHCP in rootfs mode"), \ 222b816364aSSasha Levin \ 2236078a454SJean-Philippe Brucker OPT_GROUP("VFIO options:"), \ 2246078a454SJean-Philippe Brucker OPT_CALLBACK('\0', "vfio-pci", NULL, "[domain:]bus:dev.fn", \ 2256078a454SJean-Philippe Brucker "Assign a PCI device to the virtual machine", \ 2266078a454SJean-Philippe Brucker vfio_device_parser, kvm), \ 2276078a454SJean-Philippe Brucker \ 228b816364aSSasha Levin OPT_GROUP("Debug options:"), \ 229b816364aSSasha Levin OPT_BOOLEAN('\0', "debug", &do_debug_print, \ 230b816364aSSasha Levin "Enable debug messages"), \ 231b816364aSSasha Levin OPT_BOOLEAN('\0', "debug-single-step", &(cfg)->single_step, \ 232b816364aSSasha Levin "Enable single stepping"), \ 2335765977dSSasha Levin OPT_BOOLEAN('\0', "debug-ioport", &(cfg)->ioport_debug, \ 234b816364aSSasha Levin "Enable ioport debugging"), \ 235e830cce7SSasha Levin OPT_BOOLEAN('\0', "debug-mmio", &(cfg)->mmio_debug, \ 236b816364aSSasha Levin "Enable MMIO debugging"), \ 2373b55dcdeSSasha Levin OPT_INTEGER('\0', "debug-iodelay", &(cfg)->debug_iodelay, \ 238b816364aSSasha Levin "Delay IO by millisecond"), \ 239ff7ba6faSWill Deacon \ 240ff7ba6faSWill Deacon OPT_ARCH(RUN, cfg) \ 241b816364aSSasha Levin OPT_END() \ 242f967c427SPrasad Joshi }; 243f967c427SPrasad Joshi 2445ee154d1SPekka Enberg static void *kvm_cpu_thread(void *arg) 2455ee154d1SPekka Enberg { 246a4d8c55eSSasha Levin char name[16]; 247a4d8c55eSSasha Levin 248d77a9efaSCyrill Gorcunov current_kvm_cpu = arg; 2495ee154d1SPekka Enberg 250a4d8c55eSSasha Levin sprintf(name, "kvm-vcpu-%lu", current_kvm_cpu->cpu_id); 251a4d8c55eSSasha Levin kvm__set_thread_name(name); 252a4d8c55eSSasha Levin 253d77a9efaSCyrill Gorcunov if (kvm_cpu__start(current_kvm_cpu)) 2545ee154d1SPekka Enberg goto panic_kvm; 2555ee154d1SPekka Enberg 2565ee154d1SPekka Enberg return (void *) (intptr_t) 0; 2575ee154d1SPekka Enberg 2585ee154d1SPekka Enberg panic_kvm: 2593fdf659dSSasha Levin fprintf(stderr, "KVM exit reason: %u (\"%s\")\n", 260d77a9efaSCyrill Gorcunov current_kvm_cpu->kvm_run->exit_reason, 261d77a9efaSCyrill Gorcunov kvm_exit_reasons[current_kvm_cpu->kvm_run->exit_reason]); 262d77a9efaSCyrill Gorcunov if (current_kvm_cpu->kvm_run->exit_reason == KVM_EXIT_UNKNOWN) 26369f50425SAndreas Herrmann fprintf(stderr, "KVM exit code: 0x%llu\n", 26469f50425SAndreas Herrmann (unsigned long long)current_kvm_cpu->kvm_run->hw.hardware_exit_reason); 2658e5accedSPekka Enberg 266b7d2f013SSasha Levin kvm_cpu__set_debug_fd(STDOUT_FILENO); 267d77a9efaSCyrill Gorcunov kvm_cpu__show_registers(current_kvm_cpu); 268d77a9efaSCyrill Gorcunov kvm_cpu__show_code(current_kvm_cpu); 269d77a9efaSCyrill Gorcunov kvm_cpu__show_page_tables(current_kvm_cpu); 2705ee154d1SPekka Enberg 2715ee154d1SPekka Enberg return (void *) (intptr_t) 1; 2725ee154d1SPekka Enberg } 2735ee154d1SPekka Enberg 274e08c0896SPrasad Joshi static char kernel[PATH_MAX]; 275b0b42ba0SPekka Enberg 276b0b42ba0SPekka Enberg static const char *host_kernels[] = { 277e08c0896SPrasad Joshi "/boot/vmlinuz", 278e08c0896SPrasad Joshi "/boot/bzImage", 279e08c0896SPrasad Joshi NULL 280e08c0896SPrasad Joshi }; 281b0b42ba0SPekka Enberg 282b0b42ba0SPekka Enberg static const char *default_kernels[] = { 283e08c0896SPrasad Joshi "./bzImage", 284b03af790SKonstantin Khlebnikov "arch/" BUILD_ARCH "/boot/bzImage", 285af7b0868SMatt Evans "../../arch/" BUILD_ARCH "/boot/bzImage", 286e08c0896SPrasad Joshi NULL 287e08c0896SPrasad Joshi }; 2888329f30bSPekka Enberg 289b0b42ba0SPekka Enberg static const char *default_vmlinux[] = { 290b03af790SKonstantin Khlebnikov "vmlinux", 291b0b42ba0SPekka Enberg "../../../vmlinux", 292b0b42ba0SPekka Enberg "../../vmlinux", 293b0b42ba0SPekka Enberg NULL 294b0b42ba0SPekka Enberg }; 295b0b42ba0SPekka Enberg 296e08c0896SPrasad Joshi static void kernel_usage_with_options(void) 2978329f30bSPekka Enberg { 298e08c0896SPrasad Joshi const char **k; 2998329f30bSPekka Enberg struct utsname uts; 300e08c0896SPrasad Joshi 301e08c0896SPrasad Joshi fprintf(stderr, "Fatal: could not find default kernel image in:\n"); 30265182f37SPrasad Joshi k = &default_kernels[0]; 303e08c0896SPrasad Joshi while (*k) { 304e08c0896SPrasad Joshi fprintf(stderr, "\t%s\n", *k); 305e08c0896SPrasad Joshi k++; 306e08c0896SPrasad Joshi } 307e08c0896SPrasad Joshi 308e08c0896SPrasad Joshi if (uname(&uts) < 0) 309e08c0896SPrasad Joshi return; 310e08c0896SPrasad Joshi 311e08c0896SPrasad Joshi k = &host_kernels[0]; 312e08c0896SPrasad Joshi while (*k) { 313e08c0896SPrasad Joshi if (snprintf(kernel, PATH_MAX, "%s-%s", *k, uts.release) < 0) 314e08c0896SPrasad Joshi return; 315e08c0896SPrasad Joshi fprintf(stderr, "\t%s\n", kernel); 316e08c0896SPrasad Joshi k++; 317e08c0896SPrasad Joshi } 318ee8b1456SWanlong Gao fprintf(stderr, "\nPlease see '%s run --help' for more options.\n\n", 319ee8b1456SWanlong Gao KVM_BINARY_NAME); 320e08c0896SPrasad Joshi } 321e08c0896SPrasad Joshi 32260ded003SPekka Enberg static u64 host_ram_size(void) 32360ded003SPekka Enberg { 32460ded003SPekka Enberg long page_size; 32560ded003SPekka Enberg long nr_pages; 32660ded003SPekka Enberg 32760ded003SPekka Enberg nr_pages = sysconf(_SC_PHYS_PAGES); 328d63c5ce6SPekka Enberg if (nr_pages < 0) { 3294542f276SCyrill Gorcunov pr_warning("sysconf(_SC_PHYS_PAGES) failed"); 330d63c5ce6SPekka Enberg return 0; 331d63c5ce6SPekka Enberg } 33260ded003SPekka Enberg 33360ded003SPekka Enberg page_size = sysconf(_SC_PAGE_SIZE); 334d63c5ce6SPekka Enberg if (page_size < 0) { 3354542f276SCyrill Gorcunov pr_warning("sysconf(_SC_PAGE_SIZE) failed"); 336d63c5ce6SPekka Enberg return 0; 337d63c5ce6SPekka Enberg } 33860ded003SPekka Enberg 3399d655190SAlexandru Elisei return (u64)nr_pages * page_size; 34060ded003SPekka Enberg } 34160ded003SPekka Enberg 34218bd8c3bSPekka Enberg /* 34318bd8c3bSPekka Enberg * If user didn't specify how much memory it wants to allocate for the guest, 34418bd8c3bSPekka Enberg * avoid filling the whole host RAM. 34518bd8c3bSPekka Enberg */ 34618bd8c3bSPekka Enberg #define RAM_SIZE_RATIO 0.8 34718bd8c3bSPekka Enberg 348fd834defSPekka Enberg static u64 get_ram_size(int nr_cpus) 349fd834defSPekka Enberg { 35006761c76SPekka Enberg u64 available; 35106761c76SPekka Enberg u64 ram_size; 352fd834defSPekka Enberg 3539d655190SAlexandru Elisei ram_size = (u64)SZ_64M * (nr_cpus + 3); 354fd834defSPekka Enberg 35560ded003SPekka Enberg available = host_ram_size() * RAM_SIZE_RATIO; 356d63c5ce6SPekka Enberg if (!available) 3579d655190SAlexandru Elisei available = MIN_RAM_SIZE; 358fd834defSPekka Enberg 359fd834defSPekka Enberg if (ram_size > available) 360fd834defSPekka Enberg ram_size = available; 361fd834defSPekka Enberg 362fd834defSPekka Enberg return ram_size; 363fd834defSPekka Enberg } 364fd834defSPekka Enberg 365e08c0896SPrasad Joshi static const char *find_kernel(void) 366e08c0896SPrasad Joshi { 367e08c0896SPrasad Joshi const char **k; 3688329f30bSPekka Enberg struct stat st; 369e08c0896SPrasad Joshi struct utsname uts; 370e08c0896SPrasad Joshi 37165182f37SPrasad Joshi k = &default_kernels[0]; 372e08c0896SPrasad Joshi while (*k) { 373e08c0896SPrasad Joshi if (stat(*k, &st) < 0 || !S_ISREG(st.st_mode)) { 374e08c0896SPrasad Joshi k++; 375e08c0896SPrasad Joshi continue; 376e08c0896SPrasad Joshi } 377266a0ed4SAndre Przywara strlcpy(kernel, *k, PATH_MAX); 378e08c0896SPrasad Joshi return kernel; 379e08c0896SPrasad Joshi } 3808329f30bSPekka Enberg 3818329f30bSPekka Enberg if (uname(&uts) < 0) 3828329f30bSPekka Enberg return NULL; 3838329f30bSPekka Enberg 384e08c0896SPrasad Joshi k = &host_kernels[0]; 385e08c0896SPrasad Joshi while (*k) { 386e08c0896SPrasad Joshi if (snprintf(kernel, PATH_MAX, "%s-%s", *k, uts.release) < 0) 3878329f30bSPekka Enberg return NULL; 3888329f30bSPekka Enberg 389e08c0896SPrasad Joshi if (stat(kernel, &st) < 0 || !S_ISREG(st.st_mode)) { 390e08c0896SPrasad Joshi k++; 391e08c0896SPrasad Joshi continue; 392e08c0896SPrasad Joshi } 393e08c0896SPrasad Joshi return kernel; 3948329f30bSPekka Enberg 395e08c0896SPrasad Joshi } 3968329f30bSPekka Enberg return NULL; 3978329f30bSPekka Enberg } 3988329f30bSPekka Enberg 399b0b42ba0SPekka Enberg static const char *find_vmlinux(void) 400b0b42ba0SPekka Enberg { 401b0b42ba0SPekka Enberg const char **vmlinux; 402b0b42ba0SPekka Enberg 403b0b42ba0SPekka Enberg vmlinux = &default_vmlinux[0]; 404b0b42ba0SPekka Enberg while (*vmlinux) { 405b0b42ba0SPekka Enberg struct stat st; 406b0b42ba0SPekka Enberg 407b0b42ba0SPekka Enberg if (stat(*vmlinux, &st) < 0 || !S_ISREG(st.st_mode)) { 408b0b42ba0SPekka Enberg vmlinux++; 409b0b42ba0SPekka Enberg continue; 410b0b42ba0SPekka Enberg } 411b0b42ba0SPekka Enberg return *vmlinux; 412b0b42ba0SPekka Enberg } 413b0b42ba0SPekka Enberg return NULL; 414b0b42ba0SPekka Enberg } 415b0b42ba0SPekka Enberg 416f6677a1dSAmerigo Wang void kvm_run_help(void) 417f6677a1dSAmerigo Wang { 4184346fd8fSSasha Levin struct kvm *kvm = NULL; 4194346fd8fSSasha Levin 4203b55dcdeSSasha Levin BUILD_OPTIONS(options, &kvm->cfg, kvm); 421f6677a1dSAmerigo Wang usage_with_options(run_usage, options); 422f6677a1dSAmerigo Wang } 423f6677a1dSAmerigo Wang 4244346fd8fSSasha Levin static int kvm_run_set_sandbox(struct kvm *kvm) 425d50fe489SSasha Levin { 42647621338SSasha Levin const char *guestfs_name = kvm->cfg.custom_rootfs_name; 427d50fe489SSasha Levin char path[PATH_MAX], script[PATH_MAX], *tmp; 428d50fe489SSasha Levin 429d50fe489SSasha Levin snprintf(path, PATH_MAX, "%s%s/virt/sandbox.sh", kvm__get_dir(), guestfs_name); 430d50fe489SSasha Levin 431d50fe489SSasha Levin remove(path); 432d50fe489SSasha Levin 43347621338SSasha Levin if (kvm->cfg.sandbox == NULL) 434d50fe489SSasha Levin return 0; 435d50fe489SSasha Levin 43647621338SSasha Levin tmp = realpath(kvm->cfg.sandbox, NULL); 437d50fe489SSasha Levin if (tmp == NULL) 438d50fe489SSasha Levin return -ENOMEM; 439d50fe489SSasha Levin 440d50fe489SSasha Levin snprintf(script, PATH_MAX, "/host/%s", tmp); 441d50fe489SSasha Levin free(tmp); 442d50fe489SSasha Levin 443d50fe489SSasha Levin return symlink(script, path); 444d50fe489SSasha Levin } 445d50fe489SSasha Levin 4465173b4afSLai Jiangshan static void kvm_write_sandbox_cmd_exactly(int fd, const char *arg) 4475173b4afSLai Jiangshan { 4485173b4afSLai Jiangshan const char *single_quote; 4495173b4afSLai Jiangshan 4505173b4afSLai Jiangshan if (!*arg) { /* zero length string */ 4515173b4afSLai Jiangshan if (write(fd, "''", 2) <= 0) 4525173b4afSLai Jiangshan die("Failed writing sandbox script"); 4535173b4afSLai Jiangshan return; 4545173b4afSLai Jiangshan } 4555173b4afSLai Jiangshan 4565173b4afSLai Jiangshan while (*arg) { 4575173b4afSLai Jiangshan single_quote = strchrnul(arg, '\''); 4585173b4afSLai Jiangshan 4595173b4afSLai Jiangshan /* write non-single-quote string as #('string') */ 4605173b4afSLai Jiangshan if (arg != single_quote) { 4615173b4afSLai Jiangshan if (write(fd, "'", 1) <= 0 || 4625173b4afSLai Jiangshan write(fd, arg, single_quote - arg) <= 0 || 4635173b4afSLai Jiangshan write(fd, "'", 1) <= 0) 4645173b4afSLai Jiangshan die("Failed writing sandbox script"); 4655173b4afSLai Jiangshan } 4665173b4afSLai Jiangshan 4675173b4afSLai Jiangshan /* write single quote as #("'") */ 4685173b4afSLai Jiangshan if (*single_quote) { 4695173b4afSLai Jiangshan if (write(fd, "\"'\"", 3) <= 0) 4705173b4afSLai Jiangshan die("Failed writing sandbox script"); 4715173b4afSLai Jiangshan } else 4725173b4afSLai Jiangshan break; 4735173b4afSLai Jiangshan 4745173b4afSLai Jiangshan arg = single_quote + 1; 4755173b4afSLai Jiangshan } 4765173b4afSLai Jiangshan } 4775173b4afSLai Jiangshan 4785cd19aa0SPekka Enberg static void resolve_program(const char *src, char *dst, size_t len) 4795cd19aa0SPekka Enberg { 4805cd19aa0SPekka Enberg struct stat st; 481c2c742d9SPekka Enberg int err; 4825cd19aa0SPekka Enberg 483c2c742d9SPekka Enberg err = stat(src, &st); 4845cd19aa0SPekka Enberg 485c2c742d9SPekka Enberg if (!err && S_ISREG(st.st_mode)) { 4865cd19aa0SPekka Enberg char resolved_path[PATH_MAX]; 4875cd19aa0SPekka Enberg 488de3f75c9SPekka Enberg if (!realpath(src, resolved_path)) 489de3f75c9SPekka Enberg die("Unable to resolve program %s: %s\n", src, strerror(errno)); 4905cd19aa0SPekka Enberg 49196eda741SAnisse Astier if (snprintf(dst, len, "/host%s", resolved_path) >= (int)len) 49296eda741SAnisse Astier die("Pathname too long: %s -> %s\n", src, resolved_path); 49396eda741SAnisse Astier 4945cd19aa0SPekka Enberg } else 495266a0ed4SAndre Przywara strlcpy(dst, src, len); 4965cd19aa0SPekka Enberg } 4975cd19aa0SPekka Enberg 4984346fd8fSSasha Levin static void kvm_run_write_sandbox_cmd(struct kvm *kvm, const char **argv, int argc) 4993c29e2aaSSasha Levin { 5003c29e2aaSSasha Levin const char script_hdr[] = "#! /bin/bash\n\n"; 5015cd19aa0SPekka Enberg char program[PATH_MAX]; 5023c29e2aaSSasha Levin int fd; 5033c29e2aaSSasha Levin 50447621338SSasha Levin remove(kvm->cfg.sandbox); 5053c29e2aaSSasha Levin 50647621338SSasha Levin fd = open(kvm->cfg.sandbox, O_RDWR | O_CREAT, 0777); 5073c29e2aaSSasha Levin if (fd < 0) 5083c29e2aaSSasha Levin die("Failed creating sandbox script"); 5093c29e2aaSSasha Levin 5103c29e2aaSSasha Levin if (write(fd, script_hdr, sizeof(script_hdr) - 1) <= 0) 5113c29e2aaSSasha Levin die("Failed writing sandbox script"); 5123c29e2aaSSasha Levin 5135cd19aa0SPekka Enberg resolve_program(argv[0], program, PATH_MAX); 5145cd19aa0SPekka Enberg kvm_write_sandbox_cmd_exactly(fd, program); 5155cd19aa0SPekka Enberg 5165cd19aa0SPekka Enberg argv++; 5175cd19aa0SPekka Enberg argc--; 5185cd19aa0SPekka Enberg 5193c29e2aaSSasha Levin while (argc) { 5203c29e2aaSSasha Levin if (write(fd, " ", 1) <= 0) 5213c29e2aaSSasha Levin die("Failed writing sandbox script"); 5225cd19aa0SPekka Enberg 5235cd19aa0SPekka Enberg kvm_write_sandbox_cmd_exactly(fd, argv[0]); 5243c29e2aaSSasha Levin argv++; 5253c29e2aaSSasha Levin argc--; 5263c29e2aaSSasha Levin } 5273c29e2aaSSasha Levin if (write(fd, "\n", 1) <= 0) 5283c29e2aaSSasha Levin die("Failed writing sandbox script"); 5293c29e2aaSSasha Levin 5303c29e2aaSSasha Levin close(fd); 5313c29e2aaSSasha Levin } 5323c29e2aaSSasha Levin 533a5253f7cSAlexandru Elisei static void kvm_run_set_real_cmdline(struct kvm *kvm) 534a5253f7cSAlexandru Elisei { 535a5253f7cSAlexandru Elisei static char real_cmdline[2048]; 536a5253f7cSAlexandru Elisei bool video; 537a5253f7cSAlexandru Elisei 538a5253f7cSAlexandru Elisei video = kvm->cfg.vnc || kvm->cfg.sdl || kvm->cfg.gtk; 539a5253f7cSAlexandru Elisei 540a5253f7cSAlexandru Elisei memset(real_cmdline, 0, sizeof(real_cmdline)); 541a5253f7cSAlexandru Elisei kvm__arch_set_cmdline(real_cmdline, video); 542a5253f7cSAlexandru Elisei 543a5253f7cSAlexandru Elisei if (video) { 544a5253f7cSAlexandru Elisei strcat(real_cmdline, " console=tty0"); 545a5253f7cSAlexandru Elisei } else { 546a5253f7cSAlexandru Elisei switch (kvm->cfg.active_console) { 547a5253f7cSAlexandru Elisei case CONSOLE_HV: 548a5253f7cSAlexandru Elisei /* Fallthrough */ 549a5253f7cSAlexandru Elisei case CONSOLE_VIRTIO: 550a5253f7cSAlexandru Elisei strcat(real_cmdline, " console=hvc0"); 551a5253f7cSAlexandru Elisei break; 552a5253f7cSAlexandru Elisei case CONSOLE_8250: 553a5253f7cSAlexandru Elisei strcat(real_cmdline, " console=ttyS0"); 554a5253f7cSAlexandru Elisei break; 555a5253f7cSAlexandru Elisei } 556a5253f7cSAlexandru Elisei } 557a5253f7cSAlexandru Elisei 558a5253f7cSAlexandru Elisei if (kvm->cfg.using_rootfs) { 559a5253f7cSAlexandru Elisei strcat(real_cmdline, " rw rootflags=trans=virtio,version=9p2000.L,cache=loose rootfstype=9p"); 560a5253f7cSAlexandru Elisei if (kvm->cfg.custom_rootfs) { 561a5253f7cSAlexandru Elisei #ifdef CONFIG_GUEST_PRE_INIT 562a5253f7cSAlexandru Elisei strcat(real_cmdline, " init=/virt/pre_init"); 563a5253f7cSAlexandru Elisei #else 564a5253f7cSAlexandru Elisei strcat(real_cmdline, " init=/virt/init"); 565a5253f7cSAlexandru Elisei #endif 566a5253f7cSAlexandru Elisei if (!kvm->cfg.no_dhcp) 567a5253f7cSAlexandru Elisei strcat(real_cmdline, " ip=dhcp"); 568a5253f7cSAlexandru Elisei } 569a5253f7cSAlexandru Elisei } else if (!kvm->cfg.kernel_cmdline || !strstr(kvm->cfg.kernel_cmdline, "root=")) { 570a5253f7cSAlexandru Elisei strlcat(real_cmdline, " root=/dev/vda rw ", sizeof(real_cmdline)); 571a5253f7cSAlexandru Elisei } 572a5253f7cSAlexandru Elisei 573a5253f7cSAlexandru Elisei if (kvm->cfg.kernel_cmdline) { 574a5253f7cSAlexandru Elisei strcat(real_cmdline, " "); 575a5253f7cSAlexandru Elisei strlcat(real_cmdline, kvm->cfg.kernel_cmdline, sizeof(real_cmdline)); 576a5253f7cSAlexandru Elisei } 577a5253f7cSAlexandru Elisei 578a5253f7cSAlexandru Elisei kvm->cfg.real_cmdline = real_cmdline; 579a5253f7cSAlexandru Elisei } 580a5253f7cSAlexandru Elisei 581cce96164SAlexandru Elisei static void kvm_run_validate_cfg(struct kvm *kvm) 582cce96164SAlexandru Elisei { 58328b96259SAlexandru Elisei u64 available_ram; 58428b96259SAlexandru Elisei 585cce96164SAlexandru Elisei if (kvm->cfg.kernel_filename && kvm->cfg.firmware_filename) 586cce96164SAlexandru Elisei die("Only one of --kernel or --firmware can be specified"); 587cce96164SAlexandru Elisei 588cce96164SAlexandru Elisei if ((kvm->cfg.vnc && (kvm->cfg.sdl || kvm->cfg.gtk)) || 589cce96164SAlexandru Elisei (kvm->cfg.sdl && kvm->cfg.gtk)) 590cce96164SAlexandru Elisei die("Only one of --vnc, --sdl or --gtk can be specified"); 591cce96164SAlexandru Elisei 592cce96164SAlexandru Elisei if (kvm->cfg.firmware_filename && kvm->cfg.initrd_filename) 593cce96164SAlexandru Elisei pr_warning("Ignoring initrd file when loading a firmware image"); 59428b96259SAlexandru Elisei 59528b96259SAlexandru Elisei if (kvm->cfg.ram_size) { 59628b96259SAlexandru Elisei available_ram = host_ram_size(); 59728b96259SAlexandru Elisei if (available_ram && kvm->cfg.ram_size > available_ram) { 59828b96259SAlexandru Elisei pr_warning("Guest memory size %lluMB exceeds host physical RAM size %lluMB", 59928b96259SAlexandru Elisei (unsigned long long)kvm->cfg.ram_size >> MB_SHIFT, 60028b96259SAlexandru Elisei (unsigned long long)available_ram >> MB_SHIFT); 60128b96259SAlexandru Elisei } 60228b96259SAlexandru Elisei } 603abe3f28aSAlexandru Elisei 604abe3f28aSAlexandru Elisei kvm__arch_validate_cfg(kvm); 605cce96164SAlexandru Elisei } 606cce96164SAlexandru Elisei 6074346fd8fSSasha Levin static struct kvm *kvm_cmd_run_init(int argc, const char **argv) 608f967c427SPrasad Joshi { 609a5253f7cSAlexandru Elisei static char default_name[20]; 610384922b3SPekka Enberg unsigned int nr_online_cpus; 6114346fd8fSSasha Levin struct kvm *kvm = kvm__new(); 61247621338SSasha Levin 61347621338SSasha Levin if (IS_ERR(kvm)) 6144346fd8fSSasha Levin return kvm; 615f967c427SPrasad Joshi 616cfd63bbbSSasha Levin nr_online_cpus = sysconf(_SC_NPROCESSORS_ONLN); 61747621338SSasha Levin kvm->cfg.custom_rootfs_name = "default"; 618*8b91a182SAlexandru Elisei /* 619*8b91a182SAlexandru Elisei * An architecture can allow the user to set the RAM base address to 620*8b91a182SAlexandru Elisei * zero. Initialize the address before parsing the command line 621*8b91a182SAlexandru Elisei * arguments, otherwise it will be impossible to distinguish between the 622*8b91a182SAlexandru Elisei * user setting the base address to zero or letting it unset and using 623*8b91a182SAlexandru Elisei * the default value. 624*8b91a182SAlexandru Elisei */ 625*8b91a182SAlexandru Elisei kvm->cfg.ram_addr = kvm__arch_default_ram_address(); 626cfd63bbbSSasha Levin 627f967c427SPrasad Joshi while (argc != 0) { 6283b55dcdeSSasha Levin BUILD_OPTIONS(options, &kvm->cfg, kvm); 629f967c427SPrasad Joshi argc = parse_options(argc, argv, options, run_usage, 6301a007c82SSasha Levin PARSE_OPT_STOP_AT_NON_OPTION | 6311a007c82SSasha Levin PARSE_OPT_KEEP_DASHDASH); 632f967c427SPrasad Joshi if (argc != 0) { 6331a007c82SSasha Levin /* Cusrom options, should have been handled elsewhere */ 6343c29e2aaSSasha Levin if (strcmp(argv[0], "--") == 0) { 6353c29e2aaSSasha Levin if (kvm_run_wrapper == KVM_RUN_SANDBOX) { 63647621338SSasha Levin kvm->cfg.sandbox = DEFAULT_SANDBOX_FILENAME; 6374346fd8fSSasha Levin kvm_run_write_sandbox_cmd(kvm, argv+1, argc-1); 6381a007c82SSasha Levin break; 6393c29e2aaSSasha Levin } 6403c29e2aaSSasha Levin } 6411a007c82SSasha Levin 64247621338SSasha Levin if ((kvm_run_wrapper == KVM_RUN_DEFAULT && kvm->cfg.kernel_filename) || 64347621338SSasha Levin (kvm_run_wrapper == KVM_RUN_SANDBOX && kvm->cfg.sandbox)) { 644f967c427SPrasad Joshi fprintf(stderr, "Cannot handle parameter: " 645f967c427SPrasad Joshi "%s\n", argv[0]); 646f967c427SPrasad Joshi usage_with_options(run_usage, options); 64747621338SSasha Levin free(kvm); 6484346fd8fSSasha Levin return ERR_PTR(-EINVAL); 649f967c427SPrasad Joshi } 650e0747665SSasha Levin if (kvm_run_wrapper == KVM_RUN_SANDBOX) { 651e0747665SSasha Levin /* 652e0747665SSasha Levin * first unhandled parameter is treated as 653e0747665SSasha Levin * sandbox command 654e0747665SSasha Levin */ 65547621338SSasha Levin kvm->cfg.sandbox = DEFAULT_SANDBOX_FILENAME; 6564346fd8fSSasha Levin kvm_run_write_sandbox_cmd(kvm, argv, argc); 657e0747665SSasha Levin } else { 658e0747665SSasha Levin /* 659e0747665SSasha Levin * first unhandled parameter is treated as a kernel 660e0747665SSasha Levin * image 661f967c427SPrasad Joshi */ 66247621338SSasha Levin kvm->cfg.kernel_filename = argv[0]; 663e0747665SSasha Levin } 664f967c427SPrasad Joshi argv++; 665f967c427SPrasad Joshi argc--; 666f967c427SPrasad Joshi } 667f967c427SPrasad Joshi 668f967c427SPrasad Joshi } 669f967c427SPrasad Joshi 670cce96164SAlexandru Elisei kvm_run_validate_cfg(kvm); 671cce96164SAlexandru Elisei 67213498576SJulien Thierry if (!kvm->cfg.kernel_filename && !kvm->cfg.firmware_filename) { 67347621338SSasha Levin kvm->cfg.kernel_filename = find_kernel(); 6748329f30bSPekka Enberg 67547621338SSasha Levin if (!kvm->cfg.kernel_filename) { 676e08c0896SPrasad Joshi kernel_usage_with_options(); 6774346fd8fSSasha Levin return ERR_PTR(-EINVAL); 6788329f30bSPekka Enberg } 67913498576SJulien Thierry } 6808329f30bSPekka Enberg 681638630c9SAlexandru Elisei if (kvm->cfg.kernel_filename) { 68247621338SSasha Levin kvm->cfg.vmlinux_filename = find_vmlinux(); 683084a1356SSasha Levin kvm->vmlinux = kvm->cfg.vmlinux_filename; 684638630c9SAlexandru Elisei } 685b0b42ba0SPekka Enberg 68600ebbe96SSasha Levin if (kvm->cfg.nrcpus == 0) 68700ebbe96SSasha Levin kvm->cfg.nrcpus = nr_online_cpus; 688d77a9efaSCyrill Gorcunov 68947621338SSasha Levin if (!kvm->cfg.ram_size) 69000ebbe96SSasha Levin kvm->cfg.ram_size = get_ram_size(kvm->cfg.nrcpus); 691f967c427SPrasad Joshi 69247621338SSasha Levin if (!kvm->cfg.dev) 69347621338SSasha Levin kvm->cfg.dev = DEFAULT_KVM_DEV; 694f967c427SPrasad Joshi 69547621338SSasha Levin if (!kvm->cfg.console) 69647621338SSasha Levin kvm->cfg.console = DEFAULT_CONSOLE; 6979aa4a0ebSAsias He 69847621338SSasha Levin if (!strncmp(kvm->cfg.console, "virtio", 6)) 6992651ea58SSasha Levin kvm->cfg.active_console = CONSOLE_VIRTIO; 70047621338SSasha Levin else if (!strncmp(kvm->cfg.console, "serial", 6)) 7012651ea58SSasha Levin kvm->cfg.active_console = CONSOLE_8250; 70247621338SSasha Levin else if (!strncmp(kvm->cfg.console, "hv", 2)) 7032651ea58SSasha Levin kvm->cfg.active_console = CONSOLE_HV; 7043bbc49b6SMatt Evans else 7053bbc49b6SMatt Evans pr_warning("No console!"); 706f967c427SPrasad Joshi 70747621338SSasha Levin if (!kvm->cfg.host_ip) 70847621338SSasha Levin kvm->cfg.host_ip = DEFAULT_HOST_ADDR; 7094d67c820SSasha Levin 71047621338SSasha Levin if (!kvm->cfg.guest_ip) 71147621338SSasha Levin kvm->cfg.guest_ip = DEFAULT_GUEST_ADDR; 712bb8ffd2fSAsias He 71347621338SSasha Levin if (!kvm->cfg.guest_mac) 71447621338SSasha Levin kvm->cfg.guest_mac = DEFAULT_GUEST_MAC; 715a4e724ddSSasha Levin 71647621338SSasha Levin if (!kvm->cfg.host_mac) 71747621338SSasha Levin kvm->cfg.host_mac = DEFAULT_HOST_MAC; 718d7098b9bSAsias He 71947621338SSasha Levin if (!kvm->cfg.script) 72047621338SSasha Levin kvm->cfg.script = DEFAULT_SCRIPT; 72173b7d038SAmos Kong 722cf5323a3SSasha Levin if (!kvm->cfg.network) 723cf5323a3SSasha Levin kvm->cfg.network = DEFAULT_NETWORK; 724cf5323a3SSasha Levin 72547621338SSasha Levin if (!kvm->cfg.guest_name) { 72647621338SSasha Levin if (kvm->cfg.custom_rootfs) { 72747621338SSasha Levin kvm->cfg.guest_name = kvm->cfg.custom_rootfs_name; 728587a4d17SLai Jiangshan } else { 7292d96f6b6SSasha Levin sprintf(default_name, "guest-%u", getpid()); 73047621338SSasha Levin kvm->cfg.guest_name = default_name; 7312d96f6b6SSasha Levin } 732587a4d17SLai Jiangshan } 7332d96f6b6SSasha Levin 7345613ae26SAlexandru Elisei if (!kvm->cfg.nodefaults && 7355613ae26SAlexandru Elisei !kvm->cfg.using_rootfs && 7365613ae26SAlexandru Elisei !kvm->cfg.disk_image[0].filename && 7375613ae26SAlexandru Elisei !kvm->cfg.initrd_filename) { 738c8675741SSasha Levin char tmp[PATH_MAX]; 7396df1471eSPekka Enberg 74047621338SSasha Levin kvm_setup_create_new(kvm->cfg.custom_rootfs_name); 74147621338SSasha Levin kvm_setup_resolv(kvm->cfg.custom_rootfs_name); 742c8675741SSasha Levin 7439667701cSPekka Enberg snprintf(tmp, PATH_MAX, "%s%s", kvm__get_dir(), "default"); 744c8675741SSasha Levin if (virtio_9p__register(kvm, tmp, "/dev/root") < 0) 745c8675741SSasha Levin die("Unable to initialize virtio 9p"); 746c8675741SSasha Levin if (virtio_9p__register(kvm, "/", "hostfs") < 0) 747c8675741SSasha Levin die("Unable to initialize virtio 9p"); 74847621338SSasha Levin kvm->cfg.using_rootfs = kvm->cfg.custom_rootfs = 1; 74926c853e4SPrasad Joshi } 75026c853e4SPrasad Joshi 75147621338SSasha Levin if (kvm->cfg.custom_rootfs) { 7524346fd8fSSasha Levin kvm_run_set_sandbox(kvm); 753cdce942cSDimitri John Ledkov if (kvm_setup_guest_init(kvm->cfg.custom_rootfs_name)) 754afc2c7c0SAsias He die("Failed to setup init for guest."); 755a8e6b4b9SSasha Levin } 75659aa2d30SSasha Levin 7575613ae26SAlexandru Elisei if (kvm->cfg.nodefaults) 7585613ae26SAlexandru Elisei kvm->cfg.real_cmdline = kvm->cfg.kernel_cmdline; 7595613ae26SAlexandru Elisei else 760a5253f7cSAlexandru Elisei kvm_run_set_real_cmdline(kvm); 761084a1356SSasha Levin 76213498576SJulien Thierry if (kvm->cfg.kernel_filename) { 763084a1356SSasha Levin printf(" # %s run -k %s -m %Lu -c %d --name %s\n", KVM_BINARY_NAME, 76469f50425SAndreas Herrmann kvm->cfg.kernel_filename, 7659d655190SAlexandru Elisei (unsigned long long)kvm->cfg.ram_size >> MB_SHIFT, 76669f50425SAndreas Herrmann kvm->cfg.nrcpus, kvm->cfg.guest_name); 76713498576SJulien Thierry } else if (kvm->cfg.firmware_filename) { 76813498576SJulien Thierry printf(" # %s run --firmware %s -m %Lu -c %d --name %s\n", KVM_BINARY_NAME, 76913498576SJulien Thierry kvm->cfg.firmware_filename, 7709d655190SAlexandru Elisei (unsigned long long)kvm->cfg.ram_size >> MB_SHIFT, 77113498576SJulien Thierry kvm->cfg.nrcpus, kvm->cfg.guest_name); 77213498576SJulien Thierry } 773084a1356SSasha Levin 7745b403dbfSWill Deacon if (init_list__init(kvm) < 0) 7755b403dbfSWill Deacon die ("Initialisation failed"); 7764346fd8fSSasha Levin 7774346fd8fSSasha Levin return kvm; 778e1e46fe6SSasha Levin } 779e1e46fe6SSasha Levin 7804346fd8fSSasha Levin static int kvm_cmd_run_work(struct kvm *kvm) 781e1e46fe6SSasha Levin { 782df4239fbSSasha Levin int i; 783e1e46fe6SSasha Levin 78400ebbe96SSasha Levin for (i = 0; i < kvm->nrcpus; i++) { 785df4239fbSSasha Levin if (pthread_create(&kvm->cpus[i]->thread, NULL, kvm_cpu_thread, kvm->cpus[i]) != 0) 7865ee154d1SPekka Enberg die("unable to create KVM VCPU thread"); 7875ee154d1SPekka Enberg } 7885ee154d1SPekka Enberg 78949e5227dSSasha Levin /* Only VCPU #0 is going to exit by itself when shutting down */ 790e8cb90fbSWill Deacon if (pthread_join(kvm->cpus[0]->thread, NULL) != 0) 791e8cb90fbSWill Deacon die("unable to join with vcpu 0"); 792e8cb90fbSWill Deacon 793e8cb90fbSWill Deacon return kvm_cpu__exit(kvm); 794e1e46fe6SSasha Levin } 795e1e46fe6SSasha Levin 7964346fd8fSSasha Levin static void kvm_cmd_run_exit(struct kvm *kvm, int guest_ret) 797e1e46fe6SSasha Levin { 798e6694207SSasha Levin compat__print_all_messages(); 799e6694207SSasha Levin 80049a8afd1SSasha Levin init_list__exit(kvm); 801f967c427SPrasad Joshi 802e1e46fe6SSasha Levin if (guest_ret == 0) 803f967c427SPrasad Joshi printf("\n # KVM session ended normally.\n"); 804e1e46fe6SSasha Levin } 805e1e46fe6SSasha Levin 806e1e46fe6SSasha Levin int kvm_cmd_run(int argc, const char **argv, const char *prefix) 807e1e46fe6SSasha Levin { 8084346fd8fSSasha Levin int ret = -EFAULT; 8094346fd8fSSasha Levin struct kvm *kvm; 810e1e46fe6SSasha Levin 8114346fd8fSSasha Levin kvm = kvm_cmd_run_init(argc, argv); 8124346fd8fSSasha Levin if (IS_ERR(kvm)) 8134346fd8fSSasha Levin return PTR_ERR(kvm); 814e1e46fe6SSasha Levin 8154346fd8fSSasha Levin ret = kvm_cmd_run_work(kvm); 8164346fd8fSSasha Levin kvm_cmd_run_exit(kvm, ret); 817e1e46fe6SSasha Levin 818e1e46fe6SSasha Levin return ret; 819f967c427SPrasad Joshi } 820