Extract the elf image from a compressed kernel image.
If the --decompress_kernel flag is given to the launcher, the kernel
image will be decompressed and stored in ${runtime_dir}/vmlinux. This
is the default (and required) behavior for crosvm.
Bug: 122978436
Test: build & run locally
Change-Id: I47e70d4cae20a398bc46772c3f5cb0dd9e3b5dcc
diff --git a/host/commands/launch/flags.cc b/host/commands/launch/flags.cc
index 5b67f2b..76cb1c8 100644
--- a/host/commands/launch/flags.cc
+++ b/host/commands/launch/flags.cc
@@ -43,6 +43,11 @@
DEFINE_int32(num_screen_buffers, 3, "The number of screen buffers");
DEFINE_string(kernel_path, "",
"Path to the kernel. Overrides the one from the boot image");
+DEFINE_bool(decompress_kernel, false,
+ "Whether to decompress the kernel image. Required for crosvm.");
+DEFINE_string(kernel_decompresser_executable,
+ vsoc::DefaultHostArtifactsPath("bin/extract-vmlinux"),
+ "Path to the extract-vmlinux executable.");
DEFINE_string(extra_kernel_cmdline, "",
"Additional flags to put on the kernel command line");
DEFINE_int32(loop_max_part, 7, "Maximum number of loop partitions");
@@ -245,6 +250,11 @@
tmp_config_obj.PerInstancePath("kernel"));
tmp_config_obj.set_use_unpacked_kernel(true);
}
+ tmp_config_obj.set_decompress_kernel(FLAGS_decompress_kernel);
+ if (FLAGS_decompress_kernel) {
+ tmp_config_obj.set_decompressed_kernel_image_path(
+ tmp_config_obj.PerInstancePath("vmlinux"));
+ }
auto ramdisk_path = tmp_config_obj.PerInstancePath("ramdisk.img");
bool use_ramdisk = boot_image_unpacker.HasRamdiskImage();
@@ -430,6 +440,8 @@
google::FlagSettingMode::SET_FLAGS_DEFAULT);
SetCommandLineOptionWithMode("adb_mode", "tunnel",
google::FlagSettingMode::SET_FLAGS_DEFAULT);
+ SetCommandLineOptionWithMode("decompress_kernel", "false",
+ google::FlagSettingMode::SET_FLAGS_DEFAULT);
}
void SetDefaultFlagsForCrosvm() {
@@ -459,6 +471,8 @@
google::FlagSettingMode::SET_FLAGS_DEFAULT);
SetCommandLineOptionWithMode("adb_mode", "vsock_tunnel",
google::FlagSettingMode::SET_FLAGS_DEFAULT);
+ SetCommandLineOptionWithMode("decompress_kernel", "true",
+ google::FlagSettingMode::SET_FLAGS_DEFAULT);
}
bool ParseCommandLineFlags(int* argc, char*** argv) {
@@ -513,6 +527,20 @@
}
return true;
}
+
+bool DecompressKernel(const std::string& src, const std::string& dst) {
+ cvd::Command decomp_cmd(FLAGS_kernel_decompresser_executable);
+ decomp_cmd.AddParameter(src);
+ auto output_file = cvd::SharedFD::Creat(dst.c_str(), 0666);
+ if (!output_file->IsOpen()) {
+ LOG(ERROR) << "Unable to create decompressed image file: "
+ << output_file->StrError();
+ return false;
+ }
+ decomp_cmd.RedirectStdIO(cvd::Subprocess::StdIOChannel::kStdOut, output_file);
+ auto decomp_proc = decomp_cmd.Start(false);
+ return decomp_proc.Started() && decomp_proc.Wait() == 0;
+}
} // namespace
vsoc::CuttlefishConfig* InitFilesystemAndCreateConfig(int* argc, char*** argv) {
@@ -563,6 +591,14 @@
exit(LauncherExitCodes::kBootImageUnpackError);
}
+ if (config->decompress_kernel()) {
+ if (!DecompressKernel(config->kernel_image_path(),
+ config->decompressed_kernel_image_path())) {
+ LOG(ERROR) << "Failed to decompress kernel";
+ exit(LauncherExitCodes::kKernelDecompressError);
+ }
+ }
+
ValidateAdbModeFlag(*config);
// Create data if necessary
diff --git a/host/commands/launch/launcher_defs.h b/host/commands/launch/launcher_defs.h
index 1f52497..ccf859c 100644
--- a/host/commands/launch/launcher_defs.h
+++ b/host/commands/launch/launcher_defs.h
@@ -35,6 +35,7 @@
kServerError = 14,
kUsbV1SocketError = 15,
kE2eTestFailed = 16,
+ kKernelDecompressError = 17,
};
// Actions supported by the launcher server
diff --git a/host/libs/config/cuttlefish_config.cpp b/host/libs/config/cuttlefish_config.cpp
index 0a3be9c..dc923e1 100644
--- a/host/libs/config/cuttlefish_config.cpp
+++ b/host/libs/config/cuttlefish_config.cpp
@@ -82,6 +82,8 @@
const char* kKernelImagePath = "kernel_image_path";
const char* kUseUnpackedKernel = "use_unpacked_kernel";
+const char* kDecompressedKernelImagePath = "decompressed_kernel_image_path";
+const char* kDecompressKernel = "decompress_kernel";
const char* kGdbFlag = "gdb_flag";
const char* kKernelCmdline = "kernel_cmdline";
const char* kRamdiskImagePath = "ramdisk_image_path";
@@ -239,6 +241,21 @@
(*dictionary_)[kUseUnpackedKernel] = use_unpacked_kernel;
}
+bool CuttlefishConfig::decompress_kernel() const {
+ return (*dictionary_)[kDecompressKernel].asBool();
+}
+void CuttlefishConfig::set_decompress_kernel(bool decompress_kernel) {
+ (*dictionary_)[kDecompressKernel] = decompress_kernel;
+}
+
+std::string CuttlefishConfig::decompressed_kernel_image_path() const {
+ return (*dictionary_)[kDecompressedKernelImagePath].asString();
+}
+void CuttlefishConfig::set_decompressed_kernel_image_path(
+ const std::string& path) {
+ SetPath(kDecompressedKernelImagePath, path);
+}
+
std::string CuttlefishConfig::gdb_flag() const {
return (*dictionary_)[kGdbFlag].asString();
}
diff --git a/host/libs/config/cuttlefish_config.h b/host/libs/config/cuttlefish_config.h
index 300250e..71aff38 100644
--- a/host/libs/config/cuttlefish_config.h
+++ b/host/libs/config/cuttlefish_config.h
@@ -84,9 +84,27 @@
int refresh_rate_hz() const;
void set_refresh_rate_hz(int refresh_rate_hz);
+ // Returns kernel image extracted from the boot image or the user-provided one
+ // if given by command line to the launcher. This function should not be used
+ // to get the kernel image the vmm should boot, GetKernelImageToUse() should
+ // be used instead.
std::string kernel_image_path() const;
void set_kernel_image_path(const std::string& kernel_image_path);
+ bool decompress_kernel() const;
+ void set_decompress_kernel(bool decompress_kernel);
+
+ // Returns the path to the kernel image that should be given to the vm manager
+ // to boot, takes into account whether the original image was decompressed or
+ // not.
+ std::string GetKernelImageToUse() const {
+ return decompress_kernel() ? decompressed_kernel_image_path()
+ : kernel_image_path();
+ }
+
+ std::string decompressed_kernel_image_path() const;
+ void set_decompressed_kernel_image_path(const std::string& path);
+
bool use_unpacked_kernel() const;
void set_use_unpacked_kernel(bool use_unpacked_kernel);
diff --git a/host/libs/vm_manager/crosvm_manager.cpp b/host/libs/vm_manager/crosvm_manager.cpp
index 78286f9..ba09257 100644
--- a/host/libs/vm_manager/crosvm_manager.cpp
+++ b/host/libs/vm_manager/crosvm_manager.cpp
@@ -91,7 +91,7 @@
}
// This needs to be the last parameter
- command.AddParameter(config_->kernel_image_path());
+ command.AddParameter(config_->GetKernelImageToUse());
return command;
}
diff --git a/host/libs/vm_manager/qemu_manager.cpp b/host/libs/vm_manager/qemu_manager.cpp
index 4a64a11..751c68c 100644
--- a/host/libs/vm_manager/qemu_manager.cpp
+++ b/host/libs/vm_manager/qemu_manager.cpp
@@ -66,7 +66,7 @@
LogAndSetEnv("cpus", std::to_string(config_->cpus()));
LogAndSetEnv("uuid", config_->uuid());
LogAndSetEnv("monitor_path", GetMonitorPath(config_));
- LogAndSetEnv("kernel_image_path", config_->kernel_image_path());
+ LogAndSetEnv("kernel_image_path", config_->GetKernelImageToUse());
LogAndSetEnv("gdb_flag", config_->gdb_flag());
LogAndSetEnv("ramdisk_image_path", config_->ramdisk_image_path());
LogAndSetEnv("kernel_cmdline", config_->kernel_cmdline_as_string());