/*-
* Copyright (c) 2012 Andrey V. Elsukov <ae@FreeBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
__FBSDID("$FreeBSD$");
#include <stand.h>
#include <sys/disklabel.h>
#include <crc32.h>
#include <part.h>
#include <uuid.h>
#ifdef PART_DEBUG
#else
#endif
#ifdef LOADER_GPT_SUPPORT
#endif
struct pentry {
union {
} type;
};
struct ptable {
};
static struct parttypes {
const char *desc;
} ptypes[] = {
{ PART_UNKNOWN, "Unknown" },
{ PART_EFI, "EFI" },
{ PART_FREEBSD, "FreeBSD" },
{ PART_FREEBSD_BOOT, "FreeBSD boot" },
{ PART_FREEBSD_NANDFS, "FreeBSD nandfs" },
{ PART_FREEBSD_UFS, "FreeBSD UFS" },
{ PART_FREEBSD_ZFS, "FreeBSD ZFS" },
{ PART_FREEBSD_SWAP, "FreeBSD swap" },
{ PART_FREEBSD_VINUM, "FreeBSD vinum" },
{ PART_LINUX, "Linux" },
{ PART_LINUX_SWAP, "Linux swap" },
{ PART_SOLARIS2, "Solaris 2" },
{ PART_ILLUMOS_UFS, "illumos UFS" },
{ PART_ILLUMOS_ZFS, "illumos ZFS" },
{ PART_RESERVED, "Reserved" },
{ PART_VTOC_BOOT, "boot" },
{ PART_VTOC_ROOT, "root" },
{ PART_VTOC_SWAP, "swap" },
{ PART_VTOC_USR, "usr" },
{ PART_VTOC_STAND, "stand" },
{ PART_VTOC_VAR, "var" },
{ PART_VTOC_HOME, "home" }
};
const char *
{
size_t i;
}
#ifdef LOADER_GPT_SUPPORT
static void
{
}
static enum partition_type
{
return (PART_EFI);
return (PART_DOS);
return (PART_FREEBSD_BOOT);
return (PART_FREEBSD_UFS);
return (PART_FREEBSD_ZFS);
return (PART_FREEBSD_SWAP);
return (PART_FREEBSD_VINUM);
return (PART_FREEBSD_NANDFS);
return (PART_FREEBSD);
return (PART_ILLUMOS_UFS);
return (PART_ILLUMOS_ZFS);
return (PART_RESERVED);
return (PART_UNKNOWN);
}
static struct gpt_hdr*
{
DEBUG("no GPT signature");
return (NULL);
}
return (NULL);
}
hdr->hdr_crc_self = 0;
DEBUG("GPT header's CRC doesn't match");
return (NULL);
}
return (NULL);
}
DEBUG("self LBA doesn't match");
return (NULL);
}
DEBUG("invalid alternate LBA");
return (NULL);
}
if (hdr->hdr_entries == 0 ||
DEBUG("invalid entry size or number of entries");
return (NULL);
}
return (hdr);
}
static int
{
/* Check CRC only when buffer size is enough for table. */
if (hdr->hdr_crc_table !=
DEBUG("GPT table's CRC doesn't match");
return (-1);
}
}
for (i = 0; i < cnt; i++) {
continue;
}
return (0);
}
static struct ptable*
{
return (NULL);
return (NULL);
}
/* Read the primary GPT header. */
goto out;
}
/* Check the primary GPT header. */
table->sectorsize);
/* Read the primary GPT table. */
pri = 1;
}
}
/* Read the backup GPT header. */
else
/*
* Compare primary and backup headers.
* If they are equal, then we do not need to read backup
* table. If they are different, then prefer backup header
* and try to read backup table.
*/
if (pri == 0 ||
/* Read the backup GPT table. */
table->sectorsize);
sec = 1;
}
}
}
/* Both primary and backup tables are invalid. */
goto out;
}
DEBUG("GPT detected");
continue;
break;
DEBUG("new GPT partition added");
}
out:
return (table);
}
#endif /* LOADER_GPT_SUPPORT */
#ifdef LOADER_MBR_SUPPORT
/* We do not need to support too many EBR partitions in the loader */
static enum partition_type
{
switch (type) {
case DOSPTYP_386BSD:
return (PART_FREEBSD);
case DOSPTYP_LINSWP:
return (PART_LINUX_SWAP);
case DOSPTYP_LINUX:
return (PART_LINUX);
case DOSPTYP_SUNIXOS2:
return (PART_SOLARIS2);
case 0x01:
case 0x04:
case 0x06:
case 0x07:
case 0x0b:
case 0x0c:
case 0x0e:
return (PART_DOS);
}
return (PART_UNKNOWN);
}
static struct ptable*
{
int i, idx;
break;
}
return (table);
idx = 5;
return (table);
DEBUG("EBR detected");
for (i = 0; i < MAXEBRENTRIES; i++) {
#if 0 /* Some BIOSes return an incorrect number of sectors */
break;
#endif
break;
break;
continue;
}
break;
DEBUG("new EBR partition added");
break;
}
return (table);
}
#endif /* LOADER_MBR_SUPPORT */
static enum partition_type
{
switch (type) {
case FS_NANDFS:
return (PART_FREEBSD_NANDFS);
case FS_SWAP:
return (PART_FREEBSD_SWAP);
case FS_BSDFFS:
return (PART_FREEBSD_UFS);
case FS_VINUM:
return (PART_FREEBSD_VINUM);
case FS_ZFS:
return (PART_FREEBSD_ZFS);
}
return (PART_UNKNOWN);
}
static struct ptable*
{
int i;
DEBUG("Too small sectorsize");
return (table);
}
return (table);
DEBUG("read failed");
goto out;
}
goto out;
DEBUG("unsupported sector size");
goto out;
}
DEBUG("invalid number of partitions");
goto out;
}
DEBUG("BSD detected");
if (i == RAW_PART)
continue;
continue;
break;
DEBUG("new BSD partition added");
}
out:
return (table);
}
#ifdef LOADER_VTOC8_SUPPORT
static enum partition_type
{
switch (type) {
case VTOC_TAG_FREEBSD_NANDFS:
return (PART_FREEBSD_NANDFS);
case VTOC_TAG_FREEBSD_SWAP:
return (PART_FREEBSD_SWAP);
case VTOC_TAG_FREEBSD_UFS:
return (PART_FREEBSD_UFS);
case VTOC_TAG_FREEBSD_VINUM:
return (PART_FREEBSD_VINUM);
case VTOC_TAG_FREEBSD_ZFS:
return (PART_FREEBSD_ZFS);
};
return (PART_UNKNOWN);
}
static struct ptable*
{
int i;
return (table);
return (table);
DEBUG("read failed");
goto out;
}
/* Check the sum */
if (sum != 0) {
DEBUG("incorrect checksum");
goto out;
}
DEBUG("invalid number of entries");
goto out;
}
DEBUG("invalid geometry");
goto out;
}
DEBUG("VTOC8 detected");
for (i = 0; i < VTOC8_NPARTS; i++) {
if (i == VTOC_RAW_PART ||
continue;
break;
DEBUG("new VTOC8 partition added");
}
out:
return (table);
}
#endif /* LOADER_VTOC8_SUPPORT */
static enum partition_type
{
switch (type) {
case VTOC_TAG_BOOT:
return (PART_VTOC_BOOT);
case VTOC_TAG_ROOT:
return (PART_VTOC_ROOT);
case VTOC_TAG_SWAP:
return (PART_VTOC_SWAP);
case VTOC_TAG_USR:
return (PART_VTOC_USR);
case VTOC_TAG_BACKUP:
return (PART_VTOC_BACKUP);
case VTOC_TAG_STAND:
return (PART_VTOC_STAND);
case VTOC_TAG_VAR:
return (PART_VTOC_VAR);
case VTOC_TAG_HOME:
return (PART_VTOC_HOME);
};
return (PART_UNKNOWN);
}
static struct ptable*
{
int i;
DEBUG("Too small sectorsize");
return (table);
}
return (table);
DEBUG("read failed");
goto out;
}
DEBUG("dk_label magic error");
goto out;
}
DEBUG("this vtoc is not sane");
goto out;
}
DEBUG("invalid number of entries");
goto out;
}
DEBUG("VTOC detected");
for (i = 0; i < NDKMAP; i++) {
if (i == VTOC_RAW_PART || /* skip slice 2 and empty */
continue;
break;
DEBUG("new VTOC partition added");
}
out:
return (table);
}
struct ptable*
{
int i, count;
#ifdef LOADER_MBR_SUPPORT
int has_ext;
#endif
return (NULL);
/* First, read the MBR. */
DEBUG("read failed");
goto out;
}
goto out;
goto out;
goto out;
#ifdef LOADER_VTOC8_SUPPORT
/* Read error. */
goto out;
goto out;
}
#endif
/* Check the BSD label. */
goto out;
goto out;
#if defined(LOADER_GPT_SUPPORT) || defined(LOADER_MBR_SUPPORT)
/* Check the MBR magic. */
DEBUG("magic sequence not found");
#if defined(LOADER_GPT_SUPPORT)
/* There is no PMBR, check that we have backup GPT */
#endif
goto out;
}
/* Check that we have PMBR. Also do some validation. */
goto out;
}
#ifdef LOADER_GPT_SUPPORT
DEBUG("PMBR detected");
}
#endif
count++;
}
/* Do we have some invalid values? */
DEBUG("Incorrect PMBR, ignore it");
} else
DEBUG("Bootcamp detected");
}
#ifdef LOADER_GPT_SUPPORT
goto out;
}
#endif
#ifdef LOADER_MBR_SUPPORT
/* Read MBR. */
DEBUG("MBR detected");
continue;
continue;
#if 0 /* Some BIOSes return an incorrect number of sectors */
continue; /* XXX: ignore */
#endif
has_ext = 1;
break;
DEBUG("new MBR partition added");
}
if (has_ext) {
/* FALLTHROUGH */
}
#endif /* LOADER_MBR_SUPPORT */
#endif /* LOADER_MBR_SUPPORT || LOADER_GPT_SUPPORT */
out:
return (table);
}
void
{
}
}
enum ptable_type
{
}
int
{
return (EINVAL);
continue;
return (0);
}
return (ENOENT);
}
/*
* Search for a slice with the following preferences:
*
* 1: Active illumos slice
* 2: Non-active illumos slice
* 3: Active Linux slice
* 4: non-active Linux slice
*/
#define PREF_RAWDISK 0
int
{
return (EINVAL);
#ifdef LOADER_MBR_SUPPORT
case DOSPTYP_SUNIXOS2:
break;
case DOSPTYP_LINUX:
break;
case 0x04:
case 0x06:
case 0x0c:
case 0x0e:
case DOSPTYP_FAT32:
break;
default:
}
}
#endif /* LOADER_MBR_SUPPORT */
#ifdef LOADER_GPT_SUPPORT
pref = PREF_ILLUMOS;
else
}
#endif /* LOADER_GPT_SUPPORT */
}
}
return (0);
}
return (ENOENT);
}
/*
* iterate will stop if iterator will return non 0.
*/
int
{
int ret = 0;
name[0] = '\0';
#ifdef LOADER_MBR_SUPPORT
else
#endif
#ifdef LOADER_GPT_SUPPORT
else
#endif
#ifdef LOADER_VTOC8_SUPPORT
else
#endif
else
if (ret != 0)
return (ret);
}
return (ret);
}