summaryrefslogtreecommitdiff
path: root/usr/src/cmd/boot/installgrub/installgrub.c
diff options
context:
space:
mode:
authorHans Rosenfeld <hans.rosenfeld@nexenta.com>2015-01-10 21:16:37 +0100
committerGordon Ross <gwr@nexenta.com>2015-02-20 18:00:32 -0500
commit1a902ef8628b0dffd6df5442354ab59bb8530962 (patch)
treea8f20055af62687834f7818a81d4ebbdf6eb881d /usr/src/cmd/boot/installgrub/installgrub.c
parent44bc9120699af80bb18366ca474cb2c618608ca9 (diff)
downloadillumos-joyent-1a902ef8628b0dffd6df5442354ab59bb8530962.tar.gz
5561 support root pools on EFI/GPT partitioned disks
5125 update zpool/libzfs to manage bootable whole disk pools (EFI/GPT labeled disks) Reviewed by: Jean McCormack <jean.mccormack@nexenta.com> Reviewed by: Josef 'Jeff' Sipek <josef.sipek@nexenta.com> Approved by: Dan McDonald <danmcd@omniti.com>
Diffstat (limited to 'usr/src/cmd/boot/installgrub/installgrub.c')
-rw-r--r--usr/src/cmd/boot/installgrub/installgrub.c74
1 files changed, 60 insertions, 14 deletions
diff --git a/usr/src/cmd/boot/installgrub/installgrub.c b/usr/src/cmd/boot/installgrub/installgrub.c
index c27dca802b..4d29d0236e 100644
--- a/usr/src/cmd/boot/installgrub/installgrub.c
+++ b/usr/src/cmd/boot/installgrub/installgrub.c
@@ -21,7 +21,7 @@
/*
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright 2012 Milan Jurik. All rights reserved.
- * Copyright 2012 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
*/
#include <stdio.h>
@@ -48,6 +48,10 @@
#include <sys/stat.h>
#include <sys/multiboot.h>
#include <sys/sysmacros.h>
+#include <sys/efi_partition.h>
+
+#include <libnvpair.h>
+#include <libfstyp.h>
#include "message.h"
#include "installgrub.h"
@@ -107,7 +111,7 @@ static void usage(char *);
static int read_stage1_from_file(char *, ig_data_t *);
static int read_stage2_from_file(char *, ig_data_t *);
static int read_stage1_from_disk(int, char *);
-static int read_stage2_from_disk(int, ig_stage2_t *);
+static int read_stage2_from_disk(int, ig_stage2_t *, int);
static int prepare_stage1(ig_data_t *);
static int prepare_stage2(ig_data_t *, char *);
static void prepare_fake_multiboot(ig_stage2_t *);
@@ -389,7 +393,7 @@ handle_getinfo(char *progname, char **argv)
goto out_dev;
}
- ret = read_stage2_from_disk(device->part_fd, stage2);
+ ret = read_stage2_from_disk(device->part_fd, stage2, device->type);
if (ret == BC_ERROR) {
(void) fprintf(stderr, gettext("Error reading stage2 from "
"%s\n"), device_path);
@@ -487,7 +491,8 @@ handle_mirror(char *progname, char **argv)
goto out_devs;
}
- ret = read_stage2_from_disk(curr_device->part_fd, stage2_curr);
+ ret = read_stage2_from_disk(curr_device->part_fd, stage2_curr,
+ curr_device->type);
if (ret == BC_ERROR) {
BOOT_DEBUG("Error reading first stage2 blocks from %s\n",
curr_device->path);
@@ -623,6 +628,10 @@ propagate_bootblock(ig_data_t *source, ig_data_t *target, char *updt_str)
static int
init_device(ig_device_t *device, char *path)
{
+ struct dk_gpt *vtoc;
+ fstyp_handle_t fhdl;
+ const char *fident;
+
bzero(device, sizeof (*device));
device->part_fd = -1;
device->disk_fd = -1;
@@ -655,9 +664,25 @@ init_device(ig_device_t *device, char *path)
return (BC_ERROR);
}
+ if (efi_alloc_and_read(device->disk_fd, &vtoc) > 0) {
+ device->type = IG_DEV_EFI;
+ efi_free(vtoc);
+ }
+
if (get_raw_partition_fd(device) != BC_SUCCESS)
return (BC_ERROR);
+ if (fstyp_init(device->part_fd, 0, NULL, &fhdl) != 0)
+ return (BC_ERROR);
+
+ if (fstyp_ident(fhdl, "zfs", &fident) != 0) {
+ fstyp_fini(fhdl);
+ (void) fprintf(stderr, gettext("Booting of EFI labeled disks "
+ "is only supported with ZFS\n"));
+ return (BC_ERROR);
+ }
+ fstyp_fini(fhdl);
+
if (get_start_sector(device) != BC_SUCCESS)
return (BC_ERROR);
@@ -701,6 +726,21 @@ get_start_sector(ig_device_t *device)
struct part_info dkpi;
struct extpart_info edkpi;
+ if (is_efi(device->type)) {
+ struct dk_gpt *vtoc;
+
+ if (efi_alloc_and_read(device->disk_fd, &vtoc) <= 0)
+ return (BC_ERROR);
+
+ device->start_sector = vtoc->efi_parts[device->slice].p_start;
+ /* GPT doesn't use traditional slice letters */
+ device->slice = 0xff;
+ device->partition = 0;
+
+ efi_free(vtoc);
+ goto found_part;
+ }
+
mboot = (struct mboot *)device->boot_sector;
if (is_bootpar(device->type)) {
@@ -959,7 +999,8 @@ write_stage2(ig_data_t *install)
* Note that we use stage2->buf rather than stage2->file, because we
* may have extended information after the latter.
*/
- offset = STAGE2_BLKOFF * SECTOR_SIZE;
+ offset = STAGE2_BLKOFF(device->type) * SECTOR_SIZE;
+
if (write_out(device->part_fd, stage2->buf, stage2->buf_size,
offset) != BC_SUCCESS) {
perror("write");
@@ -968,7 +1009,7 @@ write_stage2(ig_data_t *install)
/* Simulate the "old" installgrub output. */
(void) fprintf(stdout, WRITE_STAGE2_DISK, device->partition,
- (stage2->buf_size / SECTOR_SIZE) + 1, STAGE2_BLKOFF,
+ (stage2->buf_size / SECTOR_SIZE) + 1, STAGE2_BLKOFF(device->type),
stage2->first_sector);
return (BC_SUCCESS);
@@ -1162,7 +1203,7 @@ read_stage1_from_disk(int dev_fd, char *stage1_buf)
}
static int
-read_stage2_from_disk(int dev_fd, ig_stage2_t *stage2)
+read_stage2_from_disk(int dev_fd, ig_stage2_t *stage2, int type)
{
uint32_t size;
uint32_t buf_size;
@@ -1173,7 +1214,7 @@ read_stage2_from_disk(int dev_fd, ig_stage2_t *stage2)
assert(dev_fd != -1);
if (read_in(dev_fd, mboot_scan, sizeof (mboot_scan),
- STAGE2_BLKOFF * SECTOR_SIZE) != BC_SUCCESS) {
+ STAGE2_BLKOFF(type) * SECTOR_SIZE) != BC_SUCCESS) {
perror(gettext("Error reading stage2 sectors"));
return (BC_ERROR);
}
@@ -1209,7 +1250,7 @@ read_stage2_from_disk(int dev_fd, ig_stage2_t *stage2)
}
stage2->buf_size = buf_size;
- if (read_in(dev_fd, stage2->buf, buf_size, STAGE2_BLKOFF *
+ if (read_in(dev_fd, stage2->buf, buf_size, STAGE2_BLKOFF(type) *
SECTOR_SIZE) != BC_SUCCESS) {
perror("read");
free(stage2->buf);
@@ -1243,7 +1284,8 @@ is_update_necessary(ig_data_t *data, char *updt_str)
bzero(&stage2_disk, sizeof (ig_stage2_t));
/* Gather stage2 (if present) from the target device. */
- if (read_stage2_from_disk(dev_fd, &stage2_disk) != BC_SUCCESS) {
+ if (read_stage2_from_disk(dev_fd, &stage2_disk, device->type)
+ != BC_SUCCESS) {
BOOT_DEBUG("Unable to read stage2 from %s\n", device->path);
BOOT_DEBUG("No multiboot wrapped stage2 on %s\n", device->path);
return (B_TRUE);
@@ -1367,7 +1409,8 @@ prepare_stage2(ig_data_t *install, char *updt_str)
}
} else {
/* Solaris VTOC */
- stage2->first_sector = device->start_sector + STAGE2_BLKOFF;
+ stage2->first_sector = device->start_sector +
+ STAGE2_BLKOFF(device->type);
BOOT_DEBUG("stage2 first sector: %d\n", stage2->first_sector);
/*
* In a solaris partition, stage2 is written to contiguous
@@ -1441,15 +1484,18 @@ get_raw_partition_path(ig_device_t *device)
}
len = strlen(raw);
- if (raw[len - 2] != 's' || raw[len - 1] == '2') {
+ if (!is_efi(device->type) &&
+ (raw[len - 2] != 's' || raw[len - 1] == '2')) {
(void) fprintf(stderr, NOT_ROOT_SLICE);
free(raw);
return (NULL);
}
device->slice = atoi(&raw[len - 1]);
- raw[len - 2] = 's';
- raw[len - 1] = '2';
+ if (!is_efi(device->type)) {
+ raw[len - 2] = 's';
+ raw[len - 1] = '2';
+ }
return (raw);
}