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" 3495d13a52SSasha Levin #include "kvm/pci-shmem.h" 354b1addaeSSasha Levin #include "kvm/kvm-ipc.h" 364b1c6f6eSSasha Levin #include "kvm/builtin-debug.h" 37ece09f8fSPekka Enberg 38ece09f8fSPekka Enberg #include <linux/types.h> 3948d9e01aSSasha Levin #include <linux/err.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 52f967c427SPrasad Joshi #define MB_SHIFT (20) 5395d13a52SSasha Levin #define KB_SHIFT (10) 5495d13a52SSasha Levin #define GB_SHIFT (30) 55f967c427SPrasad Joshi 56656be1b8SSasha Levin __thread struct kvm_cpu *current_kvm_cpu; 57f967c427SPrasad Joshi 583c29e2aaSSasha Levin static int kvm_run_wrapper; 59f967c427SPrasad Joshi 60ed036f03SCyrill Gorcunov bool do_debug_print = false; 61ed036f03SCyrill Gorcunov 62afc2c7c0SAsias He extern char _binary_guest_init_start; 63afc2c7c0SAsias He extern char _binary_guest_init_size; 64afc2c7c0SAsias He 65f967c427SPrasad Joshi static const char * const run_usage[] = { 668d2ff5daSWanlong Gao "lkvm run [<options>] [<kernel image>]", 67f967c427SPrasad Joshi NULL 68f967c427SPrasad Joshi }; 69f967c427SPrasad Joshi 703c29e2aaSSasha Levin enum { 71e0747665SSasha Levin KVM_RUN_DEFAULT, 723c29e2aaSSasha Levin KVM_RUN_SANDBOX, 733c29e2aaSSasha Levin }; 743c29e2aaSSasha Levin 75a33979d8SSasha Levin static int img_name_parser(const struct option *opt, const char *arg, int unset) 76a33979d8SSasha Levin { 7782d65b5eSSasha Levin char path[PATH_MAX]; 785236b505SAsias He struct stat st; 79a33979d8SSasha Levin 809667701cSPekka Enberg snprintf(path, PATH_MAX, "%s%s", kvm__get_dir(), arg); 8182d65b5eSSasha Levin 82cac9e8fdSSasha Levin if ((stat(arg, &st) == 0 && S_ISDIR(st.st_mode)) || 83cac9e8fdSSasha Levin (stat(path, &st) == 0 && S_ISDIR(st.st_mode))) 84cac9e8fdSSasha Levin return virtio_9p_img_name_parser(opt, arg, unset); 853b55dcdeSSasha Levin return disk_img_name_parser(opt, arg, unset); 86a67da3beSAsias He } 87a67da3beSAsias He 883b55dcdeSSasha Levin void kvm_run_set_wrapper_sandbox(void) 893b55dcdeSSasha Levin { 903b55dcdeSSasha Levin kvm_run_wrapper = KVM_RUN_SANDBOX; 91a33979d8SSasha Levin } 92a33979d8SSasha Levin 93ff7ba6faSWill Deacon #ifndef OPT_ARCH_RUN 94ff7ba6faSWill Deacon #define OPT_ARCH_RUN(...) 95ff7ba6faSWill Deacon #endif 96ff7ba6faSWill Deacon 973b55dcdeSSasha Levin #define BUILD_OPTIONS(name, cfg, kvm) \ 98b816364aSSasha Levin struct option name[] = { \ 99b816364aSSasha Levin OPT_GROUP("Basic options:"), \ 100b816364aSSasha Levin OPT_STRING('\0', "name", &(cfg)->guest_name, "guest name", \ 101b816364aSSasha Levin "A name for the guest"), \ 10200ebbe96SSasha Levin OPT_INTEGER('c', "cpus", &(cfg)->nrcpus, "Number of CPUs"), \ 103b5e56fa3SWilliam Dauchy OPT_U64('m', "mem", &(cfg)->ram_size, "Virtual machine memory" \ 104b5e56fa3SWilliam Dauchy " size in MiB."), \ 105b816364aSSasha Levin OPT_CALLBACK('\0', "shmem", NULL, \ 106b816364aSSasha Levin "[pci:]<addr>:<size>[:handle=<handle>][:create]", \ 107b816364aSSasha Levin "Share host shmem with guest via pci device", \ 1081dc24dccSSasha Levin shmem_parser, NULL), \ 109b5e56fa3SWilliam Dauchy OPT_CALLBACK('d', "disk", kvm, "image or rootfs_dir", "Disk " \ 110b5e56fa3SWilliam Dauchy " image or rootfs directory", img_name_parser, \ 1113b55dcdeSSasha Levin kvm), \ 112b5e56fa3SWilliam Dauchy OPT_BOOLEAN('\0', "balloon", &(cfg)->balloon, "Enable virtio" \ 113b5e56fa3SWilliam Dauchy " balloon"), \ 114b816364aSSasha Levin OPT_BOOLEAN('\0', "vnc", &(cfg)->vnc, "Enable VNC framebuffer"),\ 115*7bcceb95SPekka Enberg OPT_BOOLEAN('\0', "gtk", &(cfg)->gtk, "Enable GTK framebuffer"),\ 116b816364aSSasha Levin OPT_BOOLEAN('\0', "sdl", &(cfg)->sdl, "Enable SDL framebuffer"),\ 117b5e56fa3SWilliam Dauchy OPT_BOOLEAN('\0', "rng", &(cfg)->virtio_rng, "Enable virtio" \ 118b5e56fa3SWilliam Dauchy " Random Number Generator"), \ 119b816364aSSasha Levin OPT_CALLBACK('\0', "9p", NULL, "dir_to_share,tag_name", \ 120b5e56fa3SWilliam Dauchy "Enable virtio 9p to share files between host and" \ 121b5e56fa3SWilliam Dauchy " guest", virtio_9p_rootdir_parser, kvm), \ 122b5e56fa3SWilliam Dauchy OPT_STRING('\0', "console", &(cfg)->console, "serial, virtio or"\ 123b5e56fa3SWilliam Dauchy " hv", "Console to use"), \ 124b816364aSSasha Levin OPT_STRING('\0', "dev", &(cfg)->dev, "device_file", \ 125b816364aSSasha Levin "KVM device file"), \ 126b816364aSSasha Levin OPT_CALLBACK('\0', "tty", NULL, "tty id", \ 127b816364aSSasha Levin "Remap guest TTY into a pty on the host", \ 1281dc24dccSSasha Levin tty_parser, NULL), \ 129b816364aSSasha Levin OPT_STRING('\0', "sandbox", &(cfg)->sandbox, "script", \ 130b5e56fa3SWilliam Dauchy "Run this script when booting into custom" \ 131b5e56fa3SWilliam Dauchy " rootfs"), \ 132b816364aSSasha Levin OPT_STRING('\0', "hugetlbfs", &(cfg)->hugetlbfs_path, "path", \ 133b816364aSSasha Levin "Hugetlbfs path"), \ 134b816364aSSasha Levin \ 135b816364aSSasha Levin OPT_GROUP("Kernel options:"), \ 136b816364aSSasha Levin OPT_STRING('k', "kernel", &(cfg)->kernel_filename, "kernel", \ 137b816364aSSasha Levin "Kernel to boot in virtual machine"), \ 138b816364aSSasha Levin OPT_STRING('i', "initrd", &(cfg)->initrd_filename, "initrd", \ 139b816364aSSasha Levin "Initial RAM disk image"), \ 140b816364aSSasha Levin OPT_STRING('p', "params", &(cfg)->kernel_cmdline, "params", \ 141b816364aSSasha Levin "Kernel command line arguments"), \ 142b816364aSSasha Levin OPT_STRING('f', "firmware", &(cfg)->firmware_filename, "firmware",\ 143b816364aSSasha Levin "Firmware image to boot in virtual machine"), \ 144b816364aSSasha Levin \ 145b816364aSSasha Levin OPT_GROUP("Networking options:"), \ 146b816364aSSasha Levin OPT_CALLBACK_DEFAULT('n', "network", NULL, "network params", \ 147b816364aSSasha Levin "Create a new guest NIC", \ 1485f225124SSasha Levin netdev_parser, NULL, kvm), \ 149b5e56fa3SWilliam Dauchy OPT_BOOLEAN('\0', "no-dhcp", &(cfg)->no_dhcp, "Disable kernel" \ 150b5e56fa3SWilliam Dauchy " DHCP in rootfs mode"), \ 151b816364aSSasha Levin \ 152b816364aSSasha Levin OPT_GROUP("Debug options:"), \ 153b816364aSSasha Levin OPT_BOOLEAN('\0', "debug", &do_debug_print, \ 154b816364aSSasha Levin "Enable debug messages"), \ 155b816364aSSasha Levin OPT_BOOLEAN('\0', "debug-single-step", &(cfg)->single_step, \ 156b816364aSSasha Levin "Enable single stepping"), \ 1575765977dSSasha Levin OPT_BOOLEAN('\0', "debug-ioport", &(cfg)->ioport_debug, \ 158b816364aSSasha Levin "Enable ioport debugging"), \ 159e830cce7SSasha Levin OPT_BOOLEAN('\0', "debug-mmio", &(cfg)->mmio_debug, \ 160b816364aSSasha Levin "Enable MMIO debugging"), \ 1613b55dcdeSSasha Levin OPT_INTEGER('\0', "debug-iodelay", &(cfg)->debug_iodelay, \ 162b816364aSSasha Levin "Delay IO by millisecond"), \ 163ff7ba6faSWill Deacon \ 164ff7ba6faSWill Deacon OPT_ARCH(RUN, cfg) \ 165b816364aSSasha Levin OPT_END() \ 166f967c427SPrasad Joshi }; 167f967c427SPrasad Joshi 1685002444cSSasha Levin static void handle_sigalrm(int sig, siginfo_t *si, void *uc) 1699e854d1aSPekka Enberg { 1705002444cSSasha Levin struct kvm *kvm = si->si_value.sival_ptr; 1715002444cSSasha Levin 1720b69bdefSMatt Evans kvm__arch_periodic_poll(kvm); 1739e854d1aSPekka Enberg } 1749e854d1aSPekka Enberg 1755ee154d1SPekka Enberg static void *kvm_cpu_thread(void *arg) 1765ee154d1SPekka Enberg { 177a4d8c55eSSasha Levin char name[16]; 178a4d8c55eSSasha Levin 179d77a9efaSCyrill Gorcunov current_kvm_cpu = arg; 1805ee154d1SPekka Enberg 181a4d8c55eSSasha Levin sprintf(name, "kvm-vcpu-%lu", current_kvm_cpu->cpu_id); 182a4d8c55eSSasha Levin kvm__set_thread_name(name); 183a4d8c55eSSasha Levin 184d77a9efaSCyrill Gorcunov if (kvm_cpu__start(current_kvm_cpu)) 1855ee154d1SPekka Enberg goto panic_kvm; 1865ee154d1SPekka Enberg 1875ee154d1SPekka Enberg return (void *) (intptr_t) 0; 1885ee154d1SPekka Enberg 1895ee154d1SPekka Enberg panic_kvm: 1903fdf659dSSasha Levin fprintf(stderr, "KVM exit reason: %u (\"%s\")\n", 191d77a9efaSCyrill Gorcunov current_kvm_cpu->kvm_run->exit_reason, 192d77a9efaSCyrill Gorcunov kvm_exit_reasons[current_kvm_cpu->kvm_run->exit_reason]); 193d77a9efaSCyrill Gorcunov if (current_kvm_cpu->kvm_run->exit_reason == KVM_EXIT_UNKNOWN) 1945ee154d1SPekka Enberg fprintf(stderr, "KVM exit code: 0x%Lu\n", 195d77a9efaSCyrill Gorcunov current_kvm_cpu->kvm_run->hw.hardware_exit_reason); 1968e5accedSPekka Enberg 197b7d2f013SSasha Levin kvm_cpu__set_debug_fd(STDOUT_FILENO); 198d77a9efaSCyrill Gorcunov kvm_cpu__show_registers(current_kvm_cpu); 199d77a9efaSCyrill Gorcunov kvm_cpu__show_code(current_kvm_cpu); 200d77a9efaSCyrill Gorcunov kvm_cpu__show_page_tables(current_kvm_cpu); 2015ee154d1SPekka Enberg 2025ee154d1SPekka Enberg return (void *) (intptr_t) 1; 2035ee154d1SPekka Enberg } 2045ee154d1SPekka Enberg 205e08c0896SPrasad Joshi static char kernel[PATH_MAX]; 206b0b42ba0SPekka Enberg 207b0b42ba0SPekka Enberg static const char *host_kernels[] = { 208e08c0896SPrasad Joshi "/boot/vmlinuz", 209e08c0896SPrasad Joshi "/boot/bzImage", 210e08c0896SPrasad Joshi NULL 211e08c0896SPrasad Joshi }; 212b0b42ba0SPekka Enberg 213b0b42ba0SPekka Enberg static const char *default_kernels[] = { 214e08c0896SPrasad Joshi "./bzImage", 215b03af790SKonstantin Khlebnikov "arch/" BUILD_ARCH "/boot/bzImage", 216af7b0868SMatt Evans "../../arch/" BUILD_ARCH "/boot/bzImage", 217e08c0896SPrasad Joshi NULL 218e08c0896SPrasad Joshi }; 2198329f30bSPekka Enberg 220b0b42ba0SPekka Enberg static const char *default_vmlinux[] = { 221b03af790SKonstantin Khlebnikov "vmlinux", 222b0b42ba0SPekka Enberg "../../../vmlinux", 223b0b42ba0SPekka Enberg "../../vmlinux", 224b0b42ba0SPekka Enberg NULL 225b0b42ba0SPekka Enberg }; 226b0b42ba0SPekka Enberg 227e08c0896SPrasad Joshi static void kernel_usage_with_options(void) 2288329f30bSPekka Enberg { 229e08c0896SPrasad Joshi const char **k; 2308329f30bSPekka Enberg struct utsname uts; 231e08c0896SPrasad Joshi 232e08c0896SPrasad Joshi fprintf(stderr, "Fatal: could not find default kernel image in:\n"); 23365182f37SPrasad Joshi k = &default_kernels[0]; 234e08c0896SPrasad Joshi while (*k) { 235e08c0896SPrasad Joshi fprintf(stderr, "\t%s\n", *k); 236e08c0896SPrasad Joshi k++; 237e08c0896SPrasad Joshi } 238e08c0896SPrasad Joshi 239e08c0896SPrasad Joshi if (uname(&uts) < 0) 240e08c0896SPrasad Joshi return; 241e08c0896SPrasad Joshi 242e08c0896SPrasad Joshi k = &host_kernels[0]; 243e08c0896SPrasad Joshi while (*k) { 244e08c0896SPrasad Joshi if (snprintf(kernel, PATH_MAX, "%s-%s", *k, uts.release) < 0) 245e08c0896SPrasad Joshi return; 246e08c0896SPrasad Joshi fprintf(stderr, "\t%s\n", kernel); 247e08c0896SPrasad Joshi k++; 248e08c0896SPrasad Joshi } 249ee8b1456SWanlong Gao fprintf(stderr, "\nPlease see '%s run --help' for more options.\n\n", 250ee8b1456SWanlong Gao KVM_BINARY_NAME); 251e08c0896SPrasad Joshi } 252e08c0896SPrasad Joshi 25360ded003SPekka Enberg static u64 host_ram_size(void) 25460ded003SPekka Enberg { 25560ded003SPekka Enberg long page_size; 25660ded003SPekka Enberg long nr_pages; 25760ded003SPekka Enberg 25860ded003SPekka Enberg nr_pages = sysconf(_SC_PHYS_PAGES); 259d63c5ce6SPekka Enberg if (nr_pages < 0) { 2604542f276SCyrill Gorcunov pr_warning("sysconf(_SC_PHYS_PAGES) failed"); 261d63c5ce6SPekka Enberg return 0; 262d63c5ce6SPekka Enberg } 26360ded003SPekka Enberg 26460ded003SPekka Enberg page_size = sysconf(_SC_PAGE_SIZE); 265d63c5ce6SPekka Enberg if (page_size < 0) { 2664542f276SCyrill Gorcunov pr_warning("sysconf(_SC_PAGE_SIZE) failed"); 267d63c5ce6SPekka Enberg return 0; 268d63c5ce6SPekka Enberg } 26960ded003SPekka Enberg 27060ded003SPekka Enberg return (nr_pages * page_size) >> MB_SHIFT; 27160ded003SPekka Enberg } 27260ded003SPekka Enberg 27318bd8c3bSPekka Enberg /* 27418bd8c3bSPekka Enberg * If user didn't specify how much memory it wants to allocate for the guest, 27518bd8c3bSPekka Enberg * avoid filling the whole host RAM. 27618bd8c3bSPekka Enberg */ 27718bd8c3bSPekka Enberg #define RAM_SIZE_RATIO 0.8 27818bd8c3bSPekka Enberg 279fd834defSPekka Enberg static u64 get_ram_size(int nr_cpus) 280fd834defSPekka Enberg { 28106761c76SPekka Enberg u64 available; 28206761c76SPekka Enberg u64 ram_size; 283fd834defSPekka Enberg 284fd834defSPekka Enberg ram_size = 64 * (nr_cpus + 3); 285fd834defSPekka Enberg 28660ded003SPekka Enberg available = host_ram_size() * RAM_SIZE_RATIO; 287d63c5ce6SPekka Enberg if (!available) 288d63c5ce6SPekka Enberg available = MIN_RAM_SIZE_MB; 289fd834defSPekka Enberg 290fd834defSPekka Enberg if (ram_size > available) 291fd834defSPekka Enberg ram_size = available; 292fd834defSPekka Enberg 293fd834defSPekka Enberg return ram_size; 294fd834defSPekka Enberg } 295fd834defSPekka Enberg 296e08c0896SPrasad Joshi static const char *find_kernel(void) 297e08c0896SPrasad Joshi { 298e08c0896SPrasad Joshi const char **k; 2998329f30bSPekka Enberg struct stat st; 300e08c0896SPrasad Joshi struct utsname uts; 301e08c0896SPrasad Joshi 30265182f37SPrasad Joshi k = &default_kernels[0]; 303e08c0896SPrasad Joshi while (*k) { 304e08c0896SPrasad Joshi if (stat(*k, &st) < 0 || !S_ISREG(st.st_mode)) { 305e08c0896SPrasad Joshi k++; 306e08c0896SPrasad Joshi continue; 307e08c0896SPrasad Joshi } 308e08c0896SPrasad Joshi strncpy(kernel, *k, PATH_MAX); 309e08c0896SPrasad Joshi return kernel; 310e08c0896SPrasad Joshi } 3118329f30bSPekka Enberg 3128329f30bSPekka Enberg if (uname(&uts) < 0) 3138329f30bSPekka Enberg return NULL; 3148329f30bSPekka Enberg 315e08c0896SPrasad Joshi k = &host_kernels[0]; 316e08c0896SPrasad Joshi while (*k) { 317e08c0896SPrasad Joshi if (snprintf(kernel, PATH_MAX, "%s-%s", *k, uts.release) < 0) 3188329f30bSPekka Enberg return NULL; 3198329f30bSPekka Enberg 320e08c0896SPrasad Joshi if (stat(kernel, &st) < 0 || !S_ISREG(st.st_mode)) { 321e08c0896SPrasad Joshi k++; 322e08c0896SPrasad Joshi continue; 323e08c0896SPrasad Joshi } 324e08c0896SPrasad Joshi return kernel; 3258329f30bSPekka Enberg 326e08c0896SPrasad Joshi } 3278329f30bSPekka Enberg return NULL; 3288329f30bSPekka Enberg } 3298329f30bSPekka Enberg 330b0b42ba0SPekka Enberg static const char *find_vmlinux(void) 331b0b42ba0SPekka Enberg { 332b0b42ba0SPekka Enberg const char **vmlinux; 333b0b42ba0SPekka Enberg 334b0b42ba0SPekka Enberg vmlinux = &default_vmlinux[0]; 335b0b42ba0SPekka Enberg while (*vmlinux) { 336b0b42ba0SPekka Enberg struct stat st; 337b0b42ba0SPekka Enberg 338b0b42ba0SPekka Enberg if (stat(*vmlinux, &st) < 0 || !S_ISREG(st.st_mode)) { 339b0b42ba0SPekka Enberg vmlinux++; 340b0b42ba0SPekka Enberg continue; 341b0b42ba0SPekka Enberg } 342b0b42ba0SPekka Enberg return *vmlinux; 343b0b42ba0SPekka Enberg } 344b0b42ba0SPekka Enberg return NULL; 345b0b42ba0SPekka Enberg } 346b0b42ba0SPekka Enberg 347f6677a1dSAmerigo Wang void kvm_run_help(void) 348f6677a1dSAmerigo Wang { 3494346fd8fSSasha Levin struct kvm *kvm = NULL; 3504346fd8fSSasha Levin 3513b55dcdeSSasha Levin BUILD_OPTIONS(options, &kvm->cfg, kvm); 352f6677a1dSAmerigo Wang usage_with_options(run_usage, options); 353f6677a1dSAmerigo Wang } 354f6677a1dSAmerigo Wang 3554346fd8fSSasha Levin static int kvm_setup_guest_init(struct kvm *kvm) 3569cec19c8SSasha Levin { 35747621338SSasha Levin const char *rootfs = kvm->cfg.custom_rootfs_name; 358afc2c7c0SAsias He char tmp[PATH_MAX]; 359afc2c7c0SAsias He size_t size; 360afc2c7c0SAsias He int fd, ret; 361afc2c7c0SAsias He char *data; 3629cec19c8SSasha Levin 363afc2c7c0SAsias He /* Setup /virt/init */ 364afc2c7c0SAsias He size = (size_t)&_binary_guest_init_size; 365afc2c7c0SAsias He data = (char *)&_binary_guest_init_start; 366afc2c7c0SAsias He snprintf(tmp, PATH_MAX, "%s%s/virt/init", kvm__get_dir(), rootfs); 367afc2c7c0SAsias He remove(tmp); 368afc2c7c0SAsias He fd = open(tmp, O_CREAT | O_WRONLY, 0755); 369afc2c7c0SAsias He if (fd < 0) 370afc2c7c0SAsias He die("Fail to setup %s", tmp); 371afc2c7c0SAsias He ret = xwrite(fd, data, size); 372afc2c7c0SAsias He if (ret < 0) 373afc2c7c0SAsias He die("Fail to setup %s", tmp); 374afc2c7c0SAsias He close(fd); 3759cec19c8SSasha Levin 376afc2c7c0SAsias He return 0; 3779cec19c8SSasha Levin } 3789cec19c8SSasha Levin 3794346fd8fSSasha Levin static int kvm_run_set_sandbox(struct kvm *kvm) 380d50fe489SSasha Levin { 38147621338SSasha Levin const char *guestfs_name = kvm->cfg.custom_rootfs_name; 382d50fe489SSasha Levin char path[PATH_MAX], script[PATH_MAX], *tmp; 383d50fe489SSasha Levin 384d50fe489SSasha Levin snprintf(path, PATH_MAX, "%s%s/virt/sandbox.sh", kvm__get_dir(), guestfs_name); 385d50fe489SSasha Levin 386d50fe489SSasha Levin remove(path); 387d50fe489SSasha Levin 38847621338SSasha Levin if (kvm->cfg.sandbox == NULL) 389d50fe489SSasha Levin return 0; 390d50fe489SSasha Levin 39147621338SSasha Levin tmp = realpath(kvm->cfg.sandbox, NULL); 392d50fe489SSasha Levin if (tmp == NULL) 393d50fe489SSasha Levin return -ENOMEM; 394d50fe489SSasha Levin 395d50fe489SSasha Levin snprintf(script, PATH_MAX, "/host/%s", tmp); 396d50fe489SSasha Levin free(tmp); 397d50fe489SSasha Levin 398d50fe489SSasha Levin return symlink(script, path); 399d50fe489SSasha Levin } 400d50fe489SSasha Levin 4015173b4afSLai Jiangshan static void kvm_write_sandbox_cmd_exactly(int fd, const char *arg) 4025173b4afSLai Jiangshan { 4035173b4afSLai Jiangshan const char *single_quote; 4045173b4afSLai Jiangshan 4055173b4afSLai Jiangshan if (!*arg) { /* zero length string */ 4065173b4afSLai Jiangshan if (write(fd, "''", 2) <= 0) 4075173b4afSLai Jiangshan die("Failed writing sandbox script"); 4085173b4afSLai Jiangshan return; 4095173b4afSLai Jiangshan } 4105173b4afSLai Jiangshan 4115173b4afSLai Jiangshan while (*arg) { 4125173b4afSLai Jiangshan single_quote = strchrnul(arg, '\''); 4135173b4afSLai Jiangshan 4145173b4afSLai Jiangshan /* write non-single-quote string as #('string') */ 4155173b4afSLai Jiangshan if (arg != single_quote) { 4165173b4afSLai Jiangshan if (write(fd, "'", 1) <= 0 || 4175173b4afSLai Jiangshan write(fd, arg, single_quote - arg) <= 0 || 4185173b4afSLai Jiangshan write(fd, "'", 1) <= 0) 4195173b4afSLai Jiangshan die("Failed writing sandbox script"); 4205173b4afSLai Jiangshan } 4215173b4afSLai Jiangshan 4225173b4afSLai Jiangshan /* write single quote as #("'") */ 4235173b4afSLai Jiangshan if (*single_quote) { 4245173b4afSLai Jiangshan if (write(fd, "\"'\"", 3) <= 0) 4255173b4afSLai Jiangshan die("Failed writing sandbox script"); 4265173b4afSLai Jiangshan } else 4275173b4afSLai Jiangshan break; 4285173b4afSLai Jiangshan 4295173b4afSLai Jiangshan arg = single_quote + 1; 4305173b4afSLai Jiangshan } 4315173b4afSLai Jiangshan } 4325173b4afSLai Jiangshan 4335cd19aa0SPekka Enberg static void resolve_program(const char *src, char *dst, size_t len) 4345cd19aa0SPekka Enberg { 4355cd19aa0SPekka Enberg struct stat st; 436c2c742d9SPekka Enberg int err; 4375cd19aa0SPekka Enberg 438c2c742d9SPekka Enberg err = stat(src, &st); 4395cd19aa0SPekka Enberg 440c2c742d9SPekka Enberg if (!err && S_ISREG(st.st_mode)) { 4415cd19aa0SPekka Enberg char resolved_path[PATH_MAX]; 4425cd19aa0SPekka Enberg 443de3f75c9SPekka Enberg if (!realpath(src, resolved_path)) 444de3f75c9SPekka Enberg die("Unable to resolve program %s: %s\n", src, strerror(errno)); 4455cd19aa0SPekka Enberg 4465cd19aa0SPekka Enberg snprintf(dst, len, "/host%s", resolved_path); 4475cd19aa0SPekka Enberg } else 4485cd19aa0SPekka Enberg strncpy(dst, src, len); 4495cd19aa0SPekka Enberg } 4505cd19aa0SPekka Enberg 4514346fd8fSSasha Levin static void kvm_run_write_sandbox_cmd(struct kvm *kvm, const char **argv, int argc) 4523c29e2aaSSasha Levin { 4533c29e2aaSSasha Levin const char script_hdr[] = "#! /bin/bash\n\n"; 4545cd19aa0SPekka Enberg char program[PATH_MAX]; 4553c29e2aaSSasha Levin int fd; 4563c29e2aaSSasha Levin 45747621338SSasha Levin remove(kvm->cfg.sandbox); 4583c29e2aaSSasha Levin 45947621338SSasha Levin fd = open(kvm->cfg.sandbox, O_RDWR | O_CREAT, 0777); 4603c29e2aaSSasha Levin if (fd < 0) 4613c29e2aaSSasha Levin die("Failed creating sandbox script"); 4623c29e2aaSSasha Levin 4633c29e2aaSSasha Levin if (write(fd, script_hdr, sizeof(script_hdr) - 1) <= 0) 4643c29e2aaSSasha Levin die("Failed writing sandbox script"); 4653c29e2aaSSasha Levin 4665cd19aa0SPekka Enberg resolve_program(argv[0], program, PATH_MAX); 4675cd19aa0SPekka Enberg kvm_write_sandbox_cmd_exactly(fd, program); 4685cd19aa0SPekka Enberg 4695cd19aa0SPekka Enberg argv++; 4705cd19aa0SPekka Enberg argc--; 4715cd19aa0SPekka Enberg 4723c29e2aaSSasha Levin while (argc) { 4733c29e2aaSSasha Levin if (write(fd, " ", 1) <= 0) 4743c29e2aaSSasha Levin die("Failed writing sandbox script"); 4755cd19aa0SPekka Enberg 4765cd19aa0SPekka Enberg kvm_write_sandbox_cmd_exactly(fd, argv[0]); 4773c29e2aaSSasha Levin argv++; 4783c29e2aaSSasha Levin argc--; 4793c29e2aaSSasha Levin } 4803c29e2aaSSasha Levin if (write(fd, "\n", 1) <= 0) 4813c29e2aaSSasha Levin die("Failed writing sandbox script"); 4823c29e2aaSSasha Levin 4833c29e2aaSSasha Levin close(fd); 4843c29e2aaSSasha Levin } 4853c29e2aaSSasha Levin 4864346fd8fSSasha Levin static struct kvm *kvm_cmd_run_init(int argc, const char **argv) 487f967c427SPrasad Joshi { 4882d96f6b6SSasha Levin static char real_cmdline[2048], default_name[20]; 489384922b3SPekka Enberg unsigned int nr_online_cpus; 4905002444cSSasha Levin struct sigaction sa; 4914346fd8fSSasha Levin struct kvm *kvm = kvm__new(); 49247621338SSasha Levin 49347621338SSasha Levin if (IS_ERR(kvm)) 4944346fd8fSSasha Levin return kvm; 495f967c427SPrasad Joshi 4965002444cSSasha Levin sa.sa_flags = SA_SIGINFO; 4975002444cSSasha Levin sa.sa_sigaction = handle_sigalrm; 4985002444cSSasha Levin sigemptyset(&sa.sa_mask); 4995002444cSSasha Levin sigaction(SIGALRM, &sa, NULL); 500f967c427SPrasad Joshi 501cfd63bbbSSasha Levin nr_online_cpus = sysconf(_SC_NPROCESSORS_ONLN); 50247621338SSasha Levin kvm->cfg.custom_rootfs_name = "default"; 503cfd63bbbSSasha Levin 504f967c427SPrasad Joshi while (argc != 0) { 5053b55dcdeSSasha Levin BUILD_OPTIONS(options, &kvm->cfg, kvm); 506f967c427SPrasad Joshi argc = parse_options(argc, argv, options, run_usage, 5071a007c82SSasha Levin PARSE_OPT_STOP_AT_NON_OPTION | 5081a007c82SSasha Levin PARSE_OPT_KEEP_DASHDASH); 509f967c427SPrasad Joshi if (argc != 0) { 5101a007c82SSasha Levin /* Cusrom options, should have been handled elsewhere */ 5113c29e2aaSSasha Levin if (strcmp(argv[0], "--") == 0) { 5123c29e2aaSSasha Levin if (kvm_run_wrapper == KVM_RUN_SANDBOX) { 51347621338SSasha Levin kvm->cfg.sandbox = DEFAULT_SANDBOX_FILENAME; 5144346fd8fSSasha Levin kvm_run_write_sandbox_cmd(kvm, argv+1, argc-1); 5151a007c82SSasha Levin break; 5163c29e2aaSSasha Levin } 5173c29e2aaSSasha Levin } 5181a007c82SSasha Levin 51947621338SSasha Levin if ((kvm_run_wrapper == KVM_RUN_DEFAULT && kvm->cfg.kernel_filename) || 52047621338SSasha Levin (kvm_run_wrapper == KVM_RUN_SANDBOX && kvm->cfg.sandbox)) { 521f967c427SPrasad Joshi fprintf(stderr, "Cannot handle parameter: " 522f967c427SPrasad Joshi "%s\n", argv[0]); 523f967c427SPrasad Joshi usage_with_options(run_usage, options); 52447621338SSasha Levin free(kvm); 5254346fd8fSSasha Levin return ERR_PTR(-EINVAL); 526f967c427SPrasad Joshi } 527e0747665SSasha Levin if (kvm_run_wrapper == KVM_RUN_SANDBOX) { 528e0747665SSasha Levin /* 529e0747665SSasha Levin * first unhandled parameter is treated as 530e0747665SSasha Levin * sandbox command 531e0747665SSasha Levin */ 53247621338SSasha Levin kvm->cfg.sandbox = DEFAULT_SANDBOX_FILENAME; 5334346fd8fSSasha Levin kvm_run_write_sandbox_cmd(kvm, argv, argc); 534e0747665SSasha Levin } else { 535e0747665SSasha Levin /* 536e0747665SSasha Levin * first unhandled parameter is treated as a kernel 537e0747665SSasha Levin * image 538f967c427SPrasad Joshi */ 53947621338SSasha Levin kvm->cfg.kernel_filename = argv[0]; 540e0747665SSasha Levin } 541f967c427SPrasad Joshi argv++; 542f967c427SPrasad Joshi argc--; 543f967c427SPrasad Joshi } 544f967c427SPrasad Joshi 545f967c427SPrasad Joshi } 546f967c427SPrasad Joshi 5473b55dcdeSSasha Levin kvm->nr_disks = kvm->cfg.image_count; 5483b55dcdeSSasha Levin 54947621338SSasha Levin if (!kvm->cfg.kernel_filename) 55047621338SSasha Levin kvm->cfg.kernel_filename = find_kernel(); 5518329f30bSPekka Enberg 55247621338SSasha Levin if (!kvm->cfg.kernel_filename) { 553e08c0896SPrasad Joshi kernel_usage_with_options(); 5544346fd8fSSasha Levin return ERR_PTR(-EINVAL); 5558329f30bSPekka Enberg } 5568329f30bSPekka Enberg 55747621338SSasha Levin kvm->cfg.vmlinux_filename = find_vmlinux(); 558084a1356SSasha Levin kvm->vmlinux = kvm->cfg.vmlinux_filename; 559b0b42ba0SPekka Enberg 56000ebbe96SSasha Levin if (kvm->cfg.nrcpus == 0) 56100ebbe96SSasha Levin kvm->cfg.nrcpus = nr_online_cpus; 562d77a9efaSCyrill Gorcunov 56347621338SSasha Levin if (!kvm->cfg.ram_size) 56400ebbe96SSasha Levin kvm->cfg.ram_size = get_ram_size(kvm->cfg.nrcpus); 565fd834defSPekka Enberg 56647621338SSasha Levin if (kvm->cfg.ram_size < MIN_RAM_SIZE_MB) 56747621338SSasha Levin die("Not enough memory specified: %lluMB (min %lluMB)", kvm->cfg.ram_size, MIN_RAM_SIZE_MB); 568a2a002f9SIngo Molnar 56947621338SSasha Levin if (kvm->cfg.ram_size > host_ram_size()) 57047621338SSasha Levin pr_warning("Guest memory size %lluMB exceeds host physical RAM size %lluMB", kvm->cfg.ram_size, host_ram_size()); 57160ded003SPekka Enberg 57247621338SSasha Levin kvm->cfg.ram_size <<= MB_SHIFT; 573f967c427SPrasad Joshi 57447621338SSasha Levin if (!kvm->cfg.dev) 57547621338SSasha Levin kvm->cfg.dev = DEFAULT_KVM_DEV; 576f967c427SPrasad Joshi 57747621338SSasha Levin if (!kvm->cfg.console) 57847621338SSasha Levin kvm->cfg.console = DEFAULT_CONSOLE; 5799aa4a0ebSAsias He 58047621338SSasha Levin if (!strncmp(kvm->cfg.console, "virtio", 6)) 5812651ea58SSasha Levin kvm->cfg.active_console = CONSOLE_VIRTIO; 58247621338SSasha Levin else if (!strncmp(kvm->cfg.console, "serial", 6)) 5832651ea58SSasha Levin kvm->cfg.active_console = CONSOLE_8250; 58447621338SSasha Levin else if (!strncmp(kvm->cfg.console, "hv", 2)) 5852651ea58SSasha Levin kvm->cfg.active_console = CONSOLE_HV; 5863bbc49b6SMatt Evans else 5873bbc49b6SMatt Evans pr_warning("No console!"); 588f967c427SPrasad Joshi 58947621338SSasha Levin if (!kvm->cfg.host_ip) 59047621338SSasha Levin kvm->cfg.host_ip = DEFAULT_HOST_ADDR; 5914d67c820SSasha Levin 59247621338SSasha Levin if (!kvm->cfg.guest_ip) 59347621338SSasha Levin kvm->cfg.guest_ip = DEFAULT_GUEST_ADDR; 594bb8ffd2fSAsias He 59547621338SSasha Levin if (!kvm->cfg.guest_mac) 59647621338SSasha Levin kvm->cfg.guest_mac = DEFAULT_GUEST_MAC; 597a4e724ddSSasha Levin 59847621338SSasha Levin if (!kvm->cfg.host_mac) 59947621338SSasha Levin kvm->cfg.host_mac = DEFAULT_HOST_MAC; 600d7098b9bSAsias He 60147621338SSasha Levin if (!kvm->cfg.script) 60247621338SSasha Levin kvm->cfg.script = DEFAULT_SCRIPT; 60373b7d038SAmos Kong 604cf5323a3SSasha Levin if (!kvm->cfg.network) 605cf5323a3SSasha Levin kvm->cfg.network = DEFAULT_NETWORK; 606cf5323a3SSasha Levin 607084a1356SSasha Levin memset(real_cmdline, 0, sizeof(real_cmdline)); 608*7bcceb95SPekka Enberg kvm__arch_set_cmdline(real_cmdline, kvm->cfg.vnc || kvm->cfg.sdl || kvm->cfg.gtk); 609084a1356SSasha Levin 610084a1356SSasha Levin if (strlen(real_cmdline) > 0) 611084a1356SSasha Levin strcat(real_cmdline, " "); 612084a1356SSasha Levin 613084a1356SSasha Levin if (kvm->cfg.kernel_cmdline) 614084a1356SSasha Levin strlcat(real_cmdline, kvm->cfg.kernel_cmdline, sizeof(real_cmdline)); 615f967c427SPrasad Joshi 61647621338SSasha Levin if (!kvm->cfg.guest_name) { 61747621338SSasha Levin if (kvm->cfg.custom_rootfs) { 61847621338SSasha Levin kvm->cfg.guest_name = kvm->cfg.custom_rootfs_name; 619587a4d17SLai Jiangshan } else { 6202d96f6b6SSasha Levin sprintf(default_name, "guest-%u", getpid()); 62147621338SSasha Levin kvm->cfg.guest_name = default_name; 6222d96f6b6SSasha Levin } 623587a4d17SLai Jiangshan } 6242d96f6b6SSasha Levin 62547621338SSasha Levin if (!kvm->cfg.using_rootfs && !kvm->cfg.disk_image[0].filename && !kvm->cfg.initrd_filename) { 626c8675741SSasha Levin char tmp[PATH_MAX]; 6276df1471eSPekka Enberg 62847621338SSasha Levin kvm_setup_create_new(kvm->cfg.custom_rootfs_name); 62947621338SSasha Levin kvm_setup_resolv(kvm->cfg.custom_rootfs_name); 630c8675741SSasha Levin 6319667701cSPekka Enberg snprintf(tmp, PATH_MAX, "%s%s", kvm__get_dir(), "default"); 632c8675741SSasha Levin if (virtio_9p__register(kvm, tmp, "/dev/root") < 0) 633c8675741SSasha Levin die("Unable to initialize virtio 9p"); 634c8675741SSasha Levin if (virtio_9p__register(kvm, "/", "hostfs") < 0) 635c8675741SSasha Levin die("Unable to initialize virtio 9p"); 63647621338SSasha Levin kvm->cfg.using_rootfs = kvm->cfg.custom_rootfs = 1; 63726c853e4SPrasad Joshi } 63826c853e4SPrasad Joshi 63947621338SSasha Levin if (kvm->cfg.using_rootfs) { 640ff42603fSSasha Levin strcat(real_cmdline, " root=/dev/root rw rootflags=rw,trans=virtio,version=9p2000.L rootfstype=9p"); 64147621338SSasha Levin if (kvm->cfg.custom_rootfs) { 6424346fd8fSSasha Levin kvm_run_set_sandbox(kvm); 643d50fe489SSasha Levin 644a8e6b4b9SSasha Levin strcat(real_cmdline, " init=/virt/init"); 645d50fe489SSasha Levin 64647621338SSasha Levin if (!kvm->cfg.no_dhcp) 647a8e6b4b9SSasha Levin strcat(real_cmdline, " ip=dhcp"); 6484346fd8fSSasha Levin if (kvm_setup_guest_init(kvm)) 649afc2c7c0SAsias He die("Failed to setup init for guest."); 650a8e6b4b9SSasha Levin } 65182d65b5eSSasha Levin } else if (!strstr(real_cmdline, "root=")) { 652ff42603fSSasha Levin strlcat(real_cmdline, " root=/dev/vda rw ", sizeof(real_cmdline)); 65382d65b5eSSasha Levin } 65459aa2d30SSasha Levin 655084a1356SSasha Levin kvm->cfg.real_cmdline = real_cmdline; 656084a1356SSasha Levin 657084a1356SSasha Levin printf(" # %s run -k %s -m %Lu -c %d --name %s\n", KVM_BINARY_NAME, 658084a1356SSasha Levin kvm->cfg.kernel_filename, kvm->cfg.ram_size / 1024 / 1024, kvm->cfg.nrcpus, kvm->cfg.guest_name); 659084a1356SSasha Levin 6605b403dbfSWill Deacon if (init_list__init(kvm) < 0) 6615b403dbfSWill Deacon die ("Initialisation failed"); 6624346fd8fSSasha Levin 6634346fd8fSSasha Levin return kvm; 664e1e46fe6SSasha Levin } 665e1e46fe6SSasha Levin 6664346fd8fSSasha Levin static int kvm_cmd_run_work(struct kvm *kvm) 667e1e46fe6SSasha Levin { 668df4239fbSSasha Levin int i; 669e1e46fe6SSasha Levin void *ret = NULL; 670e1e46fe6SSasha Levin 67100ebbe96SSasha Levin for (i = 0; i < kvm->nrcpus; i++) { 672df4239fbSSasha Levin if (pthread_create(&kvm->cpus[i]->thread, NULL, kvm_cpu_thread, kvm->cpus[i]) != 0) 6735ee154d1SPekka Enberg die("unable to create KVM VCPU thread"); 6745ee154d1SPekka Enberg } 6755ee154d1SPekka Enberg 67649e5227dSSasha Levin /* Only VCPU #0 is going to exit by itself when shutting down */ 677df4239fbSSasha Levin return pthread_join(kvm->cpus[0]->thread, &ret); 678e1e46fe6SSasha Levin } 679e1e46fe6SSasha Levin 6804346fd8fSSasha Levin static void kvm_cmd_run_exit(struct kvm *kvm, int guest_ret) 681e1e46fe6SSasha Levin { 682e6694207SSasha Levin compat__print_all_messages(); 683e6694207SSasha Levin 68449a8afd1SSasha Levin init_list__exit(kvm); 685f967c427SPrasad Joshi 686e1e46fe6SSasha Levin if (guest_ret == 0) 687f967c427SPrasad Joshi printf("\n # KVM session ended normally.\n"); 688e1e46fe6SSasha Levin } 689e1e46fe6SSasha Levin 690e1e46fe6SSasha Levin int kvm_cmd_run(int argc, const char **argv, const char *prefix) 691e1e46fe6SSasha Levin { 6924346fd8fSSasha Levin int ret = -EFAULT; 6934346fd8fSSasha Levin struct kvm *kvm; 694e1e46fe6SSasha Levin 6954346fd8fSSasha Levin kvm = kvm_cmd_run_init(argc, argv); 6964346fd8fSSasha Levin if (IS_ERR(kvm)) 6974346fd8fSSasha Levin return PTR_ERR(kvm); 698e1e46fe6SSasha Levin 6994346fd8fSSasha Levin ret = kvm_cmd_run_work(kvm); 7004346fd8fSSasha Levin kvm_cmd_run_exit(kvm, ret); 701e1e46fe6SSasha Levin 702e1e46fe6SSasha Levin return ret; 703f967c427SPrasad Joshi } 704