builtin-run.c 17.3 KB
Newer Older
1
2
#include "kvm/builtin-run.h"

3
#include "kvm/builtin-setup.h"
4
5
6
7
8
9
10
#include "kvm/virtio-balloon.h"
#include "kvm/virtio-console.h"
#include "kvm/parse-options.h"
#include "kvm/8250-serial.h"
#include "kvm/framebuffer.h"
#include "kvm/disk-image.h"
#include "kvm/threadpool.h"
11
#include "kvm/virtio-scsi.h"
12
13
14
15
16
17
18
19
20
21
22
23
24
#include "kvm/virtio-blk.h"
#include "kvm/virtio-net.h"
#include "kvm/virtio-rng.h"
#include "kvm/ioeventfd.h"
#include "kvm/virtio-9p.h"
#include "kvm/barrier.h"
#include "kvm/kvm-cpu.h"
#include "kvm/ioport.h"
#include "kvm/symbol.h"
#include "kvm/i8042.h"
#include "kvm/mutex.h"
#include "kvm/term.h"
#include "kvm/util.h"
25
#include "kvm/strbuf.h"
26
27
28
29
30
31
32
#include "kvm/vesa.h"
#include "kvm/irq.h"
#include "kvm/kvm.h"
#include "kvm/pci.h"
#include "kvm/rtc.h"
#include "kvm/sdl.h"
#include "kvm/vnc.h"
33
#include "kvm/guest_compat.h"
Sasha Levin's avatar
Sasha Levin committed
34
#include "kvm/pci-shmem.h"
35
#include "kvm/kvm-ipc.h"
36
#include "kvm/builtin-debug.h"
37
38

#include <linux/types.h>
Sasha Levin's avatar
Sasha Levin committed
39
#include <linux/err.h>
40

41
42
43
#include <sys/utsname.h>
#include <sys/types.h>
#include <sys/stat.h>
44
45
46
47
48
#include <termios.h>
#include <signal.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
49
#include <ctype.h>
50
#include <stdio.h>
51
52

#define MB_SHIFT		(20)
Sasha Levin's avatar
Sasha Levin committed
53
54
#define KB_SHIFT		(10)
#define GB_SHIFT		(30)
55

56
__thread struct kvm_cpu *current_kvm_cpu;
57

Sasha Levin's avatar
Sasha Levin committed
58
static int  kvm_run_wrapper;
59

60
61
bool do_debug_print = false;

62
static const char * const run_usage[] = {
63
	"lkvm run [<options>] [<kernel image>]",
64
65
66
	NULL
};

Sasha Levin's avatar
Sasha Levin committed
67
enum {
68
	KVM_RUN_DEFAULT,
Sasha Levin's avatar
Sasha Levin committed
69
70
71
	KVM_RUN_SANDBOX,
};

72
73
static int img_name_parser(const struct option *opt, const char *arg, int unset)
{
74
	char path[PATH_MAX];
Asias He's avatar
Asias He committed
75
	struct stat st;
76

77
	snprintf(path, PATH_MAX, "%s%s", kvm__get_dir(), arg);
78

Sasha Levin's avatar
Sasha Levin committed
79
80
81
	if ((stat(arg, &st) == 0 && S_ISDIR(st.st_mode)) ||
	   (stat(path, &st) == 0 && S_ISDIR(st.st_mode)))
		return virtio_9p_img_name_parser(opt, arg, unset);
82
83
	return disk_img_name_parser(opt, arg, unset);
}
84

85
86
87
void kvm_run_set_wrapper_sandbox(void)
{
	kvm_run_wrapper = KVM_RUN_SANDBOX;
88
89
}

90
91
92
93
#ifndef OPT_ARCH_RUN
#define OPT_ARCH_RUN(...)
#endif

94
#define BUILD_OPTIONS(name, cfg, kvm)					\
95
96
97
98
	struct option name[] = {					\
	OPT_GROUP("Basic options:"),					\
	OPT_STRING('\0', "name", &(cfg)->guest_name, "guest name",	\
			"A name for the guest"),			\
99
	OPT_INTEGER('c', "cpus", &(cfg)->nrcpus, "Number of CPUs"),	\
100
101
	OPT_U64('m', "mem", &(cfg)->ram_size, "Virtual machine memory"	\
		" size in MiB."),					\
102
103
104
	OPT_CALLBACK('\0', "shmem", NULL,				\
		     "[pci:]<addr>:<size>[:handle=<handle>][:create]",	\
		     "Share host shmem with guest via pci device",	\
105
		     shmem_parser, NULL),				\
106
107
	OPT_CALLBACK('d', "disk", kvm, "image or rootfs_dir", "Disk "	\
			" image or rootfs directory", img_name_parser,	\
108
			kvm),						\
109
110
	OPT_BOOLEAN('\0', "balloon", &(cfg)->balloon, "Enable virtio"	\
			" balloon"),					\
111
	OPT_BOOLEAN('\0', "vnc", &(cfg)->vnc, "Enable VNC framebuffer"),\
Pekka Enberg's avatar
Pekka Enberg committed
112
	OPT_BOOLEAN('\0', "gtk", &(cfg)->gtk, "Enable GTK framebuffer"),\
113
	OPT_BOOLEAN('\0', "sdl", &(cfg)->sdl, "Enable SDL framebuffer"),\
114
115
	OPT_BOOLEAN('\0', "rng", &(cfg)->virtio_rng, "Enable virtio"	\
			" Random Number Generator"),			\
116
	OPT_CALLBACK('\0', "9p", NULL, "dir_to_share,tag_name",		\
117
118
119
120
		     "Enable virtio 9p to share files between host and"	\
		     " guest", virtio_9p_rootdir_parser, kvm),		\
	OPT_STRING('\0', "console", &(cfg)->console, "serial, virtio or"\
			" hv", "Console to use"),			\
121
122
123
124
	OPT_STRING('\0', "dev", &(cfg)->dev, "device_file",		\
			"KVM device file"),				\
	OPT_CALLBACK('\0', "tty", NULL, "tty id",			\
		     "Remap guest TTY into a pty on the host",		\
125
		     tty_parser, NULL),					\
126
	OPT_STRING('\0', "sandbox", &(cfg)->sandbox, "script",		\
127
128
			"Run this script when booting into custom"	\
			" rootfs"),					\
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
	OPT_STRING('\0', "hugetlbfs", &(cfg)->hugetlbfs_path, "path",	\
			"Hugetlbfs path"),				\
									\
	OPT_GROUP("Kernel options:"),					\
	OPT_STRING('k', "kernel", &(cfg)->kernel_filename, "kernel",	\
			"Kernel to boot in virtual machine"),		\
	OPT_STRING('i', "initrd", &(cfg)->initrd_filename, "initrd",	\
			"Initial RAM disk image"),			\
	OPT_STRING('p', "params", &(cfg)->kernel_cmdline, "params",	\
			"Kernel command line arguments"),		\
	OPT_STRING('f', "firmware", &(cfg)->firmware_filename, "firmware",\
			"Firmware image to boot in virtual machine"),	\
									\
	OPT_GROUP("Networking options:"),				\
	OPT_CALLBACK_DEFAULT('n', "network", NULL, "network params",	\
		     "Create a new guest NIC",				\
Sasha Levin's avatar
Sasha Levin committed
145
		     netdev_parser, NULL, kvm),				\
146
147
	OPT_BOOLEAN('\0', "no-dhcp", &(cfg)->no_dhcp, "Disable kernel"	\
			" DHCP in rootfs mode"),			\
148
									\
149
150
151
152
153
	OPT_GROUP("VFIO options:"),					\
	OPT_CALLBACK('\0', "vfio-pci", NULL, "[domain:]bus:dev.fn",	\
		     "Assign a PCI device to the virtual machine",	\
		     vfio_device_parser, kvm),				\
									\
154
155
156
157
158
	OPT_GROUP("Debug options:"),					\
	OPT_BOOLEAN('\0', "debug", &do_debug_print,			\
			"Enable debug messages"),			\
	OPT_BOOLEAN('\0', "debug-single-step", &(cfg)->single_step,	\
			"Enable single stepping"),			\
159
	OPT_BOOLEAN('\0', "debug-ioport", &(cfg)->ioport_debug,		\
160
			"Enable ioport debugging"),			\
161
	OPT_BOOLEAN('\0', "debug-mmio", &(cfg)->mmio_debug,		\
162
			"Enable MMIO debugging"),			\
163
	OPT_INTEGER('\0', "debug-iodelay", &(cfg)->debug_iodelay,	\
164
			"Delay IO by millisecond"),			\
165
166
									\
	OPT_ARCH(RUN, cfg)						\
167
168
	OPT_END()							\
	};
169

170
171
static void *kvm_cpu_thread(void *arg)
{
172
173
174
175
176
177
	char name[16];

	current_kvm_cpu = arg;

	sprintf(name, "kvm-vcpu-%lu", current_kvm_cpu->cpu_id);
	kvm__set_thread_name(name);
178

179
	if (kvm_cpu__start(current_kvm_cpu))
180
181
182
183
184
		goto panic_kvm;

	return (void *) (intptr_t) 0;

panic_kvm:
185
	fprintf(stderr, "KVM exit reason: %u (\"%s\")\n",
186
187
188
		current_kvm_cpu->kvm_run->exit_reason,
		kvm_exit_reasons[current_kvm_cpu->kvm_run->exit_reason]);
	if (current_kvm_cpu->kvm_run->exit_reason == KVM_EXIT_UNKNOWN)
189
190
		fprintf(stderr, "KVM exit code: 0x%llu\n",
			(unsigned long long)current_kvm_cpu->kvm_run->hw.hardware_exit_reason);
191

192
	kvm_cpu__set_debug_fd(STDOUT_FILENO);
193
194
195
	kvm_cpu__show_registers(current_kvm_cpu);
	kvm_cpu__show_code(current_kvm_cpu);
	kvm_cpu__show_page_tables(current_kvm_cpu);
196
197
198
199

	return (void *) (intptr_t) 1;
}

200
static char kernel[PATH_MAX];
201
202

static const char *host_kernels[] = {
203
204
205
206
	"/boot/vmlinuz",
	"/boot/bzImage",
	NULL
};
207
208

static const char *default_kernels[] = {
209
	"./bzImage",
210
	"arch/" BUILD_ARCH "/boot/bzImage",
211
	"../../arch/" BUILD_ARCH "/boot/bzImage",
212
213
	NULL
};
214

215
static const char *default_vmlinux[] = {
216
	"vmlinux",
217
218
219
220
221
	"../../../vmlinux",
	"../../vmlinux",
	NULL
};

222
static void kernel_usage_with_options(void)
223
{
224
	const char **k;
225
	struct utsname uts;
226
227

	fprintf(stderr, "Fatal: could not find default kernel image in:\n");
228
	k = &default_kernels[0];
229
230
231
232
	while (*k) {
		fprintf(stderr, "\t%s\n", *k);
		k++;
	}
233
234

	if (uname(&uts) < 0)
235
236
237
238
239
240
241
242
243
		return;

	k = &host_kernels[0];
	while (*k) {
		if (snprintf(kernel, PATH_MAX, "%s-%s", *k, uts.release) < 0)
			return;
		fprintf(stderr, "\t%s\n", kernel);
		k++;
	}
244
245
	fprintf(stderr, "\nPlease see '%s run --help' for more options.\n\n",
		KVM_BINARY_NAME);
246
}
247

248
249
250
251
252
253
static u64 host_ram_size(void)
{
	long page_size;
	long nr_pages;

	nr_pages	= sysconf(_SC_PHYS_PAGES);
254
	if (nr_pages < 0) {
255
		pr_warning("sysconf(_SC_PHYS_PAGES) failed");
256
257
		return 0;
	}
258
259

	page_size	= sysconf(_SC_PAGE_SIZE);
260
	if (page_size < 0) {
261
		pr_warning("sysconf(_SC_PAGE_SIZE) failed");
262
263
		return 0;
	}
264
265
266
267

	return (nr_pages * page_size) >> MB_SHIFT;
}

268
269
270
271
272
273
/*
 * If user didn't specify how much memory it wants to allocate for the guest,
 * avoid filling the whole host RAM.
 */
#define RAM_SIZE_RATIO		0.8

274
275
static u64 get_ram_size(int nr_cpus)
{
276
277
	u64 available;
	u64 ram_size;
278
279
280

	ram_size	= 64 * (nr_cpus + 3);

281
	available	= host_ram_size() * RAM_SIZE_RATIO;
282
283
	if (!available)
		available = MIN_RAM_SIZE_MB;
284
285
286
287
288
289
290

	if (ram_size > available)
		ram_size	= available;

	return ram_size;
}

291
292
293
294
295
static const char *find_kernel(void)
{
	const char **k;
	struct stat st;
	struct utsname uts;
296

297
	k = &default_kernels[0];
298
299
300
301
302
303
304
305
	while (*k) {
		if (stat(*k, &st) < 0 || !S_ISREG(st.st_mode)) {
			k++;
			continue;
		}
		strncpy(kernel, *k, PATH_MAX);
		return kernel;
	}
306

307
	if (uname(&uts) < 0)
308
309
		return NULL;

310
311
312
313
314
315
316
317
318
319
320
321
322
	k = &host_kernels[0];
	while (*k) {
		if (snprintf(kernel, PATH_MAX, "%s-%s", *k, uts.release) < 0)
			return NULL;

		if (stat(kernel, &st) < 0 || !S_ISREG(st.st_mode)) {
			k++;
			continue;
		}
		return kernel;

	}
	return NULL;
323
324
}

325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
static const char *find_vmlinux(void)
{
	const char **vmlinux;

	vmlinux = &default_vmlinux[0];
	while (*vmlinux) {
		struct stat st;

		if (stat(*vmlinux, &st) < 0 || !S_ISREG(st.st_mode)) {
			vmlinux++;
			continue;
		}
		return *vmlinux;
	}
	return NULL;
}

342
343
void kvm_run_help(void)
{
344
345
	struct kvm *kvm = NULL;

346
	BUILD_OPTIONS(options, &kvm->cfg, kvm);
347
348
349
	usage_with_options(run_usage, options);
}

350
static int kvm_run_set_sandbox(struct kvm *kvm)
351
{
352
	const char *guestfs_name = kvm->cfg.custom_rootfs_name;
353
354
355
356
357
358
	char path[PATH_MAX], script[PATH_MAX], *tmp;

	snprintf(path, PATH_MAX, "%s%s/virt/sandbox.sh", kvm__get_dir(), guestfs_name);

	remove(path);

359
	if (kvm->cfg.sandbox == NULL)
360
361
		return 0;

362
	tmp = realpath(kvm->cfg.sandbox, NULL);
363
364
365
366
367
368
369
370
371
	if (tmp == NULL)
		return -ENOMEM;

	snprintf(script, PATH_MAX, "/host/%s", tmp);
	free(tmp);

	return symlink(script, path);
}

372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
static void kvm_write_sandbox_cmd_exactly(int fd, const char *arg)
{
	const char *single_quote;

	if (!*arg) { /* zero length string */
		if (write(fd, "''", 2) <= 0)
			die("Failed writing sandbox script");
		return;
	}

	while (*arg) {
		single_quote = strchrnul(arg, '\'');

		/* write non-single-quote string as #('string') */
		if (arg != single_quote) {
			if (write(fd, "'", 1) <= 0 ||
			    write(fd, arg, single_quote - arg) <= 0 ||
			    write(fd, "'", 1) <= 0)
				die("Failed writing sandbox script");
		}

		/* write single quote as #("'") */
		if (*single_quote) {
			if (write(fd, "\"'\"", 3) <= 0)
				die("Failed writing sandbox script");
		} else
			break;

		arg = single_quote + 1;
	}
}

404
405
406
static void resolve_program(const char *src, char *dst, size_t len)
{
	struct stat st;
407
	int err;
408

409
	err = stat(src, &st);
410

411
	if (!err && S_ISREG(st.st_mode)) {
412
413
		char resolved_path[PATH_MAX];

414
415
		if (!realpath(src, resolved_path))
			die("Unable to resolve program %s: %s\n", src, strerror(errno));
416

417
418
419
		if (snprintf(dst, len, "/host%s", resolved_path) >= (int)len)
			die("Pathname too long: %s -> %s\n", src, resolved_path);

420
421
422
423
	} else
		strncpy(dst, src, len);
}

424
static void kvm_run_write_sandbox_cmd(struct kvm *kvm, const char **argv, int argc)
Sasha Levin's avatar
Sasha Levin committed
425
426
{
	const char script_hdr[] = "#! /bin/bash\n\n";
427
	char program[PATH_MAX];
Sasha Levin's avatar
Sasha Levin committed
428
429
	int fd;

430
	remove(kvm->cfg.sandbox);
Sasha Levin's avatar
Sasha Levin committed
431

432
	fd = open(kvm->cfg.sandbox, O_RDWR | O_CREAT, 0777);
Sasha Levin's avatar
Sasha Levin committed
433
434
435
436
437
438
	if (fd < 0)
		die("Failed creating sandbox script");

	if (write(fd, script_hdr, sizeof(script_hdr) - 1) <= 0)
		die("Failed writing sandbox script");

439
440
441
442
443
444
	resolve_program(argv[0], program, PATH_MAX);
	kvm_write_sandbox_cmd_exactly(fd, program);

	argv++;
	argc--;

Sasha Levin's avatar
Sasha Levin committed
445
	while (argc) {
446
447
448
		if (write(fd, " ", 1) <= 0)
			die("Failed writing sandbox script");

449
		kvm_write_sandbox_cmd_exactly(fd, argv[0]);
Sasha Levin's avatar
Sasha Levin committed
450
451
452
453
454
455
456
457
458
		argv++;
		argc--;
	}
	if (write(fd, "\n", 1) <= 0)
		die("Failed writing sandbox script");

	close(fd);
}

459
static struct kvm *kvm_cmd_run_init(int argc, const char **argv)
460
{
461
	static char real_cmdline[2048], default_name[20];
462
	unsigned int nr_online_cpus;
463
	struct kvm *kvm = kvm__new();
464
	bool video;
465
466

	if (IS_ERR(kvm))
467
		return kvm;
468

469
	nr_online_cpus = sysconf(_SC_NPROCESSORS_ONLN);
470
	kvm->cfg.custom_rootfs_name = "default";
471

472
	while (argc != 0) {
473
		BUILD_OPTIONS(options, &kvm->cfg, kvm);
474
		argc = parse_options(argc, argv, options, run_usage,
475
476
				PARSE_OPT_STOP_AT_NON_OPTION |
				PARSE_OPT_KEEP_DASHDASH);
477
		if (argc != 0) {
478
			/* Cusrom options, should have been handled elsewhere */
Sasha Levin's avatar
Sasha Levin committed
479
480
			if (strcmp(argv[0], "--") == 0) {
				if (kvm_run_wrapper == KVM_RUN_SANDBOX) {
481
					kvm->cfg.sandbox = DEFAULT_SANDBOX_FILENAME;
482
					kvm_run_write_sandbox_cmd(kvm, argv+1, argc-1);
Sasha Levin's avatar
Sasha Levin committed
483
484
485
					break;
				}
			}
486

487
488
			if ((kvm_run_wrapper == KVM_RUN_DEFAULT && kvm->cfg.kernel_filename) ||
				(kvm_run_wrapper == KVM_RUN_SANDBOX && kvm->cfg.sandbox)) {
489
490
491
				fprintf(stderr, "Cannot handle parameter: "
						"%s\n", argv[0]);
				usage_with_options(run_usage, options);
492
				free(kvm);
493
				return ERR_PTR(-EINVAL);
494
			}
495
496
497
498
499
			if (kvm_run_wrapper == KVM_RUN_SANDBOX) {
				/*
				 * first unhandled parameter is treated as
				 * sandbox command
				 */
500
				kvm->cfg.sandbox = DEFAULT_SANDBOX_FILENAME;
501
				kvm_run_write_sandbox_cmd(kvm, argv, argc);
502
503
504
505
506
			} else {
				/*
				 * first unhandled parameter is treated as a kernel
				 * image
				 */
507
				kvm->cfg.kernel_filename = argv[0];
508
			}
509
510
511
512
513
514
			argv++;
			argc--;
		}

	}

515
516
	kvm->nr_disks = kvm->cfg.image_count;

517
	if (!kvm->cfg.kernel_filename && !kvm->cfg.firmware_filename) {
518
		kvm->cfg.kernel_filename = find_kernel();
519

520
521
522
523
		if (!kvm->cfg.kernel_filename) {
			kernel_usage_with_options();
			return ERR_PTR(-EINVAL);
		}
524
525
	}

526
	kvm->cfg.vmlinux_filename = find_vmlinux();
527
	kvm->vmlinux = kvm->cfg.vmlinux_filename;
528

529
530
	if (kvm->cfg.nrcpus == 0)
		kvm->cfg.nrcpus = nr_online_cpus;
531

532
	if (!kvm->cfg.ram_size)
533
		kvm->cfg.ram_size = get_ram_size(kvm->cfg.nrcpus);
534

535
	if (kvm->cfg.ram_size > host_ram_size())
536
537
538
		pr_warning("Guest memory size %lluMB exceeds host physical RAM size %lluMB",
			(unsigned long long)kvm->cfg.ram_size,
			(unsigned long long)host_ram_size());
539

540
	kvm->cfg.ram_size <<= MB_SHIFT;
541

542
543
	if (!kvm->cfg.dev)
		kvm->cfg.dev = DEFAULT_KVM_DEV;
544

545
546
	if (!kvm->cfg.console)
		kvm->cfg.console = DEFAULT_CONSOLE;
547

548
549
	video = kvm->cfg.vnc || kvm->cfg.sdl || kvm->cfg.gtk;

550
	if (!strncmp(kvm->cfg.console, "virtio", 6))
551
		kvm->cfg.active_console  = CONSOLE_VIRTIO;
552
	else if (!strncmp(kvm->cfg.console, "serial", 6))
553
		kvm->cfg.active_console  = CONSOLE_8250;
554
	else if (!strncmp(kvm->cfg.console, "hv", 2))
555
		kvm->cfg.active_console = CONSOLE_HV;
556
557
	else
		pr_warning("No console!");
558

559
560
	if (!kvm->cfg.host_ip)
		kvm->cfg.host_ip = DEFAULT_HOST_ADDR;
561

562
563
	if (!kvm->cfg.guest_ip)
		kvm->cfg.guest_ip = DEFAULT_GUEST_ADDR;
564

565
566
	if (!kvm->cfg.guest_mac)
		kvm->cfg.guest_mac = DEFAULT_GUEST_MAC;
567

568
569
	if (!kvm->cfg.host_mac)
		kvm->cfg.host_mac = DEFAULT_HOST_MAC;
570

571
572
	if (!kvm->cfg.script)
		kvm->cfg.script = DEFAULT_SCRIPT;
573

574
575
576
	if (!kvm->cfg.network)
                kvm->cfg.network = DEFAULT_NETWORK;

577
	memset(real_cmdline, 0, sizeof(real_cmdline));
578
579
580
	kvm__arch_set_cmdline(real_cmdline, video);

	if (video) {
581
		strcat(real_cmdline, " console=tty0");
582
583
584
585
586
	} else {
		switch (kvm->cfg.active_console) {
		case CONSOLE_HV:
			/* Fallthrough */
		case CONSOLE_VIRTIO:
587
			strcat(real_cmdline, " console=hvc0");
588
589
			break;
		case CONSOLE_8250:
590
			strcat(real_cmdline, " console=ttyS0");
591
592
593
			break;
		}
	}
594

595
596
597
	if (!kvm->cfg.guest_name) {
		if (kvm->cfg.custom_rootfs) {
			kvm->cfg.guest_name = kvm->cfg.custom_rootfs_name;
598
599
		} else {
			sprintf(default_name, "guest-%u", getpid());
600
			kvm->cfg.guest_name = default_name;
601
		}
602
603
	}

604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
	if (!kvm->cfg.using_rootfs && !kvm->cfg.disk_image[0].filename && !kvm->cfg.initrd_filename) {
		char tmp[PATH_MAX];

		kvm_setup_create_new(kvm->cfg.custom_rootfs_name);
		kvm_setup_resolv(kvm->cfg.custom_rootfs_name);

		snprintf(tmp, PATH_MAX, "%s%s", kvm__get_dir(), "default");
		if (virtio_9p__register(kvm, tmp, "/dev/root") < 0)
			die("Unable to initialize virtio 9p");
		if (virtio_9p__register(kvm, "/", "hostfs") < 0)
			die("Unable to initialize virtio 9p");
		kvm->cfg.using_rootfs = kvm->cfg.custom_rootfs = 1;
	}

	if (kvm->cfg.using_rootfs) {
619
		strcat(real_cmdline, " rw rootflags=trans=virtio,version=9p2000.L,cache=loose rootfstype=9p");
620
		if (kvm->cfg.custom_rootfs) {
621
			kvm_run_set_sandbox(kvm);
622

623
624
625
#ifdef CONFIG_GUEST_PRE_INIT
			strcat(real_cmdline, " init=/virt/pre_init");
#else
626
			strcat(real_cmdline, " init=/virt/init");
627
#endif
628
629
630

			if (!kvm->cfg.no_dhcp)
				strcat(real_cmdline, "  ip=dhcp");
631
			if (kvm_setup_guest_init(kvm->cfg.custom_rootfs_name))
632
633
				die("Failed to setup init for guest.");
		}
634
	} else if (!kvm->cfg.kernel_cmdline || !strstr(kvm->cfg.kernel_cmdline, "root=")) {
635
636
637
		strlcat(real_cmdline, " root=/dev/vda rw ", sizeof(real_cmdline));
	}

638
639
640
641
642
	if (kvm->cfg.kernel_cmdline) {
		strcat(real_cmdline, " ");
		strlcat(real_cmdline, kvm->cfg.kernel_cmdline, sizeof(real_cmdline));
	}

643
644
	kvm->cfg.real_cmdline = real_cmdline;

645
646
647
648
649
650
651
652
653
654
655
	if (kvm->cfg.kernel_filename) {
		printf("  # %s run -k %s -m %Lu -c %d --name %s\n", KVM_BINARY_NAME,
		       kvm->cfg.kernel_filename,
		       (unsigned long long)kvm->cfg.ram_size / 1024 / 1024,
		       kvm->cfg.nrcpus, kvm->cfg.guest_name);
	} else if (kvm->cfg.firmware_filename) {
		printf("  # %s run --firmware %s -m %Lu -c %d --name %s\n", KVM_BINARY_NAME,
		       kvm->cfg.firmware_filename,
		       (unsigned long long)kvm->cfg.ram_size / 1024 / 1024,
		       kvm->cfg.nrcpus, kvm->cfg.guest_name);
	}
656

657
658
	if (init_list__init(kvm) < 0)
		die ("Initialisation failed");
659
660

	return kvm;
661
662
}

663
static int kvm_cmd_run_work(struct kvm *kvm)
664
{
665
	int i;
666

667
	for (i = 0; i < kvm->nrcpus; i++) {
668
		if (pthread_create(&kvm->cpus[i]->thread, NULL, kvm_cpu_thread, kvm->cpus[i]) != 0)
669
670
			die("unable to create KVM VCPU thread");
	}
671

672
	/* Only VCPU #0 is going to exit by itself when shutting down */
673
674
675
676
	if (pthread_join(kvm->cpus[0]->thread, NULL) != 0)
		die("unable to join with vcpu 0");

	return kvm_cpu__exit(kvm);
677
678
}

679
static void kvm_cmd_run_exit(struct kvm *kvm, int guest_ret)
680
{
681
682
	compat__print_all_messages();

683
	init_list__exit(kvm);
684

685
	if (guest_ret == 0)
686
		printf("\n  # KVM session ended normally.\n");
687
688
689
690
}

int kvm_cmd_run(int argc, const char **argv, const char *prefix)
{
691
692
	int ret = -EFAULT;
	struct kvm *kvm;
693

694
695
696
	kvm = kvm_cmd_run_init(argc, argv);
	if (IS_ERR(kvm))
		return PTR_ERR(kvm);
697

698
699
	ret = kvm_cmd_run_work(kvm);
	kvm_cmd_run_exit(kvm, ret);
700
701

	return ret;
702
}