Changeset View
Changeset View
Standalone View
Standalone View
head/stand/i386/zfsboot/zfsboot.c
Show First 20 Lines • Show All 121 Lines • ▼ Show 20 Lines | |||||
void exit(int); | void exit(int); | ||||
void reboot(void); | void reboot(void); | ||||
static void load(void); | static void load(void); | ||||
static int parse_cmd(void); | static int parse_cmd(void); | ||||
static void bios_getmem(void); | static void bios_getmem(void); | ||||
int main(void); | int main(void); | ||||
#ifdef LOADER_GELI_SUPPORT | #ifdef LOADER_GELI_SUPPORT | ||||
#include "geliboot.c" | #include "geliboot.h" | ||||
static char gelipw[GELI_PW_MAXLEN]; | static char gelipw[GELI_PW_MAXLEN]; | ||||
static struct keybuf *gelibuf; | static struct keybuf *gelibuf; | ||||
#endif | #endif | ||||
struct zfsdsk { | |||||
struct dsk dsk; | |||||
#ifdef LOADER_GELI_SUPPORT | |||||
struct geli_dev *gdev; | |||||
#endif | |||||
}; | |||||
#include "zfsimpl.c" | #include "zfsimpl.c" | ||||
/* | /* | ||||
* Read from a dnode (which must be from a ZPL filesystem). | * Read from a dnode (which must be from a ZPL filesystem). | ||||
*/ | */ | ||||
static int | static int | ||||
zfs_read(spa_t *spa, const dnode_phys_t *dnode, off_t *offp, void *start, size_t size) | zfs_read(spa_t *spa, const dnode_phys_t *dnode, off_t *offp, void *start, size_t size) | ||||
{ | { | ||||
Show All 26 Lines | |||||
*/ | */ | ||||
static int | static int | ||||
vdev_read(void *xvdev, void *priv, off_t off, void *buf, size_t bytes) | vdev_read(void *xvdev, void *priv, off_t off, void *buf, size_t bytes) | ||||
{ | { | ||||
char *p; | char *p; | ||||
daddr_t lba, alignlba; | daddr_t lba, alignlba; | ||||
off_t diff; | off_t diff; | ||||
unsigned int nb, alignnb; | unsigned int nb, alignnb; | ||||
struct dsk *dsk = (struct dsk *) priv; | struct zfsdsk *zdsk = (struct zfsdsk *) priv; | ||||
if ((off & (DEV_BSIZE - 1)) || (bytes & (DEV_BSIZE - 1))) | if ((off & (DEV_BSIZE - 1)) || (bytes & (DEV_BSIZE - 1))) | ||||
return -1; | return -1; | ||||
p = buf; | p = buf; | ||||
lba = off / DEV_BSIZE; | lba = off / DEV_BSIZE; | ||||
lba += dsk->start; | lba += zdsk->dsk.start; | ||||
/* | /* | ||||
* Align reads to 4k else 4k sector GELIs will not decrypt. | * Align reads to 4k else 4k sector GELIs will not decrypt. | ||||
* Round LBA down to nearest multiple of DEV_GELIBOOT_BSIZE bytes. | * Round LBA down to nearest multiple of DEV_GELIBOOT_BSIZE bytes. | ||||
*/ | */ | ||||
alignlba = rounddown2(off, DEV_GELIBOOT_BSIZE) / DEV_BSIZE; | alignlba = rounddown2(off, DEV_GELIBOOT_BSIZE) / DEV_BSIZE; | ||||
/* | /* | ||||
* The read must be aligned to DEV_GELIBOOT_BSIZE bytes relative to the | * The read must be aligned to DEV_GELIBOOT_BSIZE bytes relative to the | ||||
* start of the GELI partition, not the start of the actual disk. | * start of the GELI partition, not the start of the actual disk. | ||||
*/ | */ | ||||
alignlba += dsk->start; | alignlba += zdsk->dsk.start; | ||||
diff = (lba - alignlba) * DEV_BSIZE; | diff = (lba - alignlba) * DEV_BSIZE; | ||||
while (bytes > 0) { | while (bytes > 0) { | ||||
nb = bytes / DEV_BSIZE; | nb = bytes / DEV_BSIZE; | ||||
/* | /* | ||||
* Ensure that the read size plus the leading offset does not | * Ensure that the read size plus the leading offset does not | ||||
* exceed the size of the read buffer. | * exceed the size of the read buffer. | ||||
*/ | */ | ||||
if (nb > (READ_BUF_SIZE - diff) / DEV_BSIZE) | if (nb > (READ_BUF_SIZE - diff) / DEV_BSIZE) | ||||
nb = (READ_BUF_SIZE - diff) / DEV_BSIZE; | nb = (READ_BUF_SIZE - diff) / DEV_BSIZE; | ||||
/* | /* | ||||
* Round the number of blocks to read up to the nearest multiple | * Round the number of blocks to read up to the nearest multiple | ||||
* of DEV_GELIBOOT_BSIZE. | * of DEV_GELIBOOT_BSIZE. | ||||
*/ | */ | ||||
alignnb = roundup2(nb * DEV_BSIZE + diff, DEV_GELIBOOT_BSIZE) | alignnb = roundup2(nb * DEV_BSIZE + diff, DEV_GELIBOOT_BSIZE) | ||||
/ DEV_BSIZE; | / DEV_BSIZE; | ||||
if (dsk->size > 0 && alignlba + alignnb > dsk->size + dsk->start) { | if (zdsk->dsk.size > 0 && alignlba + alignnb > | ||||
printf("Shortening read at %lld from %d to %lld\n", alignlba, | zdsk->dsk.size + zdsk->dsk.start) { | ||||
alignnb, (dsk->size + dsk->start) - alignlba); | printf("Shortening read at %lld from %d to %lld\n", | ||||
alignnb = (dsk->size + dsk->start) - alignlba; | alignlba, alignnb, | ||||
(zdsk->dsk.size + zdsk->dsk.start) - alignlba); | |||||
alignnb = (zdsk->dsk.size + zdsk->dsk.start) - alignlba; | |||||
} | } | ||||
if (drvread(dsk, dmadat->rdbuf, alignlba, alignnb)) | if (drvread(&zdsk->dsk, dmadat->rdbuf, alignlba, alignnb)) | ||||
return -1; | return -1; | ||||
#ifdef LOADER_GELI_SUPPORT | #ifdef LOADER_GELI_SUPPORT | ||||
/* decrypt */ | /* decrypt */ | ||||
if (is_geli(dsk) == 0) { | if (zdsk->gdev != NULL) { | ||||
if (geli_read(dsk, ((alignlba - dsk->start) * | if (geli_read(zdsk->gdev, ((alignlba - zdsk->dsk.start) * | ||||
DEV_BSIZE), dmadat->rdbuf, alignnb * DEV_BSIZE)) | DEV_BSIZE), dmadat->rdbuf, alignnb * DEV_BSIZE)) | ||||
return (-1); | return (-1); | ||||
} | } | ||||
#endif | #endif | ||||
memcpy(p, dmadat->rdbuf + diff, nb * DEV_BSIZE); | memcpy(p, dmadat->rdbuf + diff, nb * DEV_BSIZE); | ||||
p += nb * DEV_BSIZE; | p += nb * DEV_BSIZE; | ||||
lba += nb; | lba += nb; | ||||
alignlba += alignnb; | alignlba += alignnb; | ||||
Show All 13 Lines | |||||
static int | static int | ||||
vdev_write(vdev_t *vdev, void *priv, off_t off, void *buf, size_t bytes) | vdev_write(vdev_t *vdev, void *priv, off_t off, void *buf, size_t bytes) | ||||
{ | { | ||||
char *p; | char *p; | ||||
daddr_t lba; | daddr_t lba; | ||||
unsigned int nb; | unsigned int nb; | ||||
struct dsk *dsk = (struct dsk *) priv; | struct zfsdsk *zdsk = (struct zfsdsk *) priv; | ||||
if ((off & (DEV_BSIZE - 1)) || (bytes & (DEV_BSIZE - 1))) | if ((off & (DEV_BSIZE - 1)) || (bytes & (DEV_BSIZE - 1))) | ||||
return -1; | return -1; | ||||
p = buf; | p = buf; | ||||
lba = off / DEV_BSIZE; | lba = off / DEV_BSIZE; | ||||
lba += dsk->start; | lba += zdsk->dsk.start; | ||||
while (bytes > 0) { | while (bytes > 0) { | ||||
nb = bytes / DEV_BSIZE; | nb = bytes / DEV_BSIZE; | ||||
if (nb > READ_BUF_SIZE / DEV_BSIZE) | if (nb > READ_BUF_SIZE / DEV_BSIZE) | ||||
nb = READ_BUF_SIZE / DEV_BSIZE; | nb = READ_BUF_SIZE / DEV_BSIZE; | ||||
memcpy(dmadat->rdbuf, p, nb * DEV_BSIZE); | memcpy(dmadat->rdbuf, p, nb * DEV_BSIZE); | ||||
if (drvwrite(dsk, dmadat->rdbuf, lba, nb)) | if (drvwrite(&zdsk->dsk, dmadat->rdbuf, lba, nb)) | ||||
return -1; | return -1; | ||||
p += nb * DEV_BSIZE; | p += nb * DEV_BSIZE; | ||||
lba += nb; | lba += nb; | ||||
bytes -= nb * DEV_BSIZE; | bytes -= nb * DEV_BSIZE; | ||||
} | } | ||||
return 0; | return 0; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 161 Lines • ▼ Show 20 Lines | return (1); | ||||
} | } | ||||
return(0); | return(0); | ||||
} | } | ||||
/* | /* | ||||
* We call this when we find a ZFS vdev - ZFS consumes the dsk | * We call this when we find a ZFS vdev - ZFS consumes the dsk | ||||
* structure so we must make a new one. | * structure so we must make a new one. | ||||
*/ | */ | ||||
static struct dsk * | static struct zfsdsk * | ||||
copy_dsk(struct dsk *dsk) | copy_dsk(struct zfsdsk *zdsk) | ||||
{ | { | ||||
struct dsk *newdsk; | struct zfsdsk *newdsk; | ||||
newdsk = malloc(sizeof(struct dsk)); | newdsk = malloc(sizeof(struct zfsdsk)); | ||||
*newdsk = *dsk; | *newdsk = *zdsk; | ||||
return (newdsk); | return (newdsk); | ||||
} | } | ||||
/* | /* | ||||
* Get disk size from eax=0x800 and 0x4800. We need to probe both | * Get disk size from eax=0x800 and 0x4800. We need to probe both | ||||
* because 0x4800 may not be available and we would like to get more | * because 0x4800 may not be available and we would like to get more | ||||
* or less correct disk size - if it is possible at all. | * or less correct disk size - if it is possible at all. | ||||
* Note we do not really want to touch drv.c because that code is shared | * Note we do not really want to touch drv.c because that code is shared | ||||
* with boot2 and we can not afford to grow that code. | * with boot2 and we can not afford to grow that code. | ||||
*/ | */ | ||||
static uint64_t | static uint64_t | ||||
drvsize_ext(struct dsk *dskp) | drvsize_ext(struct zfsdsk *zdsk) | ||||
{ | { | ||||
struct dsk *dskp; | |||||
uint64_t size, tmp; | uint64_t size, tmp; | ||||
int cyl, hds, sec; | int cyl, hds, sec; | ||||
dskp = &zdsk->dsk; | |||||
v86.ctl = V86_FLAGS; | v86.ctl = V86_FLAGS; | ||||
v86.addr = 0x13; | v86.addr = 0x13; | ||||
v86.eax = 0x800; | v86.eax = 0x800; | ||||
v86.edx = dskp->drive; | v86.edx = dskp->drive; | ||||
v86int(); | v86int(); | ||||
/* Don't error out if we get bad sector number, try EDD as well */ | /* Don't error out if we get bad sector number, try EDD as well */ | ||||
if (V86_CY(v86.efl) || /* carry set */ | if (V86_CY(v86.efl) || /* carry set */ | ||||
Show All 28 Lines | |||||
/* | /* | ||||
* The "layered" ioctl to read disk/partition size. Unfortunately | * The "layered" ioctl to read disk/partition size. Unfortunately | ||||
* the zfsboot case is hardest, because we do not have full software | * the zfsboot case is hardest, because we do not have full software | ||||
* stack available, so we need to do some manual work here. | * stack available, so we need to do some manual work here. | ||||
*/ | */ | ||||
uint64_t | uint64_t | ||||
ldi_get_size(void *priv) | ldi_get_size(void *priv) | ||||
{ | { | ||||
struct dsk *dskp = priv; | struct zfsdsk *zdsk = priv; | ||||
uint64_t size = dskp->size; | uint64_t size = zdsk->dsk.size; | ||||
if (dskp->start == 0) | if (zdsk->dsk.start == 0) | ||||
size = drvsize_ext(dskp); | size = drvsize_ext(zdsk); | ||||
return (size * DEV_BSIZE); | return (size * DEV_BSIZE); | ||||
} | } | ||||
static void | static void | ||||
probe_drive(struct dsk *dsk) | probe_drive(struct zfsdsk *zdsk) | ||||
{ | { | ||||
#ifdef GPT | #ifdef GPT | ||||
struct gpt_hdr hdr; | struct gpt_hdr hdr; | ||||
struct gpt_ent *ent; | struct gpt_ent *ent; | ||||
unsigned part, entries_per_sec; | unsigned part, entries_per_sec; | ||||
daddr_t slba; | daddr_t slba; | ||||
#endif | #endif | ||||
#if defined(GPT) || defined(LOADER_GELI_SUPPORT) | #if defined(GPT) || defined(LOADER_GELI_SUPPORT) | ||||
daddr_t elba; | daddr_t elba; | ||||
#endif | #endif | ||||
struct dos_partition *dp; | struct dos_partition *dp; | ||||
char *sec; | char *sec; | ||||
unsigned i; | unsigned i; | ||||
/* | /* | ||||
* If we find a vdev on the whole disk, stop here. | * If we find a vdev on the whole disk, stop here. | ||||
*/ | */ | ||||
if (vdev_probe(vdev_read2, dsk, NULL) == 0) | if (vdev_probe(vdev_read2, zdsk, NULL) == 0) | ||||
return; | return; | ||||
#ifdef LOADER_GELI_SUPPORT | #ifdef LOADER_GELI_SUPPORT | ||||
/* | /* | ||||
* Taste the disk, if it is GELI encrypted, decrypt it and check to see if | * Taste the disk, if it is GELI encrypted, decrypt it and check to see if | ||||
* it is a usable vdev then. Otherwise dig | * it is a usable vdev then. Otherwise dig | ||||
* out the partition table and probe each slice/partition | * out the partition table and probe each slice/partition | ||||
* in turn for a vdev or GELI encrypted vdev. | * in turn for a vdev or GELI encrypted vdev. | ||||
*/ | */ | ||||
elba = drvsize_ext(dsk); | elba = drvsize_ext(zdsk); | ||||
if (elba > 0) { | if (elba > 0) { | ||||
elba--; | elba--; | ||||
} | } | ||||
if (geli_taste(vdev_read, dsk, elba) == 0) { | zdsk->gdev = geli_taste(vdev_read, zdsk, elba, "disk%u:0:"); | ||||
if (geli_havekey(dsk) == 0 || geli_passphrase(gelipw, dsk->unit, | if (zdsk->gdev != NULL) { | ||||
':', 0, dsk) == 0) { | if (geli_havekey(zdsk->gdev) == 0 || | ||||
if (vdev_probe(vdev_read2, dsk, NULL) == 0) { | geli_passphrase(zdsk->gdev, gelipw) == 0) { | ||||
if (vdev_probe(vdev_read2, zdsk, NULL) == 0) { | |||||
return; | return; | ||||
} | } | ||||
} | } | ||||
} | } | ||||
#endif /* LOADER_GELI_SUPPORT */ | #endif /* LOADER_GELI_SUPPORT */ | ||||
sec = dmadat->secbuf; | sec = dmadat->secbuf; | ||||
dsk->start = 0; | zdsk->dsk.start = 0; | ||||
#ifdef GPT | #ifdef GPT | ||||
/* | /* | ||||
* First check for GPT. | * First check for GPT. | ||||
*/ | */ | ||||
if (drvread(dsk, sec, 1, 1)) { | if (drvread(&zdsk->dsk, sec, 1, 1)) { | ||||
return; | return; | ||||
} | } | ||||
memcpy(&hdr, sec, sizeof(hdr)); | memcpy(&hdr, sec, sizeof(hdr)); | ||||
if (memcmp(hdr.hdr_sig, GPT_HDR_SIG, sizeof(hdr.hdr_sig)) != 0 || | if (memcmp(hdr.hdr_sig, GPT_HDR_SIG, sizeof(hdr.hdr_sig)) != 0 || | ||||
hdr.hdr_lba_self != 1 || hdr.hdr_revision < 0x00010000 || | hdr.hdr_lba_self != 1 || hdr.hdr_revision < 0x00010000 || | ||||
hdr.hdr_entsz < sizeof(*ent) || DEV_BSIZE % hdr.hdr_entsz != 0) { | hdr.hdr_entsz < sizeof(*ent) || DEV_BSIZE % hdr.hdr_entsz != 0) { | ||||
goto trymbr; | goto trymbr; | ||||
} | } | ||||
/* | /* | ||||
* Probe all GPT partitions for the presence of ZFS pools. We | * Probe all GPT partitions for the presence of ZFS pools. We | ||||
* return the spa_t for the first we find (if requested). This | * return the spa_t for the first we find (if requested). This | ||||
* will have the effect of booting from the first pool on the | * will have the effect of booting from the first pool on the | ||||
* disk. | * disk. | ||||
* | * | ||||
* If no vdev is found, GELI decrypting the device and try again | * If no vdev is found, GELI decrypting the device and try again | ||||
*/ | */ | ||||
entries_per_sec = DEV_BSIZE / hdr.hdr_entsz; | entries_per_sec = DEV_BSIZE / hdr.hdr_entsz; | ||||
slba = hdr.hdr_lba_table; | slba = hdr.hdr_lba_table; | ||||
elba = slba + hdr.hdr_entries / entries_per_sec; | elba = slba + hdr.hdr_entries / entries_per_sec; | ||||
while (slba < elba) { | while (slba < elba) { | ||||
dsk->start = 0; | zdsk->dsk.start = 0; | ||||
if (drvread(dsk, sec, slba, 1)) | if (drvread(&zdsk->dsk, sec, slba, 1)) | ||||
return; | return; | ||||
for (part = 0; part < entries_per_sec; part++) { | for (part = 0; part < entries_per_sec; part++) { | ||||
ent = (struct gpt_ent *)(sec + part * hdr.hdr_entsz); | ent = (struct gpt_ent *)(sec + part * hdr.hdr_entsz); | ||||
if (memcmp(&ent->ent_type, &freebsd_zfs_uuid, | if (memcmp(&ent->ent_type, &freebsd_zfs_uuid, | ||||
sizeof(uuid_t)) == 0) { | sizeof(uuid_t)) == 0) { | ||||
dsk->start = ent->ent_lba_start; | zdsk->dsk.start = ent->ent_lba_start; | ||||
dsk->size = ent->ent_lba_end - ent->ent_lba_start + 1; | zdsk->dsk.size = ent->ent_lba_end - ent->ent_lba_start + 1; | ||||
dsk->slice = part + 1; | zdsk->dsk.slice = part + 1; | ||||
dsk->part = 255; | zdsk->dsk.part = 255; | ||||
if (vdev_probe(vdev_read2, dsk, NULL) == 0) { | if (vdev_probe(vdev_read2, zdsk, NULL) == 0) { | ||||
/* | /* | ||||
* This slice had a vdev. We need a new dsk | * This slice had a vdev. We need a new dsk | ||||
* structure now since the vdev now owns this one. | * structure now since the vdev now owns this one. | ||||
*/ | */ | ||||
dsk = copy_dsk(dsk); | zdsk = copy_dsk(zdsk); | ||||
} | } | ||||
#ifdef LOADER_GELI_SUPPORT | #ifdef LOADER_GELI_SUPPORT | ||||
else if (geli_taste(vdev_read, dsk, ent->ent_lba_end - | else if ((zdsk->gdev = geli_taste(vdev_read, zdsk, | ||||
ent->ent_lba_start) == 0) { | ent->ent_lba_end - ent->ent_lba_start, "disk%up%u:", | ||||
if (geli_havekey(dsk) == 0 || geli_passphrase(gelipw, | zdsk->dsk.unit, zdsk->dsk.slice)) != NULL) { | ||||
dsk->unit, 'p', dsk->slice, dsk) == 0) { | if (geli_havekey(zdsk->gdev) == 0 || | ||||
geli_passphrase(zdsk->gdev, gelipw) == 0) { | |||||
/* | /* | ||||
* This slice has GELI, check it for ZFS. | * This slice has GELI, check it for ZFS. | ||||
*/ | */ | ||||
if (vdev_probe(vdev_read2, dsk, NULL) == 0) { | if (vdev_probe(vdev_read2, zdsk, NULL) == 0) { | ||||
/* | /* | ||||
* This slice had a vdev. We need a new dsk | * This slice had a vdev. We need a new dsk | ||||
* structure now since the vdev now owns this one. | * structure now since the vdev now owns this one. | ||||
*/ | */ | ||||
dsk = copy_dsk(dsk); | zdsk = copy_dsk(zdsk); | ||||
} | } | ||||
break; | break; | ||||
} | } | ||||
} | } | ||||
#endif /* LOADER_GELI_SUPPORT */ | #endif /* LOADER_GELI_SUPPORT */ | ||||
} | } | ||||
} | } | ||||
slba++; | slba++; | ||||
} | } | ||||
return; | return; | ||||
trymbr: | trymbr: | ||||
#endif /* GPT */ | #endif /* GPT */ | ||||
if (drvread(dsk, sec, DOSBBSECTOR, 1)) | if (drvread(&zdsk->dsk, sec, DOSBBSECTOR, 1)) | ||||
return; | return; | ||||
dp = (void *)(sec + DOSPARTOFF); | dp = (void *)(sec + DOSPARTOFF); | ||||
for (i = 0; i < NDOSPART; i++) { | for (i = 0; i < NDOSPART; i++) { | ||||
if (!dp[i].dp_typ) | if (!dp[i].dp_typ) | ||||
continue; | continue; | ||||
dsk->start = dp[i].dp_start; | zdsk->dsk.start = dp[i].dp_start; | ||||
dsk->size = dp[i].dp_size; | zdsk->dsk.size = dp[i].dp_size; | ||||
dsk->slice = i + 1; | zdsk->dsk.slice = i + 1; | ||||
if (vdev_probe(vdev_read2, dsk, NULL) == 0) { | if (vdev_probe(vdev_read2, zdsk, NULL) == 0) { | ||||
dsk = copy_dsk(dsk); | zdsk = copy_dsk(zdsk); | ||||
} | } | ||||
#ifdef LOADER_GELI_SUPPORT | #ifdef LOADER_GELI_SUPPORT | ||||
else if (geli_taste(vdev_read, dsk, dp[i].dp_size - | else if ((zdsk->gdev = geli_taste(vdev_read, zdsk, dp[i].dp_size - | ||||
dp[i].dp_start) == 0) { | dp[i].dp_start, "disk%us%u:")) != NULL) { | ||||
if (geli_havekey(dsk) == 0 || geli_passphrase(gelipw, dsk->unit, | if (geli_havekey(zdsk->gdev) == 0 || | ||||
's', i, dsk) == 0) { | geli_passphrase(zdsk->gdev, gelipw) == 0) { | ||||
/* | /* | ||||
* This slice has GELI, check it for ZFS. | * This slice has GELI, check it for ZFS. | ||||
*/ | */ | ||||
if (vdev_probe(vdev_read2, dsk, NULL) == 0) { | if (vdev_probe(vdev_read2, zdsk, NULL) == 0) { | ||||
/* | /* | ||||
* This slice had a vdev. We need a new dsk | * This slice had a vdev. We need a new dsk | ||||
* structure now since the vdev now owns this one. | * structure now since the vdev now owns this one. | ||||
*/ | */ | ||||
dsk = copy_dsk(dsk); | zdsk = copy_dsk(zdsk); | ||||
} | } | ||||
break; | break; | ||||
} | } | ||||
} | } | ||||
#endif /* LOADER_GELI_SUPPORT */ | #endif /* LOADER_GELI_SUPPORT */ | ||||
} | } | ||||
} | } | ||||
int | int | ||||
main(void) | main(void) | ||||
{ | { | ||||
dnode_phys_t dn; | dnode_phys_t dn; | ||||
off_t off; | off_t off; | ||||
struct dsk *dsk; | struct zfsdsk *zdsk; | ||||
int autoboot, i; | int autoboot, i; | ||||
int nextboot; | int nextboot; | ||||
int rc; | int rc; | ||||
dmadat = (void *)(roundup2(__base + (int32_t)&_end, 0x10000) - __base); | dmadat = (void *)(roundup2(__base + (int32_t)&_end, 0x10000) - __base); | ||||
bios_getmem(); | bios_getmem(); | ||||
if (high_heap_size > 0) { | if (high_heap_size > 0) { | ||||
heap_end = PTOV(high_heap_base + high_heap_size); | heap_end = PTOV(high_heap_base + high_heap_size); | ||||
heap_next = PTOV(high_heap_base); | heap_next = PTOV(high_heap_base); | ||||
} else { | } else { | ||||
heap_next = (char *)dmadat + sizeof(*dmadat); | heap_next = (char *)dmadat + sizeof(*dmadat); | ||||
heap_end = (char *)PTOV(bios_basemem); | heap_end = (char *)PTOV(bios_basemem); | ||||
} | } | ||||
setheap(heap_next, heap_end); | setheap(heap_next, heap_end); | ||||
dsk = malloc(sizeof(struct dsk)); | zdsk = malloc(sizeof(struct zfsdsk)); | ||||
dsk->drive = *(uint8_t *)PTOV(ARGS); | zdsk->gdev = NULL; | ||||
dsk->type = dsk->drive & DRV_HARD ? TYPE_AD : TYPE_FD; | zdsk->dsk.drive = *(uint8_t *)PTOV(ARGS); | ||||
dsk->unit = dsk->drive & DRV_MASK; | zdsk->dsk.type = zdsk->dsk.drive & DRV_HARD ? TYPE_AD : TYPE_FD; | ||||
dsk->slice = *(uint8_t *)PTOV(ARGS + 1) + 1; | zdsk->dsk.unit = zdsk->dsk.drive & DRV_MASK; | ||||
dsk->part = 0; | zdsk->dsk.slice = *(uint8_t *)PTOV(ARGS + 1) + 1; | ||||
dsk->start = 0; | zdsk->dsk.part = 0; | ||||
dsk->size = drvsize_ext(dsk); | zdsk->dsk.start = 0; | ||||
zdsk->dsk.size = drvsize_ext(zdsk); | |||||
bootinfo.bi_version = BOOTINFO_VERSION; | bootinfo.bi_version = BOOTINFO_VERSION; | ||||
bootinfo.bi_size = sizeof(bootinfo); | bootinfo.bi_size = sizeof(bootinfo); | ||||
bootinfo.bi_basemem = bios_basemem / 1024; | bootinfo.bi_basemem = bios_basemem / 1024; | ||||
bootinfo.bi_extmem = bios_extmem / 1024; | bootinfo.bi_extmem = bios_extmem / 1024; | ||||
bootinfo.bi_memsizes_valid++; | bootinfo.bi_memsizes_valid++; | ||||
bootinfo.bi_bios_dev = dsk->drive; | bootinfo.bi_bios_dev = zdsk->dsk.drive; | ||||
bootdev = MAKEBOOTDEV(dev_maj[dsk->type], | bootdev = MAKEBOOTDEV(dev_maj[zdsk->dsk.type], | ||||
dsk->slice, dsk->unit, dsk->part); | zdsk->dsk.slice, zdsk->dsk.unit, zdsk->dsk.part); | ||||
/* Process configuration file */ | /* Process configuration file */ | ||||
autoboot = 1; | autoboot = 1; | ||||
#ifdef LOADER_GELI_SUPPORT | |||||
geli_init(); | |||||
#endif | |||||
zfs_init(); | zfs_init(); | ||||
/* | /* | ||||
* Probe the boot drive first - we will try to boot from whatever | * Probe the boot drive first - we will try to boot from whatever | ||||
* pool we find on that drive. | * pool we find on that drive. | ||||
*/ | */ | ||||
probe_drive(dsk); | probe_drive(zdsk); | ||||
/* | /* | ||||
* Probe the rest of the drives that the bios knows about. This | * Probe the rest of the drives that the bios knows about. This | ||||
* will find any other available pools and it may fill in missing | * will find any other available pools and it may fill in missing | ||||
* vdevs for the boot pool. | * vdevs for the boot pool. | ||||
*/ | */ | ||||
#ifndef VIRTUALBOX | #ifndef VIRTUALBOX | ||||
for (i = 0; i < *(unsigned char *)PTOV(BIOS_NUMDRIVES); i++) | for (i = 0; i < *(unsigned char *)PTOV(BIOS_NUMDRIVES); i++) | ||||
#else | #else | ||||
for (i = 0; i < MAXBDDEV; i++) | for (i = 0; i < MAXBDDEV; i++) | ||||
#endif | #endif | ||||
{ | { | ||||
if ((i | DRV_HARD) == *(uint8_t *)PTOV(ARGS)) | if ((i | DRV_HARD) == *(uint8_t *)PTOV(ARGS)) | ||||
continue; | continue; | ||||
if (!int13probe(i | DRV_HARD)) | if (!int13probe(i | DRV_HARD)) | ||||
break; | break; | ||||
dsk = malloc(sizeof(struct dsk)); | zdsk = malloc(sizeof(struct zfsdsk)); | ||||
dsk->drive = i | DRV_HARD; | zdsk->dsk.drive = i | DRV_HARD; | ||||
dsk->type = dsk->drive & TYPE_AD; | zdsk->dsk.type = zdsk->dsk.drive & TYPE_AD; | ||||
dsk->unit = i; | zdsk->dsk.unit = i; | ||||
dsk->slice = 0; | zdsk->dsk.slice = 0; | ||||
dsk->part = 0; | zdsk->dsk.part = 0; | ||||
dsk->start = 0; | zdsk->dsk.start = 0; | ||||
dsk->size = drvsize_ext(dsk); | zdsk->dsk.size = drvsize_ext(zdsk); | ||||
probe_drive(dsk); | probe_drive(zdsk); | ||||
} | } | ||||
/* | /* | ||||
* The first discovered pool, if any, is the pool. | * The first discovered pool, if any, is the pool. | ||||
*/ | */ | ||||
spa = spa_get_primary(); | spa = spa_get_primary(); | ||||
if (!spa) { | if (!spa) { | ||||
printf("%s: No ZFS pools located, can't boot\n", BOOTPROG); | printf("%s: No ZFS pools located, can't boot\n", BOOTPROG); | ||||
▲ Show 20 Lines • Show All 214 Lines • ▼ Show 20 Lines | addr = hdr.eh.e_entry & 0xffffff; | ||||
bootinfo.bi_kernelname = VTOP(kname); | bootinfo.bi_kernelname = VTOP(kname); | ||||
zfsargs.size = sizeof(zfsargs); | zfsargs.size = sizeof(zfsargs); | ||||
zfsargs.pool = zfsmount.spa->spa_guid; | zfsargs.pool = zfsmount.spa->spa_guid; | ||||
zfsargs.root = zfsmount.rootobj; | zfsargs.root = zfsmount.rootobj; | ||||
zfsargs.primary_pool = primary_spa->spa_guid; | zfsargs.primary_pool = primary_spa->spa_guid; | ||||
#ifdef LOADER_GELI_SUPPORT | #ifdef LOADER_GELI_SUPPORT | ||||
explicit_bzero(gelipw, sizeof(gelipw)); | explicit_bzero(gelipw, sizeof(gelipw)); | ||||
gelibuf = malloc(sizeof(struct keybuf) + (GELI_MAX_KEYS * sizeof(struct keybuf_ent))); | gelibuf = malloc(sizeof(struct keybuf) + (GELI_MAX_KEYS * sizeof(struct keybuf_ent))); | ||||
geli_fill_keybuf(gelibuf); | geli_export_key_buffer(gelibuf); | ||||
zfsargs.notapw = '\0'; | zfsargs.notapw = '\0'; | ||||
zfsargs.keybuf_sentinel = KEYBUF_SENTINEL; | zfsargs.keybuf_sentinel = KEYBUF_SENTINEL; | ||||
zfsargs.keybuf = gelibuf; | zfsargs.keybuf = gelibuf; | ||||
#else | #else | ||||
zfsargs.gelipw[0] = '\0'; | zfsargs.gelipw[0] = '\0'; | ||||
#endif | #endif | ||||
if (primary_vdev != NULL) | if (primary_vdev != NULL) | ||||
zfsargs.primary_vdev = primary_vdev->v_guid; | zfsargs.primary_vdev = primary_vdev->v_guid; | ||||
▲ Show 20 Lines • Show All 138 Lines • Show Last 20 Lines |