Add --nodefaults command line argument

kvmtool attempts to make it as easier as possible on the user to run a VM
by doing a few different things: it tries to create a rootfs filesystem in
a directory if not disk or initrd is set by the user, and it adds various
parameters to the kernel command line based on the VM configuration
options.

While this is generally very useful, today there isn't any way for the user
to prohibit this behaviour, even though there are situations where this
might not be desirable, like, for example: loading something which is not a
kernel (kvm-unit-tests comes to mind, which expects test parameters on the
kernel command line); the kernel has a built-in initramfs and there is no
need to generate the root filesystem, or it not possible; and what is
probably the most important use case, when the user is actively trying to
break things for testing purposes.

Add a --nodefaults command line argument which disables everything that
cannot be disabled via another command line switch. The purpose of this
knob is not to disable the default options for arguments that can be set
via the kvmtool command line, but rather to inhibit behaviour that cannot
be disabled otherwise.

Signed-off-by: Alexandru Elisei <alexandru.elisei@arm.com>
Link: https://lore.kernel.org/r/20210923144505.60776-8-alexandru.elisei@arm.com
Signed-off-by: Will Deacon <will@kernel.org>
diff --git a/arm/fdt.c b/arm/fdt.c
index 7032985..635de7f 100644
--- a/arm/fdt.c
+++ b/arm/fdt.c
@@ -136,9 +136,10 @@
 		if (kvm->cfg.kernel_cmdline)
 			_FDT(fdt_property_string(fdt, "bootargs",
 						 kvm->cfg.kernel_cmdline));
-	} else
+	} else if (kvm->cfg.real_cmdline) {
 		_FDT(fdt_property_string(fdt, "bootargs",
 					 kvm->cfg.real_cmdline));
+	}
 
 	_FDT(fdt_property_u64(fdt, "kaslr-seed", kvm->cfg.arch.kaslr_seed));
 	_FDT(fdt_property_string(fdt, "stdout-path", "serial0"));
diff --git a/builtin-run.c b/builtin-run.c
index 478b5a9..9a1a0c1 100644
--- a/builtin-run.c
+++ b/builtin-run.c
@@ -108,6 +108,9 @@
 	OPT_BOOLEAN('\0', "sdl", &(cfg)->sdl, "Enable SDL framebuffer"),\
 	OPT_BOOLEAN('\0', "rng", &(cfg)->virtio_rng, "Enable virtio"	\
 			" Random Number Generator"),			\
+	OPT_BOOLEAN('\0', "nodefaults", &(cfg)->nodefaults, "Disable"   \
+			" implicit configuration that cannot be"	\
+			" disabled otherwise"),				\
 	OPT_CALLBACK('\0', "9p", NULL, "dir_to_share,tag_name",		\
 		     "Enable virtio 9p to share files between host and"	\
 		     " guest", virtio_9p_rootdir_parser, kvm),		\
@@ -642,7 +645,10 @@
 		}
 	}
 
-	if (!kvm->cfg.using_rootfs && !kvm->cfg.disk_image[0].filename && !kvm->cfg.initrd_filename) {
+	if (!kvm->cfg.nodefaults &&
+	    !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);
@@ -662,7 +668,10 @@
 			die("Failed to setup init for guest.");
 	}
 
-	kvm_run_set_real_cmdline(kvm);
+	if (kvm->cfg.nodefaults)
+		kvm->cfg.real_cmdline = kvm->cfg.kernel_cmdline;
+	else
+		kvm_run_set_real_cmdline(kvm);
 
 	if (kvm->cfg.kernel_filename) {
 		printf("  # %s run -k %s -m %Lu -c %d --name %s\n", KVM_BINARY_NAME,
diff --git a/include/kvm/kvm-config.h b/include/kvm/kvm-config.h
index 35d45c0..6a5720c 100644
--- a/include/kvm/kvm-config.h
+++ b/include/kvm/kvm-config.h
@@ -27,6 +27,7 @@
 	u8 num_vfio_devices;
 	u64 vsock_cid;
 	bool virtio_rng;
+	bool nodefaults;
 	int active_console;
 	int debug_iodelay;
 	int nrcpus;
diff --git a/mips/kvm.c b/mips/kvm.c
index e110e5d..3470dbb 100644
--- a/mips/kvm.c
+++ b/mips/kvm.c
@@ -131,7 +131,8 @@
 			(unsigned long long)kvm->ram_size - KVM_MMIO_START,
 			(unsigned long long)(KVM_MMIO_START + KVM_MMIO_SIZE));
 
-	strcat(p + cmdline_offset, kvm->cfg.real_cmdline); /* maximum size is 2K */
+	if (kvm->cfg.real_cmdline)
+		strcat(p + cmdline_offset, kvm->cfg.real_cmdline); /* maximum size is 2K */
 
 	while (p[cmdline_offset]) {
 		if (!isspace(p[cmdline_offset])) {