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 <eric.snowberg@oracle.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
This commit is contained in:
Eric Snowberg 2019-03-04 17:34:01 -08:00 committed by Vincent Batts
parent a492f4ebdb
commit 927267be58

View file

@ -205,7 +205,6 @@ save_blocklists (grub_disk_addr_t sector, unsigned offset, unsigned length,
#endif #endif
} }
#ifdef GRUB_SETUP_BIOS
/* Context for setup/identify_partmap. */ /* Context for setup/identify_partmap. */
struct identify_partmap_ctx struct identify_partmap_ctx
{ {
@ -241,7 +240,6 @@ identify_partmap (grub_disk_t disk __attribute__ ((unused)),
ctx->multiple_partmaps = 1; ctx->multiple_partmaps = 1;
return 1; return 1;
} }
#endif
#ifdef GRUB_SETUP_BIOS #ifdef GRUB_SETUP_BIOS
#define SETUP grub_util_bios_setup #define SETUP grub_util_bios_setup
@ -262,9 +260,7 @@ SETUP (const char *dir,
char *boot_img, *core_img, *boot_path; char *boot_img, *core_img, *boot_path;
char *root = 0; char *root = 0;
size_t boot_size, core_size; size_t boot_size, core_size;
#ifdef GRUB_SETUP_BIOS
grub_uint16_t core_sectors; grub_uint16_t core_sectors;
#endif
grub_device_t root_dev = 0, dest_dev, core_dev; grub_device_t root_dev = 0, dest_dev, core_dev;
grub_util_fd_t fp; grub_util_fd_t fp;
struct blocklists bl; struct blocklists bl;
@ -288,10 +284,8 @@ SETUP (const char *dir,
core_path = grub_util_get_path (dir, core_file); core_path = grub_util_get_path (dir, core_file);
core_size = grub_util_get_image_size (core_path); core_size = grub_util_get_image_size (core_path);
#ifdef GRUB_SETUP_BIOS
core_sectors = ((core_size + GRUB_DISK_SECTOR_SIZE - 1) core_sectors = ((core_size + GRUB_DISK_SECTOR_SIZE - 1)
>> GRUB_DISK_SECTOR_BITS); >> GRUB_DISK_SECTOR_BITS);
#endif
if (core_size < GRUB_DISK_SECTOR_SIZE) if (core_size < GRUB_DISK_SECTOR_SIZE)
grub_util_error (_("the size of `%s' is too small"), core_path); grub_util_error (_("the size of `%s' is too small"), core_path);
#ifdef GRUB_SETUP_BIOS #ifdef GRUB_SETUP_BIOS
@ -372,8 +366,8 @@ SETUP (const char *dir,
if (grub_env_set ("root", root) != GRUB_ERR_NONE) if (grub_env_set ("root", root) != GRUB_ERR_NONE)
grub_util_error ("%s", grub_errmsg); grub_util_error ("%s", grub_errmsg);
#ifdef GRUB_SETUP_BIOS
{ {
#ifdef GRUB_SETUP_BIOS
char *tmp_img; char *tmp_img;
grub_uint8_t *boot_drive_check; grub_uint8_t *boot_drive_check;
@ -398,6 +392,7 @@ SETUP (const char *dir,
boot_drive_check[0] = 0x90; boot_drive_check[0] = 0x90;
boot_drive_check[1] = 0x90; boot_drive_check[1] = 0x90;
} }
#endif
struct identify_partmap_ctx ctx = { struct identify_partmap_ctx ctx = {
.dest_partmap = NULL, .dest_partmap = NULL,
@ -413,6 +408,7 @@ SETUP (const char *dir,
grub_partition_iterate (dest_dev->disk, identify_partmap, &ctx); grub_partition_iterate (dest_dev->disk, identify_partmap, &ctx);
#ifdef GRUB_SETUP_BIOS
/* Copy the partition table. */ /* Copy the partition table. */
if (ctx.dest_partmap || if (ctx.dest_partmap ||
(!allow_floppy && !grub_util_biosdisk_is_floppy (dest_dev->disk))) (!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); GRUB_BOOT_MACHINE_PART_END - GRUB_BOOT_MACHINE_WINDOWS_NT_MAGIC);
free (tmp_img); free (tmp_img);
#endif
if (ctx.container if (ctx.container
&& grub_strcmp (ctx.container->partmap->name, "msdos") == 0 && grub_strcmp (ctx.container->partmap->name, "msdos") == 0
@ -508,10 +505,22 @@ SETUP (const char *dir,
else else
maxsec = core_sectors; maxsec = core_sectors;
#ifdef GRUB_SETUP_BIOS
if (maxsec > ((0x78000 - GRUB_KERNEL_I386_PC_LINK_ADDR) if (maxsec > ((0x78000 - GRUB_KERNEL_I386_PC_LINK_ADDR)
>> GRUB_DISK_SECTOR_BITS)) >> GRUB_DISK_SECTOR_BITS))
maxsec = ((0x78000 - GRUB_KERNEL_I386_PC_LINK_ADDR) maxsec = ((0x78000 - GRUB_KERNEL_I386_PC_LINK_ADDR)
>> GRUB_DISK_SECTOR_BITS); >> 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) if (is_ldm)
err = grub_util_ldm_embed (dest_dev->disk, &nsec, maxsec, err = grub_util_ldm_embed (dest_dev->disk, &nsec, maxsec,
@ -560,9 +569,39 @@ SETUP (const char *dir,
bl.block--; bl.block--;
bl.block->start = 0; bl.block->start = 0;
bl.block->len = 0; bl.block->len = 0;
#ifdef GRUB_SETUP_BIOS
bl.block->segment = 0; 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); write_rootdev (root_dev, boot_img, bl.first_sector);
#endif
/* Round up to the nearest sector boundary, and zero the extra memory */ /* Round up to the nearest sector boundary, and zero the extra memory */
core_img = xrealloc (core_img, nsec * GRUB_DISK_SECTOR_SIZE); 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 bl.first_block = (struct grub_boot_blocklist *) (core_img
+ GRUB_DISK_SECTOR_SIZE + GRUB_DISK_SECTOR_SIZE
- sizeof (*bl.block)); - sizeof (*bl.block));
#if GRUB_SETUP_BIOS
grub_size_t no_rs_length; grub_size_t no_rs_length;
no_rs_length = grub_target_to_host16 no_rs_length = grub_target_to_host16
(grub_get_unaligned16 (core_img (grub_get_unaligned16 (core_img
@ -603,14 +642,34 @@ SETUP (const char *dir,
grub_disk_write (dest_dev->disk, sectors[i], 0, grub_disk_write (dest_dev->disk, sectors[i], 0,
GRUB_DISK_SECTOR_SIZE, GRUB_DISK_SECTOR_SIZE,
core_img + i * 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); grub_free (sectors);
goto finish; goto finish;
} }
unable_to_embed: unable_to_embed:
#endif
if (dest_dev->disk->dev->id != root_dev->disk->dev->id) if (dest_dev->disk->dev->id != root_dev->disk->dev->id)
grub_util_error ("%s", _("embedding is not possible, but this is required for " 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)) 0, GRUB_DISK_SECTOR_SIZE, boot_img))
grub_util_error ("%s", grub_errmsg); grub_util_error ("%s", grub_errmsg);
#ifdef GRUB_SETUP_SPARC64
finish:
#endif
grub_util_biosdisk_flush (root_dev->disk); grub_util_biosdisk_flush (root_dev->disk);
grub_util_biosdisk_flush (dest_dev->disk); grub_util_biosdisk_flush (dest_dev->disk);