From 9a0703b55948144f58b686a7e313cbdb4203a444 Mon Sep 17 00:00:00 2001 From: Eric Snowberg Date: Mon, 4 Mar 2019 17:34:01 -0800 Subject: [PATCH] sparc64: Add bios boot partition support Add BIOS Boot Partition support for sparc64 platforms. This will work a little different than x86. With GPT, both the OBP "load" and "boot" commands are partition aware and neither command can see the partition table. Therefore the entire boot-loader is stored within the BIOS Boot Partition and nothing is stored within the bootstrap code area of MBR. To use it, the end user will issue the boot command with the path pointing to the BIOS Boot Partition. For example with the disk below: Model: Unknown (unknown) Disk /dev/nvme1n1: 1600GB Sector size (logical/physical): 512B/512B Partition Table: gpt Number Start End Size File system Name Flags 1 1049kB 1075MB 1074MB ext3 2 1075MB 1076MB 1049kB bios_grub 3 1076MB 1600GB 1599GB lvm To boot grub2 from OBP, you would use: boot /pci@302/pci@1/pci@0/pci@13/nvme@0/disk@1:b Signed-off-by: Eric Snowberg Reviewed-by: Daniel Kiper --- util/setup.c | 81 ++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 72 insertions(+), 9 deletions(-) diff --git a/util/setup.c b/util/setup.c index 8954dd479..92a5af9ba 100644 --- a/util/setup.c +++ b/util/setup.c @@ -205,7 +205,6 @@ save_blocklists (grub_disk_addr_t sector, unsigned offset, unsigned length, #endif } -#ifdef GRUB_SETUP_BIOS /* Context for setup/identify_partmap. */ struct identify_partmap_ctx { @@ -241,7 +240,6 @@ identify_partmap (grub_disk_t disk __attribute__ ((unused)), ctx->multiple_partmaps = 1; return 1; } -#endif #ifdef GRUB_SETUP_BIOS #define SETUP grub_util_bios_setup @@ -262,9 +260,7 @@ SETUP (const char *dir, char *boot_img, *core_img, *boot_path; char *root = 0; size_t boot_size, core_size; -#ifdef GRUB_SETUP_BIOS grub_uint16_t core_sectors; -#endif grub_device_t root_dev = 0, dest_dev, core_dev; grub_util_fd_t fp; struct blocklists bl; @@ -288,10 +284,8 @@ SETUP (const char *dir, core_path = grub_util_get_path (dir, core_file); core_size = grub_util_get_image_size (core_path); -#ifdef GRUB_SETUP_BIOS core_sectors = ((core_size + GRUB_DISK_SECTOR_SIZE - 1) >> GRUB_DISK_SECTOR_BITS); -#endif if (core_size < GRUB_DISK_SECTOR_SIZE) grub_util_error (_("the size of `%s' is too small"), core_path); #ifdef GRUB_SETUP_BIOS @@ -372,8 +366,8 @@ SETUP (const char *dir, if (grub_env_set ("root", root) != GRUB_ERR_NONE) grub_util_error ("%s", grub_errmsg); -#ifdef GRUB_SETUP_BIOS { +#ifdef GRUB_SETUP_BIOS char *tmp_img; grub_uint8_t *boot_drive_check; @@ -398,6 +392,7 @@ SETUP (const char *dir, boot_drive_check[0] = 0x90; boot_drive_check[1] = 0x90; } +#endif struct identify_partmap_ctx ctx = { .dest_partmap = NULL, @@ -413,6 +408,7 @@ SETUP (const char *dir, grub_partition_iterate (dest_dev->disk, identify_partmap, &ctx); +#ifdef GRUB_SETUP_BIOS /* Copy the partition table. */ if (ctx.dest_partmap || (!allow_floppy && !grub_util_biosdisk_is_floppy (dest_dev->disk))) @@ -421,6 +417,7 @@ SETUP (const char *dir, GRUB_BOOT_MACHINE_PART_END - GRUB_BOOT_MACHINE_WINDOWS_NT_MAGIC); free (tmp_img); +#endif if (ctx.container && grub_strcmp (ctx.container->partmap->name, "msdos") == 0 @@ -508,10 +505,22 @@ SETUP (const char *dir, else maxsec = core_sectors; +#ifdef GRUB_SETUP_BIOS if (maxsec > ((0x78000 - GRUB_KERNEL_I386_PC_LINK_ADDR) >> GRUB_DISK_SECTOR_BITS)) maxsec = ((0x78000 - GRUB_KERNEL_I386_PC_LINK_ADDR) >> GRUB_DISK_SECTOR_BITS); +#endif + +#ifdef GRUB_SETUP_SPARC64 + /* + * On SPARC we need two extra. One is because we are combining the + * core.img with the boot.img. The other is because the boot sector + * starts at 1. + */ + nsec += 2; + maxsec += 2; +#endif if (is_ldm) err = grub_util_ldm_embed (dest_dev->disk, &nsec, maxsec, @@ -560,9 +569,39 @@ SETUP (const char *dir, bl.block--; bl.block->start = 0; bl.block->len = 0; +#ifdef GRUB_SETUP_BIOS bl.block->segment = 0; +#endif +#ifdef GRUB_SETUP_SPARC64 + { + /* + * On SPARC, the block-list entries need to be based off the beginning + * of the parition, not the beginning of the disk. + */ + struct grub_boot_blocklist *block; + block = bl.first_block; + + while (block->len) + { + block->start -= bl.first_sector; + block--; + } + } + + /* + * Reserve space for the boot block since it can not be in the + * Parition table on SPARC. + */ + assert (bl.first_block->len > 2); + bl.first_block->start += 2; + bl.first_block->len -= 2; + write_rootdev (root_dev, boot_img, sectors[BOOT_SECTOR + 1] - bl.first_sector); +#endif + +#ifdef GRUB_SETUP_BIOS write_rootdev (root_dev, boot_img, bl.first_sector); +#endif /* Round up to the nearest sector boundary, and zero the extra memory */ core_img = xrealloc (core_img, nsec * GRUB_DISK_SECTOR_SIZE); @@ -572,7 +611,7 @@ SETUP (const char *dir, bl.first_block = (struct grub_boot_blocklist *) (core_img + GRUB_DISK_SECTOR_SIZE - sizeof (*bl.block)); - +#if GRUB_SETUP_BIOS grub_size_t no_rs_length; no_rs_length = grub_target_to_host16 (grub_get_unaligned16 (core_img @@ -603,14 +642,34 @@ SETUP (const char *dir, grub_disk_write (dest_dev->disk, sectors[i], 0, GRUB_DISK_SECTOR_SIZE, core_img + i * GRUB_DISK_SECTOR_SIZE); +#endif +#ifdef GRUB_SETUP_SPARC64 + { + int isec = BOOT_SECTOR; + + /* Write the boot image onto the disk. */ + if (grub_disk_write (dest_dev->disk, sectors[isec++], 0, + GRUB_DISK_SECTOR_SIZE, boot_img)) + grub_util_error ("%s", grub_errmsg); + + /* Write the core image onto the disk. */ + for (i = 0 ; isec < nsec; i++, isec++) + { + if (grub_disk_write (dest_dev->disk, sectors[isec], 0, + GRUB_DISK_SECTOR_SIZE, + core_img + i * GRUB_DISK_SECTOR_SIZE)) + grub_util_error ("%s", grub_errmsg); + } + } + +#endif grub_free (sectors); goto finish; } unable_to_embed: -#endif if (dest_dev->disk->dev->id != root_dev->disk->dev->id) grub_util_error ("%s", _("embedding is not possible, but this is required for " @@ -799,6 +858,10 @@ unable_to_embed: 0, GRUB_DISK_SECTOR_SIZE, boot_img)) grub_util_error ("%s", grub_errmsg); +#ifdef GRUB_SETUP_SPARC64 + finish: +#endif + grub_util_biosdisk_flush (root_dev->disk); grub_util_biosdisk_flush (dest_dev->disk);