Added vendor boot image support for cuttlefish
Bug: 138199351
Bug: 140529116
Test: Treehugger
Change-Id: I38fd5a5faa701634677289a04847243139f4ff2a
diff --git a/host/commands/assemble_cvd/Android.bp b/host/commands/assemble_cvd/Android.bp
index e296526..b03d8bf 100644
--- a/host/commands/assemble_cvd/Android.bp
+++ b/host/commands/assemble_cvd/Android.bp
@@ -39,6 +39,7 @@
"super_image_mixer.cc",
],
header_libs: [
+ "bootimg_headers",
"cuttlefish_glog",
],
shared_libs: [
diff --git a/host/commands/assemble_cvd/boot_image_unpacker.cc b/host/commands/assemble_cvd/boot_image_unpacker.cc
index 460cc1e..f1ead30 100644
--- a/host/commands/assemble_cvd/boot_image_unpacker.cc
+++ b/host/commands/assemble_cvd/boot_image_unpacker.cc
@@ -21,10 +21,10 @@
#include <sstream>
+#include <bootimg.h>
#include <glog/logging.h>
#include "common/libs/utils/subprocess.h"
-#include "host/commands/assemble_cvd/bootimg.h"
namespace cvd {
@@ -48,39 +48,58 @@
}
} // namespace
-std::unique_ptr<BootImageUnpacker> BootImageUnpacker::FromImage(
- const std::string& path) {
- auto boot_img = SharedFD::Open(path.c_str(), O_RDONLY);
+std::unique_ptr<BootImageUnpacker> BootImageUnpacker::FromImages(
+ const std::string& boot_image_path,
+ const std::string& vendor_boot_image_path) {
+ auto boot_img = SharedFD::Open(boot_image_path.c_str(), O_RDONLY);
if (!boot_img->IsOpen()) {
- LOG(ERROR) << "Unable to open boot image (" << path
+ LOG(ERROR) << "Unable to open boot image (" << boot_image_path
<< "): " << boot_img->StrError();
return nullptr;
}
- boot_img_hdr header;
+ boot_img_hdr_v3 header;
auto bytes_read = boot_img->Read(&header, sizeof(header));
if (bytes_read != sizeof(header)) {
LOG(ERROR) << "Error reading boot image header";
return nullptr;
}
- std::ostringstream cmdline;
- cmdline << reinterpret_cast<char*>(&header.cmdline[0]);
- if (header.extra_cmdline[0] != '\0') {
- cmdline << " ";
- cmdline << reinterpret_cast<char*>(&header.extra_cmdline[0]);
+ auto vendor_boot_img = SharedFD::Open(vendor_boot_image_path.c_str(),
+ O_RDONLY);
+ if (!vendor_boot_img->IsOpen()) {
+ LOG(ERROR) << "Unable to open vendor boot image (" << vendor_boot_image_path
+ << "): " << vendor_boot_img->StrError();
+ return nullptr;
+ }
+ vendor_boot_img_hdr_v3 vboot_header;
+ bytes_read = vendor_boot_img->Read(&vboot_header, sizeof(vboot_header));
+ if (bytes_read != sizeof(vboot_header)) {
+ LOG(ERROR) << "Error reading vendor boot image header";
+ return nullptr;
}
- uint32_t page_size = header.page_size;
- // See system/core/mkbootimg/include/mkbootimg/bootimg.h for the origin of
+ std::ostringstream cmdline;
+ cmdline << reinterpret_cast<char*>(&header.cmdline[0]);
+ if (vboot_header.cmdline[0] != '\0') {
+ cmdline << " ";
+ cmdline << reinterpret_cast<char*>(&vboot_header.cmdline[0]);
+ }
+
+ uint32_t page_size = 4096;
+ // See system/tools/mkbootimg/include/bootimg/bootimg.h for the origin of
// these offset calculations
uint32_t kernel_offset = page_size;
uint32_t ramdisk_offset =
kernel_offset +
((header.kernel_size + page_size - 1) / page_size) * page_size;
+ uint32_t vendor_ramdisk_offset =
+ ((vboot_header.header_size + vboot_header.page_size - 1) / vboot_header.page_size) *
+ vboot_header.page_size;
std::unique_ptr<BootImageUnpacker> ret(new BootImageUnpacker(
boot_img, cmdline.str(), header.kernel_size, kernel_offset,
- header.ramdisk_size, ramdisk_offset));
+ header.ramdisk_size, ramdisk_offset, vendor_boot_img,
+ vboot_header.vendor_ramdisk_size, vendor_ramdisk_offset));
return ret;
}
@@ -99,8 +118,14 @@
return ExtractFile(boot_image_, ramdisk_image_offset_, ramdisk_image_size_,
path);
}
+bool BootImageUnpacker::ExtractVendorRamdiskImage(const std::string& path) const {
+ if (vendor_ramdisk_image_size_ == 0) return false;
+ return ExtractFile(vendor_boot_image_, vendor_ramdisk_image_offset_,
+ vendor_ramdisk_image_size_, path);
+}
bool BootImageUnpacker::Unpack(const std::string& ramdisk_image_path,
+ const std::string& vendor_ramdisk_image_path,
const std::string& kernel_image_path) {
if (HasRamdiskImage()) {
if (!ExtractRamdiskImage(ramdisk_image_path)) {
@@ -108,6 +133,12 @@
return false;
}
}
+ if (HasVendorRamdiskImage()) {
+ if (!ExtractVendorRamdiskImage(vendor_ramdisk_image_path)) {
+ LOG(ERROR) << "Error extracting vendor ramdisk from venodr boot image";
+ return false;
+ }
+ }
if (!kernel_image_path.empty()) {
if (HasKernelImage()) {
if (!ExtractKernelImage(kernel_image_path)) {
diff --git a/host/commands/assemble_cvd/boot_image_unpacker.h b/host/commands/assemble_cvd/boot_image_unpacker.h
index 05fe671..a331f0c 100644
--- a/host/commands/assemble_cvd/boot_image_unpacker.h
+++ b/host/commands/assemble_cvd/boot_image_unpacker.h
@@ -29,7 +29,9 @@
public:
// Reads header section of boot image at path and returns a BootImageUnpacker
// preloaded with all the metadata.
- static std::unique_ptr<BootImageUnpacker> FromImage(const std::string& path);
+ static std::unique_ptr<BootImageUnpacker> FromImages(
+ const std::string& boot_image_path,
+ const std::string& vendor_boot_image_path);
~BootImageUnpacker() = default;
@@ -37,30 +39,32 @@
bool HasKernelImage() const { return kernel_image_size_ > 0; }
bool HasRamdiskImage() const { return ramdisk_image_size_ > 0; }
-
- // Extracts the kernel image to the given path
- bool ExtractKernelImage(const std::string& path) const;
- // Extracts the ramdisk image to the given path. It may return false if the
- // boot image does not contain a ramdisk, which is the case when having system
- // as root.
- bool ExtractRamdiskImage(const std::string& path) const;
+ bool HasVendorRamdiskImage() const { return vendor_ramdisk_image_size_ > 0; }
bool Unpack(const std::string& ramdisk_image_path,
+ const std::string& vendor_ramdisk_image_path,
const std::string& kernel_image_path);
private:
BootImageUnpacker(SharedFD boot_image, const std::string& cmdline,
uint32_t kernel_image_size, uint32_t kernel_image_offset,
- uint32_t ramdisk_image_size, uint32_t ramdisk_image_offset)
+ uint32_t ramdisk_image_size, uint32_t ramdisk_image_offset,
+ SharedFD vendor_boot_image,
+ uint32_t vendor_ramdisk_image_size,
+ uint32_t vendor_ramdisk_image_offset)
: boot_image_(boot_image),
+ vendor_boot_image_(vendor_boot_image),
kernel_cmdline_(cmdline),
kernel_image_size_(kernel_image_size),
kernel_image_offset_(kernel_image_offset),
ramdisk_image_size_(ramdisk_image_size),
- ramdisk_image_offset_(ramdisk_image_offset) {}
+ ramdisk_image_offset_(ramdisk_image_offset),
+ vendor_ramdisk_image_size_(vendor_ramdisk_image_size),
+ vendor_ramdisk_image_offset_(vendor_ramdisk_image_offset) {}
// Mutable because we only read from the fd, but do not modify its contents
mutable SharedFD boot_image_;
+ mutable SharedFD vendor_boot_image_;
std::string kernel_cmdline_;
// When buidling the boot image a particular page size is assumed, which may
// not match the actual page size of the system.
@@ -68,6 +72,17 @@
uint32_t kernel_image_offset_;
uint32_t ramdisk_image_size_;
uint32_t ramdisk_image_offset_;
+ uint32_t vendor_ramdisk_image_size_;
+ uint32_t vendor_ramdisk_image_offset_;
+
+ // Extracts the kernel image to the given path
+ bool ExtractKernelImage(const std::string& path) const;
+ // Extracts the ramdisk image to the given path. It may return false if the
+ // boot image does not contain a ramdisk, which is the case when having system
+ // as root.
+ bool ExtractRamdiskImage(const std::string& path) const;
+ // Extracts the vendor ramdisk image to the given path
+ bool ExtractVendorRamdiskImage(const std::string& path) const;
};
} // namespace cvd
diff --git a/host/commands/assemble_cvd/bootimg.h b/host/commands/assemble_cvd/bootimg.h
deleted file mode 100644
index 7b8fb28..0000000
--- a/host/commands/assemble_cvd/bootimg.h
+++ /dev/null
@@ -1,167 +0,0 @@
-/* tools/mkbootimg/bootimg.h
-**
-** Copyright 2007, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
-
-// This file is a clone of the one found on system/core/mkbootimg. We've made a
-// clone because the location of the original header has changed over time.
-
-#include <stdint.h>
-
-#ifndef CUTTLEFISH_LAUNCH_BOOT_IMAGE_H_
-#define CUTTLEFISH_LAUNCH_BOOT_IMAGE_H_
-
-#define BOOT_MAGIC "ANDROID!"
-#define BOOT_MAGIC_SIZE 8
-#define BOOT_NAME_SIZE 16
-#define BOOT_ARGS_SIZE 512
-#define BOOT_EXTRA_ARGS_SIZE 1024
-
-#define BOOT_HEADER_VERSION_ZERO 0
-/*
- * Bootloader expects the structure of boot_img_hdr with header version
- * BOOT_HEADER_VERSION_ZERO to be as follows:
- */
-struct boot_img_hdr_v0 {
- uint8_t magic[BOOT_MAGIC_SIZE];
-
- uint32_t kernel_size; /* size in bytes */
- uint32_t kernel_addr; /* physical load addr */
-
- uint32_t ramdisk_size; /* size in bytes */
- uint32_t ramdisk_addr; /* physical load addr */
-
- uint32_t second_size; /* size in bytes */
- uint32_t second_addr; /* physical load addr */
-
- uint32_t tags_addr; /* physical addr for kernel tags */
- uint32_t page_size; /* flash page size we assume */
- /*
- * version for the boot image header.
- */
- uint32_t header_version;
-
- /* operating system version and security patch level; for
- * version "A.B.C" and patch level "Y-M-D":
- * ver = A << 14 | B << 7 | C (7 bits for each of A, B, C)
- * lvl = ((Y - 2000) & 127) << 4 | M (7 bits for Y, 4 bits for M)
- * os_version = ver << 11 | lvl */
- uint32_t os_version;
-
- uint8_t name[BOOT_NAME_SIZE]; /* asciiz product name */
-
- uint8_t cmdline[BOOT_ARGS_SIZE];
-
- uint32_t id[8]; /* timestamp / checksum / sha1 / etc */
-
- /* Supplemental command line data; kept here to maintain
- * binary compatibility with older versions of mkbootimg */
- uint8_t extra_cmdline[BOOT_EXTRA_ARGS_SIZE];
-} __attribute__((packed));
-
-/*
- * It is expected that callers would explicitly specify which version of the
- * boot image header they need to use.
- */
-typedef struct boot_img_hdr_v0 boot_img_hdr;
-
-/* When a boot header is of version BOOT_HEADER_VERSION_ZERO, the structure of boot image is as
- * follows:
- *
- * +-----------------+
- * | boot header | 1 page
- * +-----------------+
- * | kernel | n pages
- * +-----------------+
- * | ramdisk | m pages
- * +-----------------+
- * | second stage | o pages
- * +-----------------+
- *
- * n = (kernel_size + page_size - 1) / page_size
- * m = (ramdisk_size + page_size - 1) / page_size
- * o = (second_size + page_size - 1) / page_size
- *
- * 0. all entities are page_size aligned in flash
- * 1. kernel and ramdisk are required (size != 0)
- * 2. second is optional (second_size == 0 -> no second)
- * 3. load each element (kernel, ramdisk, second) at
- * the specified physical address (kernel_addr, etc)
- * 4. prepare tags at tag_addr. kernel_args[] is
- * appended to the kernel commandline in the tags.
- * 5. r0 = 0, r1 = MACHINE_TYPE, r2 = tags_addr
- * 6. if second_size != 0: jump to second_addr
- * else: jump to kernel_addr
- */
-
-#define BOOT_HEADER_VERSION_ONE 1
-
-struct boot_img_hdr_v1 : public boot_img_hdr_v0 {
- uint32_t recovery_dtbo_size; /* size in bytes for recovery DTBO image */
- uint64_t recovery_dtbo_offset; /* physical load addr */
- uint32_t header_size;
-} __attribute__((packed));
-
-/* When the boot image header has a version of BOOT_HEADER_VERSION_ONE, the structure of the boot
- * image is as follows:
- *
- * +-----------------+
- * | boot header | 1 page
- * +-----------------+
- * | kernel | n pages
- * +-----------------+
- * | ramdisk | m pages
- * +-----------------+
- * | second stage | o pages
- * +-----------------+
- * | recovery dtbo | p pages
- * +-----------------+
- * n = (kernel_size + page_size - 1) / page_size
- * m = (ramdisk_size + page_size - 1) / page_size
- * o = (second_size + page_size - 1) / page_size
- * p = (recovery_dtbo_size + page_size - 1) / page_size
- *
- * 0. all entities are page_size aligned in flash
- * 1. kernel and ramdisk are required (size != 0)
- * 2. recovery_dtbo is required for recovery.img in non-A/B devices(recovery_dtbo_size != 0)
- * 3. second is optional (second_size == 0 -> no second)
- * 4. load each element (kernel, ramdisk, second, recovery_dtbo) at
- * the specified physical address (kernel_addr, etc)
- * 5. prepare tags at tag_addr. kernel_args[] is
- * appended to the kernel commandline in the tags.
- * 6. r0 = 0, r1 = MACHINE_TYPE, r2 = tags_addr
- * 7. if second_size != 0: jump to second_addr
- * else: jump to kernel_addr
- */
-
-#if 0
-typedef struct ptentry ptentry;
-
-struct ptentry {
- char name[16]; /* asciiz partition name */
- unsigned start; /* starting block number */
- unsigned length; /* length in blocks */
- unsigned flags; /* set to zero */
-};
-
-/* MSM Partition Table ATAG
-**
-** length: 2 + 7 * n
-** atag: 0x4d534d70
-** <ptentry> x n
-*/
-#endif
-
-#endif
diff --git a/host/commands/assemble_cvd/flags.cc b/host/commands/assemble_cvd/flags.cc
index 6de4abd..22def1b 100644
--- a/host/commands/assemble_cvd/flags.cc
+++ b/host/commands/assemble_cvd/flags.cc
@@ -71,6 +71,9 @@
DEFINE_string(boot_image, "",
"Location of cuttlefish boot image. If empty it is assumed to be "
"boot.img in the directory specified by -system_image_dir.");
+DEFINE_string(vendor_boot_image, "",
+ "Location of cuttlefish vendor boot image. If empty it is assumed to "
+ "be vendor_boot.img in the directory specified by -system_image_dir.");
DEFINE_int32(memory_mb, 2048,
"Total amount of memory available for guest, MB.");
std::string g_default_mempath{vsoc::GetDefaultMempath()};
@@ -251,6 +254,11 @@
std::string default_composite_disk = FLAGS_system_image_dir + "/composite.img";
SetCommandLineOptionWithMode("composite_disk", default_composite_disk.c_str(),
google::FlagSettingMode::SET_FLAGS_DEFAULT);
+ std::string default_vendor_boot_image = FLAGS_system_image_dir
+ + "/vendor_boot.img";
+ SetCommandLineOptionWithMode("vendor_boot_image",
+ default_vendor_boot_image.c_str(),
+ google::FlagSettingMode::SET_FLAGS_DEFAULT);
return true;
}
@@ -325,10 +333,12 @@
}
auto ramdisk_path = tmp_config_obj.PerInstancePath("ramdisk.img");
+ auto vendor_ramdisk_path = tmp_config_obj.PerInstancePath("vendor_ramdisk.img");
bool use_ramdisk = boot_image_unpacker.HasRamdiskImage();
if (!use_ramdisk) {
LOG(INFO) << "No ramdisk present; assuming system-as-root build";
ramdisk_path = "";
+ vendor_ramdisk_path = "";
}
tmp_config_obj.add_kernel_cmdline(boot_image_unpacker.kernel_cmdline());
@@ -405,11 +415,12 @@
}
tmp_config_obj.set_ramdisk_image_path(ramdisk_path);
+ // Boot as recovery is set so normal boot needs to be forced every boot
+ tmp_config_obj.add_kernel_cmdline("androidboot.force_normal_boot=1");
+ tmp_config_obj.set_vendor_ramdisk_image_path(vendor_ramdisk_path);
+ tmp_config_obj.set_final_ramdisk_path(ramdisk_path + kRamdiskConcatExt);
if(FLAGS_initramfs_path.size() > 0) {
tmp_config_obj.set_initramfs_path(FLAGS_initramfs_path);
- tmp_config_obj.set_final_ramdisk_path(ramdisk_path + kRamdiskConcatExt);
- } else {
- tmp_config_obj.set_final_ramdisk_path(ramdisk_path);
}
tmp_config_obj.set_mempath(FLAGS_mempath);
@@ -791,7 +802,14 @@
exit(cvd::kCuttlefishConfigurationInitError);
}
- auto boot_img_unpacker = cvd::BootImageUnpacker::FromImage(FLAGS_boot_image);
+ if (!cvd::FileHasContent(FLAGS_vendor_boot_image)) {
+ LOG(ERROR) << "File not found: " << FLAGS_vendor_boot_image;
+ exit(cvd::kCuttlefishConfigurationInitError);
+ }
+
+ auto boot_img_unpacker =
+ cvd::BootImageUnpacker::FromImages(FLAGS_boot_image,
+ FLAGS_vendor_boot_image);
if (!InitializeCuttlefishConfiguration(*boot_img_unpacker)) {
LOG(ERROR) << "Failed to initialize configuration";
@@ -805,6 +823,7 @@
}
if (!boot_img_unpacker->Unpack(config->ramdisk_image_path(),
+ config->vendor_ramdisk_image_path(),
config->use_unpacked_kernel()
? config->kernel_image_path()
: "")) {
@@ -812,12 +831,20 @@
exit(AssemblerExitCodes::kBootImageUnpackError);
}
- if(config->initramfs_path().size() != 0) {
- if(!ConcatRamdisks(config->final_ramdisk_path(), config->ramdisk_image_path(),
- config->initramfs_path())) {
- LOG(ERROR) << "Failed to concatenate ramdisk and initramfs";
- exit(AssemblerExitCodes::kInitRamFsConcatError);
- }
+ // TODO(134522463) as part of the bootloader refactor, repack the vendor boot
+ // image and use the bootloader to load both the boot and vendor ramdisk.
+ // Until then, this hack to get gki modules into cuttlefish will suffice.
+
+ // If a vendor ramdisk comes in via this mechanism, let it supercede the one
+ // in the vendor boot image. This flag is what kernel presubmit testing uses
+ // to pass in the kernel ramdisk.
+ const std::string& vendor_ramdisk_path = config->initramfs_path().size() ?
+ config->initramfs_path() :
+ config->vendor_ramdisk_image_path();
+ if(!ConcatRamdisks(config->final_ramdisk_path(), config->ramdisk_image_path(),
+ vendor_ramdisk_path)) {
+ LOG(ERROR) << "Failed to concatenate ramdisk and vendor ramdisk";
+ exit(AssemblerExitCodes::kInitRamFsConcatError);
}
if (config->decompress_kernel()) {
diff --git a/host/libs/config/cuttlefish_config.cpp b/host/libs/config/cuttlefish_config.cpp
index ade685b..882a951 100644
--- a/host/libs/config/cuttlefish_config.cpp
+++ b/host/libs/config/cuttlefish_config.cpp
@@ -92,6 +92,7 @@
const char* kRamdiskImagePath = "ramdisk_image_path";
const char* kInitramfsPath = "initramfs_path";
const char* kFinalRamdiskPath = "final_ramdisk_path";
+const char* kVendorRamdiskImagePath = "vendor_ramdisk_image_path";
const char* kVirtualDiskPaths = "virtual_disk_paths";
const char* kUsbV1SocketName = "usb_v1_socket_name";
@@ -380,6 +381,14 @@
SetPath(kFinalRamdiskPath, final_ramdisk_path);
}
+std::string CuttlefishConfig::vendor_ramdisk_image_path() const {
+ return (*dictionary_)[kVendorRamdiskImagePath].asString();
+}
+void CuttlefishConfig::set_vendor_ramdisk_image_path(
+ const std::string& vendor_ramdisk_image_path) {
+ SetPath(kVendorRamdiskImagePath, vendor_ramdisk_image_path);
+}
+
std::vector<std::string> CuttlefishConfig::virtual_disk_paths() const {
std::vector<std::string> virtual_disks;
auto virtual_disks_json_obj = (*dictionary_)[kVirtualDiskPaths];
diff --git a/host/libs/config/cuttlefish_config.h b/host/libs/config/cuttlefish_config.h
index 09ae4a9..0fca9f0 100644
--- a/host/libs/config/cuttlefish_config.h
+++ b/host/libs/config/cuttlefish_config.h
@@ -156,6 +156,10 @@
std::string final_ramdisk_path() const;
void set_final_ramdisk_path(const std::string& final_ramdisk_path);
+ std::string vendor_ramdisk_image_path() const;
+ void set_vendor_ramdisk_image_path(const std::string&
+ vendor_ramdisk_image_path);
+
std::vector<std::string> virtual_disk_paths() const;
void set_virtual_disk_paths(const std::vector<std::string>& disk_paths);