aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTreehugger Robot <treehugger-gerrit@google.com>2021-07-14 16:59:51 +0000
committerGerrit Code Review <noreply-gerritcodereview@google.com>2021-07-14 16:59:51 +0000
commit601f25b6555db74d9cd5645d84bac5cf4b735d77 (patch)
tree7a2c834eb31b17387c20e1f9d348aa0bc27972fa
parent33a55d5d25ac1971b585de203f6c34fc44d90d85 (diff)
parent1b87ec72ac4619bc27f103f6c4dcda0a83ae6489 (diff)
downloadcuttlefish-android-s-beta-4.tar.gz
Merge "Reland "Support auto-generation of ESP, add otheros_root""android-s-beta-4android-s-beta-3android-s-beta-4
-rw-r--r--build/Android.bp4
-rw-r--r--build/cvd-host-package.go6
-rw-r--r--host/commands/assemble_cvd/disk_flags.cc44
-rw-r--r--host/libs/config/data_image.cpp163
-rw-r--r--host/libs/config/data_image.h3
-rw-r--r--shared/config/Android.bp6
-rw-r--r--shared/config/grub.cfg43
-rw-r--r--shared/device.mk4
8 files changed, 245 insertions, 28 deletions
diff --git a/build/Android.bp b/build/Android.bp
index 787cec856..687f0cae2 100644
--- a/build/Android.bp
+++ b/build/Android.bp
@@ -23,6 +23,7 @@ soong_config_module_type {
module_type: "cvd_host_package",
config_namespace: "cvd",
value_variables: [
+ "grub_config",
"launch_configs",
"custom_action_config",
"custom_action_servers",
@@ -70,6 +71,9 @@ cvd_host_tools = [
"mkenvimage",
"modem_simulator",
"ms-tpm-20-ref",
+ "mcopy",
+ "mmd",
+ "mtools",
"newfs_msdos",
"powerwash_cvd",
"restart_cvd",
diff --git a/build/cvd-host-package.go b/build/cvd-host-package.go
index b025386cd..d15708396 100644
--- a/build/cvd-host-package.go
+++ b/build/cvd-host-package.go
@@ -56,6 +56,12 @@ func (c *cvdHostPackage) DepsMutator(ctx android.BottomUpMutatorContext) {
{Mutator: "arch", Variation: android.Common.String()},
}
for _, dep := range strings.Split(
+ ctx.Config().VendorConfig("cvd").String("grub_config"), " ") {
+ if ctx.OtherModuleExists(dep) {
+ ctx.AddVariationDependencies(variations, cvdHostPackageDependencyTag, dep)
+ }
+ }
+ for _, dep := range strings.Split(
ctx.Config().VendorConfig("cvd").String("launch_configs"), " ") {
if ctx.OtherModuleExists(dep) {
ctx.AddVariationDependencies(variations, cvdHostPackageDependencyTag, dep)
diff --git a/host/commands/assemble_cvd/disk_flags.cc b/host/commands/assemble_cvd/disk_flags.cc
index 439b3fb5d..7ae5adcf2 100644
--- a/host/commands/assemble_cvd/disk_flags.cc
+++ b/host/commands/assemble_cvd/disk_flags.cc
@@ -63,7 +63,16 @@ DEFINE_string(vbmeta_image, "",
DEFINE_string(vbmeta_system_image, "",
"Location of cuttlefish vbmeta_system image. If empty it is assumed to "
"be vbmeta_system.img in the directory specified by -system_image_dir.");
-DEFINE_string(esp, "", "Path to ESP partition image (FAT formatted)");
+DEFINE_string(otheros_esp_image, "",
+ "Location of cuttlefish esp image. If the image does not exist, "
+ "and --otheros_root_image is specified, an esp partition image "
+ "is created with default bootloaders.");
+DEFINE_string(otheros_kernel_path, "",
+ "Location of cuttlefish otheros kernel.");
+DEFINE_string(otheros_initramfs_path, "",
+ "Location of cuttlefish otheros initramfs.img.");
+DEFINE_string(otheros_root_image, "",
+ "Location of cuttlefish otheros root filesystem image.");
DEFINE_int32(blank_metadata_image_mb, 16,
"The size of the blank metadata image to generate, MB.");
@@ -104,6 +113,9 @@ bool ResolveInstanceFiles() {
std::string default_misc_image = FLAGS_system_image_dir + "/misc.img";
SetCommandLineOptionWithMode("misc_image", default_misc_image.c_str(),
google::FlagSettingMode::SET_FLAGS_DEFAULT);
+ std::string default_esp_image = FLAGS_system_image_dir + "/esp.img";
+ SetCommandLineOptionWithMode("otheros_esp_image", default_esp_image.c_str(),
+ google::FlagSettingMode::SET_FLAGS_DEFAULT);
std::string default_vendor_boot_image = FLAGS_system_image_dir
+ "/vendor_boot.img";
SetCommandLineOptionWithMode("vendor_boot_image",
@@ -127,13 +139,6 @@ std::vector<ImagePartition> os_composite_disk_config() {
.label = "misc",
.image_file_path = FLAGS_misc_image,
});
- if (!FLAGS_esp.empty()) {
- partitions.push_back(ImagePartition {
- .label = "esp",
- .image_file_path = FLAGS_esp,
- .type = kEfiSystemPartition,
- });
- }
partitions.push_back(ImagePartition {
.label = "boot_a",
.image_file_path = FLAGS_boot_image,
@@ -178,6 +183,17 @@ std::vector<ImagePartition> os_composite_disk_config() {
.label = "metadata",
.image_file_path = FLAGS_metadata_image,
});
+ if (!FLAGS_otheros_root_image.empty()) {
+ partitions.push_back(ImagePartition{
+ .label = "otheros_esp",
+ .image_file_path = FLAGS_otheros_esp_image,
+ .type = kEfiSystemPartition,
+ });
+ partitions.push_back(ImagePartition{
+ .label = "otheros_root",
+ .image_file_path = FLAGS_otheros_root_image,
+ });
+ }
return partitions;
}
@@ -430,6 +446,13 @@ void CreateDynamicDiskFiles(const FetcherConfig& fetcher_config,
// Create misc if necessary
CHECK(InitializeMiscImage(FLAGS_misc_image)) << "Failed to create misc image";
+ // Create esp if necessary
+ if (!FLAGS_otheros_root_image.empty()) {
+ CHECK(InitializeEspImage(FLAGS_otheros_esp_image, FLAGS_otheros_kernel_path,
+ FLAGS_otheros_initramfs_path))
+ << "Failed to create esp image";
+ }
+
// Create data if necessary
DataImageResult dataImageResult = ApplyDataImagePolicy(*config, FLAGS_data_image);
CHECK(dataImageResult != DataImageResult::Error) << "Failed to set up userdata";
@@ -500,11 +523,6 @@ void CreateDynamicDiskFiles(const FetcherConfig& fetcher_config,
CHECK(FileHasContent(FLAGS_bootloader))
<< "File not found: " << FLAGS_bootloader;
- if (!FLAGS_esp.empty()) {
- CHECK(FileHasContent(FLAGS_esp))
- << "File not found: " << FLAGS_esp;
- }
-
if (SuperImageNeedsRebuilding(fetcher_config, *config)) {
bool success = RebuildSuperImage(fetcher_config, *config, FLAGS_super_image);
CHECK(success) << "Super image rebuilding requested but could not be completed.";
diff --git a/host/libs/config/data_image.cpp b/host/libs/config/data_image.cpp
index 044dadbfa..189433f0c 100644
--- a/host/libs/config/data_image.cpp
+++ b/host/libs/config/data_image.cpp
@@ -20,6 +20,21 @@ const std::string kDataPolicyResizeUpTo= "resize_up_to";
const int FSCK_ERROR_CORRECTED = 1;
const int FSCK_ERROR_CORRECTED_REQUIRES_REBOOT = 2;
+// Currently the Cuttlefish bootloaders are built only for x86 (32-bit),
+// ARM (QEMU only, 32-bit) and AArch64 (64-bit), and U-Boot will hard-code
+// these search paths. Install all bootloaders to one of these paths.
+// NOTE: For now, just ignore the 32-bit ARM version, as Debian doesn't
+// build an EFI monolith for this architecture.
+const std::string kBootPathIA32 = "EFI/BOOT/BOOTIA32.EFI";
+const std::string kBootPathAA64 = "EFI/BOOT/BOOTAA64.EFI";
+
+// These are the paths Debian installs the monoliths to. If another distro
+// uses an alternative monolith path, add it to this table
+const std::pair<std::string, std::string> kGrubBlobTable[] = {
+ {"/usr/lib/grub/i386-efi/monolithic/grubia32.efi", kBootPathIA32},
+ {"/usr/lib/grub/arm64-efi/monolithic/grubaa64.efi", kBootPathAA64},
+};
+
bool ForceFsckImage(const char* data_image) {
auto fsck_path = HostBinaryPath("fsck.f2fs");
int fsck_status = execute({fsck_path, "-y", "-f", data_image});
@@ -31,6 +46,37 @@ bool ForceFsckImage(const char* data_image) {
return true;
}
+bool NewfsMsdos(const std::string& data_image, int data_image_mb,
+ int offset_num_mb) {
+ off_t image_size_bytes = static_cast<off_t>(data_image_mb) << 20;
+ off_t offset_size_bytes = static_cast<off_t>(offset_num_mb) << 20;
+ image_size_bytes -= offset_size_bytes;
+ off_t image_size_sectors = image_size_bytes / 512;
+ auto newfs_msdos_path = HostBinaryPath("newfs_msdos");
+ return execute({newfs_msdos_path,
+ "-F",
+ "32",
+ "-m",
+ "0xf8",
+ "-o",
+ "0",
+ "-c",
+ "8",
+ "-h",
+ "255",
+ "-u",
+ "63",
+ "-S",
+ "512",
+ "-s",
+ std::to_string(image_size_sectors),
+ "-C",
+ std::to_string(data_image_mb) + "M",
+ "-@",
+ std::to_string(offset_size_bytes),
+ data_image}) == 0;
+}
+
bool ResizeImage(const char* data_image, int data_image_mb) {
auto file_mb = FileSize(data_image) >> 20;
if (file_mb > data_image_mb) {
@@ -95,24 +141,17 @@ void CreateBlankImage(
// other OSes do by default when partitioning a drive
off_t offset_size_bytes = 1 << 20;
image_size_bytes -= offset_size_bytes;
- off_t image_size_sectors = image_size_bytes / 512;
- auto newfs_msdos_path = HostBinaryPath("newfs_msdos");
- execute({newfs_msdos_path, "-F", "32", "-m", "0xf8", "-a", "4088",
- "-o", "0", "-c", "8", "-h", "255",
- "-u", "63", "-S", "512",
- "-s", std::to_string(image_size_sectors),
- "-C", std::to_string(num_mb) + "M",
- "-@", std::to_string(offset_size_bytes),
- image});
+ CHECK(NewfsMsdos(image, num_mb, 1) == true)
+ << "Failed to create SD-Card filesystem";
// Write the MBR after the filesystem is formatted, as the formatting tools
// don't consistently preserve the image contents
MasterBootRecord mbr = {
- .partitions = {{
- .partition_type = 0xC,
- .first_lba = (std::uint32_t) offset_size_bytes / SECTOR_SIZE,
- .num_sectors = (std::uint32_t) image_size_bytes / SECTOR_SIZE,
- }},
- .boot_signature = { 0x55, 0xAA },
+ .partitions = {{
+ .partition_type = 0xC,
+ .first_lba = (std::uint32_t) offset_size_bytes / SECTOR_SIZE,
+ .num_sectors = (std::uint32_t) image_size_bytes / SECTOR_SIZE,
+ }},
+ .boot_signature = {0x55, 0xAA},
};
auto fd = SharedFD::Open(image, O_RDWR);
if (WriteAllBinary(fd, &mbr) != sizeof(MasterBootRecord)) {
@@ -200,4 +239,98 @@ bool InitializeMiscImage(const std::string& misc_image) {
return true;
}
+bool InitializeEspImage(const std::string& esp_image,
+ const std::string& kernel_path,
+ const std::string& initramfs_path) {
+ bool esp_exists = FileHasContent(esp_image.c_str());
+ if (esp_exists) {
+ LOG(DEBUG) << "esp partition image: use existing";
+ return true;
+ }
+
+ LOG(DEBUG) << "esp partition image: creating default";
+
+ // newfs_msdos won't make a partition smaller than 257 mb
+ // this should be enough for anybody..
+ auto tmp_esp_image = esp_image + ".tmp";
+ if (!NewfsMsdos(tmp_esp_image, 257 /* mb */, 0 /* mb (offset) */)) {
+ LOG(ERROR) << "Failed to create filesystem for " << tmp_esp_image;
+ return false;
+ }
+
+ // For licensing and build reproducibility reasons, pick up the bootloaders
+ // from the host Linux distribution (if present) and pack them into the
+ // automatically generated ESP. If the user wants their own bootloaders,
+ // they can use -esp_image=/path/to/esp.img to override, so we don't need
+ // to accommodate customizations of this packing process.
+
+ // Currently we only support Debian based distributions, and GRUB is built
+ // for those distros to always load grub.cfg from EFI/debian/grub.cfg, and
+ // nowhere else. If you want to add support for other distros, make the
+ // extra directories below and copy the initial grub.cfg there as well
+ auto mmd = HostBinaryPath("mmd");
+ auto success =
+ execute({mmd, "-i", tmp_esp_image, "EFI", "EFI/BOOT", "EFI/debian"});
+ if (success != 0) {
+ LOG(ERROR) << "Failed to create directories in " << tmp_esp_image;
+ return false;
+ }
+
+ // The grub binaries are small, so just copy all the architecture blobs
+ // we can find, which minimizes complexity. If the user removed the grub bin
+ // package from their system, the ESP will be empty and Other OS will not be
+ // supported
+ auto mcopy = HostBinaryPath("mcopy");
+ bool copied = false;
+ for (auto grub : kGrubBlobTable) {
+ if (!FileExists(grub.first)) {
+ continue;
+ }
+ success = execute(
+ {mcopy, "-o", "-i", tmp_esp_image, "-s", grub.first, "::" + grub.second});
+ if (success != 0) {
+ LOG(ERROR) << "Failed to copy " << grub.first << " to " << grub.second
+ << " in " << tmp_esp_image;
+ return false;
+ }
+ copied = true;
+ }
+
+ if (!copied) {
+ LOG(ERROR) << "No GRUB binaries were found on this system; Other OS "
+ "support will be broken";
+ return false;
+ }
+
+ auto grub_cfg = DefaultHostArtifactsPath("etc/grub/grub.cfg");
+ CHECK(FileExists(grub_cfg)) << "Missing file " << grub_cfg << "!";
+ success = execute({mcopy, "-i", tmp_esp_image, "-s", grub_cfg, "::EFI/debian/"});
+ if (success != 0) {
+ LOG(ERROR) << "Failed to copy " << grub_cfg << " to " << tmp_esp_image;
+ return false;
+ }
+
+ if (!kernel_path.empty()) {
+ success = execute({mcopy, "-i", tmp_esp_image, "-s", kernel_path, "::vmlinuz"});
+ if (success != 0) {
+ LOG(ERROR) << "Failed to copy " << kernel_path << " to " << tmp_esp_image;
+ return false;
+ }
+
+ if (!initramfs_path.empty()) {
+ success = execute(
+ {mcopy, "-i", tmp_esp_image, "-s", initramfs_path, "::initrd.img"});
+ if (success != 0) {
+ LOG(ERROR) << "Failed to copy " << initramfs_path << " to "
+ << tmp_esp_image;
+ return false;
+ }
+ }
+ }
+
+ CHECK(cuttlefish::RenameFile(tmp_esp_image, esp_image))
+ << "Renaming " << tmp_esp_image << " to " << esp_image << " failed";
+ return true;
+}
+
} // namespace cuttlefish
diff --git a/host/libs/config/data_image.h b/host/libs/config/data_image.h
index 6a6a81010..92e4eb74d 100644
--- a/host/libs/config/data_image.h
+++ b/host/libs/config/data_image.h
@@ -15,6 +15,9 @@ enum class DataImageResult {
DataImageResult ApplyDataImagePolicy(const CuttlefishConfig& config,
const std::string& path);
bool InitializeMiscImage(const std::string& misc_image);
+bool InitializeEspImage(const std::string& esp_image,
+ const std::string& kernel_path,
+ const std::string& initramfs_path);
void CreateBlankImage(
const std::string& image, int num_mb, const std::string& image_fmt);
diff --git a/shared/config/Android.bp b/shared/config/Android.bp
index 03bbc084f..439dbdfbb 100644
--- a/shared/config/Android.bp
+++ b/shared/config/Android.bp
@@ -31,3 +31,9 @@ prebuilt_etc_host {
src: "config_tv.json",
sub_dir: "cvd_config",
}
+
+prebuilt_etc_host {
+ name: "grub.cfg",
+ src: "grub.cfg",
+ sub_dir: "grub",
+}
diff --git a/shared/config/grub.cfg b/shared/config/grub.cfg
new file mode 100644
index 000000000..958c6a30e
--- /dev/null
+++ b/shared/config/grub.cfg
@@ -0,0 +1,43 @@
+# Root grub.cfg used either to boot raw kernel and/or initramfs.img, or to
+# chain to an installed distro's GRUB configuration file
+
+# These options are accessible to chain-loaded configurations as well:
+#
+# pnpacpi=off Disable on QEMU; allows serdev to claim platform serial
+# pci=noacpi Crosvm doesn't support ACPI-based PCI enumeration
+# reboot=k Reboot using keyboard method, rather than ACPI
+# noexec=off Some kernels panic when setting up NX
+# noefi Some kernels panic when trying to use U-Boot EFI
+# panic=-1 Don't reboot on panic
+# console=hvc0 Switch kernel logging to virtio-console once available
+# console=ttyAMA0 QEMU on ARM64 uses alternative serial implementation
+#
+if [ "$grub_cpu" = "i386" ]; then
+ set cmdline="pnpacpi=off pci=noacpi reboot=k noexec=off console=ttyS0 noefi panic=-1 console=hvc0 snd-hda-intel.enable=0"
+elif [ "$grub_cpu" = "arm64" ]; then
+ set cmdline="console=ttyS0 console=ttyAMA0 noefi panic=-1 console=hvc0"
+else
+ echo "Warning: No architecture found for ${grub_cpu}"
+fi
+
+# Root filesystem is on a GUID partition with label "otheros_root"
+set rootfs="PARTLABEL=otheros_root"
+
+# Root filesystem with grub installed
+search --file --set root /boot/grub/grub.cfg --hint (hd0)
+if [ $? = 0 ]; then
+ set prefix=($root)/boot/grub
+ export cmdline
+ export rootfs
+ configfile $prefix/grub.cfg
+ normal_exit
+fi
+
+# Fall back if we couldn't chain to another GRUB install
+set timeout=0
+menuentry "Linux" {
+ linux /vmlinuz $cmdline root=$rootfs
+ if [ -e /initrd.img ]; then
+ initrd /initrd.img
+ fi
+}
diff --git a/shared/device.mk b/shared/device.mk
index 17f2f1dd6..14e50ea61 100644
--- a/shared/device.mk
+++ b/shared/device.mk
@@ -167,6 +167,10 @@ SOONG_CONFIG_cvd_launch_configs += \
cvd_config_tablet.json \
cvd_config_tv.json \
+SOONG_CONFIG_cvd += grub_config
+SOONG_CONFIG_cvd_grub_config += \
+ grub.cfg \
+
#
# Packages for AOSP-available stuff we use from the framework
#