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; 61bd4ba571SAlexandru Elisei int loglevel = LOGLEVEL_INFO; 62ed036f03SCyrill Gorcunov 63f967c427SPrasad Joshi static const char * const run_usage[] = { 648d2ff5daSWanlong Gao "lkvm run [<options>] [<kernel image>]", 65f967c427SPrasad Joshi NULL 66f967c427SPrasad Joshi }; 67f967c427SPrasad Joshi 683c29e2aaSSasha Levin enum { 69e0747665SSasha Levin KVM_RUN_DEFAULT, 703c29e2aaSSasha Levin KVM_RUN_SANDBOX, 713c29e2aaSSasha Levin }; 723c29e2aaSSasha Levin 73a33979d8SSasha Levin static int img_name_parser(const struct option *opt, const char *arg, int unset) 74a33979d8SSasha Levin { 7582d65b5eSSasha Levin char path[PATH_MAX]; 765236b505SAsias He struct stat st; 77a33979d8SSasha Levin 789667701cSPekka Enberg snprintf(path, PATH_MAX, "%s%s", kvm__get_dir(), arg); 7982d65b5eSSasha Levin 80cac9e8fdSSasha Levin if ((stat(arg, &st) == 0 && S_ISDIR(st.st_mode)) || 81cac9e8fdSSasha Levin (stat(path, &st) == 0 && S_ISDIR(st.st_mode))) 82cac9e8fdSSasha Levin return virtio_9p_img_name_parser(opt, arg, unset); 833b55dcdeSSasha Levin return disk_img_name_parser(opt, arg, unset); 84a67da3beSAsias He } 85a67da3beSAsias He 863b55dcdeSSasha Levin void kvm_run_set_wrapper_sandbox(void) 873b55dcdeSSasha Levin { 883b55dcdeSSasha Levin kvm_run_wrapper = KVM_RUN_SANDBOX; 89a33979d8SSasha Levin } 90a33979d8SSasha Levin 91a9c24ec7SSuzuki K Poulose static int parse_mem_unit(char **next) 92a9c24ec7SSuzuki K Poulose { 93a9c24ec7SSuzuki K Poulose switch (**next) { 94a9c24ec7SSuzuki K Poulose case 'B': case 'b': (*next)++; return 0; 95a9c24ec7SSuzuki K Poulose case 'K': case 'k': (*next)++; return KB_SHIFT; 96a9c24ec7SSuzuki K Poulose case 'M': case 'm': (*next)++; return MB_SHIFT; 97a9c24ec7SSuzuki K Poulose case 'G': case 'g': (*next)++; return GB_SHIFT; 98a9c24ec7SSuzuki K Poulose case 'T': case 't': (*next)++; return TB_SHIFT; 99a9c24ec7SSuzuki K Poulose case 'P': case 'p': (*next)++; return PB_SHIFT; 100a9c24ec7SSuzuki K Poulose } 101a9c24ec7SSuzuki K Poulose 102a9c24ec7SSuzuki K Poulose return MB_SHIFT; 103a9c24ec7SSuzuki K Poulose } 104a9c24ec7SSuzuki K Poulose 105a9c24ec7SSuzuki K Poulose static u64 parse_mem_option(const char *nptr, char **next) 106a9c24ec7SSuzuki K Poulose { 107a9c24ec7SSuzuki K Poulose u64 shift; 108a9c24ec7SSuzuki K Poulose u64 val; 109a9c24ec7SSuzuki K Poulose 110a9c24ec7SSuzuki K Poulose errno = 0; 111a9c24ec7SSuzuki K Poulose val = strtoull(nptr, next, 10); 112a9c24ec7SSuzuki K Poulose if (errno == ERANGE) 113a9c24ec7SSuzuki K Poulose die("Memory too large: %s", nptr); 114a9c24ec7SSuzuki K Poulose if (*next == nptr) 115a9c24ec7SSuzuki K Poulose die("Invalid memory specifier: %s", nptr); 116a9c24ec7SSuzuki K Poulose 117a9c24ec7SSuzuki K Poulose shift = parse_mem_unit(next); 118a9c24ec7SSuzuki K Poulose if ((val << shift) < val) 119a9c24ec7SSuzuki K Poulose die("Memory too large: %s", nptr); 120a9c24ec7SSuzuki K Poulose 121a9c24ec7SSuzuki K Poulose return val << shift; 122a9c24ec7SSuzuki K Poulose } 123a9c24ec7SSuzuki K Poulose 124a9c24ec7SSuzuki K Poulose static int mem_parser(const struct option *opt, const char *arg, int unset) 125a9c24ec7SSuzuki K Poulose { 126a9c24ec7SSuzuki K Poulose struct kvm *kvm = opt->ptr; 1278b91a182SAlexandru Elisei char *next, *nptr; 128a9c24ec7SSuzuki K Poulose 129a9c24ec7SSuzuki K Poulose kvm->cfg.ram_size = parse_mem_option(arg, &next); 130a9c24ec7SSuzuki K Poulose if (kvm->cfg.ram_size == 0) 131a9c24ec7SSuzuki K Poulose die("Invalid RAM size: %s", arg); 132a9c24ec7SSuzuki K Poulose 1338b91a182SAlexandru Elisei if (kvm__arch_has_cfg_ram_address() && *next == '@') { 1348b91a182SAlexandru Elisei next++; 1358b91a182SAlexandru Elisei if (*next == '\0') 1368b91a182SAlexandru Elisei die("Missing memory address: %s", arg); 1378b91a182SAlexandru Elisei 1388b91a182SAlexandru Elisei nptr = next; 1398b91a182SAlexandru Elisei kvm->cfg.ram_addr = parse_mem_option(nptr, &next); 1408b91a182SAlexandru Elisei } 1418b91a182SAlexandru Elisei 142a9c24ec7SSuzuki K Poulose if (*next != '\0') 143a9c24ec7SSuzuki K Poulose die("Invalid memory specifier: %s", arg); 144a9c24ec7SSuzuki K Poulose 145a9c24ec7SSuzuki K Poulose return 0; 146a9c24ec7SSuzuki K Poulose } 147a9c24ec7SSuzuki K Poulose 148bd4ba571SAlexandru Elisei static int loglevel_parser(const struct option *opt, const char *arg, int unset) 149bd4ba571SAlexandru Elisei { 150bd4ba571SAlexandru Elisei if (strcmp(opt->long_name, "debug") == 0) { 151bd4ba571SAlexandru Elisei loglevel = LOGLEVEL_DEBUG; 152bd4ba571SAlexandru Elisei return 0; 153bd4ba571SAlexandru Elisei } 154bd4ba571SAlexandru Elisei 155bd4ba571SAlexandru Elisei if (strcmp(arg, "debug") == 0) 156bd4ba571SAlexandru Elisei loglevel = LOGLEVEL_DEBUG; 157bd4ba571SAlexandru Elisei else if (strcmp(arg, "info") == 0) 158bd4ba571SAlexandru Elisei loglevel = LOGLEVEL_INFO; 159bd4ba571SAlexandru Elisei else if (strcmp(arg, "warning") == 0) 160bd4ba571SAlexandru Elisei loglevel = LOGLEVEL_WARNING; 161bd4ba571SAlexandru Elisei else if (strcmp(arg, "error") == 0) 162bd4ba571SAlexandru Elisei loglevel = LOGLEVEL_ERROR; 163bd4ba571SAlexandru Elisei else 164bd4ba571SAlexandru Elisei die("Unknown loglevel: %s", arg); 165bd4ba571SAlexandru Elisei 166bd4ba571SAlexandru Elisei return 0; 167bd4ba571SAlexandru Elisei } 168bd4ba571SAlexandru Elisei 169ff7ba6faSWill Deacon #ifndef OPT_ARCH_RUN 170ff7ba6faSWill Deacon #define OPT_ARCH_RUN(...) 171ff7ba6faSWill Deacon #endif 172ff7ba6faSWill Deacon 1738b91a182SAlexandru Elisei #ifdef ARCH_HAS_CFG_RAM_ADDRESS 1748b91a182SAlexandru Elisei #define MEM_OPT_HELP_SHORT "size[BKMGTP][@addr[BKMGTP]]" 1758b91a182SAlexandru Elisei #define MEM_OPT_HELP_LONG \ 1768b91a182SAlexandru Elisei "Virtual machine memory size and optional base address, both" \ 1778b91a182SAlexandru Elisei " measured by default in megabytes (M)" 1788b91a182SAlexandru Elisei #else 1798b91a182SAlexandru Elisei #define MEM_OPT_HELP_SHORT "size[BKMGTP]" 1808b91a182SAlexandru Elisei #define MEM_OPT_HELP_LONG \ 1818b91a182SAlexandru Elisei "Virtual machine memory size, by default measured in" \ 1828b91a182SAlexandru Elisei " in megabytes (M)" 1838b91a182SAlexandru Elisei #endif 1848b91a182SAlexandru Elisei 1859b46ebc5SRajnesh Kanwal #if defined(CONFIG_ARM) || defined(CONFIG_ARM64) || defined(CONFIG_RISCV) 1869b46ebc5SRajnesh Kanwal #define VIRTIO_TRANS_OPT_HELP_SHORT "[pci|pci-legacy|mmio|mmio-legacy]" 1879b46ebc5SRajnesh Kanwal #else 1889b46ebc5SRajnesh Kanwal #define VIRTIO_TRANS_OPT_HELP_SHORT "[pci|pci-legacy]" 1899b46ebc5SRajnesh Kanwal #endif 1909b46ebc5SRajnesh Kanwal 1913b55dcdeSSasha Levin #define BUILD_OPTIONS(name, cfg, kvm) \ 192b816364aSSasha Levin struct option name[] = { \ 193b816364aSSasha Levin OPT_GROUP("Basic options:"), \ 194b816364aSSasha Levin OPT_STRING('\0', "name", &(cfg)->guest_name, "guest name", \ 195b816364aSSasha Levin "A name for the guest"), \ 19600ebbe96SSasha Levin OPT_INTEGER('c', "cpus", &(cfg)->nrcpus, "Number of CPUs"), \ 1978b91a182SAlexandru Elisei OPT_CALLBACK('m', "mem", NULL, MEM_OPT_HELP_SHORT, \ 1988b91a182SAlexandru Elisei MEM_OPT_HELP_LONG, mem_parser, kvm), \ 199b5e56fa3SWilliam Dauchy OPT_CALLBACK('d', "disk", kvm, "image or rootfs_dir", "Disk " \ 200b5e56fa3SWilliam Dauchy " image or rootfs directory", img_name_parser, \ 2013b55dcdeSSasha Levin kvm), \ 202b5e56fa3SWilliam Dauchy OPT_BOOLEAN('\0', "balloon", &(cfg)->balloon, "Enable virtio" \ 203b5e56fa3SWilliam Dauchy " balloon"), \ 204b816364aSSasha Levin OPT_BOOLEAN('\0', "vnc", &(cfg)->vnc, "Enable VNC framebuffer"),\ 2057bcceb95SPekka Enberg OPT_BOOLEAN('\0', "gtk", &(cfg)->gtk, "Enable GTK framebuffer"),\ 206b816364aSSasha Levin OPT_BOOLEAN('\0', "sdl", &(cfg)->sdl, "Enable SDL framebuffer"),\ 207b5e56fa3SWilliam Dauchy OPT_BOOLEAN('\0', "rng", &(cfg)->virtio_rng, "Enable virtio" \ 208b5e56fa3SWilliam Dauchy " Random Number Generator"), \ 2095613ae26SAlexandru Elisei OPT_BOOLEAN('\0', "nodefaults", &(cfg)->nodefaults, "Disable" \ 2105613ae26SAlexandru Elisei " implicit configuration that cannot be" \ 2115613ae26SAlexandru Elisei " disabled otherwise"), \ 212b816364aSSasha Levin OPT_CALLBACK('\0', "9p", NULL, "dir_to_share,tag_name", \ 213b5e56fa3SWilliam Dauchy "Enable virtio 9p to share files between host and" \ 214b5e56fa3SWilliam Dauchy " guest", virtio_9p_rootdir_parser, kvm), \ 215b5e56fa3SWilliam Dauchy OPT_STRING('\0', "console", &(cfg)->console, "serial, virtio or"\ 216b5e56fa3SWilliam Dauchy " hv", "Console to use"), \ 217117d6495STianjia Zhang OPT_U64('\0', "vsock", &(cfg)->vsock_cid, \ 218117d6495STianjia Zhang "Guest virtio socket CID"), \ 219b816364aSSasha Levin OPT_STRING('\0', "dev", &(cfg)->dev, "device_file", \ 220b816364aSSasha Levin "KVM device file"), \ 221b816364aSSasha Levin OPT_CALLBACK('\0', "tty", NULL, "tty id", \ 222b816364aSSasha Levin "Remap guest TTY into a pty on the host", \ 2231dc24dccSSasha Levin tty_parser, NULL), \ 224b816364aSSasha Levin OPT_STRING('\0', "sandbox", &(cfg)->sandbox, "script", \ 225b5e56fa3SWilliam Dauchy "Run this script when booting into custom" \ 226b5e56fa3SWilliam Dauchy " rootfs"), \ 227b816364aSSasha Levin OPT_STRING('\0', "hugetlbfs", &(cfg)->hugetlbfs_path, "path", \ 228b816364aSSasha Levin "Hugetlbfs path"), \ 2299b46ebc5SRajnesh Kanwal OPT_CALLBACK_NOOPT('\0', "virtio-legacy", \ 230c1eecc61SAndre Przywara &(cfg)->virtio_transport, "", \ 2319b46ebc5SRajnesh Kanwal "Use legacy virtio transport (Deprecated:" \ 2329b46ebc5SRajnesh Kanwal " Use --virtio-transport option instead)", \ 2339b46ebc5SRajnesh Kanwal virtio_transport_parser, NULL), \ 2349b46ebc5SRajnesh Kanwal OPT_CALLBACK('\0', "virtio-transport", &(cfg)->virtio_transport,\ 2359b46ebc5SRajnesh Kanwal VIRTIO_TRANS_OPT_HELP_SHORT, \ 2369b46ebc5SRajnesh Kanwal "Type of virtio transport", \ 2379b46ebc5SRajnesh Kanwal virtio_transport_parser, NULL), \ 238bd4ba571SAlexandru Elisei OPT_CALLBACK('\0', "loglevel", NULL, "[error|warning|info|debug]",\ 239bd4ba571SAlexandru Elisei "Set the verbosity level", loglevel_parser, NULL),\ 240b816364aSSasha Levin \ 241b816364aSSasha Levin OPT_GROUP("Kernel options:"), \ 242b816364aSSasha Levin OPT_STRING('k', "kernel", &(cfg)->kernel_filename, "kernel", \ 243b816364aSSasha Levin "Kernel to boot in virtual machine"), \ 244b816364aSSasha Levin OPT_STRING('i', "initrd", &(cfg)->initrd_filename, "initrd", \ 245b816364aSSasha Levin "Initial RAM disk image"), \ 246b816364aSSasha Levin OPT_STRING('p', "params", &(cfg)->kernel_cmdline, "params", \ 247b816364aSSasha Levin "Kernel command line arguments"), \ 248b816364aSSasha Levin OPT_STRING('f', "firmware", &(cfg)->firmware_filename, "firmware",\ 249b816364aSSasha Levin "Firmware image to boot in virtual machine"), \ 25025cf3198SRaphael Gault OPT_STRING('F', "flash", &(cfg)->flash_filename, "flash",\ 25125cf3198SRaphael Gault "Flash image to present to virtual machine"), \ 252b816364aSSasha Levin \ 253b816364aSSasha Levin OPT_GROUP("Networking options:"), \ 254b816364aSSasha Levin OPT_CALLBACK_DEFAULT('n', "network", NULL, "network params", \ 255b816364aSSasha Levin "Create a new guest NIC", \ 2565f225124SSasha Levin netdev_parser, NULL, kvm), \ 257b5e56fa3SWilliam Dauchy OPT_BOOLEAN('\0', "no-dhcp", &(cfg)->no_dhcp, "Disable kernel" \ 258b5e56fa3SWilliam Dauchy " DHCP in rootfs mode"), \ 259b816364aSSasha Levin \ 2606078a454SJean-Philippe Brucker OPT_GROUP("VFIO options:"), \ 2616078a454SJean-Philippe Brucker OPT_CALLBACK('\0', "vfio-pci", NULL, "[domain:]bus:dev.fn", \ 2626078a454SJean-Philippe Brucker "Assign a PCI device to the virtual machine", \ 2636078a454SJean-Philippe Brucker vfio_device_parser, kvm), \ 2646078a454SJean-Philippe Brucker \ 265b816364aSSasha Levin OPT_GROUP("Debug options:"), \ 266bd4ba571SAlexandru Elisei OPT_CALLBACK_NOOPT('\0', "debug", kvm, NULL, \ 267bd4ba571SAlexandru Elisei "Enable debug messages (deprecated, use " \ 268bd4ba571SAlexandru Elisei "--loglevel=debug instead)", \ 269bd4ba571SAlexandru Elisei loglevel_parser, NULL), \ 270b816364aSSasha Levin OPT_BOOLEAN('\0', "debug-single-step", &(cfg)->single_step, \ 271b816364aSSasha Levin "Enable single stepping"), \ 2725765977dSSasha Levin OPT_BOOLEAN('\0', "debug-ioport", &(cfg)->ioport_debug, \ 273b816364aSSasha Levin "Enable ioport debugging"), \ 274e830cce7SSasha Levin OPT_BOOLEAN('\0', "debug-mmio", &(cfg)->mmio_debug, \ 275b816364aSSasha Levin "Enable MMIO debugging"), \ 2763b55dcdeSSasha Levin OPT_INTEGER('\0', "debug-iodelay", &(cfg)->debug_iodelay, \ 277b816364aSSasha Levin "Delay IO by millisecond"), \ 278ff7ba6faSWill Deacon \ 279ff7ba6faSWill Deacon OPT_ARCH(RUN, cfg) \ 280b816364aSSasha Levin OPT_END() \ 281f967c427SPrasad Joshi }; 282f967c427SPrasad Joshi 2835ee154d1SPekka Enberg static void *kvm_cpu_thread(void *arg) 2845ee154d1SPekka Enberg { 285a4d8c55eSSasha Levin char name[16]; 286a4d8c55eSSasha Levin 287d77a9efaSCyrill Gorcunov current_kvm_cpu = arg; 2885ee154d1SPekka Enberg 289a4d8c55eSSasha Levin sprintf(name, "kvm-vcpu-%lu", current_kvm_cpu->cpu_id); 290a4d8c55eSSasha Levin kvm__set_thread_name(name); 291a4d8c55eSSasha Levin 292d77a9efaSCyrill Gorcunov if (kvm_cpu__start(current_kvm_cpu)) 2935ee154d1SPekka Enberg goto panic_kvm; 2945ee154d1SPekka Enberg 2955ee154d1SPekka Enberg return (void *) (intptr_t) 0; 2965ee154d1SPekka Enberg 2975ee154d1SPekka Enberg panic_kvm: 29872e13944SAlexandru Elisei pr_err("KVM exit reason: %u (\"%s\")", 299d77a9efaSCyrill Gorcunov current_kvm_cpu->kvm_run->exit_reason, 300d77a9efaSCyrill Gorcunov kvm_exit_reasons[current_kvm_cpu->kvm_run->exit_reason]); 30172e13944SAlexandru Elisei 30272e13944SAlexandru Elisei if (current_kvm_cpu->kvm_run->exit_reason == KVM_EXIT_UNKNOWN) { 30372e13944SAlexandru Elisei pr_err("KVM exit code: %llu", 30469f50425SAndreas Herrmann (unsigned long long)current_kvm_cpu->kvm_run->hw.hardware_exit_reason); 30572e13944SAlexandru Elisei } 3068e5accedSPekka Enberg 307b7d2f013SSasha Levin kvm_cpu__set_debug_fd(STDOUT_FILENO); 308d77a9efaSCyrill Gorcunov kvm_cpu__show_registers(current_kvm_cpu); 309d77a9efaSCyrill Gorcunov kvm_cpu__show_code(current_kvm_cpu); 310d77a9efaSCyrill Gorcunov kvm_cpu__show_page_tables(current_kvm_cpu); 3115ee154d1SPekka Enberg 3125ee154d1SPekka Enberg return (void *) (intptr_t) 1; 3135ee154d1SPekka Enberg } 3145ee154d1SPekka Enberg 315e08c0896SPrasad Joshi static char kernel[PATH_MAX]; 316b0b42ba0SPekka Enberg 317b0b42ba0SPekka Enberg static const char *host_kernels[] = { 318e08c0896SPrasad Joshi "/boot/vmlinuz", 319e08c0896SPrasad Joshi "/boot/bzImage", 320e08c0896SPrasad Joshi NULL 321e08c0896SPrasad Joshi }; 322b0b42ba0SPekka Enberg 323b0b42ba0SPekka Enberg static const char *default_kernels[] = { 324e08c0896SPrasad Joshi "./bzImage", 325b03af790SKonstantin Khlebnikov "arch/" BUILD_ARCH "/boot/bzImage", 326af7b0868SMatt Evans "../../arch/" BUILD_ARCH "/boot/bzImage", 327e08c0896SPrasad Joshi NULL 328e08c0896SPrasad Joshi }; 3298329f30bSPekka Enberg 330b0b42ba0SPekka Enberg static const char *default_vmlinux[] = { 331b03af790SKonstantin Khlebnikov "vmlinux", 332b0b42ba0SPekka Enberg "../../../vmlinux", 333b0b42ba0SPekka Enberg "../../vmlinux", 334b0b42ba0SPekka Enberg NULL 335b0b42ba0SPekka Enberg }; 336b0b42ba0SPekka Enberg 337e08c0896SPrasad Joshi static void kernel_usage_with_options(void) 3388329f30bSPekka Enberg { 339e08c0896SPrasad Joshi const char **k; 3408329f30bSPekka Enberg struct utsname uts; 341e08c0896SPrasad Joshi 34272e13944SAlexandru Elisei pr_err("Could not find default kernel image in:"); 34365182f37SPrasad Joshi k = &default_kernels[0]; 344e08c0896SPrasad Joshi while (*k) { 34572e13944SAlexandru Elisei pr_err("\t%s", *k); 346e08c0896SPrasad Joshi k++; 347e08c0896SPrasad Joshi } 348e08c0896SPrasad Joshi 349e08c0896SPrasad Joshi if (uname(&uts) < 0) 350e08c0896SPrasad Joshi return; 351e08c0896SPrasad Joshi 352e08c0896SPrasad Joshi k = &host_kernels[0]; 353e08c0896SPrasad Joshi while (*k) { 354e08c0896SPrasad Joshi if (snprintf(kernel, PATH_MAX, "%s-%s", *k, uts.release) < 0) 355e08c0896SPrasad Joshi return; 35672e13944SAlexandru Elisei pr_err("\t%s", kernel); 357e08c0896SPrasad Joshi k++; 358e08c0896SPrasad Joshi } 35972e13944SAlexandru Elisei pr_info("Please see '%s run --help' for more options.", 360ee8b1456SWanlong Gao KVM_BINARY_NAME); 361e08c0896SPrasad Joshi } 362e08c0896SPrasad Joshi 363b6bae725SFuad Tabba static long host_page_size(void) 364b6bae725SFuad Tabba { 365b6bae725SFuad Tabba long page_size = sysconf(_SC_PAGE_SIZE); 366b6bae725SFuad Tabba 367b6bae725SFuad Tabba if (page_size < 0) { 368b6bae725SFuad Tabba pr_warning("sysconf(_SC_PAGE_SIZE) failed"); 369b6bae725SFuad Tabba return 0; 370b6bae725SFuad Tabba } 371b6bae725SFuad Tabba 372b6bae725SFuad Tabba return page_size; 373b6bae725SFuad Tabba } 374b6bae725SFuad Tabba 375*834e5ed6SFuad Tabba static long host_ram_nrpages(void) 37660ded003SPekka Enberg { 377*834e5ed6SFuad Tabba long nr_pages = sysconf(_SC_PHYS_PAGES); 37860ded003SPekka Enberg 379d63c5ce6SPekka Enberg if (nr_pages < 0) { 3804542f276SCyrill Gorcunov pr_warning("sysconf(_SC_PHYS_PAGES) failed"); 381d63c5ce6SPekka Enberg return 0; 382d63c5ce6SPekka Enberg } 38360ded003SPekka Enberg 384*834e5ed6SFuad Tabba return nr_pages; 385*834e5ed6SFuad Tabba } 386*834e5ed6SFuad Tabba 387*834e5ed6SFuad Tabba static u64 host_ram_size(void) 388*834e5ed6SFuad Tabba { 389*834e5ed6SFuad Tabba long page_size = host_page_size(); 390*834e5ed6SFuad Tabba long nr_pages = host_ram_nrpages(); 391*834e5ed6SFuad Tabba 3929d655190SAlexandru Elisei return (u64)nr_pages * page_size; 39360ded003SPekka Enberg } 39460ded003SPekka Enberg 39518bd8c3bSPekka Enberg /* 39618bd8c3bSPekka Enberg * If user didn't specify how much memory it wants to allocate for the guest, 39718bd8c3bSPekka Enberg * avoid filling the whole host RAM. 39818bd8c3bSPekka Enberg */ 39918bd8c3bSPekka Enberg #define RAM_SIZE_RATIO 0.8 40018bd8c3bSPekka Enberg 401fd834defSPekka Enberg static u64 get_ram_size(int nr_cpus) 402fd834defSPekka Enberg { 40306761c76SPekka Enberg u64 available; 40406761c76SPekka Enberg u64 ram_size; 405fd834defSPekka Enberg 4069d655190SAlexandru Elisei ram_size = (u64)SZ_64M * (nr_cpus + 3); 407fd834defSPekka Enberg 40860ded003SPekka Enberg available = host_ram_size() * RAM_SIZE_RATIO; 409d63c5ce6SPekka Enberg if (!available) 4109d655190SAlexandru Elisei available = MIN_RAM_SIZE; 411fd834defSPekka Enberg 412fd834defSPekka Enberg if (ram_size > available) 413fd834defSPekka Enberg ram_size = available; 414fd834defSPekka Enberg 415fd834defSPekka Enberg return ram_size; 416fd834defSPekka Enberg } 417fd834defSPekka Enberg 418e08c0896SPrasad Joshi static const char *find_kernel(void) 419e08c0896SPrasad Joshi { 420e08c0896SPrasad Joshi const char **k; 4218329f30bSPekka Enberg struct stat st; 422e08c0896SPrasad Joshi struct utsname uts; 423e08c0896SPrasad Joshi 42465182f37SPrasad Joshi k = &default_kernels[0]; 425e08c0896SPrasad Joshi while (*k) { 426e08c0896SPrasad Joshi if (stat(*k, &st) < 0 || !S_ISREG(st.st_mode)) { 427e08c0896SPrasad Joshi k++; 428e08c0896SPrasad Joshi continue; 429e08c0896SPrasad Joshi } 430266a0ed4SAndre Przywara strlcpy(kernel, *k, PATH_MAX); 431e08c0896SPrasad Joshi return kernel; 432e08c0896SPrasad Joshi } 4338329f30bSPekka Enberg 4348329f30bSPekka Enberg if (uname(&uts) < 0) 4358329f30bSPekka Enberg return NULL; 4368329f30bSPekka Enberg 437e08c0896SPrasad Joshi k = &host_kernels[0]; 438e08c0896SPrasad Joshi while (*k) { 439e08c0896SPrasad Joshi if (snprintf(kernel, PATH_MAX, "%s-%s", *k, uts.release) < 0) 4408329f30bSPekka Enberg return NULL; 4418329f30bSPekka Enberg 442e08c0896SPrasad Joshi if (stat(kernel, &st) < 0 || !S_ISREG(st.st_mode)) { 443e08c0896SPrasad Joshi k++; 444e08c0896SPrasad Joshi continue; 445e08c0896SPrasad Joshi } 446e08c0896SPrasad Joshi return kernel; 4478329f30bSPekka Enberg 448e08c0896SPrasad Joshi } 4498329f30bSPekka Enberg return NULL; 4508329f30bSPekka Enberg } 4518329f30bSPekka Enberg 452b0b42ba0SPekka Enberg static const char *find_vmlinux(void) 453b0b42ba0SPekka Enberg { 454b0b42ba0SPekka Enberg const char **vmlinux; 455b0b42ba0SPekka Enberg 456b0b42ba0SPekka Enberg vmlinux = &default_vmlinux[0]; 457b0b42ba0SPekka Enberg while (*vmlinux) { 458b0b42ba0SPekka Enberg struct stat st; 459b0b42ba0SPekka Enberg 460b0b42ba0SPekka Enberg if (stat(*vmlinux, &st) < 0 || !S_ISREG(st.st_mode)) { 461b0b42ba0SPekka Enberg vmlinux++; 462b0b42ba0SPekka Enberg continue; 463b0b42ba0SPekka Enberg } 464b0b42ba0SPekka Enberg return *vmlinux; 465b0b42ba0SPekka Enberg } 466b0b42ba0SPekka Enberg return NULL; 467b0b42ba0SPekka Enberg } 468b0b42ba0SPekka Enberg 469f6677a1dSAmerigo Wang void kvm_run_help(void) 470f6677a1dSAmerigo Wang { 4714346fd8fSSasha Levin struct kvm *kvm = NULL; 4724346fd8fSSasha Levin 4733b55dcdeSSasha Levin BUILD_OPTIONS(options, &kvm->cfg, kvm); 474f6677a1dSAmerigo Wang usage_with_options(run_usage, options); 475f6677a1dSAmerigo Wang } 476f6677a1dSAmerigo Wang 4774346fd8fSSasha Levin static int kvm_run_set_sandbox(struct kvm *kvm) 478d50fe489SSasha Levin { 47947621338SSasha Levin const char *guestfs_name = kvm->cfg.custom_rootfs_name; 480d50fe489SSasha Levin char path[PATH_MAX], script[PATH_MAX], *tmp; 481d50fe489SSasha Levin 482d50fe489SSasha Levin snprintf(path, PATH_MAX, "%s%s/virt/sandbox.sh", kvm__get_dir(), guestfs_name); 483d50fe489SSasha Levin 484d50fe489SSasha Levin remove(path); 485d50fe489SSasha Levin 48647621338SSasha Levin if (kvm->cfg.sandbox == NULL) 487d50fe489SSasha Levin return 0; 488d50fe489SSasha Levin 48947621338SSasha Levin tmp = realpath(kvm->cfg.sandbox, NULL); 490d50fe489SSasha Levin if (tmp == NULL) 491d50fe489SSasha Levin return -ENOMEM; 492d50fe489SSasha Levin 493d50fe489SSasha Levin snprintf(script, PATH_MAX, "/host/%s", tmp); 494d50fe489SSasha Levin free(tmp); 495d50fe489SSasha Levin 496d50fe489SSasha Levin return symlink(script, path); 497d50fe489SSasha Levin } 498d50fe489SSasha Levin 4995173b4afSLai Jiangshan static void kvm_write_sandbox_cmd_exactly(int fd, const char *arg) 5005173b4afSLai Jiangshan { 5015173b4afSLai Jiangshan const char *single_quote; 5025173b4afSLai Jiangshan 5035173b4afSLai Jiangshan if (!*arg) { /* zero length string */ 5045173b4afSLai Jiangshan if (write(fd, "''", 2) <= 0) 5055173b4afSLai Jiangshan die("Failed writing sandbox script"); 5065173b4afSLai Jiangshan return; 5075173b4afSLai Jiangshan } 5085173b4afSLai Jiangshan 5095173b4afSLai Jiangshan while (*arg) { 5105173b4afSLai Jiangshan single_quote = strchrnul(arg, '\''); 5115173b4afSLai Jiangshan 5125173b4afSLai Jiangshan /* write non-single-quote string as #('string') */ 5135173b4afSLai Jiangshan if (arg != single_quote) { 5145173b4afSLai Jiangshan if (write(fd, "'", 1) <= 0 || 5155173b4afSLai Jiangshan write(fd, arg, single_quote - arg) <= 0 || 5165173b4afSLai Jiangshan write(fd, "'", 1) <= 0) 5175173b4afSLai Jiangshan die("Failed writing sandbox script"); 5185173b4afSLai Jiangshan } 5195173b4afSLai Jiangshan 5205173b4afSLai Jiangshan /* write single quote as #("'") */ 5215173b4afSLai Jiangshan if (*single_quote) { 5225173b4afSLai Jiangshan if (write(fd, "\"'\"", 3) <= 0) 5235173b4afSLai Jiangshan die("Failed writing sandbox script"); 5245173b4afSLai Jiangshan } else 5255173b4afSLai Jiangshan break; 5265173b4afSLai Jiangshan 5275173b4afSLai Jiangshan arg = single_quote + 1; 5285173b4afSLai Jiangshan } 5295173b4afSLai Jiangshan } 5305173b4afSLai Jiangshan 5315cd19aa0SPekka Enberg static void resolve_program(const char *src, char *dst, size_t len) 5325cd19aa0SPekka Enberg { 5335cd19aa0SPekka Enberg struct stat st; 534c2c742d9SPekka Enberg int err; 5355cd19aa0SPekka Enberg 536c2c742d9SPekka Enberg err = stat(src, &st); 5375cd19aa0SPekka Enberg 538c2c742d9SPekka Enberg if (!err && S_ISREG(st.st_mode)) { 5395cd19aa0SPekka Enberg char resolved_path[PATH_MAX]; 5405cd19aa0SPekka Enberg 541de3f75c9SPekka Enberg if (!realpath(src, resolved_path)) 542de3f75c9SPekka Enberg die("Unable to resolve program %s: %s\n", src, strerror(errno)); 5435cd19aa0SPekka Enberg 54496eda741SAnisse Astier if (snprintf(dst, len, "/host%s", resolved_path) >= (int)len) 54596eda741SAnisse Astier die("Pathname too long: %s -> %s\n", src, resolved_path); 54696eda741SAnisse Astier 5475cd19aa0SPekka Enberg } else 548266a0ed4SAndre Przywara strlcpy(dst, src, len); 5495cd19aa0SPekka Enberg } 5505cd19aa0SPekka Enberg 5514346fd8fSSasha Levin static void kvm_run_write_sandbox_cmd(struct kvm *kvm, const char **argv, int argc) 5523c29e2aaSSasha Levin { 5533c29e2aaSSasha Levin const char script_hdr[] = "#! /bin/bash\n\n"; 5545cd19aa0SPekka Enberg char program[PATH_MAX]; 5553c29e2aaSSasha Levin int fd; 5563c29e2aaSSasha Levin 55747621338SSasha Levin remove(kvm->cfg.sandbox); 5583c29e2aaSSasha Levin 55947621338SSasha Levin fd = open(kvm->cfg.sandbox, O_RDWR | O_CREAT, 0777); 5603c29e2aaSSasha Levin if (fd < 0) 5613c29e2aaSSasha Levin die("Failed creating sandbox script"); 5623c29e2aaSSasha Levin 5633c29e2aaSSasha Levin if (write(fd, script_hdr, sizeof(script_hdr) - 1) <= 0) 5643c29e2aaSSasha Levin die("Failed writing sandbox script"); 5653c29e2aaSSasha Levin 5665cd19aa0SPekka Enberg resolve_program(argv[0], program, PATH_MAX); 5675cd19aa0SPekka Enberg kvm_write_sandbox_cmd_exactly(fd, program); 5685cd19aa0SPekka Enberg 5695cd19aa0SPekka Enberg argv++; 5705cd19aa0SPekka Enberg argc--; 5715cd19aa0SPekka Enberg 5723c29e2aaSSasha Levin while (argc) { 5733c29e2aaSSasha Levin if (write(fd, " ", 1) <= 0) 5743c29e2aaSSasha Levin die("Failed writing sandbox script"); 5755cd19aa0SPekka Enberg 5765cd19aa0SPekka Enberg kvm_write_sandbox_cmd_exactly(fd, argv[0]); 5773c29e2aaSSasha Levin argv++; 5783c29e2aaSSasha Levin argc--; 5793c29e2aaSSasha Levin } 5803c29e2aaSSasha Levin if (write(fd, "\n", 1) <= 0) 5813c29e2aaSSasha Levin die("Failed writing sandbox script"); 5823c29e2aaSSasha Levin 5833c29e2aaSSasha Levin close(fd); 5843c29e2aaSSasha Levin } 5853c29e2aaSSasha Levin 586a5253f7cSAlexandru Elisei static void kvm_run_set_real_cmdline(struct kvm *kvm) 587a5253f7cSAlexandru Elisei { 588a5253f7cSAlexandru Elisei static char real_cmdline[2048]; 589a5253f7cSAlexandru Elisei bool video; 590a5253f7cSAlexandru Elisei 591a5253f7cSAlexandru Elisei video = kvm->cfg.vnc || kvm->cfg.sdl || kvm->cfg.gtk; 592a5253f7cSAlexandru Elisei 593a5253f7cSAlexandru Elisei memset(real_cmdline, 0, sizeof(real_cmdline)); 594a5253f7cSAlexandru Elisei kvm__arch_set_cmdline(real_cmdline, video); 595a5253f7cSAlexandru Elisei 596a5253f7cSAlexandru Elisei if (video) { 597a5253f7cSAlexandru Elisei strcat(real_cmdline, " console=tty0"); 598a5253f7cSAlexandru Elisei } else { 599a5253f7cSAlexandru Elisei switch (kvm->cfg.active_console) { 600a5253f7cSAlexandru Elisei case CONSOLE_HV: 601a5253f7cSAlexandru Elisei /* Fallthrough */ 602a5253f7cSAlexandru Elisei case CONSOLE_VIRTIO: 603a5253f7cSAlexandru Elisei strcat(real_cmdline, " console=hvc0"); 604a5253f7cSAlexandru Elisei break; 605a5253f7cSAlexandru Elisei case CONSOLE_8250: 606a5253f7cSAlexandru Elisei strcat(real_cmdline, " console=ttyS0"); 607a5253f7cSAlexandru Elisei break; 608a5253f7cSAlexandru Elisei } 609a5253f7cSAlexandru Elisei } 610a5253f7cSAlexandru Elisei 611a5253f7cSAlexandru Elisei if (kvm->cfg.using_rootfs) { 612a5253f7cSAlexandru Elisei strcat(real_cmdline, " rw rootflags=trans=virtio,version=9p2000.L,cache=loose rootfstype=9p"); 613a5253f7cSAlexandru Elisei if (kvm->cfg.custom_rootfs) { 614a5253f7cSAlexandru Elisei #ifdef CONFIG_GUEST_PRE_INIT 615a5253f7cSAlexandru Elisei strcat(real_cmdline, " init=/virt/pre_init"); 616a5253f7cSAlexandru Elisei #else 617a5253f7cSAlexandru Elisei strcat(real_cmdline, " init=/virt/init"); 618a5253f7cSAlexandru Elisei #endif 619a5253f7cSAlexandru Elisei if (!kvm->cfg.no_dhcp) 620a5253f7cSAlexandru Elisei strcat(real_cmdline, " ip=dhcp"); 621a5253f7cSAlexandru Elisei } 622a5253f7cSAlexandru Elisei } else if (!kvm->cfg.kernel_cmdline || !strstr(kvm->cfg.kernel_cmdline, "root=")) { 623a5253f7cSAlexandru Elisei strlcat(real_cmdline, " root=/dev/vda rw ", sizeof(real_cmdline)); 624a5253f7cSAlexandru Elisei } 625a5253f7cSAlexandru Elisei 626a5253f7cSAlexandru Elisei if (kvm->cfg.kernel_cmdline) { 627a5253f7cSAlexandru Elisei strcat(real_cmdline, " "); 628a5253f7cSAlexandru Elisei strlcat(real_cmdline, kvm->cfg.kernel_cmdline, sizeof(real_cmdline)); 629a5253f7cSAlexandru Elisei } 630a5253f7cSAlexandru Elisei 631a5253f7cSAlexandru Elisei kvm->cfg.real_cmdline = real_cmdline; 632a5253f7cSAlexandru Elisei } 633a5253f7cSAlexandru Elisei 634cce96164SAlexandru Elisei static void kvm_run_validate_cfg(struct kvm *kvm) 635cce96164SAlexandru Elisei { 63628b96259SAlexandru Elisei u64 available_ram; 63728b96259SAlexandru Elisei 638cce96164SAlexandru Elisei if (kvm->cfg.kernel_filename && kvm->cfg.firmware_filename) 639cce96164SAlexandru Elisei die("Only one of --kernel or --firmware can be specified"); 640cce96164SAlexandru Elisei 641cce96164SAlexandru Elisei if ((kvm->cfg.vnc && (kvm->cfg.sdl || kvm->cfg.gtk)) || 642cce96164SAlexandru Elisei (kvm->cfg.sdl && kvm->cfg.gtk)) 643cce96164SAlexandru Elisei die("Only one of --vnc, --sdl or --gtk can be specified"); 644cce96164SAlexandru Elisei 645cce96164SAlexandru Elisei if (kvm->cfg.firmware_filename && kvm->cfg.initrd_filename) 646cce96164SAlexandru Elisei pr_warning("Ignoring initrd file when loading a firmware image"); 64728b96259SAlexandru Elisei 64828b96259SAlexandru Elisei if (kvm->cfg.ram_size) { 64928b96259SAlexandru Elisei available_ram = host_ram_size(); 65028b96259SAlexandru Elisei if (available_ram && kvm->cfg.ram_size > available_ram) { 65128b96259SAlexandru Elisei pr_warning("Guest memory size %lluMB exceeds host physical RAM size %lluMB", 65228b96259SAlexandru Elisei (unsigned long long)kvm->cfg.ram_size >> MB_SHIFT, 65328b96259SAlexandru Elisei (unsigned long long)available_ram >> MB_SHIFT); 65428b96259SAlexandru Elisei } 65528b96259SAlexandru Elisei } 656abe3f28aSAlexandru Elisei 657abe3f28aSAlexandru Elisei kvm__arch_validate_cfg(kvm); 658cce96164SAlexandru Elisei } 659cce96164SAlexandru Elisei 6604346fd8fSSasha Levin static struct kvm *kvm_cmd_run_init(int argc, const char **argv) 661f967c427SPrasad Joshi { 662a5253f7cSAlexandru Elisei static char default_name[20]; 663384922b3SPekka Enberg unsigned int nr_online_cpus; 6644346fd8fSSasha Levin struct kvm *kvm = kvm__new(); 66547621338SSasha Levin 66647621338SSasha Levin if (IS_ERR(kvm)) 6674346fd8fSSasha Levin return kvm; 668f967c427SPrasad Joshi 669cfd63bbbSSasha Levin nr_online_cpus = sysconf(_SC_NPROCESSORS_ONLN); 67047621338SSasha Levin kvm->cfg.custom_rootfs_name = "default"; 6718b91a182SAlexandru Elisei /* 6728b91a182SAlexandru Elisei * An architecture can allow the user to set the RAM base address to 6738b91a182SAlexandru Elisei * zero. Initialize the address before parsing the command line 6748b91a182SAlexandru Elisei * arguments, otherwise it will be impossible to distinguish between the 6758b91a182SAlexandru Elisei * user setting the base address to zero or letting it unset and using 6768b91a182SAlexandru Elisei * the default value. 6778b91a182SAlexandru Elisei */ 6788b91a182SAlexandru Elisei kvm->cfg.ram_addr = kvm__arch_default_ram_address(); 679cfd63bbbSSasha Levin 680f967c427SPrasad Joshi while (argc != 0) { 6813b55dcdeSSasha Levin BUILD_OPTIONS(options, &kvm->cfg, kvm); 682f967c427SPrasad Joshi argc = parse_options(argc, argv, options, run_usage, 6831a007c82SSasha Levin PARSE_OPT_STOP_AT_NON_OPTION | 6841a007c82SSasha Levin PARSE_OPT_KEEP_DASHDASH); 685f967c427SPrasad Joshi if (argc != 0) { 6861a007c82SSasha Levin /* Cusrom options, should have been handled elsewhere */ 6873c29e2aaSSasha Levin if (strcmp(argv[0], "--") == 0) { 6883c29e2aaSSasha Levin if (kvm_run_wrapper == KVM_RUN_SANDBOX) { 68947621338SSasha Levin kvm->cfg.sandbox = DEFAULT_SANDBOX_FILENAME; 6904346fd8fSSasha Levin kvm_run_write_sandbox_cmd(kvm, argv+1, argc-1); 6911a007c82SSasha Levin break; 6923c29e2aaSSasha Levin } 6933c29e2aaSSasha Levin } 6941a007c82SSasha Levin 69547621338SSasha Levin if ((kvm_run_wrapper == KVM_RUN_DEFAULT && kvm->cfg.kernel_filename) || 69647621338SSasha Levin (kvm_run_wrapper == KVM_RUN_SANDBOX && kvm->cfg.sandbox)) { 69772e13944SAlexandru Elisei pr_err("Cannot handle parameter: %s", argv[0]); 698f967c427SPrasad Joshi usage_with_options(run_usage, options); 69947621338SSasha Levin free(kvm); 7004346fd8fSSasha Levin return ERR_PTR(-EINVAL); 701f967c427SPrasad Joshi } 702e0747665SSasha Levin if (kvm_run_wrapper == KVM_RUN_SANDBOX) { 703e0747665SSasha Levin /* 704e0747665SSasha Levin * first unhandled parameter is treated as 705e0747665SSasha Levin * sandbox command 706e0747665SSasha Levin */ 70747621338SSasha Levin kvm->cfg.sandbox = DEFAULT_SANDBOX_FILENAME; 7084346fd8fSSasha Levin kvm_run_write_sandbox_cmd(kvm, argv, argc); 709e0747665SSasha Levin } else { 710e0747665SSasha Levin /* 711e0747665SSasha Levin * first unhandled parameter is treated as a kernel 712e0747665SSasha Levin * image 713f967c427SPrasad Joshi */ 71447621338SSasha Levin kvm->cfg.kernel_filename = argv[0]; 715e0747665SSasha Levin } 716f967c427SPrasad Joshi argv++; 717f967c427SPrasad Joshi argc--; 718f967c427SPrasad Joshi } 719f967c427SPrasad Joshi 720f967c427SPrasad Joshi } 721f967c427SPrasad Joshi 722cce96164SAlexandru Elisei kvm_run_validate_cfg(kvm); 723cce96164SAlexandru Elisei 72413498576SJulien Thierry if (!kvm->cfg.kernel_filename && !kvm->cfg.firmware_filename) { 72547621338SSasha Levin kvm->cfg.kernel_filename = find_kernel(); 7268329f30bSPekka Enberg 72747621338SSasha Levin if (!kvm->cfg.kernel_filename) { 728e08c0896SPrasad Joshi kernel_usage_with_options(); 7294346fd8fSSasha Levin return ERR_PTR(-EINVAL); 7308329f30bSPekka Enberg } 73113498576SJulien Thierry } 7328329f30bSPekka Enberg 733638630c9SAlexandru Elisei if (kvm->cfg.kernel_filename) { 73447621338SSasha Levin kvm->cfg.vmlinux_filename = find_vmlinux(); 735084a1356SSasha Levin kvm->vmlinux = kvm->cfg.vmlinux_filename; 736638630c9SAlexandru Elisei } 737b0b42ba0SPekka Enberg 73800ebbe96SSasha Levin if (kvm->cfg.nrcpus == 0) 73900ebbe96SSasha Levin kvm->cfg.nrcpus = nr_online_cpus; 740d77a9efaSCyrill Gorcunov 74147621338SSasha Levin if (!kvm->cfg.ram_size) 74200ebbe96SSasha Levin kvm->cfg.ram_size = get_ram_size(kvm->cfg.nrcpus); 743f967c427SPrasad Joshi 74447621338SSasha Levin if (!kvm->cfg.dev) 74547621338SSasha Levin kvm->cfg.dev = DEFAULT_KVM_DEV; 746f967c427SPrasad Joshi 74747621338SSasha Levin if (!kvm->cfg.console) 74847621338SSasha Levin kvm->cfg.console = DEFAULT_CONSOLE; 7499aa4a0ebSAsias He 75047621338SSasha Levin if (!strncmp(kvm->cfg.console, "virtio", 6)) 7512651ea58SSasha Levin kvm->cfg.active_console = CONSOLE_VIRTIO; 75247621338SSasha Levin else if (!strncmp(kvm->cfg.console, "serial", 6)) 7532651ea58SSasha Levin kvm->cfg.active_console = CONSOLE_8250; 75447621338SSasha Levin else if (!strncmp(kvm->cfg.console, "hv", 2)) 7552651ea58SSasha Levin kvm->cfg.active_console = CONSOLE_HV; 7563bbc49b6SMatt Evans else 7573bbc49b6SMatt Evans pr_warning("No console!"); 758f967c427SPrasad Joshi 75947621338SSasha Levin if (!kvm->cfg.host_ip) 76047621338SSasha Levin kvm->cfg.host_ip = DEFAULT_HOST_ADDR; 7614d67c820SSasha Levin 76247621338SSasha Levin if (!kvm->cfg.guest_ip) 76347621338SSasha Levin kvm->cfg.guest_ip = DEFAULT_GUEST_ADDR; 764bb8ffd2fSAsias He 76547621338SSasha Levin if (!kvm->cfg.guest_mac) 76647621338SSasha Levin kvm->cfg.guest_mac = DEFAULT_GUEST_MAC; 767a4e724ddSSasha Levin 76847621338SSasha Levin if (!kvm->cfg.host_mac) 76947621338SSasha Levin kvm->cfg.host_mac = DEFAULT_HOST_MAC; 770d7098b9bSAsias He 77147621338SSasha Levin if (!kvm->cfg.script) 77247621338SSasha Levin kvm->cfg.script = DEFAULT_SCRIPT; 77373b7d038SAmos Kong 774cf5323a3SSasha Levin if (!kvm->cfg.network) 775cf5323a3SSasha Levin kvm->cfg.network = DEFAULT_NETWORK; 776cf5323a3SSasha Levin 77747621338SSasha Levin if (!kvm->cfg.guest_name) { 77847621338SSasha Levin if (kvm->cfg.custom_rootfs) { 77947621338SSasha Levin kvm->cfg.guest_name = kvm->cfg.custom_rootfs_name; 780587a4d17SLai Jiangshan } else { 7812d96f6b6SSasha Levin sprintf(default_name, "guest-%u", getpid()); 78247621338SSasha Levin kvm->cfg.guest_name = default_name; 7832d96f6b6SSasha Levin } 784587a4d17SLai Jiangshan } 7852d96f6b6SSasha Levin 7865613ae26SAlexandru Elisei if (!kvm->cfg.nodefaults && 7875613ae26SAlexandru Elisei !kvm->cfg.using_rootfs && 7885613ae26SAlexandru Elisei !kvm->cfg.disk_image[0].filename && 7895613ae26SAlexandru Elisei !kvm->cfg.initrd_filename) { 790c8675741SSasha Levin char tmp[PATH_MAX]; 7916df1471eSPekka Enberg 79247621338SSasha Levin kvm_setup_create_new(kvm->cfg.custom_rootfs_name); 79347621338SSasha Levin kvm_setup_resolv(kvm->cfg.custom_rootfs_name); 794c8675741SSasha Levin 7959667701cSPekka Enberg snprintf(tmp, PATH_MAX, "%s%s", kvm__get_dir(), "default"); 796c8675741SSasha Levin if (virtio_9p__register(kvm, tmp, "/dev/root") < 0) 797c8675741SSasha Levin die("Unable to initialize virtio 9p"); 798c8675741SSasha Levin if (virtio_9p__register(kvm, "/", "hostfs") < 0) 799c8675741SSasha Levin die("Unable to initialize virtio 9p"); 80047621338SSasha Levin kvm->cfg.using_rootfs = kvm->cfg.custom_rootfs = 1; 80126c853e4SPrasad Joshi } 80226c853e4SPrasad Joshi 80347621338SSasha Levin if (kvm->cfg.custom_rootfs) { 8044346fd8fSSasha Levin kvm_run_set_sandbox(kvm); 805cdce942cSDimitri John Ledkov if (kvm_setup_guest_init(kvm->cfg.custom_rootfs_name)) 806afc2c7c0SAsias He die("Failed to setup init for guest."); 807a8e6b4b9SSasha Levin } 80859aa2d30SSasha Levin 8095613ae26SAlexandru Elisei if (kvm->cfg.nodefaults) 8105613ae26SAlexandru Elisei kvm->cfg.real_cmdline = kvm->cfg.kernel_cmdline; 8115613ae26SAlexandru Elisei else 812a5253f7cSAlexandru Elisei kvm_run_set_real_cmdline(kvm); 813084a1356SSasha Levin 81413498576SJulien Thierry if (kvm->cfg.kernel_filename) { 81572e13944SAlexandru Elisei pr_info("# %s run -k %s -m %Lu -c %d --name %s", KVM_BINARY_NAME, 81669f50425SAndreas Herrmann kvm->cfg.kernel_filename, 8179d655190SAlexandru Elisei (unsigned long long)kvm->cfg.ram_size >> MB_SHIFT, 81869f50425SAndreas Herrmann kvm->cfg.nrcpus, kvm->cfg.guest_name); 81913498576SJulien Thierry } else if (kvm->cfg.firmware_filename) { 82072e13944SAlexandru Elisei pr_info("# %s run --firmware %s -m %Lu -c %d --name %s", KVM_BINARY_NAME, 82113498576SJulien Thierry kvm->cfg.firmware_filename, 8229d655190SAlexandru Elisei (unsigned long long)kvm->cfg.ram_size >> MB_SHIFT, 82313498576SJulien Thierry kvm->cfg.nrcpus, kvm->cfg.guest_name); 82413498576SJulien Thierry } 825084a1356SSasha Levin 8265b403dbfSWill Deacon if (init_list__init(kvm) < 0) 8275b403dbfSWill Deacon die ("Initialisation failed"); 8284346fd8fSSasha Levin 8294346fd8fSSasha Levin return kvm; 830e1e46fe6SSasha Levin } 831e1e46fe6SSasha Levin 8324346fd8fSSasha Levin static int kvm_cmd_run_work(struct kvm *kvm) 833e1e46fe6SSasha Levin { 834df4239fbSSasha Levin int i; 835e1e46fe6SSasha Levin 83600ebbe96SSasha Levin for (i = 0; i < kvm->nrcpus; i++) { 837df4239fbSSasha Levin if (pthread_create(&kvm->cpus[i]->thread, NULL, kvm_cpu_thread, kvm->cpus[i]) != 0) 8385ee154d1SPekka Enberg die("unable to create KVM VCPU thread"); 8395ee154d1SPekka Enberg } 8405ee154d1SPekka Enberg 84149e5227dSSasha Levin /* Only VCPU #0 is going to exit by itself when shutting down */ 842e8cb90fbSWill Deacon if (pthread_join(kvm->cpus[0]->thread, NULL) != 0) 843e8cb90fbSWill Deacon die("unable to join with vcpu 0"); 844e8cb90fbSWill Deacon 845e8cb90fbSWill Deacon return kvm_cpu__exit(kvm); 846e1e46fe6SSasha Levin } 847e1e46fe6SSasha Levin 8484346fd8fSSasha Levin static void kvm_cmd_run_exit(struct kvm *kvm, int guest_ret) 849e1e46fe6SSasha Levin { 850e6694207SSasha Levin compat__print_all_messages(); 851e6694207SSasha Levin 85249a8afd1SSasha Levin init_list__exit(kvm); 853f967c427SPrasad Joshi 854e1e46fe6SSasha Levin if (guest_ret == 0) 85572e13944SAlexandru Elisei pr_info("KVM session ended normally."); 856e1e46fe6SSasha Levin } 857e1e46fe6SSasha Levin 858e1e46fe6SSasha Levin int kvm_cmd_run(int argc, const char **argv, const char *prefix) 859e1e46fe6SSasha Levin { 8604346fd8fSSasha Levin int ret = -EFAULT; 8614346fd8fSSasha Levin struct kvm *kvm; 862e1e46fe6SSasha Levin 8634346fd8fSSasha Levin kvm = kvm_cmd_run_init(argc, argv); 8644346fd8fSSasha Levin if (IS_ERR(kvm)) 8654346fd8fSSasha Levin return PTR_ERR(kvm); 866e1e46fe6SSasha Levin 8674346fd8fSSasha Levin ret = kvm_cmd_run_work(kvm); 8684346fd8fSSasha Levin kvm_cmd_run_exit(kvm, ret); 869e1e46fe6SSasha Levin 870e1e46fe6SSasha Levin return ret; 871f967c427SPrasad Joshi } 872