xref: /kvmtool/builtin-run.c (revision a67da3beff7afdf98679be09b0d8ce501bd71ac1)
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"
11*a67da3beSAsias 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 DEFAULT_KVM_DEV		"/dev/kvm"
539aa4a0ebSAsias He #define DEFAULT_CONSOLE		"serial"
54bd30e200SAsias He #define DEFAULT_NETWORK		"user"
55745c7231SAsias He #define DEFAULT_HOST_ADDR	"192.168.33.1"
56bb8ffd2fSAsias He #define DEFAULT_GUEST_ADDR	"192.168.33.15"
577c88c87eSSasha Levin #define DEFAULT_GUEST_MAC	"02:15:15:15:15:15"
587c88c87eSSasha Levin #define DEFAULT_HOST_MAC	"02:01:01:01:01:01"
5973b7d038SAmos Kong #define DEFAULT_SCRIPT		"none"
603c29e2aaSSasha Levin const char *DEFAULT_SANDBOX_FILENAME = "guest/sandbox.sh";
61f967c427SPrasad Joshi 
62f967c427SPrasad Joshi #define MB_SHIFT		(20)
6395d13a52SSasha Levin #define KB_SHIFT		(10)
6495d13a52SSasha Levin #define GB_SHIFT		(30)
65a2a002f9SIngo Molnar #define MIN_RAM_SIZE_MB		(64ULL)
66f967c427SPrasad Joshi #define MIN_RAM_SIZE_BYTE	(MIN_RAM_SIZE_MB << MB_SHIFT)
67f967c427SPrasad Joshi 
684298ddadSSasha Levin struct kvm *kvm;
69e2077857SMatt Evans struct kvm_cpu **kvm_cpus;
70656be1b8SSasha Levin __thread struct kvm_cpu *current_kvm_cpu;
71f967c427SPrasad Joshi 
7297f16d66SAsias He static struct disk_image_params disk_image[MAX_DISK_IMAGES];
73fd834defSPekka Enberg static u64 ram_size;
74a33979d8SSasha Levin static u8  image_count;
759a6d73f1SSasha Levin static u8 num_net_devices;
76cf55d6aeSLiming Wang static bool virtio_rng;
77f967c427SPrasad Joshi static const char *kernel_cmdline;
78f967c427SPrasad Joshi static const char *kernel_filename;
79b0b42ba0SPekka Enberg static const char *vmlinux_filename;
80f967c427SPrasad Joshi static const char *initrd_filename;
815ad8db5eSPekka Enberg static const char *firmware_filename;
829aa4a0ebSAsias He static const char *console;
835929637bSAsias He static const char *dev;
844f56d42cSAsias He static const char *network;
85e80ddf6aSAsias He static const char *host_ip;
86bb8ffd2fSAsias He static const char *guest_ip;
87a4e724ddSSasha Levin static const char *guest_mac;
88d7098b9bSAsias He static const char *host_mac;
8973b7d038SAmos Kong static const char *script;
905358b0e6SSasha Levin static const char *guest_name;
91d50fe489SSasha Levin static const char *sandbox;
9261061257SMatt Evans static const char *hugetlbfs_path;
93cb540c93SSasha Levin static const char *custom_rootfs_name = "default";
949a6d73f1SSasha Levin static struct virtio_net_params *net_params;
950ea58e5bSPekka Enberg static bool single_step;
965ffd4178SJohn Floren static bool vnc;
973f838fecSPekka Enberg static bool sdl;
9882d2f21eSSasha Levin static bool balloon;
9959aa2d30SSasha Levin static bool using_rootfs;
10082d65b5eSSasha Levin static bool custom_rootfs;
1019a6d73f1SSasha Levin static bool no_net;
102a8e6b4b9SSasha Levin static bool no_dhcp;
103f967c427SPrasad Joshi extern bool ioport_debug;
104d562e086SCyrill Gorcunov extern bool mmio_debug;
1053c29e2aaSSasha Levin static int  kvm_run_wrapper;
106f967c427SPrasad Joshi extern int  active_console;
107aa400b00SPrasad Joshi extern int  debug_iodelay;
108f967c427SPrasad Joshi 
109ed036f03SCyrill Gorcunov bool do_debug_print = false;
110ed036f03SCyrill Gorcunov 
111cfd63bbbSSasha Levin static int nrcpus;
112890364f8SCyrill Gorcunov static int vidmode = -1;
113d77a9efaSCyrill Gorcunov 
114f967c427SPrasad Joshi static const char * const run_usage[] = {
1158d2ff5daSWanlong Gao 	"lkvm run [<options>] [<kernel image>]",
116f967c427SPrasad Joshi 	NULL
117f967c427SPrasad Joshi };
118f967c427SPrasad Joshi 
1193c29e2aaSSasha Levin enum {
120e0747665SSasha Levin 	KVM_RUN_DEFAULT,
1213c29e2aaSSasha Levin 	KVM_RUN_SANDBOX,
1223c29e2aaSSasha Levin };
1233c29e2aaSSasha Levin 
1243c29e2aaSSasha Levin void kvm_run_set_wrapper_sandbox(void)
1253c29e2aaSSasha Levin {
1263c29e2aaSSasha Levin 	kvm_run_wrapper = KVM_RUN_SANDBOX;
1273c29e2aaSSasha Levin }
1283c29e2aaSSasha Levin 
129a33979d8SSasha Levin static int img_name_parser(const struct option *opt, const char *arg, int unset)
130a33979d8SSasha Levin {
13182d65b5eSSasha Levin 	char path[PATH_MAX];
1325236b505SAsias He 	const char *cur;
1335236b505SAsias He 	struct stat st;
1345236b505SAsias He 	char *sep;
13559aa2d30SSasha Levin 
13659aa2d30SSasha Levin 	if (stat(arg, &st) == 0 &&
13759aa2d30SSasha Levin 	    S_ISDIR(st.st_mode)) {
13859aa2d30SSasha Levin 		char tmp[PATH_MAX];
13959aa2d30SSasha Levin 
1402c908af9SLai Jiangshan 		if (using_rootfs)
1412c908af9SLai Jiangshan 			die("Please use only one rootfs directory atmost");
1422c908af9SLai Jiangshan 
14359aa2d30SSasha Levin 		if (realpath(arg, tmp) == 0 ||
144c7838fbdSSasha Levin 		    virtio_9p__register(kvm, tmp, "/dev/root") < 0)
14559aa2d30SSasha Levin 			die("Unable to initialize virtio 9p");
14659aa2d30SSasha Levin 		using_rootfs = 1;
14759aa2d30SSasha Levin 		return 0;
14859aa2d30SSasha Levin 	}
149a33979d8SSasha Levin 
1509667701cSPekka Enberg 	snprintf(path, PATH_MAX, "%s%s", kvm__get_dir(), arg);
15182d65b5eSSasha Levin 
15282d65b5eSSasha Levin 	if (stat(path, &st) == 0 &&
15382d65b5eSSasha Levin 	    S_ISDIR(st.st_mode)) {
15482d65b5eSSasha Levin 		char tmp[PATH_MAX];
15582d65b5eSSasha Levin 
1562c908af9SLai Jiangshan 		if (using_rootfs)
1572c908af9SLai Jiangshan 			die("Please use only one rootfs directory atmost");
1582c908af9SLai Jiangshan 
15982d65b5eSSasha Levin 		if (realpath(path, tmp) == 0 ||
16082d65b5eSSasha Levin 		    virtio_9p__register(kvm, tmp, "/dev/root") < 0)
16182d65b5eSSasha Levin 			die("Unable to initialize virtio 9p");
16282d65b5eSSasha Levin 		if (virtio_9p__register(kvm, "/", "hostfs") < 0)
16382d65b5eSSasha Levin 			die("Unable to initialize virtio 9p");
16469c88b95SSasha Levin 		kvm_setup_resolv(arg);
16582d65b5eSSasha Levin 		using_rootfs = custom_rootfs = 1;
166cb540c93SSasha Levin 		custom_rootfs_name = arg;
16782d65b5eSSasha Levin 		return 0;
16882d65b5eSSasha Levin 	}
16982d65b5eSSasha Levin 
170a33979d8SSasha Levin 	if (image_count >= MAX_DISK_IMAGES)
171a33979d8SSasha Levin 		die("Currently only 4 images are supported");
172a33979d8SSasha Levin 
17397f16d66SAsias He 	disk_image[image_count].filename = arg;
1745236b505SAsias He 	cur = arg;
175*a67da3beSAsias He 
176*a67da3beSAsias He 	if (strncmp(arg, "scsi:", 5) == 0) {
177*a67da3beSAsias He 		sep = strstr(arg, ":");
178*a67da3beSAsias He 		if (sep)
179*a67da3beSAsias He 			disk_image[image_count].wwpn = sep + 1;
180*a67da3beSAsias He 		sep = strstr(sep + 1, ":");
181*a67da3beSAsias He 		if (sep) {
182*a67da3beSAsias He 			*sep = 0;
183*a67da3beSAsias He 			disk_image[image_count].tpgt = sep + 1;
184*a67da3beSAsias He 		}
185*a67da3beSAsias He 		cur = sep + 1;
186*a67da3beSAsias He 	}
187*a67da3beSAsias He 
1885236b505SAsias He 	do {
1895236b505SAsias He 		sep = strstr(cur, ",");
190a33979d8SSasha Levin 		if (sep) {
1915236b505SAsias He 			if (strncmp(sep + 1, "ro", 2) == 0)
19297f16d66SAsias He 				disk_image[image_count].readonly = true;
1935236b505SAsias He 			else if (strncmp(sep + 1, "direct", 6) == 0)
1945236b505SAsias He 				disk_image[image_count].direct = true;
195a33979d8SSasha Levin 			*sep = 0;
1965236b505SAsias He 			cur = sep + 1;
197a33979d8SSasha Levin 		}
1985236b505SAsias He 	} while (sep);
199a33979d8SSasha Levin 
200a33979d8SSasha Levin 	image_count++;
201a33979d8SSasha Levin 
202a33979d8SSasha Levin 	return 0;
203a33979d8SSasha Levin }
204a33979d8SSasha Levin 
205b4422bf3SAneesh Kumar K.V static int virtio_9p_rootdir_parser(const struct option *opt, const char *arg, int unset)
206b4422bf3SAneesh Kumar K.V {
207b4422bf3SAneesh Kumar K.V 	char *tag_name;
208b4422bf3SAneesh Kumar K.V 	char tmp[PATH_MAX];
209b4422bf3SAneesh Kumar K.V 
210b4422bf3SAneesh Kumar K.V 	/*
211b4422bf3SAneesh Kumar K.V 	 * 9p dir can be of the form dirname,tag_name or
212b4422bf3SAneesh Kumar K.V 	 * just dirname. In the later case we use the
213b4422bf3SAneesh Kumar K.V 	 * default tag name
214b4422bf3SAneesh Kumar K.V 	 */
215b4422bf3SAneesh Kumar K.V 	tag_name = strstr(arg, ",");
216b4422bf3SAneesh Kumar K.V 	if (tag_name) {
217b4422bf3SAneesh Kumar K.V 		*tag_name = '\0';
218b4422bf3SAneesh Kumar K.V 		tag_name++;
219b4422bf3SAneesh Kumar K.V 	}
22054f6802dSPekka Enberg 	if (realpath(arg, tmp)) {
221c7838fbdSSasha Levin 		if (virtio_9p__register(kvm, tmp, tag_name) < 0)
22254f6802dSPekka Enberg 			die("Unable to initialize virtio 9p");
22354f6802dSPekka Enberg 	} else
224b4422bf3SAneesh Kumar K.V 		die("Failed resolving 9p path");
225b4422bf3SAneesh Kumar K.V 	return 0;
226b4422bf3SAneesh Kumar K.V }
227b4422bf3SAneesh Kumar K.V 
2281add4b76SSasha Levin static int tty_parser(const struct option *opt, const char *arg, int unset)
2291add4b76SSasha Levin {
2301add4b76SSasha Levin 	int tty = atoi(arg);
2311add4b76SSasha Levin 
2321add4b76SSasha Levin 	term_set_tty(tty);
2331add4b76SSasha Levin 
2341add4b76SSasha Levin 	return 0;
2351add4b76SSasha Levin }
2361add4b76SSasha Levin 
2379a6d73f1SSasha Levin static inline void str_to_mac(const char *str, char *mac)
2389a6d73f1SSasha Levin {
2399a6d73f1SSasha Levin 	sscanf(str, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx",
2409a6d73f1SSasha Levin 		mac, mac+1, mac+2, mac+3, mac+4, mac+5);
2419a6d73f1SSasha Levin }
2429a6d73f1SSasha Levin static int set_net_param(struct virtio_net_params *p, const char *param,
2439a6d73f1SSasha Levin 				const char *val)
2449a6d73f1SSasha Levin {
2459a6d73f1SSasha Levin 	if (strcmp(param, "guest_mac") == 0) {
2469a6d73f1SSasha Levin 		str_to_mac(val, p->guest_mac);
2479a6d73f1SSasha Levin 	} else if (strcmp(param, "mode") == 0) {
2489a6d73f1SSasha Levin 		if (!strncmp(val, "user", 4)) {
2499a6d73f1SSasha Levin 			int i;
2509a6d73f1SSasha Levin 
2519a6d73f1SSasha Levin 			for (i = 0; i < num_net_devices; i++)
2529a6d73f1SSasha Levin 				if (net_params[i].mode == NET_MODE_USER)
2539a6d73f1SSasha Levin 					die("Only one usermode network device allowed at a time");
2549a6d73f1SSasha Levin 			p->mode = NET_MODE_USER;
2559a6d73f1SSasha Levin 		} else if (!strncmp(val, "tap", 3)) {
2569a6d73f1SSasha Levin 			p->mode = NET_MODE_TAP;
2579a6d73f1SSasha Levin 		} else if (!strncmp(val, "none", 4)) {
2589a6d73f1SSasha Levin 			no_net = 1;
2599a6d73f1SSasha Levin 			return -1;
2609a6d73f1SSasha Levin 		} else
2619a6d73f1SSasha Levin 			die("Unkown network mode %s, please use user, tap or none", network);
2629a6d73f1SSasha Levin 	} else if (strcmp(param, "script") == 0) {
2639a6d73f1SSasha Levin 		p->script = strdup(val);
2649a6d73f1SSasha Levin 	} else if (strcmp(param, "guest_ip") == 0) {
2659a6d73f1SSasha Levin 		p->guest_ip = strdup(val);
2669a6d73f1SSasha Levin 	} else if (strcmp(param, "host_ip") == 0) {
2679a6d73f1SSasha Levin 		p->host_ip = strdup(val);
26869205aa1SAsias He 	} else if (strcmp(param, "trans") == 0) {
26969205aa1SAsias He 		p->trans = strdup(val);
2709ed67cdcSSasha Levin 	} else if (strcmp(param, "vhost") == 0) {
2719ed67cdcSSasha Levin 		p->vhost = atoi(val);
272f19edd1eSSasha Levin 	} else if (strcmp(param, "fd") == 0) {
273f19edd1eSSasha Levin 		p->fd = atoi(val);
27421aa628eSMichael Ellerman 	} else
27521aa628eSMichael Ellerman 		die("Unknown network parameter %s", param);
2769a6d73f1SSasha Levin 
2779a6d73f1SSasha Levin 	return 0;
2789a6d73f1SSasha Levin }
2799a6d73f1SSasha Levin 
2809a6d73f1SSasha Levin static int netdev_parser(const struct option *opt, const char *arg, int unset)
2819a6d73f1SSasha Levin {
2829a6d73f1SSasha Levin 	struct virtio_net_params p;
2839a6d73f1SSasha Levin 	char *buf = NULL, *cmd = NULL, *cur = NULL;
2849a6d73f1SSasha Levin 	bool on_cmd = true;
2859a6d73f1SSasha Levin 
2869a6d73f1SSasha Levin 	if (arg) {
2879a6d73f1SSasha Levin 		buf = strdup(arg);
2889a6d73f1SSasha Levin 		if (buf == NULL)
2899a6d73f1SSasha Levin 			die("Failed allocating new net buffer");
2909a6d73f1SSasha Levin 		cur = strtok(buf, ",=");
2919a6d73f1SSasha Levin 	}
2929a6d73f1SSasha Levin 
2939a6d73f1SSasha Levin 	p = (struct virtio_net_params) {
2949a6d73f1SSasha Levin 		.guest_ip	= DEFAULT_GUEST_ADDR,
2959a6d73f1SSasha Levin 		.host_ip	= DEFAULT_HOST_ADDR,
2969a6d73f1SSasha Levin 		.script		= DEFAULT_SCRIPT,
2979a6d73f1SSasha Levin 		.mode		= NET_MODE_TAP,
2989a6d73f1SSasha Levin 	};
2999a6d73f1SSasha Levin 
3009a6d73f1SSasha Levin 	str_to_mac(DEFAULT_GUEST_MAC, p.guest_mac);
3019a6d73f1SSasha Levin 	p.guest_mac[5] += num_net_devices;
3029a6d73f1SSasha Levin 
3039a6d73f1SSasha Levin 	while (cur) {
3049a6d73f1SSasha Levin 		if (on_cmd) {
3059a6d73f1SSasha Levin 			cmd = cur;
3069a6d73f1SSasha Levin 		} else {
3079a6d73f1SSasha Levin 			if (set_net_param(&p, cmd, cur) < 0)
3089a6d73f1SSasha Levin 				goto done;
3099a6d73f1SSasha Levin 		}
3109a6d73f1SSasha Levin 		on_cmd = !on_cmd;
3119a6d73f1SSasha Levin 
3129a6d73f1SSasha Levin 		cur = strtok(NULL, ",=");
3139a6d73f1SSasha Levin 	};
3149a6d73f1SSasha Levin 
3159a6d73f1SSasha Levin 	num_net_devices++;
3169a6d73f1SSasha Levin 
3179a6d73f1SSasha Levin 	net_params = realloc(net_params, num_net_devices * sizeof(*net_params));
3189a6d73f1SSasha Levin 	if (net_params == NULL)
3199a6d73f1SSasha Levin 		die("Failed adding new network device");
3209a6d73f1SSasha Levin 
3219a6d73f1SSasha Levin 	net_params[num_net_devices - 1] = p;
3229a6d73f1SSasha Levin 
3239a6d73f1SSasha Levin done:
3249a6d73f1SSasha Levin 	free(buf);
3259a6d73f1SSasha Levin 	return 0;
3269a6d73f1SSasha Levin }
3279a6d73f1SSasha Levin 
32895d13a52SSasha Levin static int shmem_parser(const struct option *opt, const char *arg, int unset)
32995d13a52SSasha Levin {
33072f1ad6dSSasha Levin 	const u64 default_size = SHMEM_DEFAULT_SIZE;
33172f1ad6dSSasha Levin 	const u64 default_phys_addr = SHMEM_DEFAULT_ADDR;
33295d13a52SSasha Levin 	const char *default_handle = SHMEM_DEFAULT_HANDLE;
33395d13a52SSasha Levin 	struct shmem_info *si = malloc(sizeof(struct shmem_info));
33472f1ad6dSSasha Levin 	u64 phys_addr;
33572f1ad6dSSasha Levin 	u64 size;
33695d13a52SSasha Levin 	char *handle = NULL;
33795d13a52SSasha Levin 	int create = 0;
33895d13a52SSasha Levin 	const char *p = arg;
33995d13a52SSasha Levin 	char *next;
34095d13a52SSasha Levin 	int base = 10;
34195d13a52SSasha Levin 	int verbose = 0;
34295d13a52SSasha Levin 
34395d13a52SSasha Levin 	const int skip_pci = strlen("pci:");
34495d13a52SSasha Levin 	if (verbose)
34595d13a52SSasha Levin 		pr_info("shmem_parser(%p,%s,%d)", opt, arg, unset);
34695d13a52SSasha Levin 	/* parse out optional addr family */
34795d13a52SSasha Levin 	if (strcasestr(p, "pci:")) {
34895d13a52SSasha Levin 		p += skip_pci;
34995d13a52SSasha Levin 	} else if (strcasestr(p, "mem:")) {
35095d13a52SSasha Levin 		die("I can't add to E820 map yet.\n");
35195d13a52SSasha Levin 	}
35295d13a52SSasha Levin 	/* parse out physical addr */
35395d13a52SSasha Levin 	base = 10;
35495d13a52SSasha Levin 	if (strcasestr(p, "0x"))
35595d13a52SSasha Levin 		base = 16;
35695d13a52SSasha Levin 	phys_addr = strtoll(p, &next, base);
35795d13a52SSasha Levin 	if (next == p && phys_addr == 0) {
35895d13a52SSasha Levin 		pr_info("shmem: no physical addr specified, using default.");
35995d13a52SSasha Levin 		phys_addr = default_phys_addr;
36095d13a52SSasha Levin 	}
36195d13a52SSasha Levin 	if (*next != ':' && *next != '\0')
36295d13a52SSasha Levin 		die("shmem: unexpected chars after phys addr.\n");
36395d13a52SSasha Levin 	if (*next == '\0')
36495d13a52SSasha Levin 		p = next;
36595d13a52SSasha Levin 	else
36695d13a52SSasha Levin 		p = next + 1;
36795d13a52SSasha Levin 	/* parse out size */
36895d13a52SSasha Levin 	base = 10;
36995d13a52SSasha Levin 	if (strcasestr(p, "0x"))
37095d13a52SSasha Levin 		base = 16;
37195d13a52SSasha Levin 	size = strtoll(p, &next, base);
37295d13a52SSasha Levin 	if (next == p && size == 0) {
37395d13a52SSasha Levin 		pr_info("shmem: no size specified, using default.");
37495d13a52SSasha Levin 		size = default_size;
37595d13a52SSasha Levin 	}
37695d13a52SSasha Levin 	/* look for [KMGkmg][Bb]*  uses base 2. */
37795d13a52SSasha Levin 	int skip_B = 0;
37895d13a52SSasha Levin 	if (strspn(next, "KMGkmg")) {	/* might have a prefix */
37995d13a52SSasha Levin 		if (*(next + 1) == 'B' || *(next + 1) == 'b')
38095d13a52SSasha Levin 			skip_B = 1;
38195d13a52SSasha Levin 		switch (*next) {
38295d13a52SSasha Levin 		case 'K':
38395d13a52SSasha Levin 		case 'k':
38495d13a52SSasha Levin 			size = size << KB_SHIFT;
38595d13a52SSasha Levin 			break;
38695d13a52SSasha Levin 		case 'M':
38795d13a52SSasha Levin 		case 'm':
38895d13a52SSasha Levin 			size = size << MB_SHIFT;
38995d13a52SSasha Levin 			break;
39095d13a52SSasha Levin 		case 'G':
39195d13a52SSasha Levin 		case 'g':
39295d13a52SSasha Levin 			size = size << GB_SHIFT;
39395d13a52SSasha Levin 			break;
39495d13a52SSasha Levin 		default:
39595d13a52SSasha Levin 			die("shmem: bug in detecting size prefix.");
39695d13a52SSasha Levin 			break;
39795d13a52SSasha Levin 		}
39895d13a52SSasha Levin 		next += 1 + skip_B;
39995d13a52SSasha Levin 	}
40095d13a52SSasha Levin 	if (*next != ':' && *next != '\0') {
40195d13a52SSasha Levin 		die("shmem: unexpected chars after phys size. <%c><%c>\n",
40295d13a52SSasha Levin 		    *next, *p);
40395d13a52SSasha Levin 	}
40495d13a52SSasha Levin 	if (*next == '\0')
40595d13a52SSasha Levin 		p = next;
40695d13a52SSasha Levin 	else
40795d13a52SSasha Levin 		p = next + 1;
40895d13a52SSasha Levin 	/* parse out optional shmem handle */
40995d13a52SSasha Levin 	const int skip_handle = strlen("handle=");
41095d13a52SSasha Levin 	next = strcasestr(p, "handle=");
41195d13a52SSasha Levin 	if (*p && next) {
41295d13a52SSasha Levin 		if (p != next)
41395d13a52SSasha Levin 			die("unexpected chars before handle\n");
41495d13a52SSasha Levin 		p += skip_handle;
41595d13a52SSasha Levin 		next = strchrnul(p, ':');
41695d13a52SSasha Levin 		if (next - p) {
41795d13a52SSasha Levin 			handle = malloc(next - p + 1);
41895d13a52SSasha Levin 			strncpy(handle, p, next - p);
41995d13a52SSasha Levin 			handle[next - p] = '\0';	/* just in case. */
42095d13a52SSasha Levin 		}
42195d13a52SSasha Levin 		if (*next == '\0')
42295d13a52SSasha Levin 			p = next;
42395d13a52SSasha Levin 		else
42495d13a52SSasha Levin 			p = next + 1;
42595d13a52SSasha Levin 	}
42695d13a52SSasha Levin 	/* parse optional create flag to see if we should create shm seg. */
42795d13a52SSasha Levin 	if (*p && strcasestr(p, "create")) {
42895d13a52SSasha Levin 		create = 1;
42995d13a52SSasha Levin 		p += strlen("create");
43095d13a52SSasha Levin 	}
43195d13a52SSasha Levin 	if (*p != '\0')
43295d13a52SSasha Levin 		die("shmem: unexpected trailing chars\n");
43395d13a52SSasha Levin 	if (handle == NULL) {
43495d13a52SSasha Levin 		handle = malloc(strlen(default_handle) + 1);
43595d13a52SSasha Levin 		strcpy(handle, default_handle);
43695d13a52SSasha Levin 	}
43795d13a52SSasha Levin 	if (verbose) {
43872f1ad6dSSasha Levin 		pr_info("shmem: phys_addr = %llx", phys_addr);
43972f1ad6dSSasha Levin 		pr_info("shmem: size      = %llx", size);
44095d13a52SSasha Levin 		pr_info("shmem: handle    = %s", handle);
44195d13a52SSasha Levin 		pr_info("shmem: create    = %d", create);
44295d13a52SSasha Levin 	}
44395d13a52SSasha Levin 
44495d13a52SSasha Levin 	si->phys_addr = phys_addr;
44595d13a52SSasha Levin 	si->size = size;
44695d13a52SSasha Levin 	si->handle = handle;
44795d13a52SSasha Levin 	si->create = create;
44895d13a52SSasha Levin 	pci_shmem__register_mem(si);	/* ownership of si, etc. passed on. */
44995d13a52SSasha Levin 	return 0;
45095d13a52SSasha Levin }
451b4422bf3SAneesh Kumar K.V 
452f967c427SPrasad Joshi static const struct option options[] = {
4535e3af62dSSasha Levin 	OPT_GROUP("Basic options:"),
4545358b0e6SSasha Levin 	OPT_STRING('\0', "name", &guest_name, "guest name",
4555358b0e6SSasha Levin 			"A name for the guest"),
45680b1f72fSPekka Enberg 	OPT_INTEGER('c', "cpus", &nrcpus, "Number of CPUs"),
457f967c427SPrasad Joshi 	OPT_U64('m', "mem", &ram_size, "Virtual machine memory size in MiB."),
45895d13a52SSasha Levin 	OPT_CALLBACK('\0', "shmem", NULL,
45995d13a52SSasha Levin 		     "[pci:]<addr>:<size>[:handle=<handle>][:create]",
46095d13a52SSasha Levin 		     "Share host shmem with guest via pci device",
46195d13a52SSasha Levin 		     shmem_parser),
462cadb9ab7SAsias He 	OPT_CALLBACK('d', "disk", NULL, "image or rootfs_dir", "Disk image or rootfs directory", img_name_parser),
46382d2f21eSSasha Levin 	OPT_BOOLEAN('\0', "balloon", &balloon, "Enable virtio balloon"),
4645ffd4178SJohn Floren 	OPT_BOOLEAN('\0', "vnc", &vnc, "Enable VNC framebuffer"),
4653f838fecSPekka Enberg 	OPT_BOOLEAN('\0', "sdl", &sdl, "Enable SDL framebuffer"),
466cf55d6aeSLiming Wang 	OPT_BOOLEAN('\0', "rng", &virtio_rng, "Enable virtio Random Number Generator"),
4678b7565e8SAsias He 	OPT_CALLBACK('\0', "9p", NULL, "dir_to_share,tag_name",
4688b7565e8SAsias He 		     "Enable virtio 9p to share files between host and guest", virtio_9p_rootdir_parser),
4693bbc49b6SMatt Evans 	OPT_STRING('\0', "console", &console, "serial, virtio or hv",
4708b7565e8SAsias He 			"Console to use"),
4718b7565e8SAsias He 	OPT_STRING('\0', "dev", &dev, "device_file", "KVM device file"),
4721add4b76SSasha Levin 	OPT_CALLBACK('\0', "tty", NULL, "tty id",
4731add4b76SSasha Levin 		     "Remap guest TTY into a pty on the host",
4741add4b76SSasha Levin 		     tty_parser),
475d50fe489SSasha Levin 	OPT_STRING('\0', "sandbox", &sandbox, "script",
476d50fe489SSasha Levin 			"Run this script when booting into custom rootfs"),
47761061257SMatt Evans 	OPT_STRING('\0', "hugetlbfs", &hugetlbfs_path, "path", "Hugetlbfs path"),
4785e3af62dSSasha Levin 
4795e3af62dSSasha Levin 	OPT_GROUP("Kernel options:"),
4805e3af62dSSasha Levin 	OPT_STRING('k', "kernel", &kernel_filename, "kernel",
4815e3af62dSSasha Levin 			"Kernel to boot in virtual machine"),
482d6c19027SAsias He 	OPT_STRING('i', "initrd", &initrd_filename, "initrd",
4835e3af62dSSasha Levin 			"Initial RAM disk image"),
4845e3af62dSSasha Levin 	OPT_STRING('p', "params", &kernel_cmdline, "params",
4855e3af62dSSasha Levin 			"Kernel command line arguments"),
4865ad8db5eSPekka Enberg 	OPT_STRING('f', "firmware", &firmware_filename, "firmware",
4875ad8db5eSPekka Enberg 			"Firmware image to boot in virtual machine"),
4885e3af62dSSasha Levin 
4894d67c820SSasha Levin 	OPT_GROUP("Networking options:"),
4909a6d73f1SSasha Levin 	OPT_CALLBACK_DEFAULT('n', "network", NULL, "network params",
4919a6d73f1SSasha Levin 		     "Create a new guest NIC",
4929a6d73f1SSasha Levin 		     netdev_parser, NULL),
493a8e6b4b9SSasha Levin 	OPT_BOOLEAN('\0', "no-dhcp", &no_dhcp, "Disable kernel DHCP in rootfs mode"),
494d6c19027SAsias He 
495890364f8SCyrill Gorcunov 	OPT_GROUP("BIOS options:"),
496890364f8SCyrill Gorcunov 	OPT_INTEGER('\0', "vidmode", &vidmode,
497890364f8SCyrill Gorcunov 		    "Video mode"),
498890364f8SCyrill Gorcunov 
4995e3af62dSSasha Levin 	OPT_GROUP("Debug options:"),
500ed036f03SCyrill Gorcunov 	OPT_BOOLEAN('\0', "debug", &do_debug_print,
501ed036f03SCyrill Gorcunov 			"Enable debug messages"),
502d6c19027SAsias He 	OPT_BOOLEAN('\0', "debug-single-step", &single_step,
503d6c19027SAsias He 			"Enable single stepping"),
504001690a4SSasha Levin 	OPT_BOOLEAN('\0', "debug-ioport", &ioport_debug,
505d6c19027SAsias He 			"Enable ioport debugging"),
506d562e086SCyrill Gorcunov 	OPT_BOOLEAN('\0', "debug-mmio", &mmio_debug,
507d562e086SCyrill Gorcunov 			"Enable MMIO debugging"),
508001690a4SSasha Levin 	OPT_INTEGER('\0', "debug-iodelay", &debug_iodelay,
509aa400b00SPrasad Joshi 			"Delay IO by millisecond"),
510f967c427SPrasad Joshi 	OPT_END()
511f967c427SPrasad Joshi };
512f967c427SPrasad Joshi 
513b5b501ccSIngo Molnar /*
514b5b501ccSIngo Molnar  * Serialize debug printout so that the output of multiple vcpus does not
515b5b501ccSIngo Molnar  * get mixed up:
516b5b501ccSIngo Molnar  */
517cffeab25SIngo Molnar static int printout_done;
518b5b501ccSIngo Molnar 
51943119af7SPekka Enberg static void handle_sigusr1(int sig)
52043119af7SPekka Enberg {
52143119af7SPekka Enberg 	struct kvm_cpu *cpu = current_kvm_cpu;
522b7d2f013SSasha Levin 	int fd = kvm_cpu__get_debug_fd();
52343119af7SPekka Enberg 
5244b1c6f6eSSasha Levin 	if (!cpu || cpu->needs_nmi)
52543119af7SPekka Enberg 		return;
52643119af7SPekka Enberg 
527b7d2f013SSasha Levin 	dprintf(fd, "\n #\n # vCPU #%ld's dump:\n #\n", cpu->cpu_id);
52843119af7SPekka Enberg 	kvm_cpu__show_registers(cpu);
52943119af7SPekka Enberg 	kvm_cpu__show_code(cpu);
53043119af7SPekka Enberg 	kvm_cpu__show_page_tables(cpu);
531b5b501ccSIngo Molnar 	fflush(stdout);
532cffeab25SIngo Molnar 	printout_done = 1;
533cffeab25SIngo Molnar 	mb();
53443119af7SPekka Enberg }
53543119af7SPekka Enberg 
536d94e22b9SSasha Levin /* Pause/resume the guest using SIGUSR2 */
537d94e22b9SSasha Levin static int is_paused;
538d94e22b9SSasha Levin 
5394b1addaeSSasha Levin static void handle_pause(int fd, u32 type, u32 len, u8 *msg)
540d94e22b9SSasha Levin {
5415aa502e4SLai Jiangshan 	if (WARN_ON(len))
5425aa502e4SLai Jiangshan 		return;
5435aa502e4SLai Jiangshan 
5447021c50bSAsias He 	if (type == KVM_IPC_RESUME && is_paused) {
5457021c50bSAsias He 		kvm->vm_state = KVM_VMSTATE_RUNNING;
546d94e22b9SSasha Levin 		kvm__continue();
5477021c50bSAsias He 	} else if (type == KVM_IPC_PAUSE && !is_paused) {
5487021c50bSAsias He 		kvm->vm_state = KVM_VMSTATE_PAUSED;
549eb8dad9dSSasha Levin 		ioctl(kvm->vm_fd, KVM_KVMCLOCK_CTRL);
550d94e22b9SSasha Levin 		kvm__pause();
5517021c50bSAsias He 	} else {
55202317b74SSasha Levin 		return;
5535aa502e4SLai Jiangshan 	}
554d94e22b9SSasha Levin 
555d94e22b9SSasha Levin 	is_paused = !is_paused;
556d94e22b9SSasha Levin }
557d94e22b9SSasha Levin 
5587021c50bSAsias He static void handle_vmstate(int fd, u32 type, u32 len, u8 *msg)
5597021c50bSAsias He {
5607021c50bSAsias He 	int r = 0;
5617021c50bSAsias He 
5627021c50bSAsias He 	if (type == KVM_IPC_VMSTATE)
5637021c50bSAsias He 		r = write(fd, &kvm->vm_state, sizeof(kvm->vm_state));
5647021c50bSAsias He 
5657021c50bSAsias He 	if (r < 0)
5667021c50bSAsias He 		pr_warning("Failed sending VMSTATE");
5677021c50bSAsias He }
5687021c50bSAsias He 
5694b1addaeSSasha Levin static void handle_debug(int fd, u32 type, u32 len, u8 *msg)
5709e854d1aSPekka Enberg {
5719e854d1aSPekka Enberg 	int i;
572a59cdf44SLai Jiangshan 	struct debug_cmd_params *params;
573a59cdf44SLai Jiangshan 	u32 dbg_type;
574a59cdf44SLai Jiangshan 	u32 vcpu;
575a59cdf44SLai Jiangshan 
576a59cdf44SLai Jiangshan 	if (WARN_ON(type != KVM_IPC_DEBUG || len != sizeof(*params)))
577a59cdf44SLai Jiangshan 		return;
578a59cdf44SLai Jiangshan 
579a59cdf44SLai Jiangshan 	params = (void *)msg;
580a59cdf44SLai Jiangshan 	dbg_type = params->dbg_type;
581a59cdf44SLai Jiangshan 	vcpu = params->cpu;
5824b1c6f6eSSasha Levin 
583226e727bSSasha Levin 	if (dbg_type & KVM_DEBUG_CMD_TYPE_SYSRQ)
584226e727bSSasha Levin 		serial8250__inject_sysrq(kvm, params->sysrq);
585226e727bSSasha Levin 
5864b1c6f6eSSasha Levin 	if (dbg_type & KVM_DEBUG_CMD_TYPE_NMI) {
5877070414aSSasha Levin 		if ((int)vcpu >= kvm->nrcpus)
5884b1c6f6eSSasha Levin 			return;
5894b1c6f6eSSasha Levin 
5904b1c6f6eSSasha Levin 		kvm_cpus[vcpu]->needs_nmi = 1;
5914b1c6f6eSSasha Levin 		pthread_kill(kvm_cpus[vcpu]->thread, SIGUSR1);
5924b1c6f6eSSasha Levin 	}
5934b1c6f6eSSasha Levin 
5944b1c6f6eSSasha Levin 	if (!(dbg_type & KVM_DEBUG_CMD_TYPE_DUMP))
5954b1c6f6eSSasha Levin 		return;
5969e854d1aSPekka Enberg 
5979e854d1aSPekka Enberg 	for (i = 0; i < nrcpus; i++) {
5989e854d1aSPekka Enberg 		struct kvm_cpu *cpu = kvm_cpus[i];
5999e854d1aSPekka Enberg 
60043119af7SPekka Enberg 		if (!cpu)
60143119af7SPekka Enberg 			continue;
60243119af7SPekka Enberg 
603cffeab25SIngo Molnar 		printout_done = 0;
604b7d2f013SSasha Levin 
605b7d2f013SSasha Levin 		kvm_cpu__set_debug_fd(fd);
60643119af7SPekka Enberg 		pthread_kill(cpu->thread, SIGUSR1);
607cffeab25SIngo Molnar 		/*
608cffeab25SIngo Molnar 		 * Wait for the vCPU to dump state before signalling
609cffeab25SIngo Molnar 		 * the next thread. Since this is debug code it does
610cffeab25SIngo Molnar 		 * not matter that we are burning CPU time a bit:
611cffeab25SIngo Molnar 		 */
612cffeab25SIngo Molnar 		while (!printout_done)
613cffeab25SIngo Molnar 			mb();
6149e854d1aSPekka Enberg 	}
6159e854d1aSPekka Enberg 
616b7d2f013SSasha Levin 	close(fd);
617b7d2f013SSasha Levin 
618226e727bSSasha Levin 	serial8250__inject_sysrq(kvm, 'p');
6199e854d1aSPekka Enberg }
6209e854d1aSPekka Enberg 
6219e854d1aSPekka Enberg static void handle_sigalrm(int sig)
6229e854d1aSPekka Enberg {
6230b69bdefSMatt Evans 	kvm__arch_periodic_poll(kvm);
6249e854d1aSPekka Enberg }
6259e854d1aSPekka Enberg 
6264b1addaeSSasha Levin static void handle_stop(int fd, u32 type, u32 len, u8 *msg)
627daf4cb5aSSasha Levin {
628e333e41aSLai Jiangshan 	if (WARN_ON(type != KVM_IPC_STOP || len))
629e333e41aSLai Jiangshan 		return;
630e333e41aSLai Jiangshan 
631daf4cb5aSSasha Levin 	kvm_cpu__reboot();
632daf4cb5aSSasha Levin }
633daf4cb5aSSasha Levin 
6345ee154d1SPekka Enberg static void *kvm_cpu_thread(void *arg)
6355ee154d1SPekka Enberg {
636d77a9efaSCyrill Gorcunov 	current_kvm_cpu		= arg;
6375ee154d1SPekka Enberg 
638d77a9efaSCyrill Gorcunov 	if (kvm_cpu__start(current_kvm_cpu))
6395ee154d1SPekka Enberg 		goto panic_kvm;
6405ee154d1SPekka Enberg 
6415ee154d1SPekka Enberg 	return (void *) (intptr_t) 0;
6425ee154d1SPekka Enberg 
6435ee154d1SPekka Enberg panic_kvm:
6443fdf659dSSasha Levin 	fprintf(stderr, "KVM exit reason: %u (\"%s\")\n",
645d77a9efaSCyrill Gorcunov 		current_kvm_cpu->kvm_run->exit_reason,
646d77a9efaSCyrill Gorcunov 		kvm_exit_reasons[current_kvm_cpu->kvm_run->exit_reason]);
647d77a9efaSCyrill Gorcunov 	if (current_kvm_cpu->kvm_run->exit_reason == KVM_EXIT_UNKNOWN)
6485ee154d1SPekka Enberg 		fprintf(stderr, "KVM exit code: 0x%Lu\n",
649d77a9efaSCyrill Gorcunov 			current_kvm_cpu->kvm_run->hw.hardware_exit_reason);
6508e5accedSPekka Enberg 
651b7d2f013SSasha Levin 	kvm_cpu__set_debug_fd(STDOUT_FILENO);
652d77a9efaSCyrill Gorcunov 	kvm_cpu__show_registers(current_kvm_cpu);
653d77a9efaSCyrill Gorcunov 	kvm_cpu__show_code(current_kvm_cpu);
654d77a9efaSCyrill Gorcunov 	kvm_cpu__show_page_tables(current_kvm_cpu);
6555ee154d1SPekka Enberg 
6565ee154d1SPekka Enberg 	return (void *) (intptr_t) 1;
6575ee154d1SPekka Enberg }
6585ee154d1SPekka Enberg 
659e08c0896SPrasad Joshi static char kernel[PATH_MAX];
660b0b42ba0SPekka Enberg 
661b0b42ba0SPekka Enberg static const char *host_kernels[] = {
662e08c0896SPrasad Joshi 	"/boot/vmlinuz",
663e08c0896SPrasad Joshi 	"/boot/bzImage",
664e08c0896SPrasad Joshi 	NULL
665e08c0896SPrasad Joshi };
666b0b42ba0SPekka Enberg 
667b0b42ba0SPekka Enberg static const char *default_kernels[] = {
668e08c0896SPrasad Joshi 	"./bzImage",
669b03af790SKonstantin Khlebnikov 	"arch/" BUILD_ARCH "/boot/bzImage",
670af7b0868SMatt Evans 	"../../arch/" BUILD_ARCH "/boot/bzImage",
671e08c0896SPrasad Joshi 	NULL
672e08c0896SPrasad Joshi };
6738329f30bSPekka Enberg 
674b0b42ba0SPekka Enberg static const char *default_vmlinux[] = {
675b03af790SKonstantin Khlebnikov 	"vmlinux",
676b0b42ba0SPekka Enberg 	"../../../vmlinux",
677b0b42ba0SPekka Enberg 	"../../vmlinux",
678b0b42ba0SPekka Enberg 	NULL
679b0b42ba0SPekka Enberg };
680b0b42ba0SPekka Enberg 
681e08c0896SPrasad Joshi static void kernel_usage_with_options(void)
6828329f30bSPekka Enberg {
683e08c0896SPrasad Joshi 	const char **k;
6848329f30bSPekka Enberg 	struct utsname uts;
685e08c0896SPrasad Joshi 
686e08c0896SPrasad Joshi 	fprintf(stderr, "Fatal: could not find default kernel image in:\n");
68765182f37SPrasad Joshi 	k = &default_kernels[0];
688e08c0896SPrasad Joshi 	while (*k) {
689e08c0896SPrasad Joshi 		fprintf(stderr, "\t%s\n", *k);
690e08c0896SPrasad Joshi 		k++;
691e08c0896SPrasad Joshi 	}
692e08c0896SPrasad Joshi 
693e08c0896SPrasad Joshi 	if (uname(&uts) < 0)
694e08c0896SPrasad Joshi 		return;
695e08c0896SPrasad Joshi 
696e08c0896SPrasad Joshi 	k = &host_kernels[0];
697e08c0896SPrasad Joshi 	while (*k) {
698e08c0896SPrasad Joshi 		if (snprintf(kernel, PATH_MAX, "%s-%s", *k, uts.release) < 0)
699e08c0896SPrasad Joshi 			return;
700e08c0896SPrasad Joshi 		fprintf(stderr, "\t%s\n", kernel);
701e08c0896SPrasad Joshi 		k++;
702e08c0896SPrasad Joshi 	}
703ee8b1456SWanlong Gao 	fprintf(stderr, "\nPlease see '%s run --help' for more options.\n\n",
704ee8b1456SWanlong Gao 		KVM_BINARY_NAME);
705e08c0896SPrasad Joshi }
706e08c0896SPrasad Joshi 
70760ded003SPekka Enberg static u64 host_ram_size(void)
70860ded003SPekka Enberg {
70960ded003SPekka Enberg 	long page_size;
71060ded003SPekka Enberg 	long nr_pages;
71160ded003SPekka Enberg 
71260ded003SPekka Enberg 	nr_pages	= sysconf(_SC_PHYS_PAGES);
713d63c5ce6SPekka Enberg 	if (nr_pages < 0) {
7144542f276SCyrill Gorcunov 		pr_warning("sysconf(_SC_PHYS_PAGES) failed");
715d63c5ce6SPekka Enberg 		return 0;
716d63c5ce6SPekka Enberg 	}
71760ded003SPekka Enberg 
71860ded003SPekka Enberg 	page_size	= sysconf(_SC_PAGE_SIZE);
719d63c5ce6SPekka Enberg 	if (page_size < 0) {
7204542f276SCyrill Gorcunov 		pr_warning("sysconf(_SC_PAGE_SIZE) failed");
721d63c5ce6SPekka Enberg 		return 0;
722d63c5ce6SPekka Enberg 	}
72360ded003SPekka Enberg 
72460ded003SPekka Enberg 	return (nr_pages * page_size) >> MB_SHIFT;
72560ded003SPekka Enberg }
72660ded003SPekka Enberg 
72718bd8c3bSPekka Enberg /*
72818bd8c3bSPekka Enberg  * If user didn't specify how much memory it wants to allocate for the guest,
72918bd8c3bSPekka Enberg  * avoid filling the whole host RAM.
73018bd8c3bSPekka Enberg  */
73118bd8c3bSPekka Enberg #define RAM_SIZE_RATIO		0.8
73218bd8c3bSPekka Enberg 
733fd834defSPekka Enberg static u64 get_ram_size(int nr_cpus)
734fd834defSPekka Enberg {
73506761c76SPekka Enberg 	u64 available;
73606761c76SPekka Enberg 	u64 ram_size;
737fd834defSPekka Enberg 
738fd834defSPekka Enberg 	ram_size	= 64 * (nr_cpus + 3);
739fd834defSPekka Enberg 
74060ded003SPekka Enberg 	available	= host_ram_size() * RAM_SIZE_RATIO;
741d63c5ce6SPekka Enberg 	if (!available)
742d63c5ce6SPekka Enberg 		available = MIN_RAM_SIZE_MB;
743fd834defSPekka Enberg 
744fd834defSPekka Enberg 	if (ram_size > available)
745fd834defSPekka Enberg 		ram_size	= available;
746fd834defSPekka Enberg 
747fd834defSPekka Enberg 	return ram_size;
748fd834defSPekka Enberg }
749fd834defSPekka Enberg 
750e08c0896SPrasad Joshi static const char *find_kernel(void)
751e08c0896SPrasad Joshi {
752e08c0896SPrasad Joshi 	const char **k;
7538329f30bSPekka Enberg 	struct stat st;
754e08c0896SPrasad Joshi 	struct utsname uts;
755e08c0896SPrasad Joshi 
75665182f37SPrasad Joshi 	k = &default_kernels[0];
757e08c0896SPrasad Joshi 	while (*k) {
758e08c0896SPrasad Joshi 		if (stat(*k, &st) < 0 || !S_ISREG(st.st_mode)) {
759e08c0896SPrasad Joshi 			k++;
760e08c0896SPrasad Joshi 			continue;
761e08c0896SPrasad Joshi 		}
762e08c0896SPrasad Joshi 		strncpy(kernel, *k, PATH_MAX);
763e08c0896SPrasad Joshi 		return kernel;
764e08c0896SPrasad Joshi 	}
7658329f30bSPekka Enberg 
7668329f30bSPekka Enberg 	if (uname(&uts) < 0)
7678329f30bSPekka Enberg 		return NULL;
7688329f30bSPekka Enberg 
769e08c0896SPrasad Joshi 	k = &host_kernels[0];
770e08c0896SPrasad Joshi 	while (*k) {
771e08c0896SPrasad Joshi 		if (snprintf(kernel, PATH_MAX, "%s-%s", *k, uts.release) < 0)
7728329f30bSPekka Enberg 			return NULL;
7738329f30bSPekka Enberg 
774e08c0896SPrasad Joshi 		if (stat(kernel, &st) < 0 || !S_ISREG(st.st_mode)) {
775e08c0896SPrasad Joshi 			k++;
776e08c0896SPrasad Joshi 			continue;
777e08c0896SPrasad Joshi 		}
778e08c0896SPrasad Joshi 		return kernel;
7798329f30bSPekka Enberg 
780e08c0896SPrasad Joshi 	}
7818329f30bSPekka Enberg 	return NULL;
7828329f30bSPekka Enberg }
7838329f30bSPekka Enberg 
784b0b42ba0SPekka Enberg static const char *find_vmlinux(void)
785b0b42ba0SPekka Enberg {
786b0b42ba0SPekka Enberg 	const char **vmlinux;
787b0b42ba0SPekka Enberg 
788b0b42ba0SPekka Enberg 	vmlinux = &default_vmlinux[0];
789b0b42ba0SPekka Enberg 	while (*vmlinux) {
790b0b42ba0SPekka Enberg 		struct stat st;
791b0b42ba0SPekka Enberg 
792b0b42ba0SPekka Enberg 		if (stat(*vmlinux, &st) < 0 || !S_ISREG(st.st_mode)) {
793b0b42ba0SPekka Enberg 			vmlinux++;
794b0b42ba0SPekka Enberg 			continue;
795b0b42ba0SPekka Enberg 		}
796b0b42ba0SPekka Enberg 		return *vmlinux;
797b0b42ba0SPekka Enberg 	}
798b0b42ba0SPekka Enberg 	return NULL;
799b0b42ba0SPekka Enberg }
800b0b42ba0SPekka Enberg 
801f6677a1dSAmerigo Wang void kvm_run_help(void)
802f6677a1dSAmerigo Wang {
803f6677a1dSAmerigo Wang 	usage_with_options(run_usage, options);
804f6677a1dSAmerigo Wang }
805f6677a1dSAmerigo Wang 
8069cec19c8SSasha Levin static int kvm_custom_stage2(void)
8079cec19c8SSasha Levin {
8089cec19c8SSasha Levin 	char tmp[PATH_MAX], dst[PATH_MAX], *src;
809cb540c93SSasha Levin 	const char *rootfs = custom_rootfs_name;
8109cec19c8SSasha Levin 	int r;
8119cec19c8SSasha Levin 
8129cec19c8SSasha Levin 	src = realpath("guest/init_stage2", NULL);
8139cec19c8SSasha Levin 	if (src == NULL)
8149cec19c8SSasha Levin 		return -ENOMEM;
8159cec19c8SSasha Levin 
8169cec19c8SSasha Levin 	snprintf(tmp, PATH_MAX, "%s%s/virt/init_stage2", kvm__get_dir(), rootfs);
8179cec19c8SSasha Levin 	remove(tmp);
8189cec19c8SSasha Levin 
8199cec19c8SSasha Levin 	snprintf(dst, PATH_MAX, "/host/%s", src);
8209cec19c8SSasha Levin 	r = symlink(dst, tmp);
8219cec19c8SSasha Levin 	free(src);
8229cec19c8SSasha Levin 
8239cec19c8SSasha Levin 	return r;
8249cec19c8SSasha Levin }
8259cec19c8SSasha Levin 
826d50fe489SSasha Levin static int kvm_run_set_sandbox(void)
827d50fe489SSasha Levin {
828cb540c93SSasha Levin 	const char *guestfs_name = custom_rootfs_name;
829d50fe489SSasha Levin 	char path[PATH_MAX], script[PATH_MAX], *tmp;
830d50fe489SSasha Levin 
831d50fe489SSasha Levin 	snprintf(path, PATH_MAX, "%s%s/virt/sandbox.sh", kvm__get_dir(), guestfs_name);
832d50fe489SSasha Levin 
833d50fe489SSasha Levin 	remove(path);
834d50fe489SSasha Levin 
835d50fe489SSasha Levin 	if (sandbox == NULL)
836d50fe489SSasha Levin 		return 0;
837d50fe489SSasha Levin 
838d50fe489SSasha Levin 	tmp = realpath(sandbox, NULL);
839d50fe489SSasha Levin 	if (tmp == NULL)
840d50fe489SSasha Levin 		return -ENOMEM;
841d50fe489SSasha Levin 
842d50fe489SSasha Levin 	snprintf(script, PATH_MAX, "/host/%s", tmp);
843d50fe489SSasha Levin 	free(tmp);
844d50fe489SSasha Levin 
845d50fe489SSasha Levin 	return symlink(script, path);
846d50fe489SSasha Levin }
847d50fe489SSasha Levin 
8485173b4afSLai Jiangshan static void kvm_write_sandbox_cmd_exactly(int fd, const char *arg)
8495173b4afSLai Jiangshan {
8505173b4afSLai Jiangshan 	const char *single_quote;
8515173b4afSLai Jiangshan 
8525173b4afSLai Jiangshan 	if (!*arg) { /* zero length string */
8535173b4afSLai Jiangshan 		if (write(fd, "''", 2) <= 0)
8545173b4afSLai Jiangshan 			die("Failed writing sandbox script");
8555173b4afSLai Jiangshan 		return;
8565173b4afSLai Jiangshan 	}
8575173b4afSLai Jiangshan 
8585173b4afSLai Jiangshan 	while (*arg) {
8595173b4afSLai Jiangshan 		single_quote = strchrnul(arg, '\'');
8605173b4afSLai Jiangshan 
8615173b4afSLai Jiangshan 		/* write non-single-quote string as #('string') */
8625173b4afSLai Jiangshan 		if (arg != single_quote) {
8635173b4afSLai Jiangshan 			if (write(fd, "'", 1) <= 0 ||
8645173b4afSLai Jiangshan 			    write(fd, arg, single_quote - arg) <= 0 ||
8655173b4afSLai Jiangshan 			    write(fd, "'", 1) <= 0)
8665173b4afSLai Jiangshan 				die("Failed writing sandbox script");
8675173b4afSLai Jiangshan 		}
8685173b4afSLai Jiangshan 
8695173b4afSLai Jiangshan 		/* write single quote as #("'") */
8705173b4afSLai Jiangshan 		if (*single_quote) {
8715173b4afSLai Jiangshan 			if (write(fd, "\"'\"", 3) <= 0)
8725173b4afSLai Jiangshan 				die("Failed writing sandbox script");
8735173b4afSLai Jiangshan 		} else
8745173b4afSLai Jiangshan 			break;
8755173b4afSLai Jiangshan 
8765173b4afSLai Jiangshan 		arg = single_quote + 1;
8775173b4afSLai Jiangshan 	}
8785173b4afSLai Jiangshan }
8795173b4afSLai Jiangshan 
8805cd19aa0SPekka Enberg static void resolve_program(const char *src, char *dst, size_t len)
8815cd19aa0SPekka Enberg {
8825cd19aa0SPekka Enberg 	struct stat st;
883c2c742d9SPekka Enberg 	int err;
8845cd19aa0SPekka Enberg 
885c2c742d9SPekka Enberg 	err = stat(src, &st);
8865cd19aa0SPekka Enberg 
887c2c742d9SPekka Enberg 	if (!err && S_ISREG(st.st_mode)) {
8885cd19aa0SPekka Enberg 		char resolved_path[PATH_MAX];
8895cd19aa0SPekka Enberg 
890de3f75c9SPekka Enberg 		if (!realpath(src, resolved_path))
891de3f75c9SPekka Enberg 			die("Unable to resolve program %s: %s\n", src, strerror(errno));
8925cd19aa0SPekka Enberg 
8935cd19aa0SPekka Enberg 		snprintf(dst, len, "/host%s", resolved_path);
8945cd19aa0SPekka Enberg 	} else
8955cd19aa0SPekka Enberg 		strncpy(dst, src, len);
8965cd19aa0SPekka Enberg }
8975cd19aa0SPekka Enberg 
8983c29e2aaSSasha Levin static void kvm_run_write_sandbox_cmd(const char **argv, int argc)
8993c29e2aaSSasha Levin {
9003c29e2aaSSasha Levin 	const char script_hdr[] = "#! /bin/bash\n\n";
9015cd19aa0SPekka Enberg 	char program[PATH_MAX];
9023c29e2aaSSasha Levin 	int fd;
9033c29e2aaSSasha Levin 
9043c29e2aaSSasha Levin 	remove(sandbox);
9053c29e2aaSSasha Levin 
9063c29e2aaSSasha Levin 	fd = open(sandbox, O_RDWR | O_CREAT, 0777);
9073c29e2aaSSasha Levin 	if (fd < 0)
9083c29e2aaSSasha Levin 		die("Failed creating sandbox script");
9093c29e2aaSSasha Levin 
9103c29e2aaSSasha Levin 	if (write(fd, script_hdr, sizeof(script_hdr) - 1) <= 0)
9113c29e2aaSSasha Levin 		die("Failed writing sandbox script");
9123c29e2aaSSasha Levin 
9135cd19aa0SPekka Enberg 	resolve_program(argv[0], program, PATH_MAX);
9145cd19aa0SPekka Enberg 	kvm_write_sandbox_cmd_exactly(fd, program);
9155cd19aa0SPekka Enberg 
9165cd19aa0SPekka Enberg 	argv++;
9175cd19aa0SPekka Enberg 	argc--;
9185cd19aa0SPekka Enberg 
9193c29e2aaSSasha Levin 	while (argc) {
9203c29e2aaSSasha Levin 		if (write(fd, " ", 1) <= 0)
9213c29e2aaSSasha Levin 			die("Failed writing sandbox script");
9225cd19aa0SPekka Enberg 
9235cd19aa0SPekka Enberg 		kvm_write_sandbox_cmd_exactly(fd, argv[0]);
9243c29e2aaSSasha Levin 		argv++;
9253c29e2aaSSasha Levin 		argc--;
9263c29e2aaSSasha Levin 	}
9273c29e2aaSSasha Levin 	if (write(fd, "\n", 1) <= 0)
9283c29e2aaSSasha Levin 		die("Failed writing sandbox script");
9293c29e2aaSSasha Levin 
9303c29e2aaSSasha Levin 	close(fd);
9313c29e2aaSSasha Levin }
9323c29e2aaSSasha Levin 
933e1e46fe6SSasha Levin static int kvm_cmd_run_init(int argc, const char **argv)
934f967c427SPrasad Joshi {
9352d96f6b6SSasha Levin 	static char real_cmdline[2048], default_name[20];
936aba1efa5SPekka Enberg 	struct framebuffer *fb = NULL;
937384922b3SPekka Enberg 	unsigned int nr_online_cpus;
9388259b8ccSSasha Levin 	int max_cpus, recommended_cpus;
9394932d174SSasha Levin 	int i, r;
940f967c427SPrasad Joshi 
9415ee154d1SPekka Enberg 	signal(SIGALRM, handle_sigalrm);
9424b1addaeSSasha Levin 	kvm_ipc__register_handler(KVM_IPC_DEBUG, handle_debug);
94343119af7SPekka Enberg 	signal(SIGUSR1, handle_sigusr1);
9444b1addaeSSasha Levin 	kvm_ipc__register_handler(KVM_IPC_PAUSE, handle_pause);
9454b1addaeSSasha Levin 	kvm_ipc__register_handler(KVM_IPC_RESUME, handle_pause);
9464b1addaeSSasha Levin 	kvm_ipc__register_handler(KVM_IPC_STOP, handle_stop);
9477021c50bSAsias He 	kvm_ipc__register_handler(KVM_IPC_VMSTATE, handle_vmstate);
948f967c427SPrasad Joshi 
949cfd63bbbSSasha Levin 	nr_online_cpus = sysconf(_SC_NPROCESSORS_ONLN);
950cfd63bbbSSasha Levin 
951f967c427SPrasad Joshi 	while (argc != 0) {
952f967c427SPrasad Joshi 		argc = parse_options(argc, argv, options, run_usage,
9531a007c82SSasha Levin 				PARSE_OPT_STOP_AT_NON_OPTION |
9541a007c82SSasha Levin 				PARSE_OPT_KEEP_DASHDASH);
955f967c427SPrasad Joshi 		if (argc != 0) {
9561a007c82SSasha Levin 			/* Cusrom options, should have been handled elsewhere */
9573c29e2aaSSasha Levin 			if (strcmp(argv[0], "--") == 0) {
9583c29e2aaSSasha Levin 				if (kvm_run_wrapper == KVM_RUN_SANDBOX) {
9593c29e2aaSSasha Levin 					sandbox = DEFAULT_SANDBOX_FILENAME;
9603c29e2aaSSasha Levin 					kvm_run_write_sandbox_cmd(argv+1, argc-1);
9611a007c82SSasha Levin 					break;
9623c29e2aaSSasha Levin 				}
9633c29e2aaSSasha Levin 			}
9641a007c82SSasha Levin 
965e0747665SSasha Levin 			if ((kvm_run_wrapper == KVM_RUN_DEFAULT && kernel_filename) ||
966e0747665SSasha Levin 				(kvm_run_wrapper == KVM_RUN_SANDBOX && sandbox)) {
967f967c427SPrasad Joshi 				fprintf(stderr, "Cannot handle parameter: "
968f967c427SPrasad Joshi 						"%s\n", argv[0]);
969f967c427SPrasad Joshi 				usage_with_options(run_usage, options);
970e120b624SPaul Neumann 				return -EINVAL;
971f967c427SPrasad Joshi 			}
972e0747665SSasha Levin 			if (kvm_run_wrapper == KVM_RUN_SANDBOX) {
973e0747665SSasha Levin 				/*
974e0747665SSasha Levin 				 * first unhandled parameter is treated as
975e0747665SSasha Levin 				 * sandbox command
976e0747665SSasha Levin 				 */
977e0747665SSasha Levin 				sandbox = DEFAULT_SANDBOX_FILENAME;
978e0747665SSasha Levin 				kvm_run_write_sandbox_cmd(argv, argc);
979e0747665SSasha Levin 			} else {
980e0747665SSasha Levin 				/*
981e0747665SSasha Levin 				 * first unhandled parameter is treated as a kernel
982e0747665SSasha Levin 				 * image
983f967c427SPrasad Joshi 				 */
984f967c427SPrasad Joshi 				kernel_filename = argv[0];
985e0747665SSasha Levin 			}
986f967c427SPrasad Joshi 			argv++;
987f967c427SPrasad Joshi 			argc--;
988f967c427SPrasad Joshi 		}
989f967c427SPrasad Joshi 
990f967c427SPrasad Joshi 	}
991f967c427SPrasad Joshi 
99245bc2f02SPekka Enberg 	if (!kernel_filename)
993e08c0896SPrasad Joshi 		kernel_filename = find_kernel();
9948329f30bSPekka Enberg 
9958329f30bSPekka Enberg 	if (!kernel_filename) {
996e08c0896SPrasad Joshi 		kernel_usage_with_options();
997e120b624SPaul Neumann 		return -EINVAL;
9988329f30bSPekka Enberg 	}
9998329f30bSPekka Enberg 
1000b0b42ba0SPekka Enberg 	vmlinux_filename = find_vmlinux();
1001b0b42ba0SPekka Enberg 
1002cfd63bbbSSasha Levin 	if (nrcpus == 0)
1003cfd63bbbSSasha Levin 		nrcpus = nr_online_cpus;
1004d77a9efaSCyrill Gorcunov 
1005fd834defSPekka Enberg 	if (!ram_size)
1006fd834defSPekka Enberg 		ram_size	= get_ram_size(nrcpus);
1007fd834defSPekka Enberg 
1008a2a002f9SIngo Molnar 	if (ram_size < MIN_RAM_SIZE_MB)
1009a2a002f9SIngo Molnar 		die("Not enough memory specified: %lluMB (min %lluMB)", ram_size, MIN_RAM_SIZE_MB);
1010a2a002f9SIngo Molnar 
101160ded003SPekka Enberg 	if (ram_size > host_ram_size())
10124542f276SCyrill Gorcunov 		pr_warning("Guest memory size %lluMB exceeds host physical RAM size %lluMB", ram_size, host_ram_size());
101360ded003SPekka Enberg 
1014f967c427SPrasad Joshi 	ram_size <<= MB_SHIFT;
1015f967c427SPrasad Joshi 
10165929637bSAsias He 	if (!dev)
10175929637bSAsias He 		dev = DEFAULT_KVM_DEV;
1018f967c427SPrasad Joshi 
10199aa4a0ebSAsias He 	if (!console)
10209aa4a0ebSAsias He 		console = DEFAULT_CONSOLE;
10219aa4a0ebSAsias He 
10229aa4a0ebSAsias He 	if (!strncmp(console, "virtio", 6))
1023f967c427SPrasad Joshi 		active_console  = CONSOLE_VIRTIO;
10243bbc49b6SMatt Evans 	else if (!strncmp(console, "serial", 6))
10259aa4a0ebSAsias He 		active_console  = CONSOLE_8250;
10263bbc49b6SMatt Evans 	else if (!strncmp(console, "hv", 2))
10273bbc49b6SMatt Evans 		active_console = CONSOLE_HV;
10283bbc49b6SMatt Evans 	else
10293bbc49b6SMatt Evans 		pr_warning("No console!");
1030f967c427SPrasad Joshi 
1031e80ddf6aSAsias He 	if (!host_ip)
1032e80ddf6aSAsias He 		host_ip = DEFAULT_HOST_ADDR;
10334d67c820SSasha Levin 
1034bb8ffd2fSAsias He 	if (!guest_ip)
1035bb8ffd2fSAsias He 		guest_ip = DEFAULT_GUEST_ADDR;
1036bb8ffd2fSAsias He 
1037a4e724ddSSasha Levin 	if (!guest_mac)
1038a4e724ddSSasha Levin 		guest_mac = DEFAULT_GUEST_MAC;
1039a4e724ddSSasha Levin 
1040d7098b9bSAsias He 	if (!host_mac)
1041d7098b9bSAsias He 		host_mac = DEFAULT_HOST_MAC;
1042d7098b9bSAsias He 
104373b7d038SAmos Kong 	if (!script)
104473b7d038SAmos Kong 		script = DEFAULT_SCRIPT;
104573b7d038SAmos Kong 
1046f967c427SPrasad Joshi 	term_init();
1047f967c427SPrasad Joshi 
10482d96f6b6SSasha Levin 	if (!guest_name) {
1049587a4d17SLai Jiangshan 		if (custom_rootfs) {
1050587a4d17SLai Jiangshan 			guest_name = custom_rootfs_name;
1051587a4d17SLai Jiangshan 		} else {
10522d96f6b6SSasha Levin 			sprintf(default_name, "guest-%u", getpid());
10532d96f6b6SSasha Levin 			guest_name = default_name;
10542d96f6b6SSasha Levin 		}
1055587a4d17SLai Jiangshan 	}
10562d96f6b6SSasha Levin 
105761061257SMatt Evans 	kvm = kvm__init(dev, hugetlbfs_path, ram_size, guest_name);
1058d648dbf5SCyrill Gorcunov 	if (IS_ERR(kvm)) {
1059d648dbf5SCyrill Gorcunov 		r = PTR_ERR(kvm);
1060d648dbf5SCyrill Gorcunov 		goto fail;
1061d648dbf5SCyrill Gorcunov 	}
1062f967c427SPrasad Joshi 
10636d6a4d41SPekka Enberg 	kvm->single_step = single_step;
10646d6a4d41SPekka Enberg 
1065ea6eeb1cSSasha Levin 	r = ioeventfd__init(kvm);
1066ea6eeb1cSSasha Levin 	if (r < 0) {
1067ea6eeb1cSSasha Levin 		pr_err("ioeventfd__init() failed with error %d\n", r);
1068ea6eeb1cSSasha Levin 		goto fail;
1069ea6eeb1cSSasha Levin 	}
107037f3d50eSSasha Levin 
1071384922b3SPekka Enberg 	max_cpus = kvm__max_cpus(kvm);
10728259b8ccSSasha Levin 	recommended_cpus = kvm__recommended_cpus(kvm);
1073384922b3SPekka Enberg 
1074384922b3SPekka Enberg 	if (nrcpus > max_cpus) {
1075384922b3SPekka Enberg 		printf("  # Limit the number of CPUs to %d\n", max_cpus);
107690c05188SMatt Evans 		nrcpus = max_cpus;
10778259b8ccSSasha Levin 	} else if (nrcpus > recommended_cpus) {
10788259b8ccSSasha Levin 		printf("  # Warning: The maximum recommended amount of VCPUs"
10798259b8ccSSasha Levin 			" is %d\n", recommended_cpus);
1080384922b3SPekka Enberg 	}
1081384922b3SPekka Enberg 
10820c7c14a7SCyrill Gorcunov 	kvm->nrcpus = nrcpus;
10830c7c14a7SCyrill Gorcunov 
1084e2077857SMatt Evans 	/* Alloc one pointer too many, so array ends up 0-terminated */
1085e2077857SMatt Evans 	kvm_cpus = calloc(nrcpus + 1, sizeof(void *));
1086e2077857SMatt Evans 	if (!kvm_cpus)
1087e2077857SMatt Evans 		die("Couldn't allocate array for %d CPUs", nrcpus);
1088e2077857SMatt Evans 
1089e3c4f8aaSSasha Levin 	r = irq__init(kvm);
1090e3c4f8aaSSasha Levin 	if (r < 0) {
1091e3c4f8aaSSasha Levin 		pr_err("irq__init() failed with error %d\n", r);
1092e3c4f8aaSSasha Levin 		goto fail;
1093e3c4f8aaSSasha Levin 	}
109419e6c8b8SMatt Evans 
10956d987703SSasha Levin 	r = pci__init(kvm);
10966d987703SSasha Levin 	if (r < 0) {
10976d987703SSasha Levin 		pr_err("pci__init() failed with error %d\n", r);
10986d987703SSasha Levin 		goto fail;
10996d987703SSasha Levin 	}
1100b91be965SMatt Evans 
11017af40b91SSasha Levin 	r = ioport__init(kvm);
11027af40b91SSasha Levin 	if (r < 0) {
11037af40b91SSasha Levin 		pr_err("ioport__init() failed with error %d\n", r);
11047af40b91SSasha Levin 		goto fail;
11057af40b91SSasha Levin 	}
11067af40b91SSasha Levin 
1107890364f8SCyrill Gorcunov 	/*
1108890364f8SCyrill Gorcunov 	 * vidmode should be either specified
1109890364f8SCyrill Gorcunov 	 * either set by default
1110890364f8SCyrill Gorcunov 	 */
1111890364f8SCyrill Gorcunov 	if (vnc || sdl) {
1112890364f8SCyrill Gorcunov 		if (vidmode == -1)
1113890364f8SCyrill Gorcunov 			vidmode = 0x312;
111448d9e01aSSasha Levin 	} else {
1115890364f8SCyrill Gorcunov 		vidmode = 0;
111648d9e01aSSasha Levin 	}
1117890364f8SCyrill Gorcunov 
111826c853e4SPrasad Joshi 	memset(real_cmdline, 0, sizeof(real_cmdline));
11198e704a7aSMatt Evans 	kvm__arch_set_cmdline(real_cmdline, vnc || sdl);
11208e704a7aSMatt Evans 
11218e704a7aSMatt Evans 	if (strlen(real_cmdline) > 0)
1122d74181ccSSasha Levin 		strcat(real_cmdline, " ");
11238e704a7aSMatt Evans 
112426c853e4SPrasad Joshi 	if (kernel_cmdline)
112526c853e4SPrasad Joshi 		strlcat(real_cmdline, kernel_cmdline, sizeof(real_cmdline));
112626c853e4SPrasad Joshi 
112797f16d66SAsias He 	if (!using_rootfs && !disk_image[0].filename && !initrd_filename) {
1128c8675741SSasha Levin 		char tmp[PATH_MAX];
11296df1471eSPekka Enberg 
1130cb540c93SSasha Levin 		kvm_setup_create_new(custom_rootfs_name);
1131cb540c93SSasha Levin 		kvm_setup_resolv(custom_rootfs_name);
1132c8675741SSasha Levin 
11339667701cSPekka Enberg 		snprintf(tmp, PATH_MAX, "%s%s", kvm__get_dir(), "default");
1134c8675741SSasha Levin 		if (virtio_9p__register(kvm, tmp, "/dev/root") < 0)
1135c8675741SSasha Levin 			die("Unable to initialize virtio 9p");
1136c8675741SSasha Levin 		if (virtio_9p__register(kvm, "/", "hostfs") < 0)
1137c8675741SSasha Levin 			die("Unable to initialize virtio 9p");
1138c8675741SSasha Levin 		using_rootfs = custom_rootfs = 1;
113926c853e4SPrasad Joshi 	}
114026c853e4SPrasad Joshi 
114182d65b5eSSasha Levin 	if (using_rootfs) {
1142ff42603fSSasha Levin 		strcat(real_cmdline, " root=/dev/root rw rootflags=rw,trans=virtio,version=9p2000.L rootfstype=9p");
1143a8e6b4b9SSasha Levin 		if (custom_rootfs) {
1144d50fe489SSasha Levin 			kvm_run_set_sandbox();
1145d50fe489SSasha Levin 
1146a8e6b4b9SSasha Levin 			strcat(real_cmdline, " init=/virt/init");
1147d50fe489SSasha Levin 
1148a8e6b4b9SSasha Levin 			if (!no_dhcp)
1149a8e6b4b9SSasha Levin 				strcat(real_cmdline, "  ip=dhcp");
11509cec19c8SSasha Levin 			if (kvm_custom_stage2())
11519cec19c8SSasha Levin 				die("Failed linking stage 2 of init.");
1152a8e6b4b9SSasha Levin 		}
115382d65b5eSSasha Levin 	} else if (!strstr(real_cmdline, "root=")) {
1154ff42603fSSasha Levin 		strlcat(real_cmdline, " root=/dev/vda rw ", sizeof(real_cmdline));
115582d65b5eSSasha Levin 	}
115659aa2d30SSasha Levin 
1157c1ed214eSPrasad Joshi 	if (image_count) {
1158bcb6aacaSPrasad Joshi 		kvm->nr_disks = image_count;
115997f16d66SAsias He 		kvm->disks = disk_image__open_all((struct disk_image_params *)&disk_image, image_count);
11609f9207c5SSasha Levin 		if (IS_ERR(kvm->disks)) {
11619f9207c5SSasha Levin 			r = PTR_ERR(kvm->disks);
11629f9207c5SSasha Levin 			pr_err("disk_image__open_all() failed with error %ld\n",
11639f9207c5SSasha Levin 					PTR_ERR(kvm->disks));
11649f9207c5SSasha Levin 			goto fail;
11659f9207c5SSasha Levin 		}
1166f967c427SPrasad Joshi 	}
1167c1ed214eSPrasad Joshi 
1168ee8b1456SWanlong Gao 	printf("  # %s run -k %s -m %Lu -c %d --name %s\n", KVM_BINARY_NAME,
1169ee8b1456SWanlong Gao 		kernel_filename, ram_size / 1024 / 1024, nrcpus, guest_name);
1170471c6facSPekka Enberg 
11715ad8db5eSPekka Enberg 	if (!firmware_filename) {
11725ad8db5eSPekka Enberg 		if (!kvm__load_kernel(kvm, kernel_filename,
11735ad8db5eSPekka Enberg 				initrd_filename, real_cmdline, vidmode))
1174f967c427SPrasad Joshi 			die("unable to load kernel %s", kernel_filename);
1175f967c427SPrasad Joshi 
1176b0b42ba0SPekka Enberg 		kvm->vmlinux = vmlinux_filename;
1177807b77b9SCyrill Gorcunov 		r = symbol_init(kvm);
1178b56f1728SCyrill Gorcunov 		if (r < 0)
1179c4b716ecSPekka Enberg 			pr_debug("symbol_init() failed with error %d\n", r);
11805ad8db5eSPekka Enberg 	}
1181b0b42ba0SPekka Enberg 
1182af7b0868SMatt Evans 	ioport__setup_arch();
1183ac38f433SPekka Enberg 
118420c39545SSasha Levin 	r = rtc__init(kvm);
118520c39545SSasha Levin 	if (r < 0) {
118620c39545SSasha Levin 		pr_err("rtc__init() failed with error %d\n", r);
118720c39545SSasha Levin 		goto fail;
118820c39545SSasha Levin 	}
118964136c1cSPekka Enberg 
119020715a22SSasha Levin 	r = serial8250__init(kvm);
119120715a22SSasha Levin 	if (r < 0) {
119220715a22SSasha Levin 		pr_err("serial__init() failed with error %d\n", r);
119320715a22SSasha Levin 		goto fail;
119420715a22SSasha Levin 	}
1195f967c427SPrasad Joshi 
11969f9207c5SSasha Levin 	r = virtio_blk__init(kvm);
11979f9207c5SSasha Levin 	if (r < 0) {
11989f9207c5SSasha Levin 		pr_err("virtio_blk__init() failed with error %d\n", r);
11999f9207c5SSasha Levin 		goto fail;
12009f9207c5SSasha Levin 	}
12019f9207c5SSasha Levin 
1202*a67da3beSAsias He 	r = virtio_scsi_init(kvm);
1203*a67da3beSAsias He 	if (r < 0) {
1204*a67da3beSAsias He 		pr_err("virtio_scsi_init() failed with error %d\n", r);
1205*a67da3beSAsias He 		goto fail;
1206*a67da3beSAsias He 	}
1207*a67da3beSAsias He 
1208*a67da3beSAsias He 
12091621292eSSasha Levin 	if (active_console == CONSOLE_VIRTIO)
1210f967c427SPrasad Joshi 		virtio_console__init(kvm);
1211f967c427SPrasad Joshi 
121253eca082SSasha Levin 	if (virtio_rng)
121353eca082SSasha Levin 		virtio_rng__init(kvm);
121453eca082SSasha Levin 
121582d2f21eSSasha Levin 	if (balloon)
121682d2f21eSSasha Levin 		virtio_bln__init(kvm);
121782d2f21eSSasha Levin 
12184f56d42cSAsias He 	if (!network)
12194f56d42cSAsias He 		network = DEFAULT_NETWORK;
12204f56d42cSAsias He 
1221c7838fbdSSasha Levin 	virtio_9p__init(kvm);
1222c7838fbdSSasha Levin 
12239a6d73f1SSasha Levin 	for (i = 0; i < num_net_devices; i++) {
12249a6d73f1SSasha Levin 		net_params[i].kvm = kvm;
12259a6d73f1SSasha Levin 		virtio_net__init(&net_params[i]);
12269a6d73f1SSasha Levin 	}
1227a4e724ddSSasha Levin 
12289a6d73f1SSasha Levin 	if (num_net_devices == 0 && no_net == 0) {
12299a6d73f1SSasha Levin 		struct virtio_net_params net_params;
12309a6d73f1SSasha Levin 
12319a6d73f1SSasha Levin 		net_params = (struct virtio_net_params) {
12329a6d73f1SSasha Levin 			.guest_ip	= guest_ip,
12339a6d73f1SSasha Levin 			.host_ip	= host_ip,
12349a6d73f1SSasha Levin 			.kvm		= kvm,
12359a6d73f1SSasha Levin 			.script		= script,
12369a6d73f1SSasha Levin 			.mode		= NET_MODE_USER,
12379a6d73f1SSasha Levin 		};
12389a6d73f1SSasha Levin 		str_to_mac(guest_mac, net_params.guest_mac);
12399a6d73f1SSasha Levin 		str_to_mac(host_mac, net_params.host_mac);
12409a6d73f1SSasha Levin 
1241bdfcfca6SSasha Levin 		virtio_net__init(&net_params);
1242bdfcfca6SSasha Levin 	}
12434f56d42cSAsias He 
1244839051d9SSasha Levin 	kvm__init_ram(kvm);
1245839051d9SSasha Levin 
124657d7832bSMatt Evans #ifdef CONFIG_X86
1247714e5b7fSSasha Levin 	kbd__init(kvm);
124857d7832bSMatt Evans #endif
1249714e5b7fSSasha Levin 
125095d13a52SSasha Levin 	pci_shmem__init(kvm);
125195d13a52SSasha Levin 
125248d9e01aSSasha Levin 	if (vnc || sdl) {
12533f838fecSPekka Enberg 		fb = vesa__init(kvm);
125448d9e01aSSasha Levin 		if (IS_ERR(fb)) {
125548d9e01aSSasha Levin 			pr_err("vesa__init() failed with error %ld\n", PTR_ERR(fb));
125648d9e01aSSasha Levin 			goto fail;
125748d9e01aSSasha Levin 		}
12583f838fecSPekka Enberg 	}
12593f838fecSPekka Enberg 
126048d9e01aSSasha Levin 	if (vnc && fb) {
126148d9e01aSSasha Levin 		r = vnc__init(fb);
126248d9e01aSSasha Levin 		if (r < 0) {
126348d9e01aSSasha Levin 			pr_err("vnc__init() failed with error %d\n", r);
126448d9e01aSSasha Levin 			goto fail;
126548d9e01aSSasha Levin 		}
126648d9e01aSSasha Levin 	}
126748d9e01aSSasha Levin 
126848d9e01aSSasha Levin 	if (sdl && fb) {
12693f838fecSPekka Enberg 		sdl__init(fb);
127048d9e01aSSasha Levin 		if (r < 0) {
127148d9e01aSSasha Levin 			pr_err("sdl__init() failed with error %d\n", r);
127248d9e01aSSasha Levin 			goto fail;
127348d9e01aSSasha Levin 		}
12743f838fecSPekka Enberg 	}
1275aba1efa5SPekka Enberg 
127648d9e01aSSasha Levin 	r = fb__start();
127748d9e01aSSasha Levin 	if (r < 0) {
127848d9e01aSSasha Levin 		pr_err("fb__init() failed with error %d\n", r);
127948d9e01aSSasha Levin 		goto fail;
128048d9e01aSSasha Levin 	}
1281aba1efa5SPekka Enberg 
128225af47eeSMatt Evans 	/* Device init all done; firmware init must
128325af47eeSMatt Evans 	 * come after this (it may set up device trees etc.)
128425af47eeSMatt Evans 	 */
128525af47eeSMatt Evans 
128625af47eeSMatt Evans 	kvm__start_timer(kvm);
128725af47eeSMatt Evans 
12885ad8db5eSPekka Enberg 	if (firmware_filename) {
12895ad8db5eSPekka Enberg 		if (!kvm__load_firmware(kvm, firmware_filename))
12905ad8db5eSPekka Enberg 			die("unable to load firmware image %s: %s", firmware_filename, strerror(errno));
12915ad8db5eSPekka Enberg 	} else {
1292e1e46fe6SSasha Levin 		kvm__arch_setup_firmware(kvm);
12931add9f73SSasha Levin 		if (r < 0) {
12941add9f73SSasha Levin 			pr_err("kvm__arch_setup_firmware() failed with error %d\n", r);
12951add9f73SSasha Levin 			goto fail;
12961add9f73SSasha Levin 		}
12975ad8db5eSPekka Enberg 	}
129825af47eeSMatt Evans 
129925af47eeSMatt Evans 	for (i = 0; i < nrcpus; i++) {
130025af47eeSMatt Evans 		kvm_cpus[i] = kvm_cpu__init(kvm, i);
130125af47eeSMatt Evans 		if (!kvm_cpus[i])
130225af47eeSMatt Evans 			die("unable to initialize KVM VCPU");
130325af47eeSMatt Evans 	}
130425af47eeSMatt Evans 
1305d60bafe5SSasha Levin 	thread_pool__init(nr_online_cpus);
13064932d174SSasha Levin fail:
13074932d174SSasha Levin 	return r;
1308e1e46fe6SSasha Levin }
1309e1e46fe6SSasha Levin 
1310e1e46fe6SSasha Levin static int kvm_cmd_run_work(void)
1311e1e46fe6SSasha Levin {
1312e1e46fe6SSasha Levin 	int i, r = -1;
1313e1e46fe6SSasha Levin 	void *ret = NULL;
1314e1e46fe6SSasha Levin 
1315839051d9SSasha Levin 	for (i = 0; i < nrcpus; i++) {
1316d77a9efaSCyrill Gorcunov 		if (pthread_create(&kvm_cpus[i]->thread, NULL, kvm_cpu_thread, kvm_cpus[i]) != 0)
13175ee154d1SPekka Enberg 			die("unable to create KVM VCPU thread");
13185ee154d1SPekka Enberg 	}
13195ee154d1SPekka Enberg 
132049e5227dSSasha Levin 	/* Only VCPU #0 is going to exit by itself when shutting down */
132149e5227dSSasha Levin 	if (pthread_join(kvm_cpus[0]->thread, &ret) != 0)
1322e1e46fe6SSasha Levin 		r = 0;
13235ee154d1SPekka Enberg 
132489e0575aSPekka Enberg 	kvm_cpu__delete(kvm_cpus[0]);
132520715a22SSasha Levin 	kvm_cpus[0] = NULL;
132689e0575aSPekka Enberg 
132749e5227dSSasha Levin 	for (i = 1; i < nrcpus; i++) {
1328c23d9748SSasha Levin 		if (kvm_cpus[i]->is_running) {
132949e5227dSSasha Levin 			pthread_kill(kvm_cpus[i]->thread, SIGKVMEXIT);
1330d77a9efaSCyrill Gorcunov 			if (pthread_join(kvm_cpus[i]->thread, &ret) != 0)
13315ee154d1SPekka Enberg 				die("pthread_join");
133289e0575aSPekka Enberg 			kvm_cpu__delete(kvm_cpus[i]);
1333c23d9748SSasha Levin 		}
1334e1e46fe6SSasha Levin 		if (ret == NULL)
1335e1e46fe6SSasha Levin 			r = 0;
13365ee154d1SPekka Enberg 	}
1337f967c427SPrasad Joshi 
1338e1e46fe6SSasha Levin 	return r;
1339e1e46fe6SSasha Levin }
1340e1e46fe6SSasha Levin 
13414932d174SSasha Levin static void kvm_cmd_run_exit(int guest_ret)
1342e1e46fe6SSasha Levin {
13434932d174SSasha Levin 	int r = 0;
13444932d174SSasha Levin 
1345e6694207SSasha Levin 	compat__print_all_messages();
1346e6694207SSasha Levin 
1347807b77b9SCyrill Gorcunov 	r = symbol_exit(kvm);
13484932d174SSasha Levin 	if (r < 0)
1349807b77b9SCyrill Gorcunov 		pr_warning("symbol_exit() failed with error %d\n", r);
13504932d174SSasha Levin 
1351e3c4f8aaSSasha Levin 	r = irq__exit(kvm);
1352e3c4f8aaSSasha Levin 	if (r < 0)
1353e3c4f8aaSSasha Levin 		pr_warning("irq__exit() failed with error %d\n", r);
1354e3c4f8aaSSasha Levin 
1355aba1efa5SPekka Enberg 	fb__stop();
1356aba1efa5SPekka Enberg 
1357*a67da3beSAsias He 	r = virtio_scsi_exit(kvm);
1358*a67da3beSAsias He 	if (r < 0)
1359*a67da3beSAsias He 		pr_warning("virtio_scsi_exit() failed with error %d\n", r);
1360*a67da3beSAsias He 
13619f9207c5SSasha Levin 	r = virtio_blk__exit(kvm);
13629f9207c5SSasha Levin 	if (r < 0)
13639f9207c5SSasha Levin 		pr_warning("virtio_blk__exit() failed with error %d\n", r);
13649f9207c5SSasha Levin 
1365495fbd4eSSasha Levin 	r = virtio_rng__exit(kvm);
1366495fbd4eSSasha Levin 	if (r < 0)
1367495fbd4eSSasha Levin 		pr_warning("virtio_rng__exit() failed with error %d\n", r);
1368a0a1e3c2SPrasad Joshi 
13699f9207c5SSasha Levin 	r = disk_image__close_all(kvm->disks, image_count);
13709f9207c5SSasha Levin 	if (r < 0)
13719f9207c5SSasha Levin 		pr_warning("disk_image__close_all() failed with error %d\n", r);
13727af40b91SSasha Levin 
137320715a22SSasha Levin 	r = serial8250__exit(kvm);
137420715a22SSasha Levin 	if (r < 0)
137520715a22SSasha Levin 		pr_warning("serial8250__exit() failed with error %d\n", r);
137620715a22SSasha Levin 
137720c39545SSasha Levin 	r = rtc__exit(kvm);
137820c39545SSasha Levin 	if (r < 0)
137920c39545SSasha Levin 		pr_warning("rtc__exit() failed with error %d\n", r);
138020c39545SSasha Levin 
13811add9f73SSasha Levin 	r = kvm__arch_free_firmware(kvm);
13821add9f73SSasha Levin 	if (r < 0)
13831add9f73SSasha Levin 		pr_warning("kvm__arch_free_firmware() failed with error %d\n", r);
13841add9f73SSasha Levin 
13857af40b91SSasha Levin 	r = ioport__exit(kvm);
13867af40b91SSasha Levin 	if (r < 0)
13877af40b91SSasha Levin 		pr_warning("ioport__exit() failed with error %d\n", r);
13887af40b91SSasha Levin 
1389ea6eeb1cSSasha Levin 	r = ioeventfd__exit(kvm);
1390ea6eeb1cSSasha Levin 	if (r < 0)
1391ea6eeb1cSSasha Levin 		pr_warning("ioeventfd__exit() failed with error %d\n", r);
1392ea6eeb1cSSasha Levin 
13936d987703SSasha Levin 	r = pci__exit(kvm);
13946d987703SSasha Levin 	if (r < 0)
13956d987703SSasha Levin 		pr_warning("pci__exit() failed with error %d\n", r);
13966d987703SSasha Levin 
1397495fbd4eSSasha Levin 	r = kvm__exit(kvm);
1398495fbd4eSSasha Levin 	if (r < 0)
1399495fbd4eSSasha Levin 		pr_warning("pci__exit() failed with error %d\n", r);
1400f967c427SPrasad Joshi 
140149777800SPekka Enberg 	free(kvm_cpus);
140249777800SPekka Enberg 
1403e1e46fe6SSasha Levin 	if (guest_ret == 0)
1404f967c427SPrasad Joshi 		printf("\n  # KVM session ended normally.\n");
1405e1e46fe6SSasha Levin }
1406e1e46fe6SSasha Levin 
1407e1e46fe6SSasha Levin int kvm_cmd_run(int argc, const char **argv, const char *prefix)
1408e1e46fe6SSasha Levin {
14094932d174SSasha Levin 	int r, ret = -EFAULT;
1410e1e46fe6SSasha Levin 
1411e1e46fe6SSasha Levin 	r = kvm_cmd_run_init(argc, argv);
1412e1e46fe6SSasha Levin 	if (r < 0)
1413e1e46fe6SSasha Levin 		return r;
1414e1e46fe6SSasha Levin 
1415e1e46fe6SSasha Levin 	ret = kvm_cmd_run_work();
1416e1e46fe6SSasha Levin 	kvm_cmd_run_exit(ret);
1417e1e46fe6SSasha Levin 
1418e1e46fe6SSasha Levin 	return ret;
1419f967c427SPrasad Joshi }
1420