diff options
author | Treehugger Robot <treehugger-gerrit@google.com> | 2021-07-14 16:59:51 +0000 |
---|---|---|
committer | Gerrit Code Review <noreply-gerritcodereview@google.com> | 2021-07-14 16:59:51 +0000 |
commit | 601f25b6555db74d9cd5645d84bac5cf4b735d77 (patch) | |
tree | 7a2c834eb31b17387c20e1f9d348aa0bc27972fa | |
parent | 33a55d5d25ac1971b585de203f6c34fc44d90d85 (diff) | |
parent | 1b87ec72ac4619bc27f103f6c4dcda0a83ae6489 (diff) | |
download | cuttlefish-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.bp | 4 | ||||
-rw-r--r-- | build/cvd-host-package.go | 6 | ||||
-rw-r--r-- | host/commands/assemble_cvd/disk_flags.cc | 44 | ||||
-rw-r--r-- | host/libs/config/data_image.cpp | 163 | ||||
-rw-r--r-- | host/libs/config/data_image.h | 3 | ||||
-rw-r--r-- | shared/config/Android.bp | 6 | ||||
-rw-r--r-- | shared/config/grub.cfg | 43 | ||||
-rw-r--r-- | shared/device.mk | 4 |
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 # |