MFC: Add support for booting from GPT-labeled disks from the BIOS. This

includes /boot/pmbr, /boot/gptboot, and 'gpt boot'.
This commit is contained in:
jhb 2008-01-24 22:23:22 +00:00
parent 681ef96d1c
commit 2f930c2edb
12 changed files with 469 additions and 117 deletions

View File

@ -123,6 +123,10 @@ SRCS+= ashldi3.c ashrdi3.c
SRCS+= syncicache.c
.endif
# uuid functions from libc
.PATH: ${.CURDIR}/../libc/uuid
SRCS+= uuid_equal.c uuid_is_nil.c
# _setjmp/_longjmp
.if ${MACHINE_ARCH} == "amd64"
.PATH: ${.CURDIR}/i386

View File

@ -1,8 +1,8 @@
# $FreeBSD$
PROG= gpt
SRCS= add.c create.c destroy.c gpt.c label.c map.c migrate.c recover.c \
remove.c show.c
SRCS= add.c boot.c create.c destroy.c gpt.c label.c map.c migrate.c \
recover.c remove.c show.c
WARNS?= 4
MAN= gpt.8

View File

@ -39,9 +39,9 @@ __FBSDID("$FreeBSD$");
#include "map.h"
#include "gpt.h"
static uuid_t type;
static off_t block, size;
static unsigned int entry;
static uuid_t add_type;
static off_t add_block, add_size;
static unsigned int add_entry;
static void
usage_add(void)
@ -53,8 +53,8 @@ usage_add(void)
exit(1);
}
static void
add(int fd)
map_t *
gpt_add_part(int fd, uuid_t type, off_t start, off_t size, unsigned int *entry)
{
map_t *gpt, *tpg;
map_t *tbl, *lbt;
@ -67,38 +67,38 @@ add(int fd)
if (gpt == NULL) {
warnx("%s: error: no primary GPT header; run create or recover",
device_name);
return;
return (NULL);
}
tpg = map_find(MAP_TYPE_SEC_GPT_HDR);
if (tpg == NULL) {
warnx("%s: error: no secondary GPT header; run recover",
device_name);
return;
return (NULL);
}
tbl = map_find(MAP_TYPE_PRI_GPT_TBL);
lbt = map_find(MAP_TYPE_SEC_GPT_TBL);
if (tbl == NULL || lbt == NULL) {
warnx("%s: error: run recover -- trust me", device_name);
return;
return (NULL);
}
hdr = gpt->map_data;
if (entry > le32toh(hdr->hdr_entries)) {
if (*entry > le32toh(hdr->hdr_entries)) {
warnx("%s: error: index %u out of range (%u max)", device_name,
entry, le32toh(hdr->hdr_entries));
return;
*entry, le32toh(hdr->hdr_entries));
return (NULL);
}
if (entry > 0) {
i = entry - 1;
if (*entry > 0) {
i = *entry - 1;
ent = (void*)((char*)tbl->map_data + i *
le32toh(hdr->hdr_entsz));
if (!uuid_is_nil(&ent->ent_type, NULL)) {
warnx("%s: error: entry at index %u is not free",
device_name, entry);
return;
device_name, *entry);
return (NULL);
}
} else {
/* Find empty slot in GPT table. */
@ -111,14 +111,14 @@ add(int fd)
if (i == le32toh(hdr->hdr_entries)) {
warnx("%s: error: no available table entries",
device_name);
return;
return (NULL);
}
}
map = map_alloc(block, size);
map = map_alloc(start, size);
if (map == NULL) {
warnx("%s: error: no space available on device", device_name);
return;
return (NULL);
}
le_uuid_enc(&ent->ent_type, &type);
@ -148,7 +148,19 @@ add(int fd)
gpt_write(fd, lbt);
gpt_write(fd, tpg);
printf("%sp%u added\n", device_name, i + 1);
*entry = i + 1;
return (map);
}
static void
add(int fd)
{
if (gpt_add_part(fd, add_type, add_block, add_size, &add_entry) != 0)
return;
printf("%sp%u added\n", device_name, add_entry);
}
int
@ -161,30 +173,30 @@ cmd_add(int argc, char *argv[])
while ((ch = getopt(argc, argv, "b:i:s:t:")) != -1) {
switch(ch) {
case 'b':
if (block > 0)
if (add_block > 0)
usage_add();
block = strtoll(optarg, &p, 10);
if (*p != 0 || block < 1)
add_block = strtoll(optarg, &p, 10);
if (*p != 0 || add_block < 1)
usage_add();
break;
case 'i':
if (entry > 0)
if (add_entry > 0)
usage_add();
entry = strtol(optarg, &p, 10);
if (*p != 0 || entry < 1)
add_entry = strtol(optarg, &p, 10);
if (*p != 0 || add_entry < 1)
usage_add();
break;
case 's':
if (size > 0)
if (add_size > 0)
usage_add();
size = strtoll(optarg, &p, 10);
if (*p != 0 || size < 1)
add_size = strtoll(optarg, &p, 10);
if (*p != 0 || add_size < 1)
usage_add();
break;
case 't':
if (!uuid_is_nil(&type, NULL))
if (!uuid_is_nil(&add_type, NULL))
usage_add();
if (parse_uuid(optarg, &type) != 0)
if (parse_uuid(optarg, &add_type) != 0)
usage_add();
break;
default:
@ -196,9 +208,9 @@ cmd_add(int argc, char *argv[])
usage_add();
/* Create UFS partitions by default. */
if (uuid_is_nil(&type, NULL)) {
if (uuid_is_nil(&add_type, NULL)) {
uuid_t ufs = GPT_ENT_TYPE_FREEBSD_UFS;
type = ufs;
add_type = ufs;
}
while (optind < argc) {

View File

@ -24,7 +24,7 @@
.\"
.\" $FreeBSD$
.\"
.Dd June 22, 2006
.Dd October 24, 2007
.Os
.Dt GPT 8
.Sh NAME
@ -130,10 +130,51 @@ option allows the user to specify the partition type.
The type is given as an UUID, but
.Nm
accepts
.Cm efi , swap , ufs , hfs , linux
.Cm boot , efi , swap , ufs , hfs , linux
and
.Cm windows
as aliases for the most commonly used partition types.
.\" ==== boot ====
.It Xo
.Nm
.Ic boot
.Op Fl b Ar pmbr
.Op Fl g Ar gptboot
.Op Fl s Ar count
.Ar device ...
.Xc
The
.Ic boot
command allows the user to make a GPT labeled disk bootable via the BIOS
bootstrap on i386 and amd64 machines.
By default,
the
.Pa /boot/pmbr
boot loader is installed into the PMBR and the
.Pa /boot/gptboot
boot loader is installed into the first boot partition.
If no boot partition exists and there is available space,
a boot partition will be created.
.Pp
The
.Fl b Ar pmbr
option allows the user to specify an alternate path for the PMBR boot loader.
.Pp
The
.Fl g Ar gptboot
option allows the user to specify an alternate path for the GPT boot loader
that is installed into the boot partition.
.Pp
The
.Fl s Ar count
option allows the user to specify the size in sectors of the boot partition
if one does not already exist.
A boot partition must be at least 16 kilobytes.
By default,
a size of 64 kilobytes is used.
Note that the PMBR boot loader will load the entire boot partition into
memory.
As a result, the boot partition may not exceed 545 kilobytes.
.\" ==== create ====
.It Nm Ic create Oo Fl fp Oc Ar device ...
The

View File

@ -615,6 +615,7 @@ static struct {
const char *name;
} cmdsw[] = {
{ cmd_add, "add" },
{ cmd_boot, "boot" },
{ cmd_create, "create" },
{ cmd_destroy, "destroy" },
{ NULL, "help" },

View File

@ -67,6 +67,7 @@ extern u_int secsz;
extern int readonly, verbose;
uint32_t crc32(const void *, size_t);
map_t *gpt_add_part(int, uuid_t, off_t, off_t, unsigned int *);
void gpt_close(int);
int gpt_open(const char *);
void* gpt_read(int, off_t, size_t);
@ -76,6 +77,7 @@ uint8_t *utf16_to_utf8(uint16_t *);
void utf8_to_utf16(const uint8_t *, uint16_t *, size_t);
int cmd_add(int, char *[]);
int cmd_boot(int, char *[]);
int cmd_create(int, char *[]);
int cmd_destroy(int, char *[]);
int cmd_label(int, char *[]);

View File

@ -54,6 +54,7 @@ usage_show(void)
static const char *
friendly(uuid_t *t)
{
static uuid_t boot = GPT_ENT_TYPE_FREEBSD_BOOT;
static uuid_t efi_slice = GPT_ENT_TYPE_EFI;
static uuid_t mslinux = GPT_ENT_TYPE_MS_BASIC_DATA;
static uuid_t freebsd = GPT_ENT_TYPE_FREEBSD;
@ -71,6 +72,8 @@ friendly(uuid_t *t)
if (uuid_equal(t, &efi_slice, NULL))
return ("EFI System");
if (uuid_equal(t, &boot, NULL))
return ("FreeBSD boot");
if (uuid_equal(t, &swap, NULL))
return ("FreeBSD swap");
if (uuid_equal(t, &ufs, NULL))

View File

@ -1,6 +1,7 @@
# $FreeBSD$
SUBDIR= mbr boot0 boot0sio btx boot2 cdboot kgzldr libi386 loader
SUBDIR= mbr pmbr boot0 boot0sio btx boot2 cdboot gptboot kgzldr \
libi386 loader
# special boot programs, 'self-extracting boot2+loader'
SUBDIR+= pxeldr

View File

@ -41,9 +41,11 @@ __FBSDID("$FreeBSD$");
#include <sys/disklabel.h>
#include <sys/diskmbr.h>
#include <sys/gpt.h>
#include <machine/bootinfo.h>
#include <stdarg.h>
#include <uuid.h>
#include <bootstrap.h>
#include <btxv86.h>
@ -66,6 +68,13 @@ __FBSDID("$FreeBSD$");
# define DEBUG(fmt, args...)
#endif
struct gpt_part {
int gp_index;
uuid_t gp_type;
uint64_t gp_start;
uint64_t gp_end;
};
struct open_disk {
int od_dkunit; /* disk unit number */
int od_unit; /* BIOS unit number */
@ -81,11 +90,26 @@ struct open_disk {
#define BD_FLOPPY 0x0004
#define BD_LABELOK 0x0008
#define BD_PARTTABOK 0x0010
struct disklabel od_disklabel;
int od_nslices; /* slice count */
struct dos_partition od_slicetab[NEXTDOSPART];
#define BD_GPTOK 0x0020
union {
struct {
struct disklabel mbr_disklabel;
int mbr_nslices; /* slice count */
struct dos_partition mbr_slicetab[NEXTDOSPART];
} _mbr;
struct {
int gpt_nparts;
struct gpt_part *gpt_partitions;
} _gpt;
} _data;
};
#define od_disklabel _data._mbr.mbr_disklabel
#define od_nslices _data._mbr.mbr_nslices
#define od_slicetab _data._mbr.mbr_slicetab
#define od_nparts _data._gpt.gpt_nparts
#define od_partitions _data._gpt.gpt_partitions
/*
* List of BIOS devices, translation from disk unit number to
* BIOS unit number.
@ -106,6 +130,8 @@ static int bd_write(struct open_disk *od, daddr_t dblk, int blks,
static int bd_int13probe(struct bdinfo *bd);
static void bd_printgptpart(struct open_disk *od, struct gpt_part *gp,
char *prefix, int verbose);
static void bd_printslice(struct open_disk *od, struct dos_partition *dp,
char *prefix, int verbose);
static void bd_printbsdslice(struct open_disk *od, daddr_t offset,
@ -134,8 +160,11 @@ struct devsw biosdisk = {
static int bd_opendisk(struct open_disk **odp, struct i386_devdesc *dev);
static void bd_closedisk(struct open_disk *od);
static int bd_open_mbr(struct open_disk *od, struct i386_devdesc *dev);
static int bd_bestslice(struct open_disk *od);
static void bd_checkextended(struct open_disk *od, int slicenum);
static int bd_open_gpt(struct open_disk *od, struct i386_devdesc *dev);
static struct gpt_part *bd_best_gptpart(struct open_disk *od);
/*
* Translate between BIOS device numbers and our private unit numbers.
@ -257,8 +286,16 @@ bd_print(int verbose)
if (!bd_opendisk(&od, &dev)) {
/* Do we have a GPT table? */
if (od->od_flags & BD_GPTOK) {
for (j = 0; j < od->od_nparts; j++) {
sprintf(line, " disk%dp%d", i,
od->od_partitions[j].gp_index);
bd_printgptpart(od, &od->od_partitions[j], line, verbose);
}
/* Do we have a partition table? */
if (od->od_flags & BD_PARTTABOK) {
} else if (od->od_flags & BD_PARTTABOK) {
dptr = &od->od_slicetab[0];
/* Check for a "dedicated" disk */
@ -279,6 +316,56 @@ bd_print(int verbose)
}
}
static uuid_t efi = GPT_ENT_TYPE_EFI;
static uuid_t freebsd_boot = GPT_ENT_TYPE_FREEBSD_BOOT;
static uuid_t freebsd_ufs = GPT_ENT_TYPE_FREEBSD_UFS;
static uuid_t freebsd_swap = GPT_ENT_TYPE_FREEBSD_SWAP;
static uuid_t ms_basic_data = GPT_ENT_TYPE_MS_BASIC_DATA;
static void
bd_printgptpart(struct open_disk *od, struct gpt_part *gp, char *prefix,
int verbose)
{
char stats[80];
char line[96];
uint64_t size;
char unit;
if (verbose) {
size = (gp->gp_end + 1 - gp->gp_start) / 2048;
unit = 'M';
if (size >= 10240000) {
size /= 1048576;
unit = 'T';
} else if (size >= 10000) {
size /= 1024;
unit = 'G';
}
sprintf(stats, " %.6ld%cB", (long)size, unit);
} else
stats[0] = '\0';
if (uuid_equal(&gp->gp_type, &efi, NULL))
sprintf(line, "%s: EFI%s\n", prefix, stats);
else if (uuid_equal(&gp->gp_type, &ms_basic_data, NULL))
sprintf(line, "%s: FAT/NTFS%s\n", prefix, stats);
else if (uuid_equal(&gp->gp_type, &freebsd_boot, NULL))
sprintf(line, "%s: FreeBSD boot%s\n", prefix, stats);
else if (uuid_equal(&gp->gp_type, &freebsd_ufs, NULL))
sprintf(line, "%s: FreeBSD UFS%s\n", prefix, stats);
else if (uuid_equal(&gp->gp_type, &freebsd_swap, NULL))
sprintf(line, "%s: FreeBSD swap%s\n", prefix, stats);
else
sprintf(line, "%s: %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x%s\n",
gp->gp_type.time_low, gp->gp_type.time_mid,
gp->gp_type.time_hi_and_version,
gp->gp_type.clock_seq_hi_and_reserved, gp->gp_type.clock_seq_low,
gp->gp_type.node[0], gp->gp_type.node[1], gp->gp_type.node[2],
gp->gp_type.node[3], gp->gp_type.node[4], gp->gp_type.node[5],
stats);
pager_output(line);
}
/*
* Print information about slices on a disk. For the size calculations we
* assume a 512 byte sector.
@ -447,12 +534,8 @@ bd_open(struct open_file *f, ...)
static int
bd_opendisk(struct open_disk **odp, struct i386_devdesc *dev)
{
struct dos_partition *dptr;
struct disklabel *lp;
struct open_disk *od;
int sector, slice, i;
int error;
char buf[BUFSIZE];
if (dev->d_kind.biosdisk.unit >= nbdinfo) {
DEBUG("attempt to open nonexistent disk");
@ -470,11 +553,10 @@ bd_opendisk(struct open_disk **odp, struct i386_devdesc *dev)
od->od_unit = bdinfo[od->od_dkunit].bd_unit;
od->od_flags = bdinfo[od->od_dkunit].bd_flags;
od->od_boff = 0;
od->od_nslices = 0;
error = 0;
DEBUG("open '%s', unit 0x%x slice %d partition %c",
DEBUG("open '%s', unit 0x%x slice %d partition %d",
i386_fmtdev(dev), dev->d_kind.biosdisk.unit,
dev->d_kind.biosdisk.slice, dev->d_kind.biosdisk.partition + 'a');
dev->d_kind.biosdisk.slice, dev->d_kind.biosdisk.partition);
/* Get geometry for this open (removable device may have changed) */
if (bd_getgeom(od)) {
@ -483,6 +565,29 @@ bd_opendisk(struct open_disk **odp, struct i386_devdesc *dev)
goto out;
}
/* Determine disk layout. */
error = bd_open_gpt(od, dev);
if (error)
error = bd_open_mbr(od, dev);
out:
if (error) {
free(od);
} else {
*odp = od; /* return the open disk */
}
return(error);
}
static int
bd_open_mbr(struct open_disk *od, struct i386_devdesc *dev)
{
struct dos_partition *dptr;
struct disklabel *lp;
int sector, slice, i;
int error;
char buf[BUFSIZE];
/*
* Following calculations attempt to determine the correct value
* for d->od_boff by looking for the slice and partition specified,
@ -492,10 +597,10 @@ bd_opendisk(struct open_disk **odp, struct i386_devdesc *dev)
/*
* Find the slice in the DOS slice table.
*/
od->od_nslices = 0;
if (bd_read(od, 0, 1, buf)) {
DEBUG("error reading MBR");
error = EIO;
goto out;
return (EIO);
}
/*
@ -505,8 +610,7 @@ bd_opendisk(struct open_disk **odp, struct i386_devdesc *dev)
/* If a slice number was explicitly supplied, this is an error */
if (dev->d_kind.biosdisk.slice > 0) {
DEBUG("no slice table/MBR (no magic)");
error = ENOENT;
goto out;
return (ENOENT);
}
sector = 0;
goto unsliced; /* may be a floppy */
@ -536,8 +640,7 @@ bd_opendisk(struct open_disk **odp, struct i386_devdesc *dev)
slice = dev->d_kind.biosdisk.slice - 1;
if (slice >= od->od_nslices) {
DEBUG("slice %d not found", slice);
error = ENOENT;
goto out;
return (ENOENT);
}
}
@ -555,8 +658,7 @@ bd_opendisk(struct open_disk **odp, struct i386_devdesc *dev)
if (dev->d_kind.biosdisk.slice == 0) {
slice = bd_bestslice(od);
if (slice == -1) {
error = ENOENT;
goto out;
return (ENOENT);
}
dev->d_kind.biosdisk.slice = slice;
}
@ -590,8 +692,7 @@ bd_opendisk(struct open_disk **odp, struct i386_devdesc *dev)
if (bd_read(od, sector + LABELSECTOR, 1, buf)) {
DEBUG("error reading disklabel");
error = EIO;
goto out;
return (EIO);
}
DEBUG("copy %d bytes of label from %p to %p", sizeof(struct disklabel), buf + LABELOFFSET, &od->od_disklabel);
bcopy(buf + LABELOFFSET, &od->od_disklabel, sizeof(struct disklabel));
@ -600,15 +701,12 @@ bd_opendisk(struct open_disk **odp, struct i386_devdesc *dev)
if (lp->d_magic != DISKMAGIC) {
DEBUG("no disklabel");
error = ENOENT;
goto out;
return (ENOENT);
}
if (dev->d_kind.biosdisk.partition >= lp->d_npartitions) {
DEBUG("partition '%c' exceeds partitions in table (a-'%c')",
'a' + dev->d_kind.biosdisk.partition, 'a' + lp->d_npartitions);
error = EPART;
goto out;
return (EPART);
}
#ifdef DISK_DEBUG
@ -623,14 +721,7 @@ bd_opendisk(struct open_disk **odp, struct i386_devdesc *dev)
lp->d_partitions[RAW_PART].p_offset +
sector;
}
out:
if (error) {
free(od);
} else {
*odp = od; /* return the open disk */
}
return(error);
return (0);
}
static void
@ -739,7 +830,182 @@ bd_bestslice(struct open_disk *od)
}
return (prefslice);
}
static int
bd_open_gpt(struct open_disk *od, struct i386_devdesc *dev)
{
struct dos_partition *dp;
struct gpt_hdr *hdr;
struct gpt_ent *ent;
struct gpt_part *gp;
int entries_per_sec, error, i, part;
daddr_t lba, elba;
char gpt[BIOSDISK_SECSIZE], tbl[BIOSDISK_SECSIZE];
/*
* Following calculations attempt to determine the correct value
* for d->od_boff by looking for the slice and partition specified,
* or searching for reasonable defaults.
*/
error = 0;
/* First, read the MBR and see if we have a PMBR. */
if (bd_read(od, 0, 1, tbl)) {
DEBUG("error reading MBR");
return (EIO);
}
/* Check the slice table magic. */
if (((u_char)tbl[0x1fe] != 0x55) || ((u_char)tbl[0x1ff] != 0xaa))
return (ENXIO);
/* Check for GPT slice. */
part = 0;
dp = (struct dos_partition *)(tbl + DOSPARTOFF);
for (i = 0; i < NDOSPART; i++) {
if (dp[i].dp_typ == 0xee)
part++;
else if (dp[i].dp_typ != 0x00)
return (EINVAL);
}
if (part != 1)
return (EINVAL);
/* Read primary GPT table header. */
if (bd_read(od, 1, 1, gpt)) {
DEBUG("error reading GPT header");
return (EIO);
}
hdr = (struct gpt_hdr *)gpt;
if (bcmp(hdr->hdr_sig, GPT_HDR_SIG, sizeof(hdr->hdr_sig)) != 0 ||
hdr->hdr_lba_self != 1 || hdr->hdr_revision < 0x00010000 ||
hdr->hdr_entsz < sizeof(*ent) ||
BIOSDISK_SECSIZE % hdr->hdr_entsz != 0) {
DEBUG("Invalid GPT header\n");
return (EINVAL);
}
/* Now walk the partition table to count the number of valid partitions. */
part = 0;
entries_per_sec = BIOSDISK_SECSIZE / hdr->hdr_entsz;
elba = hdr->hdr_lba_table + hdr->hdr_entries / entries_per_sec;
for (lba = hdr->hdr_lba_table; lba < elba; lba++) {
if (bd_read(od, lba, 1, tbl)) {
DEBUG("error reading GPT table");
return (EIO);
}
for (i = 0; i < entries_per_sec; i++) {
ent = (struct gpt_ent *)(tbl + i * hdr->hdr_entsz);
if (uuid_is_nil(&ent->ent_type, NULL) || ent->ent_lba_start == 0 ||
ent->ent_lba_end < ent->ent_lba_start)
continue;
part++;
}
}
/* Save the important information about all the valid partitions. */
od->od_nparts = part;
if (part != 0) {
od->od_partitions = malloc(part * sizeof(struct gpt_part));
part = 0;
for (lba = hdr->hdr_lba_table; lba < elba; lba++) {
if (bd_read(od, lba, 1, tbl)) {
DEBUG("error reading GPT table");
error = EIO;
goto out;
}
for (i = 0; i < entries_per_sec; i++) {
ent = (struct gpt_ent *)(tbl + i * hdr->hdr_entsz);
if (uuid_is_nil(&ent->ent_type, NULL) ||
ent->ent_lba_start == 0 ||
ent->ent_lba_end < ent->ent_lba_start)
continue;
od->od_partitions[part].gp_index = (lba - hdr->hdr_lba_table) *
entries_per_sec + i + 1;
od->od_partitions[part].gp_type = ent->ent_type;
od->od_partitions[part].gp_start = ent->ent_lba_start;
od->od_partitions[part].gp_end = ent->ent_lba_end;
part++;
}
}
}
od->od_flags |= BD_GPTOK;
/* Is this a request for the whole disk? */
if (dev->d_kind.biosdisk.slice < 0) {
od->od_boff = 0;
return (0);
}
/*
* If a partition number was supplied, then the user is trying to use
* an MBR address rather than a GPT address, so fail.
*/
if (dev->d_kind.biosdisk.partition != 0xff) {
error = ENOENT;
goto out;
}
/* If a slice number was supplied but not found, this is an error. */
gp = NULL;
if (dev->d_kind.biosdisk.slice > 0) {
for (i = 0; i < od->od_nparts; i++) {
if (od->od_partitions[i].gp_index == dev->d_kind.biosdisk.slice) {
gp = &od->od_partitions[i];
break;
}
}
if (gp == NULL) {
DEBUG("partition %d not found", dev->d_kind.biosdisk.slice);
error = ENOENT;
goto out;
}
}
/* Try to auto-detect the best partition. */
if (dev->d_kind.biosdisk.slice == 0) {
gp = bd_best_gptpart(od);
if (gp == NULL) {
error = ENOENT;
goto out;
}
dev->d_kind.biosdisk.slice = gp->gp_index;
}
od->od_boff = gp->gp_start;
out:
if (error)
free(od->od_partitions);
return (error);
}
static struct gpt_part *
bd_best_gptpart(struct open_disk *od)
{
struct gpt_part *gp, *prefpart;
int i, pref, preflevel;
prefpart = NULL;
preflevel = PREF_NONE;
gp = od->od_partitions;
for (i = 0; i < od->od_nparts; i++, gp++) {
/* Windows. XXX: Also Linux. */
if (uuid_equal(&gp->gp_type, &ms_basic_data, NULL))
pref = PREF_DOS;
/* FreeBSD */
else if (uuid_equal(&gp->gp_type, &freebsd_ufs, NULL))
pref = PREF_FBSD;
else
pref = PREF_NONE;
if (pref < preflevel) {
preflevel = pref;
prefpart = gp;
}
}
return (prefpart);
}
static int
bd_close(struct open_file *f)
{
@ -758,6 +1024,8 @@ bd_closedisk(struct open_disk *od)
if (od->od_flags & BD_FLOPPY)
delay(3000000);
#endif
if (od->od_flags & BD_GPTOK)
free(od->od_partitions);
free(od);
}

View File

@ -120,21 +120,35 @@ i386_parsedev(struct i386_devdesc **dev, const char *devspec, const char **path)
err = EUNIT;
goto fail;
}
if (*cp == 's') { /* got a slice number */
if (*cp == 'p') { /* got a GPT partition */
np = cp + 1;
slice = strtol(np, &cp, 10);
if (cp == np) {
err = ESLICE;
goto fail;
}
}
if (*cp && (*cp != ':')) {
partition = *cp - 'a'; /* get a partition number */
if ((partition < 0) || (partition >= MAXPARTITIONS)) {
err = EPART;
if (*cp && (*cp != ':')) {
err = EINVAL;
goto fail;
}
cp++;
partition = 0xff;
} else {
if (*cp == 's') { /* got a slice number */
np = cp + 1;
slice = strtol(np, &cp, 10);
if (cp == np) {
err = ESLICE;
goto fail;
}
}
if (*cp && (*cp != ':')) {
partition = *cp - 'a'; /* got a partition number */
if ((partition < 0) || (partition >= MAXPARTITIONS)) {
err = EPART;
goto fail;
}
cp++;
}
}
}
if (*cp && (*cp != ':')) {
@ -211,10 +225,14 @@ i386_fmtdev(void *vdev)
case DEVT_DISK:
cp = buf;
cp += sprintf(cp, "%s%d", dev->d_dev->dv_name, dev->d_kind.biosdisk.unit);
if (dev->d_kind.biosdisk.slice > 0)
cp += sprintf(cp, "s%d", dev->d_kind.biosdisk.slice);
if (dev->d_kind.biosdisk.partition >= 0)
cp += sprintf(cp, "%c", dev->d_kind.biosdisk.partition + 'a');
if (dev->d_kind.biosdisk.partition == 0xff) {
cp += sprintf(cp, "p%d", dev->d_kind.biosdisk.slice);
} else {
if (dev->d_kind.biosdisk.slice > 0)
cp += sprintf(cp, "s%d", dev->d_kind.biosdisk.slice);
if (dev->d_kind.biosdisk.partition >= 0)
cp += sprintf(cp, "%c", dev->d_kind.biosdisk.partition + 'a');
}
strcat(cp, ":");
break;
@ -241,4 +259,3 @@ i386_setcurrdev(struct env_var *ev, int flags, const void *value)
env_setenv(ev->ev_name, flags | EV_NOHOOK, value, NULL, NULL);
return(0);
}

View File

@ -136,6 +136,7 @@ struct devsw biosdisk = {
static int bd_opendisk(struct open_disk **odp, struct i386_devdesc *dev);
static void bd_closedisk(struct open_disk *od);
static int bd_open_pc98(struct open_disk *od, struct i386_devdesc *dev);
static int bd_bestslice(struct open_disk *od);
static void bd_checkextended(struct open_disk *od, int slicenum);
@ -378,12 +379,8 @@ bd_open(struct open_file *f, ...)
static int
bd_opendisk(struct open_disk **odp, struct i386_devdesc *dev)
{
struct pc98_partition *dptr;
struct disklabel *lp;
struct open_disk *od;
int sector, slice, i;
int error;
char buf[BUFSIZE];
if (dev->d_kind.biosdisk.unit >= nbdinfo) {
DEBUG("attempt to open nonexistent disk");
@ -401,11 +398,10 @@ bd_opendisk(struct open_disk **odp, struct i386_devdesc *dev)
od->od_unit = bdinfo[od->od_dkunit].bd_unit;
od->od_flags = bdinfo[od->od_dkunit].bd_flags;
od->od_boff = 0;
od->od_nslices = 0;
error = 0;
DEBUG("open '%s', unit 0x%x slice %d partition %c",
DEBUG("open '%s', unit 0x%x slice %d partition %d",
i386_fmtdev(dev), dev->d_kind.biosdisk.unit,
dev->d_kind.biosdisk.slice, dev->d_kind.biosdisk.partition + 'a');
dev->d_kind.biosdisk.slice, dev->d_kind.biosdisk.partition);
/* Get geometry for this open (removable device may have changed) */
if (bd_getgeom(od)) {
@ -414,6 +410,26 @@ bd_opendisk(struct open_disk **odp, struct i386_devdesc *dev)
goto out;
}
/* Determine disk layout. */
error = bd_open_pc98(od, dev);
out:
if (error) {
free(od);
} else {
*odp = od; /* return the open disk */
}
return(error);
}
static int
bd_open_pc98(struct open_disk *od, struct i386_devdesc *dev)
{
struct pc98_partition *dptr;
struct disklabel *lp;
int sector, slice, i;
char buf[BUFSIZE];
/*
* Following calculations attempt to determine the correct value
* for d->od_boff by looking for the slice and partition specified,
@ -423,14 +439,14 @@ bd_opendisk(struct open_disk **odp, struct i386_devdesc *dev)
/*
* Find the slice in the DOS slice table.
*/
od->od_nslices = 0;
if (od->od_flags & BD_FLOPPY) {
sector = 0;
goto unsliced;
}
if (bd_read(od, 0, 1, buf)) {
DEBUG("error reading MBR");
error = EIO;
goto out;
return (EIO);
}
/*
@ -440,16 +456,14 @@ bd_opendisk(struct open_disk **odp, struct i386_devdesc *dev)
/* If a slice number was explicitly supplied, this is an error */
if (dev->d_kind.biosdisk.slice > 0) {
DEBUG("no slice table/MBR (no magic)");
error = ENOENT;
goto out;
return (ENOENT);
}
sector = 0;
goto unsliced; /* may be a floppy */
}
if (bd_read(od, 1, 1, buf)) {
DEBUG("error reading MBR");
error = EIO;
goto out;
return (EIO);
}
/*
@ -474,8 +488,7 @@ bd_opendisk(struct open_disk **odp, struct i386_devdesc *dev)
slice = dev->d_kind.biosdisk.slice - 1;
if (slice >= od->od_nslices) {
DEBUG("slice %d not found", slice);
error = ENOENT;
goto out;
return (ENOENT);
}
}
@ -483,8 +496,7 @@ bd_opendisk(struct open_disk **odp, struct i386_devdesc *dev)
if (dev->d_kind.biosdisk.slice == 0) {
slice = bd_bestslice(od);
if (slice == -1) {
error = ENOENT;
goto out;
return (ENOENT);
}
dev->d_kind.biosdisk.slice = slice;
}
@ -524,8 +536,7 @@ bd_opendisk(struct open_disk **odp, struct i386_devdesc *dev)
if (bd_read(od, sector + LABELSECTOR, 1, buf)) {
DEBUG("error reading disklabel");
error = EIO;
goto out;
return (EIO);
}
DEBUG("copy %d bytes of label from %p to %p", sizeof(struct disklabel), buf + LABELOFFSET, &od->od_disklabel);
bcopy(buf + LABELOFFSET, &od->od_disklabel, sizeof(struct disklabel));
@ -534,15 +545,12 @@ bd_opendisk(struct open_disk **odp, struct i386_devdesc *dev)
if (lp->d_magic != DISKMAGIC) {
DEBUG("no disklabel");
error = ENOENT;
goto out;
return (ENOENT);
}
if (dev->d_kind.biosdisk.partition >= lp->d_npartitions) {
DEBUG("partition '%c' exceeds partitions in table (a-'%c')",
'a' + dev->d_kind.biosdisk.partition, 'a' + lp->d_npartitions);
error = EPART;
goto out;
return (EPART);
}
#ifdef DISK_DEBUG
@ -557,14 +565,7 @@ bd_opendisk(struct open_disk **odp, struct i386_devdesc *dev)
lp->d_partitions[RAW_PART].p_offset +
sector;
}
out:
if (error) {
free(od);
} else {
*odp = od; /* return the open disk */
}
return(error);
return (0);
}
/*

View File

@ -82,6 +82,8 @@ struct gpt_ent {
{0x516e7cb6,0x6ecf,0x11d6,0x8f,0xf8,{0x00,0x02,0x2d,0x09,0x71,0x2b}}
#define GPT_ENT_TYPE_FREEBSD_VINUM \
{0x516e7cb8,0x6ecf,0x11d6,0x8f,0xf8,{0x00,0x02,0x2d,0x09,0x71,0x2b}}
#define GPT_ENT_TYPE_FREEBSD_BOOT \
{0x83bd6b9d,0x7f41,0x11dc,0xbe,0x0b,{0x00,0x15,0x60,0xb8,0x4f,0x0f}}
/*
* The following are unused but documented here to avoid reuse.
@ -93,7 +95,7 @@ struct gpt_ent {
/*
* Foreign partition types that we're likely to encounter. Note that Linux
* apparently choose to share data partitions with MS. I don't what the
* advantage might be. I can see how sharing swap partitions is advantaous
* advantage might be. I can see how sharing swap partitions is advantageous
* though.
*/
#define GPT_ENT_TYPE_MS_RESERVED \