Changeset View
Changeset View
Standalone View
Standalone View
stand/i386/libi386/biosdisk.c
Show First 20 Lines • Show All 114 Lines • ▼ Show 20 Lines | #define BD_FLOPPY 0x0004 | ||||
int bd_type; /* BIOS 'drive type' (floppy only) */ | int bd_type; /* BIOS 'drive type' (floppy only) */ | ||||
uint16_t bd_sectorsize; /* Sector size */ | uint16_t bd_sectorsize; /* Sector size */ | ||||
uint64_t bd_sectors; /* Disk size */ | uint64_t bd_sectors; /* Disk size */ | ||||
int bd_open; /* reference counter */ | int bd_open; /* reference counter */ | ||||
void *bd_bcache; /* buffer cache data */ | void *bd_bcache; /* buffer cache data */ | ||||
} bdinfo [MAXBDDEV]; | } bdinfo [MAXBDDEV]; | ||||
static int nbdinfo = 0; | static int nbdinfo = 0; | ||||
#define BD(dev) (bdinfo[(dev)->d_unit]) | #define BD(dev) (bdinfo[(dev)->dd.d_unit]) | ||||
static int bd_read(struct disk_devdesc *dev, daddr_t dblk, int blks, | static int bd_read(struct disk_devdesc *dev, daddr_t dblk, int blks, | ||||
caddr_t dest); | caddr_t dest); | ||||
static int bd_write(struct disk_devdesc *dev, daddr_t dblk, int blks, | static int bd_write(struct disk_devdesc *dev, daddr_t dblk, int blks, | ||||
caddr_t dest); | caddr_t dest); | ||||
static int bd_int13probe(struct bdinfo *bd); | static int bd_int13probe(struct bdinfo *bd); | ||||
static int bd_init(void); | static int bd_init(void); | ||||
▲ Show 20 Lines • Show All 212 Lines • ▼ Show 20 Lines | for (i = 0; i < nbdinfo; i++) { | ||||
snprintf(line, sizeof(line), | snprintf(line, sizeof(line), | ||||
" disk%d: BIOS drive %c (%ju X %u):\n", i, | " disk%d: BIOS drive %c (%ju X %u):\n", i, | ||||
(bdinfo[i].bd_unit < 0x80) ? ('A' + bdinfo[i].bd_unit): | (bdinfo[i].bd_unit < 0x80) ? ('A' + bdinfo[i].bd_unit): | ||||
('C' + bdinfo[i].bd_unit - 0x80), | ('C' + bdinfo[i].bd_unit - 0x80), | ||||
(uintmax_t)bdinfo[i].bd_sectors, | (uintmax_t)bdinfo[i].bd_sectors, | ||||
bdinfo[i].bd_sectorsize); | bdinfo[i].bd_sectorsize); | ||||
if ((ret = pager_output(line)) != 0) | if ((ret = pager_output(line)) != 0) | ||||
break; | break; | ||||
dev.d_dev = &biosdisk; | dev.dd.d_dev = &biosdisk; | ||||
dev.d_unit = i; | dev.dd.d_unit = i; | ||||
dev.d_slice = -1; | dev.d_slice = -1; | ||||
dev.d_partition = -1; | dev.d_partition = -1; | ||||
if (disk_open(&dev, | if (disk_open(&dev, | ||||
bdinfo[i].bd_sectorsize * bdinfo[i].bd_sectors, | bdinfo[i].bd_sectorsize * bdinfo[i].bd_sectors, | ||||
bdinfo[i].bd_sectorsize) == 0) { | bdinfo[i].bd_sectorsize) == 0) { | ||||
snprintf(line, sizeof(line), " disk%d", i); | snprintf(line, sizeof(line), " disk%d", i); | ||||
ret = disk_print(&dev, line, verbose); | ret = disk_print(&dev, line, verbose); | ||||
disk_close(&dev); | disk_close(&dev); | ||||
Show All 22 Lines | bd_open(struct open_file *f, ...) | ||||
int err, g_err; | int err, g_err; | ||||
va_list ap; | va_list ap; | ||||
uint64_t size; | uint64_t size; | ||||
va_start(ap, f); | va_start(ap, f); | ||||
dev = va_arg(ap, struct disk_devdesc *); | dev = va_arg(ap, struct disk_devdesc *); | ||||
va_end(ap); | va_end(ap); | ||||
if (dev->d_unit < 0 || dev->d_unit >= nbdinfo) | if (dev->dd.d_unit < 0 || dev->dd.d_unit >= nbdinfo) | ||||
return (EIO); | return (EIO); | ||||
BD(dev).bd_open++; | BD(dev).bd_open++; | ||||
if (BD(dev).bd_bcache == NULL) | if (BD(dev).bd_bcache == NULL) | ||||
BD(dev).bd_bcache = bcache_allocate(); | BD(dev).bd_bcache = bcache_allocate(); | ||||
/* | /* | ||||
* Read disk size from partition. | * Read disk size from partition. | ||||
* This is needed to work around buggy BIOS systems returning | * This is needed to work around buggy BIOS systems returning | ||||
* wrong (truncated) disk media size. | * wrong (truncated) disk media size. | ||||
* During bd_probe() we tested if the mulitplication of bd_sectors | * During bd_probe() we tested if the mulitplication of bd_sectors | ||||
* would overflow so it should be safe to perform here. | * would overflow so it should be safe to perform here. | ||||
*/ | */ | ||||
disk.d_dev = dev->d_dev; | disk.dd.d_dev = dev->dd.d_dev; | ||||
disk.d_type = dev->d_type; | disk.dd.d_unit = dev->dd.d_unit; | ||||
disk.d_unit = dev->d_unit; | disk.dd.d_opendata = NULL; | ||||
disk.d_opendata = NULL; | |||||
disk.d_slice = -1; | disk.d_slice = -1; | ||||
disk.d_partition = -1; | disk.d_partition = -1; | ||||
disk.d_offset = 0; | disk.d_offset = 0; | ||||
if (disk_open(&disk, BD(dev).bd_sectors * BD(dev).bd_sectorsize, | if (disk_open(&disk, BD(dev).bd_sectors * BD(dev).bd_sectorsize, | ||||
BD(dev).bd_sectorsize) == 0) { | BD(dev).bd_sectorsize) == 0) { | ||||
if (disk_ioctl(&disk, DIOCGMEDIASIZE, &size) == 0) { | if (disk_ioctl(&disk, DIOCGMEDIASIZE, &size) == 0) { | ||||
size /= BD(dev).bd_sectorsize; | size /= BD(dev).bd_sectorsize; | ||||
Show All 9 Lines | |||||
#ifdef LOADER_GELI_SUPPORT | #ifdef LOADER_GELI_SUPPORT | ||||
static char gelipw[GELI_PW_MAXLEN]; | static char gelipw[GELI_PW_MAXLEN]; | ||||
char *passphrase; | char *passphrase; | ||||
if (err) | if (err) | ||||
return (err); | return (err); | ||||
/* if we already know there is no GELI, skip the rest */ | /* if we already know there is no GELI, skip the rest */ | ||||
if (geli_status[dev->d_unit][dev->d_slice] != ISGELI_UNKNOWN) | if (geli_status[dev->dd.d_unit][dev->d_slice] != ISGELI_UNKNOWN) | ||||
return (err); | return (err); | ||||
struct dsk dskp; | struct dsk dskp; | ||||
struct ptable *table = NULL; | struct ptable *table = NULL; | ||||
struct ptable_entry part; | struct ptable_entry part; | ||||
struct pentry *entry; | struct pentry *entry; | ||||
int geli_part = 0; | int geli_part = 0; | ||||
dskp.drive = bd_unit2bios(dev->d_unit); | dskp.drive = bd_unit2bios(dev->dd.d_unit); | ||||
dskp.type = dev->d_type; | dskp.type = dev->dd.d_dev->dv_type; | ||||
dskp.unit = dev->d_unit; | dskp.unit = dev->dd.d_unit; | ||||
dskp.slice = dev->d_slice; | dskp.slice = dev->d_slice; | ||||
dskp.part = dev->d_partition; | dskp.part = dev->d_partition; | ||||
dskp.start = dev->d_offset; | dskp.start = dev->d_offset; | ||||
memcpy(&rdev, dev, sizeof(rdev)); | memcpy(&rdev, dev, sizeof(rdev)); | ||||
/* to read the GPT table, we need to read the first sector */ | /* to read the GPT table, we need to read the first sector */ | ||||
rdev.d_offset = 0; | rdev.d_offset = 0; | ||||
/* We need the LBA of the end of the partition */ | /* We need the LBA of the end of the partition */ | ||||
table = ptable_open(&rdev, BD(dev).bd_sectors, | table = ptable_open(&rdev, BD(dev).bd_sectors, | ||||
BD(dev).bd_sectorsize, ptblread); | BD(dev).bd_sectorsize, ptblread); | ||||
if (table == NULL) { | if (table == NULL) { | ||||
DEBUG("Can't read partition table"); | DEBUG("Can't read partition table"); | ||||
/* soft failure, return the exit status of disk_open */ | /* soft failure, return the exit status of disk_open */ | ||||
return (err); | return (err); | ||||
} | } | ||||
if (table->type == PTABLE_GPT) | if (table->type == PTABLE_GPT) | ||||
dskp.part = 255; | dskp.part = 255; | ||||
STAILQ_FOREACH(entry, &table->entries, entry) { | STAILQ_FOREACH(entry, &table->entries, entry) { | ||||
dskp.slice = entry->part.index; | dskp.slice = entry->part.index; | ||||
dskp.start = entry->part.start; | dskp.start = entry->part.start; | ||||
if (is_geli(&dskp) == 0) { | if (is_geli(&dskp) == 0) { | ||||
geli_status[dev->d_unit][dskp.slice] = ISGELI_YES; | geli_status[dev->dd.d_unit][dskp.slice] = ISGELI_YES; | ||||
return (0); | return (0); | ||||
} | } | ||||
if (geli_taste(bios_read, &dskp, | if (geli_taste(bios_read, &dskp, | ||||
entry->part.end - entry->part.start) == 0) { | entry->part.end - entry->part.start) == 0) { | ||||
if (geli_havekey(&dskp) == 0) { | if (geli_havekey(&dskp) == 0) { | ||||
geli_status[dev->d_unit][dskp.slice] = ISGELI_YES; | geli_status[dev->dd.d_unit][dskp.slice] = ISGELI_YES; | ||||
geli_part++; | geli_part++; | ||||
continue; | continue; | ||||
} | } | ||||
if ((passphrase = getenv("kern.geom.eli.passphrase")) | if ((passphrase = getenv("kern.geom.eli.passphrase")) | ||||
!= NULL) { | != NULL) { | ||||
/* Use the cached passphrase */ | /* Use the cached passphrase */ | ||||
bcopy(passphrase, &gelipw, GELI_PW_MAXLEN); | bcopy(passphrase, &gelipw, GELI_PW_MAXLEN); | ||||
} | } | ||||
if (geli_passphrase(gelipw, dskp.unit, 'p', | if (geli_passphrase(gelipw, dskp.unit, 'p', | ||||
(dskp.slice > 0 ? dskp.slice : dskp.part), | (dskp.slice > 0 ? dskp.slice : dskp.part), | ||||
&dskp) == 0) { | &dskp) == 0) { | ||||
setenv("kern.geom.eli.passphrase", gelipw, 1); | setenv("kern.geom.eli.passphrase", gelipw, 1); | ||||
bzero(gelipw, sizeof(gelipw)); | bzero(gelipw, sizeof(gelipw)); | ||||
geli_status[dev->d_unit][dskp.slice] = ISGELI_YES; | geli_status[dev->dd.d_unit][dskp.slice] = ISGELI_YES; | ||||
geli_part++; | geli_part++; | ||||
continue; | continue; | ||||
} | } | ||||
} else | } else | ||||
geli_status[dev->d_unit][dskp.slice] = ISGELI_NO; | geli_status[dev->dd.d_unit][dskp.slice] = ISGELI_NO; | ||||
} | } | ||||
/* none of the partitions on this disk have GELI */ | /* none of the partitions on this disk have GELI */ | ||||
if (geli_part == 0) { | if (geli_part == 0) { | ||||
/* found no GELI */ | /* found no GELI */ | ||||
geli_status[dev->d_unit][dev->d_slice] = ISGELI_NO; | geli_status[dev->dd.d_unit][dev->d_slice] = ISGELI_NO; | ||||
} | } | ||||
#endif /* LOADER_GELI_SUPPORT */ | #endif /* LOADER_GELI_SUPPORT */ | ||||
return (err); | return (err); | ||||
} | } | ||||
static int | static int | ||||
bd_close(struct open_file *f) | bd_close(struct open_file *f) | ||||
▲ Show 20 Lines • Show All 320 Lines • ▼ Show 20 Lines | |||||
#ifdef LOADER_GELI_SUPPORT | #ifdef LOADER_GELI_SUPPORT | ||||
struct dsk dskp; | struct dsk dskp; | ||||
off_t p_off, diff; | off_t p_off, diff; | ||||
daddr_t alignlba; | daddr_t alignlba; | ||||
int err, n, alignblks; | int err, n, alignblks; | ||||
char *tmpbuf; | char *tmpbuf; | ||||
/* if we already know there is no GELI, skip the rest */ | /* if we already know there is no GELI, skip the rest */ | ||||
if (geli_status[dev->d_unit][dev->d_slice] != ISGELI_YES) | if (geli_status[dev->dd.d_unit][dev->d_slice] != ISGELI_YES) | ||||
return (bd_io(dev, dblk, blks, dest, 0)); | return (bd_io(dev, dblk, blks, dest, 0)); | ||||
if (geli_status[dev->d_unit][dev->d_slice] == ISGELI_YES) { | if (geli_status[dev->dd.d_unit][dev->d_slice] == ISGELI_YES) { | ||||
/* | /* | ||||
* Align reads to DEV_GELIBOOT_BSIZE bytes because partial | * Align reads to DEV_GELIBOOT_BSIZE bytes because partial | ||||
* sectors cannot be decrypted. Round the requested LBA down to | * sectors cannot be decrypted. Round the requested LBA down to | ||||
* nearest multiple of DEV_GELIBOOT_BSIZE bytes. | * nearest multiple of DEV_GELIBOOT_BSIZE bytes. | ||||
*/ | */ | ||||
alignlba = rounddown2(dblk * BD(dev).bd_sectorsize, | alignlba = rounddown2(dblk * BD(dev).bd_sectorsize, | ||||
DEV_GELIBOOT_BSIZE) / BD(dev).bd_sectorsize; | DEV_GELIBOOT_BSIZE) / BD(dev).bd_sectorsize; | ||||
/* | /* | ||||
Show All 17 Lines | if (diff == 0) { | ||||
return (-1); | return (-1); | ||||
} | } | ||||
} | } | ||||
err = bd_io(dev, alignlba, alignblks, tmpbuf, 0); | err = bd_io(dev, alignlba, alignblks, tmpbuf, 0); | ||||
if (err) | if (err) | ||||
return (err); | return (err); | ||||
dskp.drive = bd_unit2bios(dev->d_unit); | dskp.drive = bd_unit2bios(dev->dd.d_unit); | ||||
dskp.type = dev->d_type; | dskp.type = dev->dd.d_dev->dv_type; | ||||
dskp.unit = dev->d_unit; | dskp.unit = dev->dd.d_unit; | ||||
dskp.slice = dev->d_slice; | dskp.slice = dev->d_slice; | ||||
dskp.part = dev->d_partition; | dskp.part = dev->d_partition; | ||||
dskp.start = dev->d_offset; | dskp.start = dev->d_offset; | ||||
/* GELI needs the offset relative to the partition start */ | /* GELI needs the offset relative to the partition start */ | ||||
p_off = alignlba - dskp.start; | p_off = alignlba - dskp.start; | ||||
err = geli_read(&dskp, p_off * BD(dev).bd_sectorsize, (u_char *)tmpbuf, | err = geli_read(&dskp, p_off * BD(dev).bd_sectorsize, (u_char *)tmpbuf, | ||||
▲ Show 20 Lines • Show All 60 Lines • ▼ Show 20 Lines | bd_getdev(struct i386_devdesc *d) | ||||
struct disk_devdesc *dev; | struct disk_devdesc *dev; | ||||
int biosdev; | int biosdev; | ||||
int major; | int major; | ||||
int rootdev; | int rootdev; | ||||
char *nip, *cp; | char *nip, *cp; | ||||
int i, unit; | int i, unit; | ||||
dev = (struct disk_devdesc *)d; | dev = (struct disk_devdesc *)d; | ||||
biosdev = bd_unit2bios(dev->d_unit); | biosdev = bd_unit2bios(dev->dd.d_unit); | ||||
DEBUG("unit %d BIOS device %d", dev->d_unit, biosdev); | DEBUG("unit %d BIOS device %d", dev->dd.d_unit, biosdev); | ||||
if (biosdev == -1) /* not a BIOS device */ | if (biosdev == -1) /* not a BIOS device */ | ||||
return(-1); | return(-1); | ||||
if (disk_open(dev, BD(dev).bd_sectors * BD(dev).bd_sectorsize, | if (disk_open(dev, BD(dev).bd_sectors * BD(dev).bd_sectorsize, | ||||
BD(dev).bd_sectorsize) != 0) /* oops, not a viable device */ | BD(dev).bd_sectorsize) != 0) /* oops, not a viable device */ | ||||
return (-1); | return (-1); | ||||
else | else | ||||
disk_close(dev); | disk_close(dev); | ||||
if (biosdev < 0x80) { | if (biosdev < 0x80) { | ||||
/* floppy (or emulated floppy) or ATAPI device */ | /* floppy (or emulated floppy) or ATAPI device */ | ||||
if (bdinfo[dev->d_unit].bd_type == DT_ATAPI) { | if (bdinfo[dev->dd.d_unit].bd_type == DT_ATAPI) { | ||||
/* is an ATAPI disk */ | /* is an ATAPI disk */ | ||||
major = WFDMAJOR; | major = WFDMAJOR; | ||||
} else { | } else { | ||||
/* is a floppy disk */ | /* is a floppy disk */ | ||||
major = FDMAJOR; | major = FDMAJOR; | ||||
} | } | ||||
} else { | } else { | ||||
/* assume an IDE disk */ | /* assume an IDE disk */ | ||||
Show All 17 Lines | |||||
#ifdef LOADER_GELI_SUPPORT | #ifdef LOADER_GELI_SUPPORT | ||||
int | int | ||||
bios_read(void *vdev __unused, void *xpriv, off_t off, void *buf, size_t bytes) | bios_read(void *vdev __unused, void *xpriv, off_t off, void *buf, size_t bytes) | ||||
{ | { | ||||
struct disk_devdesc dev; | struct disk_devdesc dev; | ||||
struct dsk *priv = xpriv; | struct dsk *priv = xpriv; | ||||
dev.d_dev = &biosdisk; | dev.dd.d_dev = &biosdisk; | ||||
dev.d_type = priv->type; | dev.dd.d_unit = priv->unit; | ||||
dev.d_unit = priv->unit; | |||||
dev.d_slice = priv->slice; | dev.d_slice = priv->slice; | ||||
dev.d_partition = priv->part; | dev.d_partition = priv->part; | ||||
dev.d_offset = priv->start; | dev.d_offset = priv->start; | ||||
off = off / BD(&dev).bd_sectorsize; | off = off / BD(&dev).bd_sectorsize; | ||||
/* GELI gives us the offset relative to the partition start */ | /* GELI gives us the offset relative to the partition start */ | ||||
off += dev.d_offset; | off += dev.d_offset; | ||||
bytes = bytes / BD(&dev).bd_sectorsize; | bytes = bytes / BD(&dev).bd_sectorsize; | ||||
return (bd_io(&dev, off, bytes, buf, 0)); | return (bd_io(&dev, off, bytes, buf, 0)); | ||||
} | } | ||||
#endif /* LOADER_GELI_SUPPORT */ | #endif /* LOADER_GELI_SUPPORT */ |