(gpt)zfsboot will read one-time boot directives from a special ZFS pool area. The area was previously described as "Boot Block Header", but currently it is know as Pad2, marked as reserved and is zeroed out on pool creation. The new code interprets data in this area, if any, using the same format as boot.config. The area is immediately wiped out. Failure to parse the directives results in a reboot right after the cleanup. Otherwise the boot sequence proceeds as usual. zfsbootcfg writes zfsboot arguments specified on its command line to the Pad2 area of a disk identified by vfs.zfs.boot.primary_pool and vfs.zfs.boot.primary_vdev kenv variables that are set by loader during boot. Please see the manual page for more. Thanks to all who reviewed, contributed and made suggestions! There are many potential improvements to the feature, please see the review for details. Reviewed by: wblock (docs) Discussed with: jhb, tsoome MFC after: 3 weeks Relnotes: yes Differential Revision: https://reviews.freebsd.org/D7612
118 lines
2.5 KiB
C
118 lines
2.5 KiB
C
/*-
|
|
* Copyright (c) 1998 Robert Nordier
|
|
* Copyright (c) 2010 Pawel Jakub Dawidek <pjd@FreeBSD.org>
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms are freely
|
|
* permitted provided that the above copyright notice and this
|
|
* paragraph and the following disclaimer are duplicated in all
|
|
* such forms.
|
|
*
|
|
* This software is provided "AS IS" and without any express or
|
|
* implied warranties, including, without limitation, the implied
|
|
* warranties of merchantability and fitness for a particular
|
|
* purpose.
|
|
*/
|
|
|
|
#include <sys/cdefs.h>
|
|
__FBSDID("$FreeBSD$");
|
|
|
|
#include <sys/param.h>
|
|
|
|
#include <btxv86.h>
|
|
|
|
#include "rbx.h"
|
|
#include "util.h"
|
|
#include "drv.h"
|
|
#include "edd.h"
|
|
#ifdef USE_XREAD
|
|
#include "xreadorg.h"
|
|
#endif
|
|
|
|
static struct edd_params params;
|
|
|
|
uint64_t
|
|
drvsize(struct dsk *dskp)
|
|
{
|
|
|
|
params.len = sizeof(struct edd_params);
|
|
v86.ctl = V86_FLAGS;
|
|
v86.addr = 0x13;
|
|
v86.eax = 0x4800;
|
|
v86.edx = dskp->drive;
|
|
v86.ds = VTOPSEG(¶ms);
|
|
v86.esi = VTOPOFF(¶ms);
|
|
v86int();
|
|
if (V86_CY(v86.efl)) {
|
|
printf("error %u\n", v86.eax >> 8 & 0xff);
|
|
return (0);
|
|
}
|
|
return (params.sectors);
|
|
}
|
|
|
|
#ifndef USE_XREAD
|
|
static struct edd_packet packet;
|
|
#endif
|
|
|
|
int
|
|
drvread(struct dsk *dskp, void *buf, daddr_t lba, unsigned nblk)
|
|
{
|
|
static unsigned c = 0x2d5c7c2f;
|
|
|
|
if (!OPT_CHECK(RBX_QUIET))
|
|
printf("%c\b", c = c << 8 | c >> 24);
|
|
#ifndef USE_XREAD
|
|
packet.len = sizeof(struct edd_packet);
|
|
packet.count = nblk;
|
|
packet.off = VTOPOFF(buf);
|
|
packet.seg = VTOPSEG(buf);
|
|
packet.lba = lba;
|
|
v86.ctl = V86_FLAGS;
|
|
v86.addr = 0x13;
|
|
v86.eax = 0x4200;
|
|
v86.edx = dskp->drive;
|
|
v86.ds = VTOPSEG(&packet);
|
|
v86.esi = VTOPOFF(&packet);
|
|
#else /* USE_XREAD */
|
|
v86.ctl = V86_ADDR | V86_CALLF | V86_FLAGS;
|
|
v86.addr = XREADORG; /* call to xread in boot1 */
|
|
v86.es = VTOPSEG(buf);
|
|
v86.eax = lba;
|
|
v86.ebx = VTOPOFF(buf);
|
|
v86.ecx = lba >> 32;
|
|
v86.edx = nblk << 8 | dskp->drive;
|
|
#endif /* USE_XREAD */
|
|
v86int();
|
|
if (V86_CY(v86.efl)) {
|
|
printf("%s: error %u lba %u\n",
|
|
BOOTPROG, v86.eax >> 8 & 0xff, lba);
|
|
return (-1);
|
|
}
|
|
return (0);
|
|
}
|
|
|
|
#if defined(GPT) || defined(ZFS)
|
|
int
|
|
drvwrite(struct dsk *dskp, void *buf, daddr_t lba, unsigned nblk)
|
|
{
|
|
|
|
packet.len = sizeof(struct edd_packet);
|
|
packet.count = nblk;
|
|
packet.off = VTOPOFF(buf);
|
|
packet.seg = VTOPSEG(buf);
|
|
packet.lba = lba;
|
|
v86.ctl = V86_FLAGS;
|
|
v86.addr = 0x13;
|
|
v86.eax = 0x4300;
|
|
v86.edx = dskp->drive;
|
|
v86.ds = VTOPSEG(&packet);
|
|
v86.esi = VTOPOFF(&packet);
|
|
v86int();
|
|
if (V86_CY(v86.efl)) {
|
|
printf("error %u lba %u\n", v86.eax >> 8 & 0xff, lba);
|
|
return (-1);
|
|
}
|
|
return (0);
|
|
}
|
|
#endif /* GPT || ZFS */
|