Changeset View
Changeset View
Standalone View
Standalone View
sys/boot/i386/zfsboot/zfsboot.c
Show First 20 Lines • Show All 113 Lines • ▼ Show 20 Lines | |||||
#define READ_BUF_SIZE 8192 | #define READ_BUF_SIZE 8192 | ||||
struct dmadat { | struct dmadat { | ||||
char rdbuf[READ_BUF_SIZE]; /* for reading large things */ | char rdbuf[READ_BUF_SIZE]; /* for reading large things */ | ||||
char secbuf[READ_BUF_SIZE]; /* for MBR/disklabel */ | char secbuf[READ_BUF_SIZE]; /* for MBR/disklabel */ | ||||
}; | }; | ||||
static struct dmadat *dmadat; | static struct dmadat *dmadat; | ||||
void exit(int); | void exit(int); | ||||
void reboot(void); | |||||
static void load(void); | static void load(void); | ||||
static int parse(void); | static int parse(void); | ||||
static void bios_getmem(void); | static void bios_getmem(void); | ||||
void *malloc(size_t n); | void *malloc(size_t n); | ||||
void free(void *ptr); | void free(void *ptr); | ||||
void * | void * | ||||
malloc(size_t n) | malloc(size_t n) | ||||
Show All 40 Lines | |||||
{ | { | ||||
const znode_phys_t *zp = (const znode_phys_t *) dnode->dn_bonus; | const znode_phys_t *zp = (const znode_phys_t *) dnode->dn_bonus; | ||||
size_t n; | size_t n; | ||||
int rc; | int rc; | ||||
n = size; | n = size; | ||||
if (*offp + n > zp->zp_size) | if (*offp + n > zp->zp_size) | ||||
n = zp->zp_size - *offp; | n = zp->zp_size - *offp; | ||||
rc = dnode_read(spa, dnode, *offp, start, n); | rc = dnode_read(spa, dnode, *offp, start, n); | ||||
if (rc) | if (rc) | ||||
return (-1); | return (-1); | ||||
*offp += n; | *offp += n; | ||||
return (n); | return (n); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 68 Lines • ▼ Show 20 Lines | #endif | ||||
/* Don't need the leading offset after the first block. */ | /* Don't need the leading offset after the first block. */ | ||||
diff = 0; | diff = 0; | ||||
} | } | ||||
return 0; | return 0; | ||||
} | } | ||||
static int | static int | ||||
vdev_write(vdev_t *vdev, void *priv, off_t off, void *buf, size_t bytes) | |||||
{ | |||||
char *p; | |||||
daddr_t lba; | |||||
unsigned int nb; | |||||
struct dsk *dsk = (struct dsk *) priv; | |||||
if ((off & (DEV_BSIZE - 1)) || (bytes & (DEV_BSIZE - 1))) | |||||
return -1; | |||||
p = buf; | |||||
lba = off / DEV_BSIZE; | |||||
lba += dsk->start; | |||||
while (bytes > 0) { | |||||
nb = bytes / DEV_BSIZE; | |||||
if (nb > READ_BUF_SIZE / DEV_BSIZE) | |||||
nb = READ_BUF_SIZE / DEV_BSIZE; | |||||
memcpy(dmadat->rdbuf, p, nb * DEV_BSIZE); | |||||
if (drvwrite(dsk, dmadat->rdbuf, lba, nb)) | |||||
return -1; | |||||
p += nb * DEV_BSIZE; | |||||
lba += nb; | |||||
bytes -= nb * DEV_BSIZE; | |||||
} | |||||
return 0; | |||||
} | |||||
static int | |||||
xfsread(const dnode_phys_t *dnode, off_t *offp, void *buf, size_t nbyte) | xfsread(const dnode_phys_t *dnode, off_t *offp, void *buf, size_t nbyte) | ||||
{ | { | ||||
if ((size_t)zfs_read(spa, dnode, offp, buf, nbyte) != nbyte) { | if ((size_t)zfs_read(spa, dnode, offp, buf, nbyte) != nbyte) { | ||||
printf("Invalid format\n"); | printf("Invalid format\n"); | ||||
return -1; | return -1; | ||||
} | } | ||||
return 0; | return 0; | ||||
} | } | ||||
/* | |||||
* Read Pad2 (formerly "Boot Block Header") area of the first | |||||
* vdev label of the given vdev. | |||||
*/ | |||||
static int | |||||
vdev_read_pad2(vdev_t *vdev, char *buf, size_t size) | |||||
{ | |||||
blkptr_t bp; | |||||
char *tmp = zap_scratch; | |||||
off_t off = offsetof(vdev_label_t, vl_pad2); | |||||
if (size > VDEV_PAD_SIZE) | |||||
size = VDEV_PAD_SIZE; | |||||
BP_ZERO(&bp); | |||||
BP_SET_LSIZE(&bp, VDEV_PAD_SIZE); | |||||
BP_SET_PSIZE(&bp, VDEV_PAD_SIZE); | |||||
BP_SET_CHECKSUM(&bp, ZIO_CHECKSUM_LABEL); | |||||
BP_SET_COMPRESS(&bp, ZIO_COMPRESS_OFF); | |||||
DVA_SET_OFFSET(BP_IDENTITY(&bp), off); | |||||
if (vdev_read_phys(vdev, &bp, tmp, off, 0)) | |||||
return (EIO); | |||||
memcpy(buf, tmp, size); | |||||
return (0); | |||||
} | |||||
static int | |||||
vdev_clear_pad2(vdev_t *vdev) | |||||
{ | |||||
char *zeroes = zap_scratch; | |||||
uint64_t *end; | |||||
off_t off = offsetof(vdev_label_t, vl_pad2); | |||||
memset(zeroes, 0, VDEV_PAD_SIZE); | |||||
end = (uint64_t *)(zeroes + VDEV_PAD_SIZE); | |||||
/* ZIO_CHECKSUM_LABEL magic and pre-calcualted checksum for all zeros */ | |||||
end[-5] = 0x0210da7ab10c7a11; | |||||
end[-4] = 0x97f48f807f6e2a3f; | |||||
end[-3] = 0xaf909f1658aacefc; | |||||
end[-2] = 0xcbd1ea57ff6db48b; | |||||
end[-1] = 0x6ec692db0d465fab; | |||||
if (vdev_write(vdev, vdev->v_read_priv, off, zeroes, VDEV_PAD_SIZE)) | |||||
return (EIO); | |||||
return (0); | |||||
} | |||||
static void | static void | ||||
bios_getmem(void) | bios_getmem(void) | ||||
{ | { | ||||
uint64_t size; | uint64_t size; | ||||
/* Parse system memory map */ | /* Parse system memory map */ | ||||
v86.ebx = 0; | v86.ebx = 0; | ||||
do { | do { | ||||
▲ Show 20 Lines • Show All 257 Lines • ▼ Show 20 Lines | #ifdef LOADER_GELI_SUPPORT | ||||
} | } | ||||
#endif /* LOADER_GELI_SUPPORT */ | #endif /* LOADER_GELI_SUPPORT */ | ||||
} | } | ||||
} | } | ||||
int | int | ||||
main(void) | main(void) | ||||
{ | { | ||||
int autoboot, i; | |||||
dnode_phys_t dn; | dnode_phys_t dn; | ||||
off_t off; | off_t off; | ||||
struct dsk *dsk; | struct dsk *dsk; | ||||
int autoboot, i; | |||||
int nextboot; | |||||
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); | ||||
▲ Show 20 Lines • Show All 72 Lines • ▼ Show 20 Lines | #endif | ||||
printf("%s: No ZFS pools located, can't boot\n", BOOTPROG); | printf("%s: No ZFS pools located, can't boot\n", BOOTPROG); | ||||
for (;;) | for (;;) | ||||
; | ; | ||||
} | } | ||||
primary_spa = spa; | primary_spa = spa; | ||||
primary_vdev = spa_get_primary_vdev(spa); | primary_vdev = spa_get_primary_vdev(spa); | ||||
if (zfs_spa_init(spa) != 0 || zfs_mount(spa, 0, &zfsmount) != 0) { | nextboot = 0; | ||||
rc = vdev_read_pad2(primary_vdev, cmd, sizeof(cmd)); | |||||
if (vdev_clear_pad2(primary_vdev)) | |||||
printf("failed to clear pad2 area of primary vdev\n"); | |||||
if (rc == 0) { | |||||
if (*cmd) { | |||||
/* | |||||
* We could find an old-style ZFS Boot Block header here. | |||||
* Simply ignore it. | |||||
*/ | |||||
if (*(uint64_t *)cmd != 0x2f5b007b10c) { | |||||
/* | |||||
* Note that parse() is destructive to cmd[] and we also want | |||||
* to honor RBX_QUIET option that could be present in cmd[]. | |||||
*/ | |||||
nextboot = 1; | |||||
memcpy(cmddup, cmd, sizeof(cmd)); | |||||
if (parse()) { | |||||
printf("failed to parse pad2 area of primary vdev\n"); | |||||
reboot(); | |||||
} | |||||
if (!OPT_CHECK(RBX_QUIET)) | |||||
printf("zfs nextboot: %s\n", cmddup); | |||||
} | |||||
/* Do not process this command twice */ | |||||
*cmd = 0; | |||||
} | |||||
} else | |||||
printf("failed to read pad2 area of primary vdev\n"); | |||||
/* Mount ZFS only if it's not already mounted via nextboot parsing. */ | |||||
if (zfsmount.spa == NULL && | |||||
(zfs_spa_init(spa) != 0 || zfs_mount(spa, 0, &zfsmount) != 0)) { | |||||
printf("%s: failed to mount default pool %s\n", | printf("%s: failed to mount default pool %s\n", | ||||
BOOTPROG, spa->spa_name); | BOOTPROG, spa->spa_name); | ||||
autoboot = 0; | autoboot = 0; | ||||
} else if (zfs_lookup(&zfsmount, PATH_CONFIG, &dn) == 0 || | } else if (zfs_lookup(&zfsmount, PATH_CONFIG, &dn) == 0 || | ||||
zfs_lookup(&zfsmount, PATH_DOTCONFIG, &dn) == 0) { | zfs_lookup(&zfsmount, PATH_DOTCONFIG, &dn) == 0) { | ||||
off = 0; | off = 0; | ||||
zfs_read(spa, &dn, &off, cmd, sizeof(cmd)); | zfs_read(spa, &dn, &off, cmd, sizeof(cmd)); | ||||
} | } | ||||
if (*cmd) { | if (*cmd) { | ||||
/* | /* | ||||
* Note that parse() is destructive to cmd[] and we also want | * Note that parse() is destructive to cmd[] and we also want | ||||
* to honor RBX_QUIET option that could be present in cmd[]. | * to honor RBX_QUIET option that could be present in cmd[]. | ||||
*/ | */ | ||||
memcpy(cmddup, cmd, sizeof(cmd)); | memcpy(cmddup, cmd, sizeof(cmd)); | ||||
if (parse()) | if (parse()) | ||||
autoboot = 0; | autoboot = 0; | ||||
if (!OPT_CHECK(RBX_QUIET)) | if (!OPT_CHECK(RBX_QUIET)) | ||||
printf("%s: %s\n", PATH_CONFIG, cmddup); | printf("%s: %s\n", PATH_CONFIG, cmddup); | ||||
/* Do not process this command twice */ | /* Do not process this command twice */ | ||||
*cmd = 0; | *cmd = 0; | ||||
} | } | ||||
/* Do not risk waiting at the prompt forever. */ | |||||
if (nextboot && !autoboot) | |||||
reboot(); | |||||
/* | /* | ||||
* Try to exec /boot/loader. If interrupted by a keypress, | * Try to exec /boot/loader. If interrupted by a keypress, | ||||
* or in case of failure, try to load a kernel directly instead. | * or in case of failure, try to load a kernel directly instead. | ||||
*/ | */ | ||||
if (autoboot && !*kname) { | if (autoboot && !*kname) { | ||||
memcpy(kname, PATH_LOADER_ZFS, sizeof(PATH_LOADER_ZFS)); | memcpy(kname, PATH_LOADER_ZFS, sizeof(PATH_LOADER_ZFS)); | ||||
if (!keyhit(3)) { | if (!keyhit(3)) { | ||||
Show All 33 Lines | else | ||||
load(); | load(); | ||||
} | } | ||||
} | } | ||||
/* XXX - Needed for btxld to link the boot2 binary; do not remove. */ | /* XXX - Needed for btxld to link the boot2 binary; do not remove. */ | ||||
void | void | ||||
exit(int x) | exit(int x) | ||||
{ | { | ||||
__exit(x); | |||||
} | |||||
void | |||||
reboot(void) | |||||
{ | |||||
__exit(0); | |||||
} | } | ||||
static void | static void | ||||
load(void) | load(void) | ||||
{ | { | ||||
union { | union { | ||||
struct exec ex; | struct exec ex; | ||||
Elf32_Ehdr eh; | Elf32_Ehdr eh; | ||||
▲ Show 20 Lines • Show All 234 Lines • Show Last 20 Lines |