From abb4747a6540a289cb8ffdd4600b34444020b3ef Mon Sep 17 00:00:00 2001 From: kevans Date: Sat, 10 Feb 2018 04:37:44 +0000 Subject: [PATCH] MFC Loader Fixes 2017q1: r311458,r312237,r312314,r312374,r312947,r313042, r313047,r313166,r313328,r313332,r313333,r313337,r313348,r313349,r313389, r313442,r313451,r313575,r313645,r313710,r314114,r314213,r314275,r314945, r314948,r315008,r315408,r315427,r315645,r315646,r315648,r315653,r315850, r316064,r316078,r316079,r316100,r316104,r316111,r316112,r316171,r316279, r316280,r316287,r316311,r316343,r316424,r316436 r311458: Use compiler driver to link BERI boot loaders r312237: loader.efi: find_currdev() can leak memory r312314: loader: move device path definitions to include/efidevp.h r312374: loader: efi devpath api usage should be more aware of NULL pointers r312947: Remove "-Xassembler -G0" from CFLAGS. r313042: loader.efi environment related cleanups r313047: loader: disk/part api needs to use uint64_t offsets r313166: loader: libefi/env.c warnings in arm build r313328: loader: Implement disk_ioctl() to support DIOCGSECTORSIZE and DIOCGMEDIASIZE. r313332: loader: bcache read ahead block count should take account the large sectors r313333: loader: Replace EFI part devices. r313337: loader: 313329 missed ZFS guard in loader/main.c r313348: loader: biosdisk fix for 2+TB disks r313349: loader: disk io should not use alloca() r313389: efipart is also using the '%S' printf format, add -Wno-format for it. r313442: loader: possible NULL pointer dereference in efipart.c r313451: loader: possible NULL pointer dereference in bcache.c r313575: makefs: make the buffer functions look exactly like the kernel ones r313645: loader: implement MEDIA_FILEPATH_DP support in efipart r313710: loader: cstyle fixes and DIOCGMEDIASIZE should use uint64_t r314114: Use LDFLAGS with CC instead of _LDFLAGS. r314213: Remove control+r handling from geliboot's pwgets() r314275: Remove unused macro from common/drv.c. r314945: Some style(9) fixes. No functional changes. r314948: Try to extract the RFC1048 data from PXE. r315008: r314948 seems to be missing a variable or two that will break r315408: loader: remove open_disk cache r315427: loader: biosdisk should report IO error from INT13 r315645: loader: disk_cleanup was left in userboot_disk.c r315646: loader: pxe.h constants have wrong values r315648: libstand: verify value provided by nfs.read_size r315653: loader: verify the value from dhcp.interface-mtu and use snprintf o set mtu r315850: The original author abused Nd (one-line description, used by makewhatis) r316064: Fix build with path names with 'align' or 'nop' in them. r316078: gpt*boot: Save a bit more memory when LOADER_NO_GELI_SUPPORT is specified r316079: Simply retire the sedification of the boot2.s file. r316100: Remove -fno-guess-branch-probability and -fno-unit-at-a-time. r316104: Use `NO_WCAST_ALIGN` instead of spelling it out as -Wno-cast-align in CFLAGS r316111: loader: move bios getsecs into time.c r316112: loader: ls command should display file types properly r316171: xfsread inlined uses more space, so remove the inline tag. r316279: loader: efipart should check disk size from partition table r316280: loader: simplify efi_zfs_probe and avoid double probing for zfs. r316287: Remove OLD_NFSV2 from loader and libstand r316311: Add explicit_bzero() to libstand, and switch GELIBoot to using it r316343: Implement boot-time encryption key passing (keybuf) r316424: Fix sparc64 build broken by r316343 and r316076 r316436: Restore EFI boot environment functionality broken in r313333 PR: 216940 217298 217935 --- lib/libstand/Makefile | 4 + lib/libstand/bootp.c | 36 +- lib/libstand/bootp.h | 6 + lib/libstand/nfs.c | 700 +--------------- lib/libstand/nfsv2.h | 43 - lib/libstand/stand.h | 1 + sys/boot/common/bcache.c | 57 +- sys/boot/common/bootstrap.h | 2 +- sys/boot/common/dev_net.c | 2 +- sys/boot/common/disk.c | 255 ++---- sys/boot/common/disk.h | 30 +- sys/boot/common/ls.c | 61 +- sys/boot/common/part.c | 35 +- sys/boot/common/part.h | 5 +- sys/boot/efi/include/efidevp.h | 30 +- sys/boot/efi/include/efilib.h | 32 +- sys/boot/efi/libefi/Makefile | 10 +- sys/boot/efi/libefi/devpath.c | 69 +- sys/boot/efi/libefi/efinet.c | 32 +- sys/boot/efi/libefi/efipart.c | 833 ++++++++++++++++--- sys/boot/efi/libefi/env.c | 404 +++++++-- sys/boot/efi/libefi/wchar.c | 73 ++ sys/boot/efi/loader/conf.c | 4 +- sys/boot/efi/loader/devicename.c | 60 +- sys/boot/efi/loader/main.c | 571 ++++--------- sys/boot/forth/beastie.4th.8 | 6 +- sys/boot/forth/loader.4th | 4 +- sys/boot/geli/Makefile | 5 +- sys/boot/geli/geliboot.c | 157 +++- sys/boot/geli/geliboot.h | 40 +- sys/boot/geli/geliboot_crypto.c | 3 +- sys/boot/geli/geliboot_internal.h | 69 ++ sys/boot/geli/pwgets.c | 8 - sys/boot/i386/boot2/Makefile | 13 +- sys/boot/i386/boot2/boot2.c | 2 +- sys/boot/i386/btx/lib/btxv86.h | 8 + sys/boot/i386/common/bootargs.h | 20 +- sys/boot/i386/common/drv.c | 15 - sys/boot/i386/gptboot/Makefile | 1 + sys/boot/i386/gptboot/gptboot.c | 32 +- sys/boot/i386/gptzfsboot/Makefile | 4 +- sys/boot/i386/libi386/bioscd.c | 8 +- sys/boot/i386/libi386/biosdisk.c | 165 ++-- sys/boot/i386/libi386/bootinfo32.c | 23 +- sys/boot/i386/libi386/bootinfo64.c | 21 +- sys/boot/i386/libi386/pxe.c | 389 ++++----- sys/boot/i386/libi386/pxe.h | 4 +- sys/boot/i386/libi386/time.c | 9 + sys/boot/i386/loader/Makefile | 1 + sys/boot/i386/loader/main.c | 13 +- sys/boot/i386/zfsboot/zfsboot.c | 30 +- sys/boot/mips/beri/boot2/Makefile | 6 +- sys/boot/mips/beri/common/common.ldscript | 1 - sys/boot/mips/beri/loader/beri_disk_cfi.c | 15 +- sys/boot/mips/beri/loader/beri_disk_sdcard.c | 14 +- sys/boot/mips/beri/loader/loader.ldscript | 1 - sys/boot/sparc64/loader/Makefile | 3 + sys/boot/uboot/lib/disk.c | 5 +- sys/boot/usb/storage/umass_loader.c | 23 +- sys/boot/userboot/userboot/userboot_disk.c | 5 +- sys/boot/zfs/libzfs.h | 20 +- sys/boot/zfs/zfs.c | 9 +- sys/crypto/intake.h | 64 ++ sys/geom/eli/g_eli.c | 234 +++--- sys/geom/eli/g_eli.h | 5 + sys/opencrypto/crypto.c | 39 +- sys/sys/linker.h | 5 +- usr.sbin/makefs/ffs.c | 2 +- usr.sbin/makefs/ffs/buf.c | 16 +- usr.sbin/makefs/ffs/buf.h | 18 +- usr.sbin/makefs/ffs/ffs_alloc.c | 20 +- usr.sbin/makefs/ffs/ffs_balloc.c | 82 +- 72 files changed, 2778 insertions(+), 2214 deletions(-) create mode 100644 sys/boot/efi/libefi/wchar.c create mode 100644 sys/boot/geli/geliboot_internal.h create mode 100644 sys/crypto/intake.h diff --git a/lib/libstand/Makefile b/lib/libstand/Makefile index 59c0745a2c5..ce40621c461 100644 --- a/lib/libstand/Makefile +++ b/lib/libstand/Makefile @@ -155,5 +155,9 @@ SRCS+= pkgfs.c SRCS+= nandfs.c .endif +# explicit_bzero +.PATH: ${SRCTOP}/sys/libkern +SRCS+= explicit_bzero.c + .include .include diff --git a/lib/libstand/bootp.c b/lib/libstand/bootp.c index 0bd37b17780..32dd937d8cb 100644 --- a/lib/libstand/bootp.c +++ b/lib/libstand/bootp.c @@ -39,6 +39,7 @@ __FBSDID("$FreeBSD$"); #include +#include #include #include #include @@ -344,6 +345,17 @@ time_t tleft; return (-1); } +int +dhcp_try_rfc1048(u_char *cp, u_int len) +{ + + expected_dhcpmsgtype = DHCPACK; + if (bcmp(vm_rfc1048, cp, sizeof(vm_rfc1048)) == 0) { + return (vend_rfc1048(cp, len)); + } + return (-1); +} + static int vend_rfc1048(cp, len) u_char *cp; @@ -392,11 +404,29 @@ vend_rfc1048(cp, len) strlcpy(hostname, val, sizeof(hostname)); } if (tag == TAG_INTF_MTU) { + intf_mtu = 0; if ((val = getenv("dhcp.interface-mtu")) != NULL) { - intf_mtu = (u_int)strtoul(val, NULL, 0); - } else { - intf_mtu = be16dec(cp); + unsigned long tmp; + char *end; + + errno = 0; + /* + * Do not allow MTU to exceed max IPv4 packet + * size, max value of 16-bit word. + */ + tmp = strtoul(val, &end, 0); + if (errno != 0 || + *val == '\0' || *end != '\0' || + tmp > USHRT_MAX) { + printf("%s: bad value: \"%s\", " + "ignoring\n", + "dhcp.interface-mtu", val); + } else { + intf_mtu = (u_int)tmp; + } } + if (intf_mtu <= 0) + intf_mtu = be16dec(cp); } #ifdef SUPPORT_DHCP if (tag == TAG_DHCP_MSGTYPE) { diff --git a/lib/libstand/bootp.h b/lib/libstand/bootp.h index 9f4d4139a5b..4a57df26e1b 100644 --- a/lib/libstand/bootp.h +++ b/lib/libstand/bootp.h @@ -22,6 +22,8 @@ * $FreeBSD$ */ +#ifndef _BOOTP_H_ +#define _BOOTP_H_ struct bootp { unsigned char bp_op; /* packet opcode type */ @@ -145,3 +147,7 @@ struct cmu_vend { /* v_flags values */ #define VF_SMASK 1 /* Subnet mask field contains valid data */ + +int dhcp_try_rfc1048(u_char *cp, u_int len); + +#endif /* _BOOTP_H_ */ diff --git a/lib/libstand/nfs.c b/lib/libstand/nfs.c index 19bc73c77a8..8a7e111fcdd 100644 --- a/lib/libstand/nfs.c +++ b/lib/libstand/nfs.c @@ -54,73 +54,6 @@ __FBSDID("$FreeBSD$"); #define NFSREAD_MIN_SIZE 1024 #define NFSREAD_MAX_SIZE 4096 -/* Define our own NFS attributes without NQNFS stuff. */ -#ifdef OLD_NFSV2 -struct nfsv2_fattrs { - n_long fa_type; - n_long fa_mode; - n_long fa_nlink; - n_long fa_uid; - n_long fa_gid; - n_long fa_size; - n_long fa_blocksize; - n_long fa_rdev; - n_long fa_blocks; - n_long fa_fsid; - n_long fa_fileid; - struct nfsv2_time fa_atime; - struct nfsv2_time fa_mtime; - struct nfsv2_time fa_ctime; -}; - -struct nfs_read_args { - u_char fh[NFS_FHSIZE]; - n_long off; - n_long len; - n_long xxx; /* XXX what's this for? */ -}; - -/* Data part of nfs rpc reply (also the largest thing we receive) */ -struct nfs_read_repl { - n_long errno; - struct nfsv2_fattrs fa; - n_long count; - u_char data[NFSREAD_MAX_SIZE]; -}; - -#ifndef NFS_NOSYMLINK -struct nfs_readlnk_repl { - n_long errno; - n_long len; - char path[NFS_MAXPATHLEN]; -}; -#endif - -struct nfs_readdir_args { - u_char fh[NFS_FHSIZE]; - n_long cookie; - n_long count; -}; - -struct nfs_readdir_data { - n_long fileid; - n_long len; - char name[0]; -}; - -struct nfs_readdir_off { - n_long cookie; - n_long follows; -}; - -struct nfs_iodesc { - struct iodesc *iodesc; - off_t off; - u_char fh[NFS_FHSIZE]; - struct nfsv2_fattrs fa; /* all in network order */ -}; -#else /* !OLD_NFSV2 */ - /* NFSv3 definitions */ #define NFS_V3MAXFHSIZE 64 #define NFS_VER3 3 @@ -185,7 +118,6 @@ struct nfs_iodesc { struct nfsv3_fattrs fa; /* all in network order */ uint64_t cookie; }; -#endif /* OLD_NFSV2 */ /* * XXX interactions with tftp? See nfswrapper.c for a confusing @@ -214,621 +146,38 @@ struct fs_ops nfs_fsops = { static int nfs_read_size = NFSREAD_MIN_SIZE; -#ifdef OLD_NFSV2 -/* - * Fetch the root file handle (call mount daemon) - * Return zero or error number. - */ -int -nfs_getrootfh(struct iodesc *d, char *path, u_char *fhp) -{ - int len; - struct args { - n_long len; - char path[FNAME_SIZE]; - } *args; - struct repl { - n_long errno; - u_char fh[NFS_FHSIZE]; - } *repl; - struct { - n_long h[RPC_HEADER_WORDS]; - struct args d; - } sdata; - struct { - n_long h[RPC_HEADER_WORDS]; - struct repl d; - } rdata; - size_t cc; - -#ifdef NFS_DEBUG - if (debug) - printf("nfs_getrootfh: %s\n", path); -#endif - - args = &sdata.d; - repl = &rdata.d; - - bzero(args, sizeof(*args)); - len = strlen(path); - if (len > sizeof(args->path)) - len = sizeof(args->path); - args->len = htonl(len); - bcopy(path, args->path, len); - len = 4 + roundup(len, 4); - - cc = rpc_call(d, RPCPROG_MNT, RPCMNT_VER1, RPCMNT_MOUNT, - args, len, repl, sizeof(*repl)); - if (cc == -1) { - /* errno was set by rpc_call */ - return (errno); - } - if (cc < 4) - return (EBADRPC); - if (repl->errno) - return (ntohl(repl->errno)); - bcopy(repl->fh, fhp, sizeof(repl->fh)); - - /* - * Improve boot performance over NFS - */ - if (getenv("nfs.read_size") != NULL) - nfs_read_size = strtol(getenv("nfs.read_size"), NULL, 0); - if (nfs_read_size < NFSREAD_MIN_SIZE) - nfs_read_size = NFSREAD_MIN_SIZE; - if (nfs_read_size > NFSREAD_MAX_SIZE) - nfs_read_size = NFSREAD_MAX_SIZE; - - return (0); -} - -/* - * Lookup a file. Store handle and attributes. - * Return zero or error number. - */ -int -nfs_lookupfh(struct nfs_iodesc *d, const char *name, struct nfs_iodesc *newfd) -{ - int len, rlen; - struct args { - u_char fh[NFS_FHSIZE]; - n_long len; - char name[FNAME_SIZE]; - } *args; - struct repl { - n_long errno; - u_char fh[NFS_FHSIZE]; - struct nfsv2_fattrs fa; - } *repl; - struct { - n_long h[RPC_HEADER_WORDS]; - struct args d; - } sdata; - struct { - n_long h[RPC_HEADER_WORDS]; - struct repl d; - } rdata; - ssize_t cc; - -#ifdef NFS_DEBUG - if (debug) - printf("lookupfh: called\n"); -#endif - - args = &sdata.d; - repl = &rdata.d; - - bzero(args, sizeof(*args)); - bcopy(d->fh, args->fh, sizeof(args->fh)); - len = strlen(name); - if (len > sizeof(args->name)) - len = sizeof(args->name); - bcopy(name, args->name, len); - args->len = htonl(len); - len = 4 + roundup(len, 4); - len += NFS_FHSIZE; - - rlen = sizeof(*repl); - - cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER2, NFSPROC_LOOKUP, - args, len, repl, rlen); - if (cc == -1) - return (errno); /* XXX - from rpc_call */ - if (cc < 4) - return (EIO); - if (repl->errno) { - /* saerrno.h now matches NFS error numbers. */ - return (ntohl(repl->errno)); - } - bcopy( repl->fh, &newfd->fh, sizeof(newfd->fh)); - bcopy(&repl->fa, &newfd->fa, sizeof(newfd->fa)); - return (0); -} - -#ifndef NFS_NOSYMLINK /* - * Get the destination of a symbolic link. + * Improve boot performance over NFS */ -int -nfs_readlink(struct nfs_iodesc *d, char *buf) +static void +set_nfs_read_size(void) { - struct { - n_long h[RPC_HEADER_WORDS]; - u_char fh[NFS_FHSIZE]; - } sdata; - struct { - n_long h[RPC_HEADER_WORDS]; - struct nfs_readlnk_repl d; - } rdata; - ssize_t cc; - -#ifdef NFS_DEBUG - if (debug) - printf("readlink: called\n"); -#endif - - bcopy(d->fh, sdata.fh, NFS_FHSIZE); - cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER2, NFSPROC_READLINK, - sdata.fh, NFS_FHSIZE, - &rdata.d, sizeof(rdata.d)); - if (cc == -1) - return (errno); - - if (cc < 4) - return (EIO); - - if (rdata.d.errno) - return (ntohl(rdata.d.errno)); - - rdata.d.len = ntohl(rdata.d.len); - if (rdata.d.len > NFS_MAXPATHLEN) - return (ENAMETOOLONG); - - bcopy(rdata.d.path, buf, rdata.d.len); - buf[rdata.d.len] = 0; - return (0); -} -#endif - -/* - * Read data from a file. - * Return transfer count or -1 (and set errno) - */ -ssize_t -nfs_readdata(struct nfs_iodesc *d, off_t off, void *addr, size_t len) -{ - struct nfs_read_args *args; - struct nfs_read_repl *repl; - struct { - n_long h[RPC_HEADER_WORDS]; - struct nfs_read_args d; - } sdata; - struct { - n_long h[RPC_HEADER_WORDS]; - struct nfs_read_repl d; - } rdata; - size_t cc; - long x; - int hlen, rlen; - - args = &sdata.d; - repl = &rdata.d; - - bcopy(d->fh, args->fh, NFS_FHSIZE); - args->off = htonl((n_long)off); - if (len > nfs_read_size) - len = nfs_read_size; - args->len = htonl((n_long)len); - args->xxx = htonl((n_long)0); - hlen = offsetof(struct nfs_read_rpl, data[0]); - - cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER2, NFSPROC_READ, - args, sizeof(*args), - repl, sizeof(*repl)); - if (cc == -1) { - /* errno was already set by rpc_call */ - return (-1); - } - if (cc < hlen) { - errno = EBADRPC; - return (-1); - } - if (repl->errno) { - errno = ntohl(repl->errno); - return (-1); - } - rlen = cc - hlen; - x = ntohl(repl->count); - if (rlen < x) { - printf("nfsread: short packet, %d < %ld\n", rlen, x); - errno = EBADRPC; - return(-1); - } - bcopy(repl->data, addr, x); - return (x); -} - -/* - * Open a file. - * return zero or error number - */ -int -nfs_open(const char *upath, struct open_file *f) -{ - struct iodesc *desc; - struct nfs_iodesc *currfd; - char buf[2 * NFS_FHSIZE + 3]; - u_char *fh; - char *cp; - int i; -#ifndef NFS_NOSYMLINK - struct nfs_iodesc *newfd; - struct nfsv2_fattrs *fa; - char *ncp; - int c; - char namebuf[NFS_MAXPATHLEN + 1]; - char linkbuf[NFS_MAXPATHLEN + 1]; - int nlinks = 0; -#endif - int error; - char *path; - - if (netproto != NET_NFS) - return (EINVAL); - -#ifdef NFS_DEBUG - if (debug) - printf("nfs_open: %s (rootpath=%s)\n", upath, rootpath); -#endif - if (!rootpath[0]) { - printf("no rootpath, no nfs\n"); - return (ENXIO); - } - - /* - * This is silly - we should look at dv_type but that value is - * arch dependant and we can't use it here. - */ -#ifndef __i386__ - if (strcmp(f->f_dev->dv_name, "net") != 0) - return(EINVAL); -#else - if (strcmp(f->f_dev->dv_name, "pxe") != 0) - return(EINVAL); -#endif - - if (!(desc = socktodesc(*(int *)(f->f_devdata)))) - return(EINVAL); - - /* Bind to a reserved port. */ - desc->myport = htons(--rpc_port); - desc->destip = rootip; - if ((error = nfs_getrootfh(desc, rootpath, nfs_root_node.fh))) - return (error); - nfs_root_node.fa.fa_type = htonl(NFDIR); - nfs_root_node.fa.fa_mode = htonl(0755); - nfs_root_node.fa.fa_nlink = htonl(2); - nfs_root_node.iodesc = desc; - - fh = &nfs_root_node.fh[0]; - buf[0] = 'X'; - cp = &buf[1]; - for (i = 0; i < NFS_FHSIZE; i++, cp += 2) - sprintf(cp, "%02x", fh[i]); - sprintf(cp, "X"); - setenv("boot.nfsroot.server", inet_ntoa(rootip), 1); - setenv("boot.nfsroot.path", rootpath, 1); - setenv("boot.nfsroot.nfshandle", buf, 1); - - /* Allocate file system specific data structure */ - currfd = malloc(sizeof(*newfd)); - if (currfd == NULL) { - error = ENOMEM; - goto out; - } - -#ifndef NFS_NOSYMLINK - bcopy(&nfs_root_node, currfd, sizeof(*currfd)); - newfd = NULL; - - cp = path = strdup(upath); - if (path == NULL) { - error = ENOMEM; - goto out; - } - while (*cp) { - /* - * Remove extra separators - */ - while (*cp == '/') - cp++; - - if (*cp == '\0') - break; - /* - * Check that current node is a directory. - */ - if (currfd->fa.fa_type != htonl(NFDIR)) { - error = ENOTDIR; - goto out; - } - - /* allocate file system specific data structure */ - newfd = malloc(sizeof(*newfd)); - newfd->iodesc = currfd->iodesc; - - /* - * Get next component of path name. - */ - { - int len = 0; - - ncp = cp; - while ((c = *cp) != '\0' && c != '/') { - if (++len > NFS_MAXNAMLEN) { - error = ENOENT; - goto out; - } - cp++; - } - *cp = '\0'; + char *env, *end; + char buf[10]; + + if ((env = getenv("nfs.read_size")) != NULL) { + errno = 0; + nfs_read_size = (int)strtol(env, &end, 0); + if (errno != 0 || *env == '\0' || *end != '\0') { + printf("%s: bad value: \"%s\", defaulting to %d\n", + "nfs.read_size", env, NFSREAD_MIN_SIZE); + nfs_read_size = NFSREAD_MIN_SIZE; } - - /* lookup a file handle */ - error = nfs_lookupfh(currfd, ncp, newfd); - *cp = c; - if (error) - goto out; - - /* - * Check for symbolic link - */ - if (newfd->fa.fa_type == htonl(NFLNK)) { - int link_len, len; - - error = nfs_readlink(newfd, linkbuf); - if (error) - goto out; - - link_len = strlen(linkbuf); - len = strlen(cp); - - if (link_len + len > MAXPATHLEN - || ++nlinks > MAXSYMLINKS) { - error = ENOENT; - goto out; - } - - bcopy(cp, &namebuf[link_len], len + 1); - bcopy(linkbuf, namebuf, link_len); - - /* - * If absolute pathname, restart at root. - * If relative pathname, restart at parent directory. - */ - cp = namebuf; - if (*cp == '/') - bcopy(&nfs_root_node, currfd, sizeof(*currfd)); - - free(newfd); - newfd = NULL; - - continue; - } - - free(currfd); - currfd = newfd; - newfd = NULL; } - - error = 0; - -out: - free(newfd); - free(path); -#else - currfd->iodesc = desc; - - error = nfs_lookupfh(&nfs_root_node, upath, currfd); -#endif - if (!error) { - currfd->off = 0; - f->f_fsdata = (void *)currfd; - return (0); - } - -#ifdef NFS_DEBUG - if (debug) - printf("nfs_open: %s lookupfh failed: %s\n", - path, strerror(error)); -#endif - free(currfd); - - return (error); -} - -int -nfs_close(struct open_file *f) -{ - struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; - -#ifdef NFS_DEBUG - if (debug) - printf("nfs_close: fp=0x%lx\n", (u_long)fp); -#endif - - if (fp) - free(fp); - f->f_fsdata = (void *)0; - - return (0); -} - -/* - * read a portion of a file - */ -int -nfs_read(struct open_file *f, void *buf, size_t size, size_t *resid) -{ - struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; - ssize_t cc; - char *addr = buf; - -#ifdef NFS_DEBUG - if (debug) - printf("nfs_read: size=%lu off=%d\n", (u_long)size, - (int)fp->off); -#endif - while ((int)size > 0) { - twiddle(16); - cc = nfs_readdata(fp, fp->off, (void *)addr, size); - /* XXX maybe should retry on certain errors */ - if (cc == -1) { -#ifdef NFS_DEBUG - if (debug) - printf("nfs_read: read: %s", strerror(errno)); -#endif - return (errno); /* XXX - from nfs_readdata */ - } - if (cc == 0) { -#ifdef NFS_DEBUG - if (debug) - printf("nfs_read: hit EOF unexpectantly"); -#endif - goto ret; - } - fp->off += cc; - addr += cc; - size -= cc; + if (nfs_read_size < NFSREAD_MIN_SIZE) { + printf("%s: bad value: \"%d\", defaulting to %d\n", + "nfs.read_size", nfs_read_size, NFSREAD_MIN_SIZE); + nfs_read_size = NFSREAD_MIN_SIZE; } -ret: - if (resid) - *resid = size; - - return (0); -} - -/* - * Not implemented. - */ -int -nfs_write(struct open_file *f, void *buf, size_t size, size_t *resid) -{ - return (EROFS); -} - -off_t -nfs_seek(struct open_file *f, off_t offset, int where) -{ - struct nfs_iodesc *d = (struct nfs_iodesc *)f->f_fsdata; - n_long size = ntohl(d->fa.fa_size); - - switch (where) { - case SEEK_SET: - d->off = offset; - break; - case SEEK_CUR: - d->off += offset; - break; - case SEEK_END: - d->off = size - offset; - break; - default: - errno = EINVAL; - return (-1); + if (nfs_read_size > NFSREAD_MAX_SIZE) { + printf("%s: bad value: \"%d\", defaulting to %d\n", + "nfs.read_size", nfs_read_size, NFSREAD_MIN_SIZE); + nfs_read_size = NFSREAD_MAX_SIZE; } - - return (d->off); -} - -/* NFNON=0, NFREG=1, NFDIR=2, NFBLK=3, NFCHR=4, NFLNK=5 */ -int nfs_stat_types[8] = { - 0, S_IFREG, S_IFDIR, S_IFBLK, S_IFCHR, S_IFLNK, 0 }; - -int -nfs_stat(struct open_file *f, struct stat *sb) -{ - struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; - n_long ftype, mode; - - ftype = ntohl(fp->fa.fa_type); - mode = ntohl(fp->fa.fa_mode); - mode |= nfs_stat_types[ftype & 7]; - - sb->st_mode = mode; - sb->st_nlink = ntohl(fp->fa.fa_nlink); - sb->st_uid = ntohl(fp->fa.fa_uid); - sb->st_gid = ntohl(fp->fa.fa_gid); - sb->st_size = ntohl(fp->fa.fa_size); - - return (0); + snprintf(buf, sizeof (buf), "%d", nfs_read_size); + setenv("nfs.read_size", buf, 1); } -static int -nfs_readdir(struct open_file *f, struct dirent *d) -{ - struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; - struct nfs_readdir_args *args; - struct nfs_readdir_data *rd; - struct nfs_readdir_off *roff = NULL; - static char *buf; - static struct nfs_iodesc *pfp = NULL; - static n_long cookie = 0; - size_t cc; - n_long eof; - - struct { - n_long h[RPC_HEADER_WORDS]; - struct nfs_readdir_args d; - } sdata; - static struct { - n_long h[RPC_HEADER_WORDS]; - u_char d[NFS_READDIRSIZE]; - } rdata; - - if (fp != pfp || fp->off != cookie) { - pfp = NULL; - refill: - args = &sdata.d; - bzero(args, sizeof(*args)); - - bcopy(fp->fh, args->fh, NFS_FHSIZE); - args->cookie = htonl(fp->off); - args->count = htonl(NFS_READDIRSIZE); - - cc = rpc_call(fp->iodesc, NFS_PROG, NFS_VER2, NFSPROC_READDIR, - args, sizeof(*args), - rdata.d, sizeof(rdata.d)); - buf = rdata.d; - roff = (struct nfs_readdir_off *)buf; - if (ntohl(roff->cookie) != 0) - return EIO; - pfp = fp; - cookie = fp->off; - } - roff = (struct nfs_readdir_off *)buf; - - if (ntohl(roff->follows) == 0) { - eof = ntohl((roff+1)->cookie); - if (eof) { - cookie = 0; - return ENOENT; - } - goto refill; - } - - buf += sizeof(struct nfs_readdir_off); - rd = (struct nfs_readdir_data *)buf; - d->d_namlen = ntohl(rd->len); - bcopy(rd->name, d->d_name, d->d_namlen); - d->d_name[d->d_namlen] = '\0'; - - buf += (sizeof(struct nfs_readdir_data) + roundup(htonl(rd->len),4)); - roff = (struct nfs_readdir_off *)buf; - fp->off = cookie = ntohl(roff->cookie); - return 0; -} -#else /* !OLD_NFSV2 */ /* * Fetch the root file handle (call mount daemon) * Return zero or error number. @@ -885,6 +234,8 @@ nfs_getrootfh(struct iodesc *d, char *path, uint32_t *fhlenp, u_char *fhp) return (ntohl(repl->errno)); *fhlenp = ntohl(repl->fhsize); bcopy(repl->fh, fhp, *fhlenp); + + set_nfs_read_size(); return (0); } @@ -1492,4 +843,3 @@ nfs_readdir(struct open_file *f, struct dirent *d) buf = (u_char *)&rent->nameplus[pos]; return (0); } -#endif /* OLD_NFSV2 */ diff --git a/lib/libstand/nfsv2.h b/lib/libstand/nfsv2.h index a6f1c4f770f..184a47bd040 100644 --- a/lib/libstand/nfsv2.h +++ b/lib/libstand/nfsv2.h @@ -119,46 +119,3 @@ typedef enum { NFCHR=4, NFLNK=5 } nfstype; - -/* Structs for common parts of the rpc's */ -struct nfsv2_time { - n_long nfs_sec; - n_long nfs_usec; -}; - -/* - * File attributes and setable attributes. - */ -struct nfsv2_fattr { - n_long fa_type; - n_long fa_mode; - n_long fa_nlink; - n_long fa_uid; - n_long fa_gid; - n_long fa_size; - n_long fa_blocksize; - n_long fa_rdev; - n_long fa_blocks; - n_long fa_fsid; - n_long fa_fileid; - struct nfsv2_time fa_atime; - struct nfsv2_time fa_mtime; - struct nfsv2_time fa_ctime; -}; - -struct nfsv2_sattr { - n_long sa_mode; - n_long sa_uid; - n_long sa_gid; - n_long sa_size; - struct nfsv2_time sa_atime; - struct nfsv2_time sa_mtime; -}; - -struct nfsv2_statfs { - n_long sf_tsize; - n_long sf_bsize; - n_long sf_blocks; - n_long sf_bfree; - n_long sf_bavail; -}; diff --git a/lib/libstand/stand.h b/lib/libstand/stand.h index 112a75b3941..537fca75995 100644 --- a/lib/libstand/stand.h +++ b/lib/libstand/stand.h @@ -168,6 +168,7 @@ struct devdesc #define DEVT_NET 2 #define DEVT_CD 3 #define DEVT_ZFS 4 +#define DEVT_FD 5 int d_unit; void *d_opendata; }; diff --git a/sys/boot/common/bcache.c b/sys/boot/common/bcache.c index a95c99fc15c..3c1ee64792a 100644 --- a/sys/boot/common/bcache.c +++ b/sys/boot/common/bcache.c @@ -64,7 +64,7 @@ struct bcachectl struct bcache { struct bcachectl *bcache_ctl; caddr_t bcache_data; - u_int bcache_nblks; + size_t bcache_nblks; size_t ra; }; @@ -86,6 +86,7 @@ static u_int bcache_rablks; ((bc)->bcache_ctl[BHASH((bc), (blkno))].bc_blkno != (blkno)) #define BCACHE_READAHEAD 256 #define BCACHE_MINREADAHEAD 32 +#define BCACHE_MARKER 0xdeadbeef static void bcache_invalidate(struct bcache *bc, daddr_t blkno); static void bcache_insert(struct bcache *bc, daddr_t blkno); @@ -95,7 +96,7 @@ static void bcache_free_instance(struct bcache *bc); * Initialise the cache for (nblks) of (bsize). */ void -bcache_init(u_int nblks, size_t bsize) +bcache_init(size_t nblks, size_t bsize) { /* set up control data */ bcache_total_nblks = nblks; @@ -122,6 +123,7 @@ bcache_allocate(void) u_int i; struct bcache *bc = malloc(sizeof (struct bcache)); int disks = bcache_numdev; + uint32_t *marker; if (disks == 0) disks = 1; /* safe guard */ @@ -140,11 +142,13 @@ bcache_allocate(void) bc->bcache_nblks = bcache_total_nblks >> i; bcache_unit_nblks = bc->bcache_nblks; - bc->bcache_data = malloc(bc->bcache_nblks * bcache_blksize); + bc->bcache_data = malloc(bc->bcache_nblks * bcache_blksize + + sizeof(uint32_t)); if (bc->bcache_data == NULL) { /* dont error out yet. fall back to 32 blocks and try again */ bc->bcache_nblks = 32; - bc->bcache_data = malloc(bc->bcache_nblks * bcache_blksize); + bc->bcache_data = malloc(bc->bcache_nblks * bcache_blksize + + sizeof(uint32_t)); } bc->bcache_ctl = malloc(bc->bcache_nblks * sizeof(struct bcachectl)); @@ -152,8 +156,11 @@ bcache_allocate(void) if ((bc->bcache_data == NULL) || (bc->bcache_ctl == NULL)) { bcache_free_instance(bc); errno = ENOMEM; - return(NULL); + return (NULL); } + /* Insert cache end marker. */ + marker = (uint32_t *)(bc->bcache_data + bc->bcache_nblks * bcache_blksize); + *marker = BCACHE_MARKER; /* Flush the cache */ for (i = 0; i < bc->bcache_nblks; i++) { @@ -215,12 +222,15 @@ read_strategy(void *devdata, int rw, daddr_t blk, size_t size, int result; daddr_t p_blk; caddr_t p_buf; + uint32_t *marker; if (bc == NULL) { errno = ENODEV; return (-1); } + marker = (uint32_t *)(bc->bcache_data + bc->bcache_nblks * bcache_blksize); + if (rsize != NULL) *rsize = 0; @@ -261,9 +271,34 @@ read_strategy(void *devdata, int rw, daddr_t blk, size_t size, p_size = MIN(r_size, nblk - i); /* read at least those blocks */ + /* + * The read ahead size setup. + * While the read ahead can save us IO, it also can complicate things: + * 1. We do not want to read ahead by wrapping around the + * bcache end - this would complicate the cache management. + * 2. We are using bc->ra as dynamic hint for read ahead size, + * detected cache hits will increase the read-ahead block count, and + * misses will decrease, see the code above. + * 3. The bcache is sized by 512B blocks, however, the underlying device + * may have a larger sector size, and we should perform the IO by + * taking into account these larger sector sizes. We could solve this by + * passing the sector size to bcache_allocate(), or by using ioctl(), but + * in this version we are using the constant, 16 blocks, and are rounding + * read ahead block count down to multiple of 16. + * Using the constant has two reasons, we are not entirely sure if the + * BIOS disk interface is providing the correct value for sector size. + * And secondly, this way we get the most conservative setup for the ra. + * + * The selection of multiple of 16 blocks (8KB) is quite arbitrary, however, + * we want to cover CDs (2K) and 4K disks. + * bcache_allocate() will always fall back to a minimum of 32 blocks. + * Our choice of 16 read ahead blocks will always fit inside the bcache. + */ + ra = bc->bcache_nblks - BHASH(bc, p_blk + p_size); - if (ra != bc->bcache_nblks) { /* do we have RA space? */ - ra = MIN(bc->ra, ra); + if (ra != 0 && ra != bc->bcache_nblks) { /* do we have RA space? */ + ra = MIN(bc->ra, ra - 1); + ra = rounddown(ra, 16); /* multiple of 16 blocks */ p_size += ra; } @@ -310,6 +345,12 @@ read_strategy(void *devdata, int rw, daddr_t blk, size_t size, result = 0; } + if (*marker != BCACHE_MARKER) { + printf("BUG: bcache corruption detected: nblks: %zu p_blk: %lu, " + "p_size: %zu, ra: %zu\n", bc->bcache_nblks, + (long unsigned)BHASH(bc, p_blk), p_size, ra); + } + done: if ((result == 0) && (rsize != NULL)) *rsize = size; @@ -338,7 +379,7 @@ bcache_strategy(void *devdata, int rw, daddr_t blk, size_t size, /* bypass large requests, or when the cache is inactive */ if (bc == NULL || ((size * 2 / bcache_blksize) > bcache_nblks)) { - DEBUG("bypass %d from %d", size / bcache_blksize, blk); + DEBUG("bypass %zu from %qu", size / bcache_blksize, blk); bcache_bypasses++; return (dd->dv_strategy(dd->dv_devdata, rw, blk, size, buf, rsize)); } diff --git a/sys/boot/common/bootstrap.h b/sys/boot/common/bootstrap.h index add50825f97..2234e05e67e 100644 --- a/sys/boot/common/bootstrap.h +++ b/sys/boot/common/bootstrap.h @@ -73,7 +73,7 @@ int kern_pread(int fd, vm_offset_t dest, size_t len, off_t off); void *alloc_pread(int fd, off_t off, size_t len); /* bcache.c */ -void bcache_init(u_int nblks, size_t bsize); +void bcache_init(size_t nblks, size_t bsize); void bcache_add_dev(int); void *bcache_allocate(void); void bcache_free(void *); diff --git a/sys/boot/common/dev_net.c b/sys/boot/common/dev_net.c index 76abb2eb50b..1795767dc5b 100644 --- a/sys/boot/common/dev_net.c +++ b/sys/boot/common/dev_net.c @@ -175,7 +175,7 @@ net_open(struct open_file *f, ...) } if (intf_mtu != 0) { char mtu[16]; - sprintf(mtu, "%u", intf_mtu); + snprintf(mtu, sizeof(mtu), "%u", intf_mtu); setenv("boot.netif.mtu", mtu, 1); } diff --git a/sys/boot/common/disk.c b/sys/boot/common/disk.c index feb0b9d7732..e441df16a6b 100644 --- a/sys/boot/common/disk.c +++ b/sys/boot/common/disk.c @@ -45,10 +45,9 @@ __FBSDID("$FreeBSD$"); struct open_disk { struct ptable *table; - off_t mediasize; + uint64_t mediasize; + uint64_t entrysize; u_int sectorsize; - u_int flags; - int rcnt; }; struct print_args { @@ -57,96 +56,6 @@ struct print_args { int verbose; }; -struct dentry { - const struct devsw *d_dev; - int d_unit; - int d_slice; - int d_partition; - - struct open_disk *od; - off_t d_offset; - STAILQ_ENTRY(dentry) entry; -#ifdef DISK_DEBUG - uint32_t count; -#endif -}; - -static STAILQ_HEAD(, dentry) opened_disks = - STAILQ_HEAD_INITIALIZER(opened_disks); - -static int -disk_lookup(struct disk_devdesc *dev) -{ - struct dentry *entry; - int rc; - - rc = ENOENT; - STAILQ_FOREACH(entry, &opened_disks, entry) { - if (entry->d_dev != dev->d_dev || - entry->d_unit != dev->d_unit) - continue; - dev->d_opendata = entry->od; - if (entry->d_slice == dev->d_slice && - entry->d_partition == dev->d_partition) { - dev->d_offset = entry->d_offset; - DEBUG("%s offset %lld", disk_fmtdev(dev), - (long long)dev->d_offset); -#ifdef DISK_DEBUG - entry->count++; -#endif - return (0); - } - rc = EAGAIN; - } - return (rc); -} - -static void -disk_insert(struct disk_devdesc *dev) -{ - struct dentry *entry; - - entry = (struct dentry *)malloc(sizeof(struct dentry)); - if (entry == NULL) { - DEBUG("no memory"); - return; - } - entry->d_dev = dev->d_dev; - entry->d_unit = dev->d_unit; - entry->d_slice = dev->d_slice; - entry->d_partition = dev->d_partition; - entry->od = (struct open_disk *)dev->d_opendata; - entry->od->rcnt++; - entry->d_offset = dev->d_offset; -#ifdef DISK_DEBUG - entry->count = 1; -#endif - STAILQ_INSERT_TAIL(&opened_disks, entry, entry); - DEBUG("%s cached", disk_fmtdev(dev)); -} - -#ifdef DISK_DEBUG -COMMAND_SET(dcachestat, "dcachestat", "get disk cache stats", - command_dcachestat); - -static int -command_dcachestat(int argc, char *argv[]) -{ - struct disk_devdesc dev; - struct dentry *entry; - - STAILQ_FOREACH(entry, &opened_disks, entry) { - dev.d_dev = (struct devsw *)entry->d_dev; - dev.d_unit = entry->d_unit; - dev.d_slice = entry->d_slice; - dev.d_partition = entry->d_partition; - printf("%s %d => %p [%d]\n", disk_fmtdev(&dev), entry->count, - entry->od, entry->od->rcnt); - } - return (CMD_OK); -} -#endif /* DISK_DEBUG */ - /* Convert size to a human-readable number. */ static char * display_size(uint64_t size, u_int sectorsize) @@ -171,7 +80,7 @@ display_size(uint64_t size, u_int sectorsize) } int -ptblread(void *d, void *buf, size_t blocks, off_t offset) +ptblread(void *d, void *buf, size_t blocks, uint64_t offset) { struct disk_devdesc *dev; struct open_disk *od; @@ -186,6 +95,7 @@ ptblread(void *d, void *buf, size_t blocks, off_t offset) static int ptable_print(void *arg, const char *pname, const struct ptable_entry *part) { + struct disk_devdesc dev; struct print_args *pa, bsd; struct open_disk *od; struct ptable *table; @@ -206,17 +116,24 @@ ptable_print(void *arg, const char *pname, const struct ptable_entry *part) res = 0; if (part->type == PART_FREEBSD) { /* Open slice with BSD label */ - pa->dev->d_offset = part->start; - table = ptable_open(pa->dev, part->end - part->start + 1, - od->sectorsize, ptblread); - if (table == NULL) - return 0; - sprintf(line, " %s%s", pa->prefix, pname); - bsd.dev = pa->dev; - bsd.prefix = line; - bsd.verbose = pa->verbose; - res = ptable_iterate(table, &bsd, ptable_print); - ptable_close(table); + dev.d_dev = pa->dev->d_dev; + dev.d_unit = pa->dev->d_unit; + dev.d_slice = part->index; + dev.d_partition = -1; + if (disk_open(&dev, part->end - part->start + 1, + od->sectorsize) == 0) { + table = ptable_open(&dev, part->end - part->start + 1, + od->sectorsize, ptblread); + if (table != NULL) { + sprintf(line, " %s%s", pa->prefix, pname); + bsd.dev = pa->dev; + bsd.prefix = line; + bsd.verbose = pa->verbose; + res = ptable_iterate(table, &bsd, ptable_print); + ptable_close(table); + } + disk_close(&dev); + } } return (res); @@ -238,7 +155,7 @@ disk_print(struct disk_devdesc *dev, char *prefix, int verbose) } int -disk_read(struct disk_devdesc *dev, void *buf, off_t offset, u_int blocks) +disk_read(struct disk_devdesc *dev, void *buf, uint64_t offset, u_int blocks) { struct open_disk *od; int ret; @@ -251,7 +168,7 @@ disk_read(struct disk_devdesc *dev, void *buf, off_t offset, u_int blocks) } int -disk_write(struct disk_devdesc *dev, void *buf, off_t offset, u_int blocks) +disk_write(struct disk_devdesc *dev, void *buf, uint64_t offset, u_int blocks) { struct open_disk *od; int ret; @@ -264,18 +181,32 @@ disk_write(struct disk_devdesc *dev, void *buf, off_t offset, u_int blocks) } int -disk_ioctl(struct disk_devdesc *dev, u_long cmd, void *buf) +disk_ioctl(struct disk_devdesc *dev, u_long cmd, void *data) { + struct open_disk *od = dev->d_opendata; + + if (od == NULL) + return (ENOTTY); + + switch (cmd) { + case DIOCGSECTORSIZE: + *(u_int *)data = od->sectorsize; + break; + case DIOCGMEDIASIZE: + if (dev->d_offset == 0) + *(uint64_t *)data = od->mediasize; + else + *(uint64_t *)data = od->entrysize * od->sectorsize; + break; + default: + return (ENOTTY); + } - if (dev->d_dev->dv_ioctl) - return ((*dev->d_dev->dv_ioctl)(dev->d_opendata, cmd, buf)); - - return (ENXIO); + return (0); } int -disk_open(struct disk_devdesc *dev, off_t mediasize, u_int sectorsize, - u_int flags) +disk_open(struct disk_devdesc *dev, uint64_t mediasize, u_int sectorsize) { struct open_disk *od; struct ptable *table; @@ -283,11 +214,6 @@ disk_open(struct disk_devdesc *dev, off_t mediasize, u_int sectorsize, int rc, slice, partition; rc = 0; - if ((flags & DISK_F_NOCACHE) == 0) { - rc = disk_lookup(dev); - if (rc == 0) - return (0); - } /* * While we are reading disk metadata, make sure we do it relative * to the start of the disk @@ -296,29 +222,15 @@ disk_open(struct disk_devdesc *dev, off_t mediasize, u_int sectorsize, table = NULL; slice = dev->d_slice; partition = dev->d_partition; - if (rc == EAGAIN) { - /* - * This entire disk was already opened and there is no - * need to allocate new open_disk structure and open the - * main partition table. - */ - od = (struct open_disk *)dev->d_opendata; - DEBUG("%s unit %d, slice %d, partition %d => %p (cached)", - disk_fmtdev(dev), dev->d_unit, dev->d_slice, - dev->d_partition, od); - goto opened; - } else { - od = (struct open_disk *)malloc(sizeof(struct open_disk)); - if (od == NULL) { - DEBUG("no memory"); - return (ENOMEM); - } - dev->d_opendata = od; - od->rcnt = 0; + od = (struct open_disk *)malloc(sizeof(struct open_disk)); + if (od == NULL) { + DEBUG("no memory"); + return (ENOMEM); } + dev->d_opendata = od; + od->entrysize = 0; od->mediasize = mediasize; od->sectorsize = sectorsize; - od->flags = flags; DEBUG("%s unit %d, slice %d, partition %d => %p", disk_fmtdev(dev), dev->d_unit, dev->d_slice, dev->d_partition, od); @@ -330,14 +242,23 @@ disk_open(struct disk_devdesc *dev, off_t mediasize, u_int sectorsize, rc = ENXIO; goto out; } -opened: - rc = 0; + + if (ptable_getsize(od->table, &mediasize) != 0) { + rc = ENXIO; + goto out; + } + if (mediasize > od->mediasize) { + od->mediasize = mediasize; + } + if (ptable_gettype(od->table) == PTABLE_BSD && partition >= 0) { /* It doesn't matter what value has d_slice */ rc = ptable_getpart(od->table, &part, partition); - if (rc == 0) + if (rc == 0) { dev->d_offset = part.start; + od->entrysize = part.end - part.start + 1; + } } else if (slice >= 0) { /* Try to get information about partition */ if (slice == 0) @@ -347,6 +268,7 @@ disk_open(struct disk_devdesc *dev, off_t mediasize, u_int sectorsize, if (rc != 0) /* Partition doesn't exist */ goto out; dev->d_offset = part.start; + od->entrysize = part.end - part.start + 1; slice = part.index; if (ptable_gettype(od->table) == PTABLE_GPT) { partition = 255; @@ -389,21 +311,18 @@ disk_open(struct disk_devdesc *dev, off_t mediasize, u_int sectorsize, if (rc != 0) goto out; dev->d_offset += part.start; + od->entrysize = part.end - part.start + 1; } out: if (table != NULL) ptable_close(table); if (rc != 0) { - if (od->rcnt < 1) { - if (od->table != NULL) - ptable_close(od->table); - free(od); - } + if (od->table != NULL) + ptable_close(od->table); + free(od); DEBUG("%s could not open", disk_fmtdev(dev)); } else { - if ((flags & DISK_F_NOCACHE) == 0) - disk_insert(dev); /* Save the slice and partition number to the dev */ dev->d_slice = slice; dev->d_partition = partition; @@ -419,44 +338,12 @@ disk_close(struct disk_devdesc *dev) struct open_disk *od; od = (struct open_disk *)dev->d_opendata; - DEBUG("%s closed => %p [%d]", disk_fmtdev(dev), od, od->rcnt); - if (od->flags & DISK_F_NOCACHE) { - ptable_close(od->table); - free(od); - } + DEBUG("%s closed => %p", disk_fmtdev(dev), od); + ptable_close(od->table); + free(od); return (0); } -void -disk_cleanup(const struct devsw *d_dev) -{ -#ifdef DISK_DEBUG - struct disk_devdesc dev; -#endif - struct dentry *entry, *tmp; - - STAILQ_FOREACH_SAFE(entry, &opened_disks, entry, tmp) { - if (entry->d_dev != d_dev) - continue; - entry->od->rcnt--; -#ifdef DISK_DEBUG - dev.d_dev = (struct devsw *)entry->d_dev; - dev.d_unit = entry->d_unit; - dev.d_slice = entry->d_slice; - dev.d_partition = entry->d_partition; - DEBUG("%s was freed => %p [%d]", disk_fmtdev(&dev), - entry->od, entry->od->rcnt); -#endif - STAILQ_REMOVE(&opened_disks, entry, dentry, entry); - if (entry->od->rcnt < 1) { - if (entry->od->table != NULL) - ptable_close(entry->od->table); - free(entry->od); - } - free(entry); - } -} - char* disk_fmtdev(struct disk_devdesc *dev) { diff --git a/sys/boot/common/disk.h b/sys/boot/common/disk.h index d17ace93f0b..51e1498e3da 100644 --- a/sys/boot/common/disk.h +++ b/sys/boot/common/disk.h @@ -78,6 +78,9 @@ * the device's strategy method. */ +#ifndef _DISK_H +#define _DISK_H + struct disk_devdesc { struct devsw *d_dev; @@ -86,7 +89,7 @@ struct disk_devdesc void *d_opendata; int d_slice; int d_partition; - off_t d_offset; + uint64_t d_offset; }; enum disk_ioctl { @@ -97,23 +100,18 @@ enum disk_ioctl { /* * Parse disk metadata and initialise dev->d_offset. */ -extern int disk_open(struct disk_devdesc *dev, off_t mediasize, - u_int sectorsize, u_int flags); -#define DISK_F_NOCACHE 0x0001 /* Do not use metadata caching */ -extern int disk_close(struct disk_devdesc *dev); -extern void disk_cleanup(const struct devsw *d_dev); -extern int disk_ioctl(struct disk_devdesc *dev, u_long cmd, void *buf); -extern int disk_read(struct disk_devdesc *dev, void *buf, off_t offset, - u_int blocks); -extern int disk_write(struct disk_devdesc *dev, void *buf, off_t offset, - u_int blocks); -extern int ptblread(void *d, void *buf, size_t blocks, off_t offset); +extern int disk_open(struct disk_devdesc *, uint64_t, u_int); +extern int disk_close(struct disk_devdesc *); +extern int disk_ioctl(struct disk_devdesc *, u_long, void *); +extern int disk_read(struct disk_devdesc *, void *, uint64_t, u_int); +extern int disk_write(struct disk_devdesc *, void *, uint64_t, u_int); +extern int ptblread(void *, void *, size_t, uint64_t); /* * Print information about slices on a disk. */ -extern int disk_print(struct disk_devdesc *dev, char *prefix, int verbose); -extern char* disk_fmtdev(struct disk_devdesc *dev); -extern int disk_parsedev(struct disk_devdesc *dev, const char *devspec, - const char **path); +extern int disk_print(struct disk_devdesc *, char *, int); +extern char* disk_fmtdev(struct disk_devdesc *); +extern int disk_parsedev(struct disk_devdesc *, const char *, const char **); +#endif /* _DISK_H */ diff --git a/sys/boot/common/ls.c b/sys/boot/common/ls.c index 70334ff3aad..cd6b7c49ea5 100644 --- a/sys/boot/common/ls.c +++ b/sys/boot/common/ls.c @@ -60,26 +60,26 @@ command_ls(int argc, char *argv[]) { int fd; struct stat sb; - struct dirent *d; + struct dirent *d; char *buf, *path; char lbuf[128]; /* one line */ int result, ch; int verbose; - + result = CMD_OK; fd = -1; verbose = 0; optind = 1; optreset = 1; while ((ch = getopt(argc, argv, "l")) != -1) { - switch(ch) { + switch (ch) { case 'l': verbose = 1; break; case '?': default: /* getopt has already reported an error */ - return(CMD_OK); + return (CMD_OK); } } argv += (optind - 1); @@ -91,6 +91,18 @@ command_ls(int argc, char *argv[]) path = argv[1]; } + if (stat(path, &sb) == 0 && !S_ISDIR(sb.st_mode)) { + if (verbose) { + printf(" %c %8d %s\n", + typestr[sb.st_mode >> 12], + (int)sb.st_size, path); + } else { + printf(" %c %s\n", + typestr[sb.st_mode >> 12], path); + } + return (CMD_OK); + } + fd = ls_getdir(&path); if (fd == -1) { result = CMD_ERROR; @@ -102,19 +114,28 @@ command_ls(int argc, char *argv[]) while ((d = readdirfd(fd)) != NULL) { if (strcmp(d->d_name, ".") && strcmp(d->d_name, "..")) { - if (verbose) { + if (d->d_type == 0 || verbose) { /* stat the file, if possible */ sb.st_size = 0; + sb.st_mode = 0; buf = malloc(strlen(path) + strlen(d->d_name) + 2); - sprintf(buf, "%s/%s", path, d->d_name); - /* ignore return, could be symlink, etc. */ - if (stat(buf, &sb)) - sb.st_size = 0; - free(buf); - sprintf(lbuf, " %c %8d %s\n", typestr[d->d_type], + if (buf != NULL) { + sprintf(buf, "%s/%s", path, d->d_name); + /* ignore return, could be symlink, etc. */ + if (stat(buf, &sb)) { + sb.st_size = 0; + sb.st_mode = 0; + } + free(buf); + } + } + if (verbose) { + snprintf(lbuf, sizeof(lbuf), " %c %8d %s\n", + typestr[d->d_type? d->d_type:sb.st_mode >> 12], (int)sb.st_size, d->d_name); } else { - sprintf(lbuf, " %c %s\n", typestr[d->d_type], d->d_name); + snprintf(lbuf, sizeof(lbuf), " %c %s\n", + typestr[d->d_type? d->d_type:sb.st_mode >> 12], d->d_name); } if (pager_output(lbuf)) goto out; @@ -124,9 +145,8 @@ command_ls(int argc, char *argv[]) pager_close(); if (fd != -1) close(fd); - if (path != NULL) - free(path); - return(result); + free(path); /* ls_getdir() did allocate path */ + return (result); } /* @@ -145,6 +165,11 @@ ls_getdir(char **pathp) /* one extra byte for a possible trailing slash required */ path = malloc(strlen(*pathp) + 2); + if (path == NULL) { + snprintf(command_errbuf, sizeof (command_errbuf), + "out of memory"); + goto out; + } strcpy(path, *pathp); /* Make sure the path is respectable to begin with */ @@ -153,7 +178,7 @@ ls_getdir(char **pathp) "bad path '%s'", path); goto out; } - + /* If there's no path on the device, assume '/' */ if (*cp == 0) strcat(path, "/"); @@ -176,12 +201,12 @@ ls_getdir(char **pathp) } *pathp = path; - return(fd); + return (fd); out: free(path); *pathp = NULL; if (fd != -1) close(fd); - return(-1); + return (-1); } diff --git a/sys/boot/common/part.c b/sys/boot/common/part.c index dac237ea57f..307ced493cc 100644 --- a/sys/boot/common/part.c +++ b/sys/boot/common/part.c @@ -310,10 +310,30 @@ ptable_gptread(struct ptable *table, void *dev, diskread_t dread) DEBUG("GPT detected"); size = MIN(hdr.hdr_entries * hdr.hdr_entsz, MAXTBLSZ * table->sectorsize); + + /* + * If the disk's sector count is smaller than the sector count recorded + * in the disk's GPT table header, set the table->sectors to the value + * recorded in GPT tables. This is done to work around buggy firmware + * that returns truncated disk sizes. + * + * Note, this is still not a foolproof way to get disk's size. For + * example, an image file can be truncated when copied to smaller media. + */ + if (hdr.hdr_lba_alt + 1 > table->sectors) + table->sectors = hdr.hdr_lba_alt + 1; + for (i = 0; i < size / hdr.hdr_entsz; i++) { ent = (struct gpt_ent *)(tbl + i * hdr.hdr_entsz); if (uuid_equal(&ent->ent_type, &gpt_uuid_unused, NULL)) continue; + + /* Simple sanity checks. */ + if (ent->ent_lba_start < hdr.hdr_lba_start || + ent->ent_lba_end > hdr.hdr_lba_end || + ent->ent_lba_start > ent->ent_lba_end) + continue; + entry = malloc(sizeof(*entry)); if (entry == NULL) break; @@ -584,7 +604,7 @@ ptable_vtoc8read(struct ptable *table, void *dev, diskread_t dread) #endif /* LOADER_VTOC8_SUPPORT */ struct ptable* -ptable_open(void *dev, off_t sectors, uint16_t sectorsize, +ptable_open(void *dev, uint64_t sectors, uint16_t sectorsize, diskread_t *dread) { struct dos_partition *dp; @@ -735,6 +755,19 @@ ptable_gettype(const struct ptable *table) return (table->type); } +int +ptable_getsize(const struct ptable *table, uint64_t *sizep) +{ + uint64_t tmp = table->sectors * table->sectorsize; + + if (tmp < table->sectors) + return (EOVERFLOW); + + if (sizep != NULL) + *sizep = tmp; + return (0); +} + int ptable_getpart(const struct ptable *table, struct ptable_entry *part, int index) { diff --git a/sys/boot/common/part.h b/sys/boot/common/part.h index 217bf3b5512..19bd6702fc6 100644 --- a/sys/boot/common/part.h +++ b/sys/boot/common/part.h @@ -62,14 +62,15 @@ struct ptable_entry { }; /* The offset and size are in sectors */ -typedef int (diskread_t)(void *arg, void *buf, size_t blocks, off_t offset); +typedef int (diskread_t)(void *arg, void *buf, size_t blocks, uint64_t offset); typedef int (ptable_iterate_t)(void *arg, const char *partname, const struct ptable_entry *part); -struct ptable *ptable_open(void *dev, off_t sectors, uint16_t sectorsize, +struct ptable *ptable_open(void *dev, uint64_t sectors, uint16_t sectorsize, diskread_t *dread); void ptable_close(struct ptable *table); enum ptable_type ptable_gettype(const struct ptable *table); +int ptable_getsize(const struct ptable *table, uint64_t *sizep); int ptable_getpart(const struct ptable *table, struct ptable_entry *part, int index); diff --git a/sys/boot/efi/include/efidevp.h b/sys/boot/efi/include/efidevp.h index dda79de7af1..4f252472a80 100644 --- a/sys/boot/efi/include/efidevp.h +++ b/sys/boot/efi/include/efidevp.h @@ -73,8 +73,6 @@ typedef struct _EFI_DEVICE_PATH { (a)->Length[1] = 0; \ } - - /* * */ @@ -424,5 +422,33 @@ typedef union { } EFI_DEV_PATH_PTR; +#define EFI_LOADED_IMAGE_DEVICE_PATH_PROTOCOL_GUID \ + { 0xbc62157e, 0x3e33, 0x4fec, { 0x99, 0x20, 0x2d, 0x3b, 0x36, 0xd7, 0x50, 0xdf } } + +#define EFI_DEVICE_PATH_TO_TEXT_PROTOCOL_GUID \ + { 0x8b843e20, 0x8132, 0x4852, { 0x90, 0xcc, 0x55, 0x1a, 0x4e, 0x4a, 0x7f, 0x1c } } + +INTERFACE_DECL(_EFI_DEVICE_PATH_PROTOCOL); + +typedef +CHAR16* +(EFIAPI *EFI_DEVICE_PATH_TO_TEXT_NODE) ( + IN struct _EFI_DEVICE_PATH *This, + IN BOOLEAN DisplayOnly, + IN BOOLEAN AllowShortCuts + ); + +typedef +CHAR16* +(EFIAPI *EFI_DEVICE_PATH_TO_TEXT_PATH) ( + IN struct _EFI_DEVICE_PATH *This, + IN BOOLEAN DisplayOnly, + IN BOOLEAN AllowShortCuts + ); + +typedef struct _EFI_DEVICE_PATH_TO_TEXT_PROTOCOL { + EFI_DEVICE_PATH_TO_TEXT_NODE ConvertDeviceNodeToText; + EFI_DEVICE_PATH_TO_TEXT_PATH ConvertDevicePathToText; +} EFI_DEVICE_PATH_TO_TEXT_PROTOCOL; #endif diff --git a/sys/boot/efi/include/efilib.h b/sys/boot/efi/include/efilib.h index 09ccc2f3647..598c1ac31f2 100644 --- a/sys/boot/efi/include/efilib.h +++ b/sys/boot/efi/include/efilib.h @@ -31,16 +31,37 @@ #define _LOADER_EFILIB_H #include +#include extern EFI_HANDLE IH; extern EFI_SYSTEM_TABLE *ST; extern EFI_BOOT_SERVICES *BS; extern EFI_RUNTIME_SERVICES *RS; -extern struct devsw efipart_dev; +extern struct devsw efipart_fddev; +extern struct devsw efipart_cddev; +extern struct devsw efipart_hddev; extern struct devsw efinet_dev; extern struct netif_driver efinetif; +/* EFI block device data, included here to help efi_zfs_probe() */ +typedef STAILQ_HEAD(pdinfo_list, pdinfo) pdinfo_list_t; + +typedef struct pdinfo +{ + STAILQ_ENTRY(pdinfo) pd_link; /* link in device list */ + pdinfo_list_t pd_part; /* link of partitions */ + EFI_HANDLE pd_handle; + EFI_HANDLE pd_alias; + EFI_DEVICE_PATH *pd_devpath; + EFI_BLOCK_IO *pd_blkio; + int pd_unit; /* unit number */ + int pd_open; /* reference counter */ + void *pd_bcache; /* buffer cache data */ +} pdinfo_t; + +pdinfo_list_t *efiblk_get_pdinfo_list(struct devsw *dev); + void *efi_get_table(EFI_GUID *tbl); int efi_register_handles(struct devsw *, EFI_HANDLE *, EFI_HANDLE *, int); @@ -53,6 +74,7 @@ EFI_DEVICE_PATH *efi_lookup_devpath(EFI_HANDLE); EFI_HANDLE efi_devpath_handle(EFI_DEVICE_PATH *); EFI_DEVICE_PATH *efi_devpath_last_node(EFI_DEVICE_PATH *); EFI_DEVICE_PATH *efi_devpath_trim(EFI_DEVICE_PATH *); +int efi_devpath_match(EFI_DEVICE_PATH *, EFI_DEVICE_PATH *); CHAR16 *efi_devpath_name(EFI_DEVICE_PATH *); void efi_free_devpath_name(CHAR16 *); @@ -65,4 +87,12 @@ EFI_STATUS main(int argc, CHAR16 *argv[]); void exit(EFI_STATUS status); void delay(int usecs); +/* EFI environment initialization. */ +void efi_init_environment(void); + +/* CHAR16 utility functions. */ +int wcscmp(CHAR16 *, CHAR16 *); +void cpy8to16(const char *, CHAR16 *, size_t); +void cpy16to8(const CHAR16 *, char *, size_t); + #endif /* _LOADER_EFILIB_H */ diff --git a/sys/boot/efi/libefi/Makefile b/sys/boot/efi/libefi/Makefile index d9619bef89d..33a8f3e7e04 100644 --- a/sys/boot/efi/libefi/Makefile +++ b/sys/boot/efi/libefi/Makefile @@ -3,6 +3,7 @@ .include .if ${MK_FORTH} != "no" +CFLAGS+= -DBOOT_FORTH .include "${.CURDIR}/../../Makefile.ficl" .endif @@ -10,17 +11,14 @@ LIB= efi INTERNALLIB= WARNS?= 2 -SRCS= delay.c devpath.c efi_console.c efinet.c efipart.c errno.c \ - handles.c libefi.c +SRCS= delay.c devpath.c efi_console.c efinet.c efipart.c env.c errno.c \ + handles.c wchar.c libefi.c .if ${MACHINE_CPUARCH} == "amd64" || ${MACHINE_CPUARCH} == "i386" SRCS+= time.c .elif ${MACHINE_CPUARCH} == "aarch64" || ${MACHINE_CPUARCH} == "arm" SRCS+= time_event.c .endif -.if ${MK_FORTH} != "no" -SRCS+= env.c -.endif # We implement a slightly non-standard %S in that it always takes a # CHAR16 that's common in UEFI-land instead of a wchar_t. This only @@ -28,6 +26,8 @@ SRCS+= env.c # of a short. There's no good cast to use here so just ignore the # warnings for now. CWARNFLAGS.efinet.c+= -Wno-format +CWARNFLAGS.efipart.c+= -Wno-format +CWARNFLAGS.env.c+= -Wno-format .if ${MACHINE_CPUARCH} == "aarch64" CFLAGS+= -msoft-float -mgeneral-regs-only diff --git a/sys/boot/efi/libefi/devpath.c b/sys/boot/efi/libefi/devpath.c index 105c86134a8..662f0a744ef 100644 --- a/sys/boot/efi/libefi/devpath.c +++ b/sys/boot/efi/libefi/devpath.c @@ -30,36 +30,6 @@ __FBSDID("$FreeBSD$"); #include #include -/* XXX: This belongs in an efifoo.h header. */ -#define EFI_LOADED_IMAGE_DEVICE_PATH_PROTOCOL_GUID \ - { 0xbc62157e, 0x3e33, 0x4fec, { 0x99, 0x20, 0x2d, 0x3b, 0x36, 0xd7, 0x50, 0xdf } } - -#define EFI_DEVICE_PATH_TO_TEXT_PROTOCOL_GUID \ - { 0x8b843e20, 0x8132, 0x4852, { 0x90, 0xcc, 0x55, 0x1a, 0x4e, 0x4a, 0x7f, 0x1c } } - -INTERFACE_DECL(_EFI_DEVICE_PATH_PROTOCOL); - -typedef -CHAR16* -(EFIAPI *EFI_DEVICE_PATH_TO_TEXT_NODE) ( - IN struct _EFI_DEVICE_PATH *This, - IN BOOLEAN DisplayOnly, - IN BOOLEAN AllowShortCuts - ); - -typedef -CHAR16* -(EFIAPI *EFI_DEVICE_PATH_TO_TEXT_PATH) ( - IN struct _EFI_DEVICE_PATH *This, - IN BOOLEAN DisplayOnly, - IN BOOLEAN AllowShortCuts - ); - -typedef struct _EFI_DEVICE_PATH_TO_TEXT_PROTOCOL { - EFI_DEVICE_PATH_TO_TEXT_NODE ConvertDeviceNodeToText; - EFI_DEVICE_PATH_TO_TEXT_PATH ConvertDevicePathToText; -} EFI_DEVICE_PATH_TO_TEXT_PROTOCOL; - static EFI_GUID ImageDevicePathGUID = EFI_LOADED_IMAGE_DEVICE_PATH_PROTOCOL_GUID; static EFI_GUID DevicePathGUID = DEVICE_PATH_PROTOCOL; @@ -136,15 +106,18 @@ efi_devpath_trim(EFI_DEVICE_PATH *devpath) EFI_DEVICE_PATH *node, *copy; size_t prefix, len; - node = efi_devpath_last_node(devpath); + if ((node = efi_devpath_last_node(devpath)) == NULL) + return (NULL); prefix = (UINT8 *)node - (UINT8 *)devpath; if (prefix == 0) return (NULL); len = prefix + DevicePathNodeLength(NextDevicePathNode(node)); copy = malloc(len); - memcpy(copy, devpath, prefix); - node = (EFI_DEVICE_PATH *)((UINT8 *)copy + prefix); - SetDevicePathEndNode(node); + if (copy != NULL) { + memcpy(copy, devpath, prefix); + node = (EFI_DEVICE_PATH *)((UINT8 *)copy + prefix); + SetDevicePathEndNode(node); + } return (copy); } @@ -165,3 +138,31 @@ efi_devpath_handle(EFI_DEVICE_PATH *devpath) return (NULL); return (h); } + +int +efi_devpath_match(EFI_DEVICE_PATH *devpath1, EFI_DEVICE_PATH *devpath2) +{ + int len; + + if (devpath1 == NULL || devpath2 == NULL) + return (0); + + while (1) { + if (DevicePathType(devpath1) != DevicePathType(devpath2) || + DevicePathSubType(devpath1) != DevicePathSubType(devpath2)) + return (0); + + len = DevicePathNodeLength(devpath1); + if (len != DevicePathNodeLength(devpath2)) + return (0); + + if (memcmp(devpath1, devpath2, (size_t)len) != 0) + return (0); + + if (IsDevicePathEnd(devpath1)) + break; + devpath1 = NextDevicePathNode(devpath1); + devpath2 = NextDevicePathNode(devpath2); + } + return (1); +} diff --git a/sys/boot/efi/libefi/efinet.c b/sys/boot/efi/libefi/efinet.c index 429bf945268..c598548ed9f 100644 --- a/sys/boot/efi/libefi/efinet.c +++ b/sys/boot/efi/libefi/efinet.c @@ -291,12 +291,18 @@ efinet_dev_init() if (EFI_ERROR(status)) return (efi_status_to_errno(status)); handles2 = (EFI_HANDLE *)malloc(sz); + if (handles2 == NULL) { + free(handles); + return (ENOMEM); + } nifs = 0; for (i = 0; i < sz / sizeof(EFI_HANDLE); i++) { devpath = efi_lookup_devpath(handles[i]); if (devpath == NULL) continue; - node = efi_devpath_last_node(devpath); + if ((node = efi_devpath_last_node(devpath)) == NULL) + continue; + if (DevicePathType(node) != MESSAGING_DEVICE_PATH || DevicePathSubType(node) != MSG_MAC_ADDR_DP) continue; @@ -318,20 +324,24 @@ efinet_dev_init() } free(handles); if (nifs == 0) { - free(handles2); - return (ENOENT); + err = ENOENT; + goto done; } err = efi_register_handles(&efinet_dev, handles2, NULL, nifs); - if (err != 0) { - free(handles2); - return (err); - } + if (err != 0) + goto done; - efinetif.netif_nifs = nifs; efinetif.netif_ifs = calloc(nifs, sizeof(struct netif_dif)); - stats = calloc(nifs, sizeof(struct netif_stats)); + if (efinetif.netif_ifs == NULL || stats == NULL) { + free(efinetif.netif_ifs); + free(stats); + efinetif.netif_ifs = NULL; + err = ENOMEM; + goto done; + } + efinetif.netif_nifs = nifs; for (i = 0; i < nifs; i++) { @@ -341,9 +351,9 @@ efinet_dev_init() dif->dif_stats = &stats[i]; dif->dif_private = handles2[i]; } +done: free(handles2); - - return (0); + return (err); } static int diff --git a/sys/boot/efi/libefi/efipart.c b/sys/boot/efi/libefi/efipart.c index 938eed996c8..d4f7edff756 100644 --- a/sys/boot/efi/libefi/efipart.c +++ b/sys/boot/efi/libefi/efipart.c @@ -27,8 +27,10 @@ #include __FBSDID("$FreeBSD$"); +#include #include #include +#include #include #include @@ -37,57 +39,110 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include static EFI_GUID blkio_guid = BLOCK_IO_PROTOCOL; -static int efipart_init(void); +static int efipart_initfd(void); +static int efipart_initcd(void); +static int efipart_inithd(void); + static int efipart_strategy(void *, int, daddr_t, size_t, char *, size_t *); static int efipart_realstrategy(void *, int, daddr_t, size_t, char *, size_t *); + static int efipart_open(struct open_file *, ...); static int efipart_close(struct open_file *); -static int efipart_print(int); +static int efipart_ioctl(struct open_file *, u_long, void *); -struct devsw efipart_dev = { - .dv_name = "part", - .dv_type = DEVT_DISK, - .dv_init = efipart_init, +static int efipart_printfd(int); +static int efipart_printcd(int); +static int efipart_printhd(int); + +struct devsw efipart_fddev = { + .dv_name = "fd", + .dv_type = DEVT_FD, + .dv_init = efipart_initfd, .dv_strategy = efipart_strategy, .dv_open = efipart_open, .dv_close = efipart_close, - .dv_ioctl = noioctl, - .dv_print = efipart_print, + .dv_ioctl = efipart_ioctl, + .dv_print = efipart_printfd, .dv_cleanup = NULL }; -/* - * info structure to support bcache - */ -struct pdinfo { - int pd_unit; /* unit number */ - int pd_open; /* reference counter */ - void *pd_bcache; /* buffer cache data */ +struct devsw efipart_cddev = { + .dv_name = "cd", + .dv_type = DEVT_CD, + .dv_init = efipart_initcd, + .dv_strategy = efipart_strategy, + .dv_open = efipart_open, + .dv_close = efipart_close, + .dv_ioctl = efipart_ioctl, + .dv_print = efipart_printcd, + .dv_cleanup = NULL +}; + +struct devsw efipart_hddev = { + .dv_name = "disk", + .dv_type = DEVT_DISK, + .dv_init = efipart_inithd, + .dv_strategy = efipart_strategy, + .dv_open = efipart_open, + .dv_close = efipart_close, + .dv_ioctl = efipart_ioctl, + .dv_print = efipart_printhd, + .dv_cleanup = NULL }; -static struct pdinfo *pdinfo; -static int npdinfo = 0; -#define PD(dev) (pdinfo[(dev)->d_unit]) +static pdinfo_list_t fdinfo; +static pdinfo_list_t cdinfo; +static pdinfo_list_t hdinfo; + +static EFI_HANDLE *efipart_handles = NULL; +static UINTN efipart_nhandles = 0; + +static pdinfo_t * +efiblk_get_pdinfo(pdinfo_list_t *pdi, int unit) +{ + pdinfo_t *pd; + + STAILQ_FOREACH(pd, pdi, pd_link) { + if (pd->pd_unit == unit) + return (pd); + } + return (NULL); +} static int -efipart_init(void) +efiblk_pdinfo_count(pdinfo_list_t *pdi) +{ + pdinfo_t *pd; + int i = 0; + + STAILQ_FOREACH(pd, pdi, pd_link) { + i++; + } + return (i); +} + +static int +efipart_inithandles(void) { - EFI_BLOCK_IO *blkio; - EFI_DEVICE_PATH *devpath, *devpathcpy, *tmpdevpath, *node; - EFI_HANDLE *hin, *hout, *aliases, handle; - EFI_STATUS status; UINTN sz; - u_int n, nin, nout, nrdisk; - int err; + EFI_HANDLE *hin; + EFI_STATUS status; + + if (efipart_nhandles != 0) { + free(efipart_handles); + efipart_handles = NULL; + efipart_nhandles = 0; + } sz = 0; hin = NULL; - status = BS->LocateHandle(ByProtocol, &blkio_guid, 0, &sz, 0); + status = BS->LocateHandle(ByProtocol, &blkio_guid, 0, &sz, hin); if (status == EFI_BUFFER_TOO_SMALL) { - hin = (EFI_HANDLE *)malloc(sz * 3); + hin = malloc(sz); status = BS->LocateHandle(ByProtocol, &blkio_guid, 0, &sz, hin); if (EFI_ERROR(status)) @@ -96,33 +151,150 @@ efipart_init(void) if (EFI_ERROR(status)) return (efi_status_to_errno(status)); - /* Filter handles to only include FreeBSD partitions. */ - nin = sz / sizeof(EFI_HANDLE); - hout = hin + nin; - aliases = hout + nin; - nout = 0; - nrdisk = 0; + efipart_handles = hin; + efipart_nhandles = sz; + return (0); +} + +static ACPI_HID_DEVICE_PATH * +efipart_floppy(EFI_DEVICE_PATH *node) +{ + ACPI_HID_DEVICE_PATH *acpi = NULL; + + if (DevicePathType(node) == ACPI_DEVICE_PATH && + DevicePathSubType(node) == ACPI_DP) { + acpi = (ACPI_HID_DEVICE_PATH *) node; + if (acpi->HID == EISA_PNP_ID(0x604) || + acpi->HID == EISA_PNP_ID(0x700) || + acpi->HID == EISA_ID(0x41d1, 0x701)) { + return (acpi); + } + } + return (acpi); +} + +/* + * Add or update entries with new handle data. + */ +static int +efipart_fdinfo_add(EFI_HANDLE handle, uint32_t uid, EFI_DEVICE_PATH *devpath) +{ + pdinfo_t *fd; - bzero(aliases, nin * sizeof(EFI_HANDLE)); - pdinfo = malloc(nin * sizeof(*pdinfo)); - if (pdinfo == NULL) + fd = malloc(sizeof(pdinfo_t)); + if (fd == NULL) { + printf("Failed to register floppy %d, out of memory\n", uid); return (ENOMEM); + } + memset(fd, 0, sizeof(pdinfo_t)); + STAILQ_INIT(&fd->pd_part); + + fd->pd_unit = uid; + fd->pd_handle = handle; + fd->pd_devpath = devpath; + STAILQ_INSERT_TAIL(&fdinfo, fd, pd_link); + return (0); +} + +static void +efipart_updatefd(void) +{ + EFI_DEVICE_PATH *devpath, *node; + ACPI_HID_DEVICE_PATH *acpi; + int i, nin; + + nin = efipart_nhandles / sizeof (*efipart_handles); + for (i = 0; i < nin; i++) { + devpath = efi_lookup_devpath(efipart_handles[i]); + if (devpath == NULL) + continue; - for (n = 0; n < nin; n++) { - devpath = efi_lookup_devpath(hin[n]); - if (devpath == NULL) { + if ((node = efi_devpath_last_node(devpath)) == NULL) continue; + if ((acpi = efipart_floppy(node)) != NULL) { + efipart_fdinfo_add(efipart_handles[i], acpi->UID, + devpath); } + } +} - status = BS->HandleProtocol(hin[n], &blkio_guid, - (void**)&blkio); - if (EFI_ERROR(status)) +static int +efipart_initfd(void) +{ + int rv; + + rv = efipart_inithandles(); + if (rv != 0) + return (rv); + STAILQ_INIT(&fdinfo); + + efipart_updatefd(); + + bcache_add_dev(efiblk_pdinfo_count(&fdinfo)); + return (0); +} + +/* + * Add or update entries with new handle data. + */ +static int +efipart_cdinfo_add(EFI_HANDLE handle, EFI_HANDLE alias, + EFI_DEVICE_PATH *devpath) +{ + int unit; + pdinfo_t *cd; + pdinfo_t *pd; + + unit = 0; + STAILQ_FOREACH(pd, &cdinfo, pd_link) { + if (efi_devpath_match(pd->pd_devpath, devpath) != 0) { + pd->pd_handle = handle; + pd->pd_alias = alias; + return (0); + } + unit++; + } + + cd = malloc(sizeof(pdinfo_t)); + if (cd == NULL) { + printf("Failed to add cd %d, out of memory\n", unit); + return (ENOMEM); + } + memset(cd, 0, sizeof(pdinfo_t)); + STAILQ_INIT(&cd->pd_part); + + cd->pd_handle = handle; + cd->pd_unit = unit; + cd->pd_alias = alias; + cd->pd_devpath = devpath; + STAILQ_INSERT_TAIL(&cdinfo, cd, pd_link); + return (0); +} + +static void +efipart_updatecd(void) +{ + int i, nin; + EFI_DEVICE_PATH *devpath, *devpathcpy, *tmpdevpath, *node; + EFI_HANDLE handle; + EFI_BLOCK_IO *blkio; + EFI_STATUS status; + + nin = efipart_nhandles / sizeof (*efipart_handles); + for (i = 0; i < nin; i++) { + devpath = efi_lookup_devpath(efipart_handles[i]); + if (devpath == NULL) continue; - if (!blkio->Media->LogicalPartition) { - nrdisk++; + + if ((node = efi_devpath_last_node(devpath)) == NULL) + continue; + if (efipart_floppy(node) != NULL) continue; - } + status = BS->HandleProtocol(efipart_handles[i], + &blkio_guid, (void **)&blkio); + if (EFI_ERROR(status)) + continue; /* * If we come across a logical partition of subtype CDROM * it doesn't refer to the CD filesystem itself, but rather @@ -130,119 +302,500 @@ efipart_init(void) * we try to find the parent device and add that instead as * that will be the CD filesystem. */ - node = efi_devpath_last_node(devpath); if (DevicePathType(node) == MEDIA_DEVICE_PATH && DevicePathSubType(node) == MEDIA_CDROM_DP) { devpathcpy = efi_devpath_trim(devpath); + if (devpathcpy == NULL) + continue; tmpdevpath = devpathcpy; status = BS->LocateDevicePath(&blkio_guid, &tmpdevpath, &handle); free(devpathcpy); if (EFI_ERROR(status)) continue; - hout[nout] = handle; - aliases[nout] = hin[n]; - } else - hout[nout] = hin[n]; - nout++; - pdinfo[npdinfo].pd_open = 0; - pdinfo[npdinfo].pd_bcache = NULL; - pdinfo[npdinfo].pd_unit = npdinfo; - npdinfo++; + devpath = efi_lookup_devpath(handle); + efipart_cdinfo_add(handle, efipart_handles[i], + devpath); + continue; + } + + if (DevicePathType(node) == MESSAGING_DEVICE_PATH && + DevicePathSubType(node) == MSG_ATAPI_DP) { + efipart_cdinfo_add(efipart_handles[i], NULL, + devpath); + continue; + } + + /* USB or SATA cd without the media. */ + if (blkio->Media->RemovableMedia && + !blkio->Media->MediaPresent) { + efipart_cdinfo_add(efipart_handles[i], NULL, + devpath); + } } +} - bcache_add_dev(npdinfo); - err = efi_register_handles(&efipart_dev, hout, aliases, nout); - free(hin); +static int +efipart_initcd(void) +{ + int rv; - if (nout == 0 && nrdisk > 0) - printf("Found %d disk(s) but no logical partition\n", nrdisk); - return (err); + rv = efipart_inithandles(); + if (rv != 0) + return (rv); + STAILQ_INIT(&cdinfo); + + efipart_updatecd(); + + bcache_add_dev(efiblk_pdinfo_count(&cdinfo)); + return (0); } static int -efipart_print(int verbose) +efipart_hdinfo_add(EFI_HANDLE disk_handle, EFI_HANDLE part_handle) { - char line[80]; + EFI_DEVICE_PATH *disk_devpath, *part_devpath; + HARDDRIVE_DEVICE_PATH *node; + int unit; + pdinfo_t *hd, *pd, *last; + + disk_devpath = efi_lookup_devpath(disk_handle); + part_devpath = efi_lookup_devpath(part_handle); + if (disk_devpath == NULL || part_devpath == NULL) { + return (ENOENT); + } + node = (HARDDRIVE_DEVICE_PATH *)efi_devpath_last_node(part_devpath); + if (node == NULL) + return (ENOENT); /* This should not happen. */ + + pd = malloc(sizeof(pdinfo_t)); + if (pd == NULL) { + printf("Failed to add disk, out of memory\n"); + return (ENOMEM); + } + memset(pd, 0, sizeof(pdinfo_t)); + STAILQ_INIT(&pd->pd_part); + + STAILQ_FOREACH(hd, &hdinfo, pd_link) { + if (efi_devpath_match(hd->pd_devpath, disk_devpath) != 0) { + /* Add the partition. */ + pd->pd_handle = part_handle; + pd->pd_unit = node->PartitionNumber; + pd->pd_devpath = part_devpath; + STAILQ_INSERT_TAIL(&hd->pd_part, pd, pd_link); + return (0); + } + } + + last = STAILQ_LAST(&hdinfo, pdinfo, pd_link); + if (last != NULL) + unit = last->pd_unit + 1; + else + unit = 0; + + /* Add the disk. */ + hd = pd; + hd->pd_handle = disk_handle; + hd->pd_unit = unit; + hd->pd_devpath = disk_devpath; + STAILQ_INSERT_TAIL(&hdinfo, hd, pd_link); + + pd = malloc(sizeof(pdinfo_t)); + if (pd == NULL) { + printf("Failed to add partition, out of memory\n"); + return (ENOMEM); + } + memset(pd, 0, sizeof(pdinfo_t)); + STAILQ_INIT(&pd->pd_part); + + /* Add the partition. */ + pd->pd_handle = part_handle; + pd->pd_unit = node->PartitionNumber; + pd->pd_devpath = part_devpath; + STAILQ_INSERT_TAIL(&hd->pd_part, pd, pd_link); + + return (0); +} + +/* + * The MEDIA_FILEPATH_DP has device name. + * From U-Boot sources it looks like names are in the form + * of typeN:M, where type is interface type, N is disk id + * and M is partition id. + */ +static int +efipart_hdinfo_add_filepath(EFI_HANDLE disk_handle) +{ + EFI_DEVICE_PATH *devpath; + FILEPATH_DEVICE_PATH *node; + char *pathname, *p; + int unit, len; + pdinfo_t *pd, *last; + + /* First collect and verify all the data */ + if ((devpath = efi_lookup_devpath(disk_handle)) == NULL) + return (ENOENT); + node = (FILEPATH_DEVICE_PATH *)efi_devpath_last_node(devpath); + if (node == NULL) + return (ENOENT); /* This should not happen. */ + + pd = malloc(sizeof(pdinfo_t)); + if (pd == NULL) { + printf("Failed to add disk, out of memory\n"); + return (ENOMEM); + } + memset(pd, 0, sizeof(pdinfo_t)); + STAILQ_INIT(&pd->pd_part); + last = STAILQ_LAST(&hdinfo, pdinfo, pd_link); + if (last != NULL) + unit = last->pd_unit + 1; + else + unit = 0; + + /* FILEPATH_DEVICE_PATH has 0 terminated string */ + for (len = 0; node->PathName[len] != 0; len++) + ; + if ((pathname = malloc(len + 1)) == NULL) { + printf("Failed to add disk, out of memory\n"); + free(pd); + return (ENOMEM); + } + cpy16to8(node->PathName, pathname, len + 1); + p = strchr(pathname, ':'); + + /* + * Assume we are receiving handles in order, first disk handle, + * then partitions for this disk. If this assumption proves + * false, this code would need update. + */ + if (p == NULL) { /* no colon, add the disk */ + pd->pd_handle = disk_handle; + pd->pd_unit = unit; + pd->pd_devpath = devpath; + STAILQ_INSERT_TAIL(&hdinfo, pd, pd_link); + free(pathname); + return (0); + } + p++; /* skip the colon */ + unit = (int)strtol(p, NULL, 0); + + /* + * We should have disk registered, if not, we are receiving + * handles out of order, and this code should be reworked + * to create "blank" disk for partition, and to find the + * disk based on PathName compares. + */ + if (last == NULL) { + printf("BUG: No disk for partition \"%s\"\n", pathname); + free(pathname); + free(pd); + return (EINVAL); + } + /* Add the partition. */ + pd->pd_handle = disk_handle; + pd->pd_unit = unit; + pd->pd_devpath = devpath; + STAILQ_INSERT_TAIL(&last->pd_part, pd, pd_link); + free(pathname); + return (0); +} + +static void +efipart_updatehd(void) +{ + int i, nin; + EFI_DEVICE_PATH *devpath, *devpathcpy, *tmpdevpath, *node; + EFI_HANDLE handle; EFI_BLOCK_IO *blkio; - EFI_HANDLE h; EFI_STATUS status; - u_int unit; + + nin = efipart_nhandles / sizeof (*efipart_handles); + for (i = 0; i < nin; i++) { + devpath = efi_lookup_devpath(efipart_handles[i]); + if (devpath == NULL) + continue; + + if ((node = efi_devpath_last_node(devpath)) == NULL) + continue; + if (efipart_floppy(node) != NULL) + continue; + + status = BS->HandleProtocol(efipart_handles[i], + &blkio_guid, (void **)&blkio); + if (EFI_ERROR(status)) + continue; + + if (DevicePathType(node) == MEDIA_DEVICE_PATH && + DevicePathSubType(node) == MEDIA_HARDDRIVE_DP) { + devpathcpy = efi_devpath_trim(devpath); + if (devpathcpy == NULL) + continue; + tmpdevpath = devpathcpy; + status = BS->LocateDevicePath(&blkio_guid, &tmpdevpath, + &handle); + free(devpathcpy); + if (EFI_ERROR(status)) + continue; + /* + * We do not support nested partitions. + */ + devpathcpy = efi_lookup_devpath(handle); + if (devpathcpy == NULL) + continue; + if ((node = efi_devpath_last_node(devpathcpy)) == NULL) + continue; + if (DevicePathType(node) == MEDIA_DEVICE_PATH && + DevicePathSubType(node) == MEDIA_HARDDRIVE_DP) + continue; + efipart_hdinfo_add(handle, efipart_handles[i]); + continue; + } + + if (DevicePathType(node) == MEDIA_DEVICE_PATH && + DevicePathSubType(node) == MEDIA_FILEPATH_DP) { + efipart_hdinfo_add_filepath(efipart_handles[i]); + continue; + } + } +} + +static int +efipart_inithd(void) +{ + int rv; + + rv = efipart_inithandles(); + if (rv != 0) + return (rv); + STAILQ_INIT(&hdinfo); + + efipart_updatehd(); + + bcache_add_dev(efiblk_pdinfo_count(&hdinfo)); + return (0); +} + +static int +efipart_print_common(struct devsw *dev, pdinfo_list_t *pdlist, int verbose) +{ int ret = 0; + EFI_BLOCK_IO *blkio; + EFI_STATUS status; + EFI_HANDLE h; + pdinfo_t *pd; + CHAR16 *text; + struct disk_devdesc pd_dev; + char line[80]; - printf("%s devices:", efipart_dev.dv_name); + if (STAILQ_EMPTY(pdlist)) + return (0); + + printf("%s devices:", dev->dv_name); if ((ret = pager_output("\n")) != 0) return (ret); - for (unit = 0, h = efi_find_handle(&efipart_dev, 0); - h != NULL; h = efi_find_handle(&efipart_dev, ++unit)) { - snprintf(line, sizeof(line), " %s%d:", - efipart_dev.dv_name, unit); - if ((ret = pager_output(line)) != 0) - break; - + STAILQ_FOREACH(pd, pdlist, pd_link) { + h = pd->pd_handle; + if (verbose) { /* Output the device path. */ + text = efi_devpath_name(efi_lookup_devpath(h)); + if (text != NULL) { + printf(" %S", text); + efi_free_devpath_name(text); + if ((ret = pager_output("\n")) != 0) + break; + } + } + snprintf(line, sizeof(line), + " %s%d", dev->dv_name, pd->pd_unit); + printf("%s:", line); status = BS->HandleProtocol(h, &blkio_guid, (void **)&blkio); if (!EFI_ERROR(status)) { - snprintf(line, sizeof(line), " %llu blocks", - (unsigned long long)(blkio->Media->LastBlock + 1)); - if ((ret = pager_output(line)) != 0) + printf(" %llu", + blkio->Media->LastBlock == 0? 0: + (unsigned long long) (blkio->Media->LastBlock + 1)); + if (blkio->Media->LastBlock != 0) { + printf(" X %u", blkio->Media->BlockSize); + } + printf(" blocks"); + if (blkio->Media->MediaPresent) { + if (blkio->Media->RemovableMedia) + printf(" (removable)"); + } else + printf(" (no media)"); + if ((ret = pager_output("\n")) != 0) + break; + if (!blkio->Media->MediaPresent) + continue; + + pd->pd_blkio = blkio; + pd_dev.d_dev = dev; + pd_dev.d_unit = pd->pd_unit; + pd_dev.d_slice = -1; + pd_dev.d_partition = -1; + pd_dev.d_opendata = blkio; + ret = disk_open(&pd_dev, blkio->Media->BlockSize * + (blkio->Media->LastBlock + 1), + blkio->Media->BlockSize); + if (ret == 0) { + ret = disk_print(&pd_dev, line, verbose); + disk_close(&pd_dev); + if (ret != 0) + return (ret); + } else { + /* Do not fail from disk_open() */ + ret = 0; + } + } else { + if ((ret = pager_output("\n")) != 0) break; - if (blkio->Media->RemovableMedia) - if ((ret = pager_output(" (removable)")) != 0) - break; } - if ((ret = pager_output("\n")) != 0) - break; } return (ret); } +static int +efipart_printfd(int verbose) +{ + return (efipart_print_common(&efipart_fddev, &fdinfo, verbose)); +} + +static int +efipart_printcd(int verbose) +{ + return (efipart_print_common(&efipart_cddev, &cdinfo, verbose)); +} + +static int +efipart_printhd(int verbose) +{ + return (efipart_print_common(&efipart_hddev, &hdinfo, verbose)); +} + +pdinfo_list_t * +efiblk_get_pdinfo_list(struct devsw *dev) +{ + if (dev->dv_type == DEVT_DISK) + return (&hdinfo); + if (dev->dv_type == DEVT_CD) + return (&cdinfo); + if (dev->dv_type == DEVT_FD) + return (&fdinfo); + return (NULL); +} + static int efipart_open(struct open_file *f, ...) { va_list args; - struct devdesc *dev; + struct disk_devdesc *dev; + pdinfo_list_t *pdi; + pdinfo_t *pd; EFI_BLOCK_IO *blkio; - EFI_HANDLE h; EFI_STATUS status; va_start(args, f); - dev = va_arg(args, struct devdesc*); + dev = va_arg(args, struct disk_devdesc*); va_end(args); + if (dev == NULL) + return (EINVAL); - h = efi_find_handle(&efipart_dev, dev->d_unit); - if (h == NULL) + pdi = efiblk_get_pdinfo_list(dev->d_dev); + if (pdi == NULL) return (EINVAL); - status = BS->HandleProtocol(h, &blkio_guid, (void **)&blkio); - if (EFI_ERROR(status)) - return (efi_status_to_errno(status)); + pd = efiblk_get_pdinfo(pdi, dev->d_unit); + if (pd == NULL) + return (EIO); + + if (pd->pd_blkio == NULL) { + status = BS->HandleProtocol(pd->pd_handle, &blkio_guid, + (void **)&pd->pd_blkio); + if (EFI_ERROR(status)) + return (efi_status_to_errno(status)); + } + blkio = pd->pd_blkio; if (!blkio->Media->MediaPresent) return (EAGAIN); - dev->d_opendata = blkio; - PD(dev).pd_open++; - if (PD(dev).pd_bcache == NULL) - PD(dev).pd_bcache = bcache_allocate(); + pd->pd_open++; + if (pd->pd_bcache == NULL) + pd->pd_bcache = bcache_allocate(); + + if (dev->d_dev->dv_type == DEVT_DISK) { + return (disk_open(dev, + blkio->Media->BlockSize * (blkio->Media->LastBlock + 1), + blkio->Media->BlockSize)); + } return (0); } static int efipart_close(struct open_file *f) { - struct devdesc *dev; + struct disk_devdesc *dev; + pdinfo_list_t *pdi; + pdinfo_t *pd; + + dev = (struct disk_devdesc *)(f->f_devdata); + if (dev == NULL) + return (EINVAL); + pdi = efiblk_get_pdinfo_list(dev->d_dev); + if (pdi == NULL) + return (EINVAL); + + pd = efiblk_get_pdinfo(pdi, dev->d_unit); + if (pd == NULL) + return (EINVAL); + + pd->pd_open--; + if (pd->pd_open == 0) { + pd->pd_blkio = NULL; + bcache_free(pd->pd_bcache); + pd->pd_bcache = NULL; + } + if (dev->d_dev->dv_type == DEVT_DISK) + return (disk_close(dev)); + return (0); +} + +static int +efipart_ioctl(struct open_file *f, u_long cmd, void *data) +{ + struct disk_devdesc *dev; + pdinfo_list_t *pdi; + pdinfo_t *pd; + int rc; + + dev = (struct disk_devdesc *)(f->f_devdata); + if (dev == NULL) + return (EINVAL); + pdi = efiblk_get_pdinfo_list(dev->d_dev); + if (pdi == NULL) + return (EINVAL); - dev = (struct devdesc *)(f->f_devdata); - if (dev->d_opendata == NULL) + pd = efiblk_get_pdinfo(pdi, dev->d_unit); + if (pd == NULL) return (EINVAL); - dev->d_opendata = NULL; - PD(dev).pd_open--; - if (PD(dev).pd_open == 0) { - bcache_free(PD(dev).pd_bcache); - PD(dev).pd_bcache = NULL; + if (dev->d_dev->dv_type == DEVT_DISK) { + rc = disk_ioctl(dev, cmd, data); + if (rc != ENOTTY) + return (rc); + } + + switch (cmd) { + case DIOCGSECTORSIZE: + *(u_int *)data = pd->pd_blkio->Media->BlockSize; + break; + case DIOCGMEDIASIZE: + *(uint64_t *)data = pd->pd_blkio->Media->BlockSize * + (pd->pd_blkio->Media->LastBlock + 1); + break; + default: + return (ENOTTY); } + return (0); } @@ -281,8 +834,10 @@ efipart_readwrite(EFI_BLOCK_IO *blkio, int rw, daddr_t blk, daddr_t nblks, return (ENOSYS); } - if (EFI_ERROR(status)) - printf("%s: rw=%d, status=%lu\n", __func__, rw, (u_long)status); + if (EFI_ERROR(status)) { + printf("%s: rw=%d, blk=%ju size=%ju status=%lu\n", __func__, rw, + blk, nblks, EFI_ERROR_CODE(status)); + } return (efi_status_to_errno(status)); } @@ -291,12 +846,33 @@ efipart_strategy(void *devdata, int rw, daddr_t blk, size_t size, char *buf, size_t *rsize) { struct bcache_devdata bcd; - struct devdesc *dev; + struct disk_devdesc *dev; + pdinfo_list_t *pdi; + pdinfo_t *pd; + + dev = (struct disk_devdesc *)devdata; + if (dev == NULL) + return (EINVAL); + pdi = efiblk_get_pdinfo_list(dev->d_dev); + if (pdi == NULL) + return (EINVAL); + + pd = efiblk_get_pdinfo(pdi, dev->d_unit); + if (pd == NULL) + return (EINVAL); + + if (pd->pd_blkio->Media->RemovableMedia && + !pd->pd_blkio->Media->MediaPresent) + return (EIO); - dev = (struct devdesc *)devdata; bcd.dv_strategy = efipart_realstrategy; bcd.dv_devdata = devdata; - bcd.dv_cache = PD(dev).pd_bcache; + bcd.dv_cache = pd->pd_bcache; + + if (dev->d_dev->dv_type == DEVT_DISK) { + return (bcache_strategy(&bcd, rw, blk + dev->d_offset, + size, buf, rsize)); + } return (bcache_strategy(&bcd, rw, blk, size, buf, rsize)); } @@ -304,9 +880,11 @@ static int efipart_realstrategy(void *devdata, int rw, daddr_t blk, size_t size, char *buf, size_t *rsize) { - struct devdesc *dev = (struct devdesc *)devdata; + struct disk_devdesc *dev = (struct disk_devdesc *)devdata; + pdinfo_list_t *pdi; + pdinfo_t *pd; EFI_BLOCK_IO *blkio; - off_t off; + uint64_t off, disk_blocks, d_offset = 0; char *blkbuf; size_t blkoff, blksz; int error; @@ -314,7 +892,15 @@ efipart_realstrategy(void *devdata, int rw, daddr_t blk, size_t size, if (dev == NULL || blk < 0) return (EINVAL); - blkio = dev->d_opendata; + pdi = efiblk_get_pdinfo_list(dev->d_dev); + if (pdi == NULL) + return (EINVAL); + + pd = efiblk_get_pdinfo(pdi, dev->d_unit); + if (pd == NULL) + return (EINVAL); + + blkio = pd->pd_blkio; if (blkio == NULL) return (ENXIO); @@ -322,21 +908,34 @@ efipart_realstrategy(void *devdata, int rw, daddr_t blk, size_t size, return (EIO); off = blk * 512; + /* + * Get disk blocks, this value is either for whole disk or for + * partition. + */ + disk_blocks = 0; + if (dev->d_dev->dv_type == DEVT_DISK) { + if (disk_ioctl(dev, DIOCGMEDIASIZE, &disk_blocks) == 0) { + /* DIOCGMEDIASIZE does return bytes. */ + disk_blocks /= blkio->Media->BlockSize; + } + d_offset = dev->d_offset; + } + if (disk_blocks == 0) + disk_blocks = blkio->Media->LastBlock + 1 - d_offset; + /* make sure we don't read past disk end */ - if ((off + size) / blkio->Media->BlockSize - 1 > - blkio->Media->LastBlock) { - size = blkio->Media->LastBlock + 1 - - off / blkio->Media->BlockSize; + if ((off + size) / blkio->Media->BlockSize > d_offset + disk_blocks) { + size = d_offset + disk_blocks - off / blkio->Media->BlockSize; size = size * blkio->Media->BlockSize; } if (rsize != NULL) *rsize = size; - if ((size % blkio->Media->BlockSize == 0) && - ((blk * 512) % blkio->Media->BlockSize == 0)) - return (efipart_readwrite(blkio, rw, - blk * 512 / blkio->Media->BlockSize, + if ((size % blkio->Media->BlockSize == 0) && + (off % blkio->Media->BlockSize == 0)) + return (efipart_readwrite(blkio, rw, + off / blkio->Media->BlockSize, size / blkio->Media->BlockSize, buf)); /* diff --git a/sys/boot/efi/libefi/env.c b/sys/boot/efi/libefi/env.c index 66b947d9b06..ceec7b2a18f 100644 --- a/sys/boot/efi/libefi/env.c +++ b/sys/boot/efi/libefi/env.c @@ -26,15 +26,17 @@ #include __FBSDID("$FreeBSD$"); +#include #include #include #include #include #include +#include #include "bootstrap.h" +#ifdef BOOT_FORTH #include "ficl.h" - -int efi_variable_support = 1; +#endif /* * Simple wrappers to the underlying UEFI functions. @@ -42,36 +44,350 @@ int efi_variable_support = 1; * for details. */ EFI_STATUS -efi_get_next_variable_name(UINTN *variable_name_size, CHAR16 *variable_name, EFI_GUID *vendor_guid) +efi_get_next_variable_name(UINTN *variable_name_size, CHAR16 *variable_name, + EFI_GUID *vendor_guid) { - return RS->GetNextVariableName(variable_name_size, variable_name, vendor_guid); + return (RS->GetNextVariableName(variable_name_size, variable_name, + vendor_guid)); } EFI_STATUS -efi_get_variable(CHAR16 *variable_name, EFI_GUID *vendor_guid, UINT32 *attributes, UINTN *data_size, - void *data) +efi_get_variable(CHAR16 *variable_name, EFI_GUID *vendor_guid, + UINT32 *attributes, UINTN *data_size, void *data) { - return RS->GetVariable(variable_name, vendor_guid, attributes, data_size, data); + return (RS->GetVariable(variable_name, vendor_guid, attributes, + data_size, data)); } EFI_STATUS -efi_set_variable(CHAR16 *variable_name, EFI_GUID *vendor_guid, UINT32 attributes, UINTN data_size, - void *data) +efi_set_variable(CHAR16 *variable_name, EFI_GUID *vendor_guid, + UINT32 attributes, UINTN data_size, void *data) +{ + return (RS->SetVariable(variable_name, vendor_guid, attributes, + data_size, data)); +} + +void +efi_init_environment(void) { - return RS->SetVariable(variable_name, vendor_guid, attributes, data_size, data); + char var[128]; + + snprintf(var, sizeof(var), "%d.%02d", ST->Hdr.Revision >> 16, + ST->Hdr.Revision & 0xffff); + env_setenv("efi-version", EV_VOLATILE, var, env_noset, env_nounset); } +COMMAND_SET(efishow, "efi-show", "print some or all EFI variables", command_efi_show); + +static int +efi_print_var(CHAR16 *varnamearg, EFI_GUID *matchguid, int lflag) +{ + UINTN datasz, i; + EFI_STATUS status; + UINT32 attr; + CHAR16 *data; + char *str; + uint32_t uuid_status; + int is_ascii; + + datasz = 0; + status = RS->GetVariable(varnamearg, matchguid, &attr, + &datasz, NULL); + if (status != EFI_BUFFER_TOO_SMALL) { + printf("Can't get the variable: error %#lx\n", + EFI_ERROR_CODE(status)); + return (CMD_ERROR); + } + data = malloc(datasz); + status = RS->GetVariable(varnamearg, matchguid, &attr, + &datasz, data); + if (status != EFI_SUCCESS) { + printf("Can't get the variable: error %#lx\n", + EFI_ERROR_CODE(status)); + return (CMD_ERROR); + } + uuid_to_string((uuid_t *)matchguid, &str, &uuid_status); + if (lflag) { + printf("%s 0x%x %S", str, attr, varnamearg); + } else { + printf("%s 0x%x %S=", str, attr, varnamearg); + is_ascii = 1; + free(str); + str = (char *)data; + for (i = 0; i < datasz - 1; i++) { + /* Quick hack to see if this ascii-ish string printable range plus tab, cr and lf */ + if ((str[i] < 32 || str[i] > 126) && str[i] != 9 && str[i] != 10 && str[i] != 13) { + is_ascii = 0; + break; + } + } + if (str[datasz - 1] != '\0') + is_ascii = 0; + if (is_ascii) + printf("%s", str); + else { + for (i = 0; i < datasz / 2; i++) { + if (isalnum(data[i]) || isspace(data[i])) + printf("%c", data[i]); + else + printf("\\x%02x", data[i]); + } + } + } + free(data); + if (pager_output("\n")) + return (CMD_WARN); + return (CMD_OK); +} + +static int +command_efi_show(int argc, char *argv[]) +{ + /* + * efi-show [-a] + * print all the env + * efi-show -u UUID + * print all the env vars tagged with UUID + * efi-show -v var + * search all the env vars and print the ones matching var + * eif-show -u UUID -v var + * eif-show UUID var + * print all the env vars that match UUID and var + */ + /* NB: We assume EFI_GUID is the same as uuid_t */ + int aflag = 0, gflag = 0, lflag = 0, vflag = 0; + int ch, rv; + unsigned i; + EFI_STATUS status; + EFI_GUID varguid = { 0,0,0,{0,0,0,0,0,0,0,0} }; + EFI_GUID matchguid = { 0,0,0,{0,0,0,0,0,0,0,0} }; + uint32_t uuid_status; + CHAR16 *varname; + CHAR16 *newnm; + CHAR16 varnamearg[128]; + UINTN varalloc; + UINTN varsz; + + while ((ch = getopt(argc, argv, "ag:lv:")) != -1) { + switch (ch) { + case 'a': + aflag = 1; + break; + case 'g': + gflag = 1; + uuid_from_string(optarg, (uuid_t *)&matchguid, + &uuid_status); + if (uuid_status != uuid_s_ok) { + printf("uid %s could not be parsed\n", optarg); + return (CMD_ERROR); + } + break; + case 'l': + lflag = 1; + break; + case 'v': + vflag = 1; + if (strlen(optarg) >= nitems(varnamearg)) { + printf("Variable %s is longer than %zd characters\n", + optarg, nitems(varnamearg)); + return (CMD_ERROR); + } + for (i = 0; i < strlen(optarg); i++) + varnamearg[i] = optarg[i]; + varnamearg[i] = 0; + break; + default: + printf("Invalid argument %c\n", ch); + return (CMD_ERROR); + } + } + + if (aflag && (gflag || vflag)) { + printf("-a isn't compatible with -v or -u\n"); + return (CMD_ERROR); + } + + if (aflag && optind < argc) { + printf("-a doesn't take any args\n"); + return (CMD_ERROR); + } + + if (optind == argc) + aflag = 1; + + argc -= optind; + argv += optind; + + pager_open(); + if (vflag && gflag) { + rv = efi_print_var(varnamearg, &matchguid, lflag); + pager_close(); + return (rv); + } + + if (argc == 2) { + optarg = argv[0]; + if (strlen(optarg) >= nitems(varnamearg)) { + printf("Variable %s is longer than %zd characters\n", + optarg, nitems(varnamearg)); + pager_close(); + return (CMD_ERROR); + } + for (i = 0; i < strlen(optarg); i++) + varnamearg[i] = optarg[i]; + varnamearg[i] = 0; + optarg = argv[1]; + uuid_from_string(optarg, (uuid_t *)&matchguid, + &uuid_status); + if (uuid_status != uuid_s_ok) { + printf("uid %s could not be parsed\n", optarg); + pager_close(); + return (CMD_ERROR); + } + rv = efi_print_var(varnamearg, &matchguid, lflag); + pager_close(); + return (rv); + } + + if (argc > 0) { + printf("Too many args %d\n", argc); + pager_close(); + return (CMD_ERROR); + } + + /* + * Initiate the search -- note the standard takes pain + * to specify the initial call must be a poiner to a NULL + * character. + */ + varalloc = 1024; + varname = malloc(varalloc); + if (varname == NULL) { + printf("Can't allocate memory to get variables\n"); + pager_close(); + return (CMD_ERROR); + } + varname[0] = 0; + while (1) { + varsz = varalloc; + status = RS->GetNextVariableName(&varsz, varname, &varguid); + if (status == EFI_BUFFER_TOO_SMALL) { + varalloc = varsz; + newnm = realloc(varname, varalloc); + if (newnm == NULL) { + printf("Can't allocate memory to get variables\n"); + free(varname); + pager_close(); + return (CMD_ERROR); + } + varname = newnm; + continue; /* Try again with bigger buffer */ + } + if (status != EFI_SUCCESS) + break; + if (aflag) { + if (efi_print_var(varname, &varguid, lflag) != CMD_OK) + break; + continue; + } + if (vflag) { + if (wcscmp(varnamearg, varname) == 0) { + if (efi_print_var(varname, &varguid, lflag) != CMD_OK) + break; + continue; + } + } + if (gflag) { + if (memcmp(&varguid, &matchguid, sizeof(varguid)) == 0) { + if (efi_print_var(varname, &varguid, lflag) != CMD_OK) + break; + continue; + } + } + } + free(varname); + pager_close(); + + return (CMD_OK); +} + +COMMAND_SET(efiset, "efi-set", "set EFI variables", command_efi_set); + +static int +command_efi_set(int argc, char *argv[]) +{ + char *uuid, *var, *val; + CHAR16 wvar[128]; + EFI_GUID guid; + uint32_t status; + EFI_STATUS err; + + if (argc != 4) { + printf("efi-set uuid var new-value\n"); + return (CMD_ERROR); + } + uuid = argv[1]; + var = argv[2]; + val = argv[3]; + uuid_from_string(uuid, (uuid_t *)&guid, &status); + if (status != uuid_s_ok) { + printf("Invalid uuid %s %d\n", uuid, status); + return (CMD_ERROR); + } + cpy8to16(var, wvar, sizeof(wvar)); + err = RS->SetVariable(wvar, &guid, + EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS, + strlen(val) + 1, val); + if (EFI_ERROR(err)) { + printf("Failed to set variable: error %lu\n", EFI_ERROR_CODE(err)); + return (CMD_ERROR); + } + return (CMD_OK); +} + +COMMAND_SET(efiunset, "efi-unset", "delete / unset EFI variables", command_efi_unset); + +static int +command_efi_unset(int argc, char *argv[]) +{ + char *uuid, *var; + CHAR16 wvar[128]; + EFI_GUID guid; + uint32_t status; + EFI_STATUS err; + + if (argc != 3) { + printf("efi-unset uuid var\n"); + return (CMD_ERROR); + } + uuid = argv[1]; + var = argv[2]; + uuid_from_string(uuid, (uuid_t *)&guid, &status); + if (status != uuid_s_ok) { + printf("Invalid uuid %s\n", uuid); + return (CMD_ERROR); + } + cpy8to16(var, wvar, sizeof(wvar)); + err = RS->SetVariable(wvar, &guid, 0, 0, NULL); + if (EFI_ERROR(err)) { + printf("Failed to unset variable: error %lu\n", EFI_ERROR_CODE(err)); + return (CMD_ERROR); + } + return (CMD_OK); +} + +#ifdef BOOT_FORTH /* - * FreeBSD's loader interaction words and extras + * FreeBSD's loader interaction words and extras * - * efi-setenv ( value n name n guid n attr -- 0 | -1) - * efi-getenv ( guid n addr n -- addr' n' | -1 ) - * efi-unsetenv ( name n guid n'' -- ) + * efi-setenv ( value n name n guid n attr -- 0 | -1) + * efi-getenv ( guid n addr n -- addr' n' | -1 ) + * efi-unsetenv ( name n guid n'' -- ) */ /* * efi-setenv - * efi-setenv ( value n name n guid n attr -- 0 | -1) + * efi-setenv ( value n name n guid n attr -- 0 | -1) * * Set environment variables using the SetVariable EFI runtime service. * @@ -87,19 +403,18 @@ efi_set_variable(CHAR16 *variable_name, EFI_GUID *vendor_guid, UINT32 attributes * 4 Run time access * (corresponding to the same bits in the UEFI spec). */ -void +static void ficlEfiSetenv(FICL_VM *pVM) { -#ifndef TESTMAIN char *value = NULL, *guid = NULL; CHAR16 *name = NULL; int i; -#endif char *namep, *valuep, *guidp; int names, values, guids, attr; - int status; + EFI_STATUS status; uuid_t u; uint32_t ustatus; + bool error = true; #if FICL_ROBUST > 1 vmCheckStack(pVM, 6, 0); @@ -112,10 +427,9 @@ ficlEfiSetenv(FICL_VM *pVM) values = stackPopINT(pVM->pStack); valuep = (char*)stackPopPtr(pVM->pStack); -#ifndef TESTMAIN guid = (char*)ficlMalloc(guids); if (guid == NULL) - vmThrowErr(pVM, "Error: out of memory"); + goto out; memcpy(guid, guidp, guids); uuid_from_string(guid, &u, &ustatus); if (ustatus != uuid_s_ok) { @@ -123,16 +437,16 @@ ficlEfiSetenv(FICL_VM *pVM) goto out; } - name = (CHAR16 *)ficlMalloc((names + 1) * sizeof(CHAR16)); + name = ficlMalloc((names + 1) * sizeof(CHAR16)); if (name == NULL) - vmThrowErr(pVM, "Error: out of memory"); + goto out; for (i = 0; i < names; i++) name[i] = namep[i]; - name[names] = (CHAR16)0; + name[names] = 0; - value = (char*)ficlMalloc(values + 1); + value = ficlMalloc(values + 1); if (value == NULL) - vmThrowErr(pVM, "Error: out of memory"); + goto out; memcpy(value, valuep, values); status = efi_set_variable(name, (EFI_GUID *)&u, attr, values, value); @@ -140,21 +454,20 @@ ficlEfiSetenv(FICL_VM *pVM) stackPushINT(pVM->pStack, 0); else stackPushINT(pVM->pStack, -1); + error = false; out: ficlFree(name); ficlFree(value); ficlFree(guid); -#endif - return; + if (error == true) + vmThrowErr(pVM, "Error: out of memory"); } -void +static void ficlEfiGetenv(FICL_VM *pVM) { -#ifndef TESTMAIN char *name, *value; -#endif char *namep; int names; @@ -164,7 +477,6 @@ ficlEfiGetenv(FICL_VM *pVM) names = stackPopINT(pVM->pStack); namep = (char*) stackPopPtr(pVM->pStack); -#ifndef TESTMAIN name = (char*) ficlMalloc(names+1); if (name == NULL) vmThrowErr(pVM, "Error: out of memory"); @@ -178,18 +490,13 @@ ficlEfiGetenv(FICL_VM *pVM) stackPushPtr(pVM->pStack, value); stackPushINT(pVM->pStack, strlen(value)); } else -#endif stackPushINT(pVM->pStack, -1); - - return; } -void +static void ficlEfiUnsetenv(FICL_VM *pVM) { -#ifndef TESTMAIN char *name; -#endif char *namep; int names; @@ -199,7 +506,6 @@ ficlEfiUnsetenv(FICL_VM *pVM) names = stackPopINT(pVM->pStack); namep = (char*) stackPopPtr(pVM->pStack); -#ifndef TESTMAIN name = (char*) ficlMalloc(names+1); if (name == NULL) vmThrowErr(pVM, "Error: out of memory"); @@ -208,9 +514,6 @@ ficlEfiUnsetenv(FICL_VM *pVM) unsetenv(name); ficlFree(name); -#endif - - return; } /************************************************************************** @@ -218,17 +521,14 @@ ficlEfiUnsetenv(FICL_VM *pVM) **************************************************************************/ void ficlEfiCompilePlatform(FICL_SYSTEM *pSys) { - FICL_DICT *dp = pSys->dp; - assert (dp); - - dictAppendWord(dp, "efi-setenv", ficlEfiSetenv, FW_DEFAULT); - dictAppendWord(dp, "efi-getenv", ficlEfiGetenv, FW_DEFAULT); - dictAppendWord(dp, "efi-unsetenv", ficlEfiUnsetenv, FW_DEFAULT); + FICL_DICT *dp = pSys->dp; + assert (dp); - /* Would like to export the EFI version, but this will do for now */ - ficlSetEnv(pSys, "efi-boot", 1); - - return; + dictAppendWord(dp, "efi-setenv", ficlEfiSetenv, FW_DEFAULT); + dictAppendWord(dp, "efi-getenv", ficlEfiGetenv, FW_DEFAULT); + dictAppendWord(dp, "efi-unsetenv", ficlEfiUnsetenv, FW_DEFAULT); } FICL_COMPILE_SET(ficlEfiCompilePlatform); + +#endif /* BOOT_FORTH */ diff --git a/sys/boot/efi/libefi/wchar.c b/sys/boot/efi/libefi/wchar.c new file mode 100644 index 00000000000..d8d81aca4bc --- /dev/null +++ b/sys/boot/efi/libefi/wchar.c @@ -0,0 +1,73 @@ +/*- + * Copyright 2016 Netflix, Inc. 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 + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include + +/* + * CHAR16 related functions moved from loader. + * Perhaps we should move those to libstand afterall, but they are + * needed only by UEFI. + */ + +int +wcscmp(CHAR16 *a, CHAR16 *b) +{ + + while (*a && *b && *a == *b) { + a++; + b++; + } + return *a - *b; +} + +/* + * cpy8to16 copies a traditional C string into a CHAR16 string and + * 0 terminates it. len is the size of *dst in bytes. + */ +void +cpy8to16(const char *src, CHAR16 *dst, size_t len) +{ + len <<= 1; /* Assume CHAR16 is 2 bytes */ + while (len > 0 && *src) { + *dst++ = *src++; + len--; + } + *dst++ = (CHAR16)0; +} + +void +cpy16to8(const CHAR16 *src, char *dst, size_t len) +{ + size_t i; + + for (i = 0; i < len && src[i]; i++) + dst[i] = (char)src[i]; + if (i < len) + dst[i] = '\0'; +} diff --git a/sys/boot/efi/loader/conf.c b/sys/boot/efi/loader/conf.c index 3596a6360c3..a98d63f1b76 100644 --- a/sys/boot/efi/loader/conf.c +++ b/sys/boot/efi/loader/conf.c @@ -36,7 +36,9 @@ __FBSDID("$FreeBSD$"); #endif struct devsw *devsw[] = { - &efipart_dev, + &efipart_fddev, + &efipart_cddev, + &efipart_hddev, &efinet_dev, #ifdef EFI_ZFS_BOOT &zfs_dev, diff --git a/sys/boot/efi/loader/devicename.c b/sys/boot/efi/loader/devicename.c index 64a417daccd..1e13d7f99ed 100644 --- a/sys/boot/efi/loader/devicename.c +++ b/sys/boot/efi/loader/devicename.c @@ -33,6 +33,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #ifdef EFI_ZFS_BOOT #include #endif @@ -90,7 +91,7 @@ efi_parsedev(struct devdesc **dev, const char *devspec, const char **path) struct devsw *dv; char *cp; const char *np; - int i; + int i, err; /* minimum length check */ if (strlen(devspec) < 2) @@ -106,11 +107,26 @@ efi_parsedev(struct devdesc **dev, const char *devspec, const char **path) return (ENOENT); np = devspec + strlen(dv->dv_name); + err = 0; -#ifdef EFI_ZFS_BOOT - if (dv->dv_type == DEVT_ZFS) { - int err; + switch (dv->dv_type) { + case DEVT_NONE: + break; + + case DEVT_DISK: + idev = malloc(sizeof(struct disk_devdesc)); + if (idev == NULL) + return (ENOMEM); + + err = disk_parsedev((struct disk_devdesc *)idev, np, path); + if (err != 0) { + free(idev); + return (err); + } + break; +#ifdef EFI_ZFS_BOOT + case DEVT_ZFS: idev = malloc(sizeof(struct zfs_devdesc)); if (idev == NULL) return (ENOMEM); @@ -120,34 +136,35 @@ efi_parsedev(struct devdesc **dev, const char *devspec, const char **path) free(idev); return (err); } - cp = strchr(np + 1, ':'); - } else + break; #endif - { + default: idev = malloc(sizeof(struct devdesc)); if (idev == NULL) return (ENOMEM); - idev->d_dev = dv; - idev->d_type = dv->dv_type; idev->d_unit = -1; + cp = (char *)np; if (*np != '\0' && *np != ':') { idev->d_unit = strtol(np, &cp, 0); if (cp == np) { - idev->d_unit = -1; free(idev); return (EUNIT); } } - } + if (*cp != '\0' && *cp != ':') { + free(idev); + return (EINVAL); + } - if (*cp != '\0' && *cp != ':') { - free(idev); - return (EINVAL); + if (path != NULL) + *path = (*cp == 0) ? cp : cp + 1; + break; } - if (path != NULL) - *path = (*cp == 0) ? cp : cp + 1; + idev->d_dev = dv; + idev->d_type = dv->dv_type; + if (dev != NULL) *dev = idev; else @@ -162,14 +179,17 @@ efi_fmtdev(void *vdev) static char buf[SPECNAMELEN + 1]; switch(dev->d_type) { -#ifdef EFI_ZFS_BOOT - case DEVT_ZFS: - return (zfs_fmtdev(dev)); -#endif case DEVT_NONE: strcpy(buf, "(no device)"); break; + case DEVT_DISK: + return (disk_fmtdev(vdev)); + +#ifdef EFI_ZFS_BOOT + case DEVT_ZFS: + return (zfs_fmtdev(dev)); +#endif default: sprintf(buf, "%s%d:", dev->d_dev->dv_name, dev->d_unit); break; diff --git a/sys/boot/efi/loader/main.c b/sys/boot/efi/loader/main.c index 5f6e5c9e7f1..0b3951156a1 100644 --- a/sys/boot/efi/loader/main.c +++ b/sys/boot/efi/loader/main.c @@ -35,6 +35,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include @@ -52,22 +53,6 @@ __FBSDID("$FreeBSD$"); extern char bootprog_info[]; -#ifdef BOOT_FORTH -/* - * Normally, efi.o from libefi.a would be brought in due to a function we call - * there that's defined there. However, none of its functions are callable from - * here since it just adds words to the FORTH environment or implement those - * words. So, add a reference to a symbol in efi.o to force it to be be brought - * in so the init function there gets added to the "compile" linker set happens - * correctly. - * - * This assumes there's no global analysys that notices dummy1 isn't used - * anywhere and tries to eliminate it. - */ -extern int efi_variable_support; -int *dummy1 = &efi_variable_support; -#endif - struct arch_switch archsw; /* MI/MD interface boundary */ EFI_GUID acpi = ACPI_TABLE_GUID; @@ -86,34 +71,9 @@ EFI_GUID inputid = SIMPLE_TEXT_INPUT_PROTOCOL; #ifdef EFI_ZFS_BOOT static void efi_zfs_probe(void); +static uint64_t pool_guid; #endif -/* - * cpy8to16 copies a traditional C string into a CHAR16 string and - * 0 terminates it. len is the size of *dst in bytes. - */ -static void -cpy8to16(const char *src, CHAR16 *dst, size_t len) -{ - len <<= 1; /* Assume CHAR16 is 2 bytes */ - while (len > 0 && *src) { - *dst++ = *src++; - len--; - } - *dst++ = (CHAR16)0; -} - -static void -cpy16to8(const CHAR16 *src, char *dst, size_t len) -{ - size_t i; - - for (i = 0; i < len && src[i]; i++) - dst[i] = (char)src[i]; - if (i < len) - dst[i] = '\0'; -} - static int has_keyboard(void) { @@ -196,12 +156,110 @@ has_keyboard(void) return retval; } +static void +set_devdesc_currdev(struct devsw *dev, int unit) +{ + struct devdesc currdev; + char *devname; + + currdev.d_dev = dev; + currdev.d_type = currdev.d_dev->dv_type; + currdev.d_unit = unit; + currdev.d_opendata = NULL; + devname = efi_fmtdev(&currdev); + + env_setenv("currdev", EV_VOLATILE, devname, efi_setcurrdev, + env_nounset); + env_setenv("loaddev", EV_VOLATILE, devname, env_noset, env_nounset); +} + static int -find_currdev(EFI_LOADED_IMAGE *img, struct devsw **dev, int *unit, - uint64_t *extra) +find_currdev(EFI_LOADED_IMAGE *img) { + pdinfo_list_t *pdi_list; + pdinfo_t *dp, *pp; EFI_DEVICE_PATH *devpath, *copy; EFI_HANDLE h; + char *devname; + struct devsw *dev; + int unit; + uint64_t extra; + +#ifdef EFI_ZFS_BOOT + /* Did efi_zfs_probe() detect the boot pool? */ + if (pool_guid != 0) { + struct zfs_devdesc currdev; + + currdev.d_dev = &zfs_dev; + currdev.d_unit = 0; + currdev.d_type = currdev.d_dev->dv_type; + currdev.d_opendata = NULL; + currdev.pool_guid = pool_guid; + currdev.root_guid = 0; + devname = efi_fmtdev(&currdev); + + env_setenv("currdev", EV_VOLATILE, devname, efi_setcurrdev, + env_nounset); + env_setenv("loaddev", EV_VOLATILE, devname, env_noset, + env_nounset); + init_zfs_bootenv(devname); + return (0); + } +#endif /* EFI_ZFS_BOOT */ + + /* We have device lists for hd, cd, fd, walk them all. */ + pdi_list = efiblk_get_pdinfo_list(&efipart_hddev); + STAILQ_FOREACH(dp, pdi_list, pd_link) { + struct disk_devdesc currdev; + + currdev.d_dev = &efipart_hddev; + currdev.d_type = currdev.d_dev->dv_type; + currdev.d_unit = dp->pd_unit; + currdev.d_opendata = NULL; + currdev.d_slice = -1; + currdev.d_partition = -1; + + if (dp->pd_handle == img->DeviceHandle) { + devname = efi_fmtdev(&currdev); + + env_setenv("currdev", EV_VOLATILE, devname, + efi_setcurrdev, env_nounset); + env_setenv("loaddev", EV_VOLATILE, devname, + env_noset, env_nounset); + return (0); + } + /* Assuming GPT partitioning. */ + STAILQ_FOREACH(pp, &dp->pd_part, pd_link) { + if (pp->pd_handle == img->DeviceHandle) { + currdev.d_slice = pp->pd_unit; + currdev.d_partition = 255; + devname = efi_fmtdev(&currdev); + + env_setenv("currdev", EV_VOLATILE, devname, + efi_setcurrdev, env_nounset); + env_setenv("loaddev", EV_VOLATILE, devname, + env_noset, env_nounset); + return (0); + } + } + } + + pdi_list = efiblk_get_pdinfo_list(&efipart_cddev); + STAILQ_FOREACH(dp, pdi_list, pd_link) { + if (dp->pd_handle == img->DeviceHandle || + dp->pd_alias == img->DeviceHandle) { + set_devdesc_currdev(&efipart_cddev, dp->pd_unit); + return (0); + } + } + + pdi_list = efiblk_get_pdinfo_list(&efipart_fddev); + STAILQ_FOREACH(dp, pdi_list, pd_link) { + if (dp->pd_handle == img->DeviceHandle) { + set_devdesc_currdev(&efipart_fddev, dp->pd_unit); + return (0); + } + } /* * Try the device handle from our loaded image first. If that @@ -209,8 +267,10 @@ find_currdev(EFI_LOADED_IMAGE *img, struct devsw **dev, int *unit, * any of the nodes in that path match one of the enumerated * handles. */ - if (efi_handle_lookup(img->DeviceHandle, dev, unit, extra) == 0) + if (efi_handle_lookup(img->DeviceHandle, &dev, &unit, &extra) == 0) { + set_devdesc_currdev(dev, unit); return (0); + } copy = NULL; devpath = efi_lookup_image_devpath(IH); @@ -219,26 +279,22 @@ find_currdev(EFI_LOADED_IMAGE *img, struct devsw **dev, int *unit, if (h == NULL) break; - if (efi_handle_lookup(h, dev, unit, extra) == 0) { - if (copy != NULL) - free(copy); + free(copy); + copy = NULL; + + if (efi_handle_lookup(h, &dev, &unit, &extra) == 0) { + set_devdesc_currdev(dev, unit); return (0); } - if (copy != NULL) - free(copy); devpath = efi_lookup_devpath(h); if (devpath != NULL) { copy = efi_devpath_trim(devpath); devpath = copy; } } + free(copy); - /* Try to fallback on first device */ - if (devsw[0] != NULL) { - *dev = devsw[0]; - return (0); - } return (ENOENT); } @@ -248,9 +304,7 @@ main(int argc, CHAR16 *argv[]) char var[128]; EFI_LOADED_IMAGE *img; EFI_GUID *guid; - int i, j, vargood, unit, howto; - struct devsw *dev; - uint64_t pool_guid; + int i, j, vargood, howto; UINTN k; int has_kbd; char buf[40]; @@ -419,46 +473,10 @@ main(int argc, CHAR16 *argv[]) */ BS->SetWatchdogTimer(0, 0, 0, NULL); - if (find_currdev(img, &dev, &unit, &pool_guid) != 0) + if (find_currdev(img) != 0) return (EFI_NOT_FOUND); - switch (dev->dv_type) { -#ifdef EFI_ZFS_BOOT - case DEVT_ZFS: { - struct zfs_devdesc currdev; - - currdev.d_dev = dev; - currdev.d_unit = unit; - currdev.d_type = currdev.d_dev->dv_type; - currdev.d_opendata = NULL; - currdev.pool_guid = pool_guid; - currdev.root_guid = 0; - env_setenv("currdev", EV_VOLATILE, efi_fmtdev(&currdev), - efi_setcurrdev, env_nounset); - env_setenv("loaddev", EV_VOLATILE, efi_fmtdev(&currdev), env_noset, - env_nounset); - init_zfs_bootenv(zfs_fmtdev(&currdev)); - break; - } -#endif - default: { - struct devdesc currdev; - - currdev.d_dev = dev; - currdev.d_unit = unit; - currdev.d_opendata = NULL; - currdev.d_type = currdev.d_dev->dv_type; - env_setenv("currdev", EV_VOLATILE, efi_fmtdev(&currdev), - efi_setcurrdev, env_nounset); - env_setenv("loaddev", EV_VOLATILE, efi_fmtdev(&currdev), env_noset, - env_nounset); - break; - } - } - - snprintf(var, sizeof(var), "%d.%02d", ST->Hdr.Revision >> 16, - ST->Hdr.Revision & 0xffff); - env_setenv("efi-version", EV_VOLATILE, var, env_noset, env_nounset); + efi_init_environment(); setenv("LINES", "24", 1); /* optional */ for (k = 0; k < ST->NumberOfTableEntries; k++) { @@ -477,19 +495,6 @@ main(int argc, CHAR16 *argv[]) return (EFI_SUCCESS); /* keep compiler happy */ } -/* XXX move to lib stand ? */ -static int -wcscmp(CHAR16 *a, CHAR16 *b) -{ - - while (*a && *b && *a == *b) { - a++; - b++; - } - return *a - *b; -} - - COMMAND_SET(reboot, "reboot", "reboot the system", command_reboot); static int @@ -771,305 +776,6 @@ command_reloadbe(int argc, char *argv[]) } #endif -COMMAND_SET(efishow, "efi-show", "print some or all EFI variables", command_efi_show); - -static int -efi_print_var(CHAR16 *varnamearg, EFI_GUID *matchguid, int lflag) -{ - UINTN datasz, i; - EFI_STATUS status; - UINT32 attr; - CHAR16 *data; - char *str; - uint32_t uuid_status; - int is_ascii; - - datasz = 0; - status = RS->GetVariable(varnamearg, matchguid, &attr, - &datasz, NULL); - if (status != EFI_BUFFER_TOO_SMALL) { - printf("Can't get the variable: error %#lx\n", status); - return (CMD_ERROR); - } - data = malloc(datasz); - status = RS->GetVariable(varnamearg, matchguid, &attr, - &datasz, data); - if (status != EFI_SUCCESS) { - printf("Can't get the variable: error %#lx\n", status); - return (CMD_ERROR); - } - uuid_to_string((uuid_t *)matchguid, &str, &uuid_status); - if (lflag) { - printf("%s 0x%x %S", str, attr, varnamearg); - } else { - printf("%s 0x%x %S=", str, attr, varnamearg); - is_ascii = 1; - free(str); - str = (char *)data; - for (i = 0; i < datasz - 1; i++) { - /* Quick hack to see if this ascii-ish string printable range plus tab, cr and lf */ - if ((str[i] < 32 || str[i] > 126) && str[i] != 9 && str[i] != 10 && str[i] != 13) { - is_ascii = 0; - break; - } - } - if (str[datasz - 1] != '\0') - is_ascii = 0; - if (is_ascii) - printf("%s", str); - else { - for (i = 0; i < datasz / 2; i++) { - if (isalnum(data[i]) || isspace(data[i])) - printf("%c", data[i]); - else - printf("\\x%02x", data[i]); - } - } - } - free(data); - if (pager_output("\n")) - return (CMD_WARN); - return (CMD_OK); -} - -static int -command_efi_show(int argc, char *argv[]) -{ - /* - * efi-show [-a] - * print all the env - * efi-show -u UUID - * print all the env vars tagged with UUID - * efi-show -v var - * search all the env vars and print the ones matching var - * eif-show -u UUID -v var - * eif-show UUID var - * print all the env vars that match UUID and var - */ - /* NB: We assume EFI_GUID is the same as uuid_t */ - int aflag = 0, gflag = 0, lflag = 0, vflag = 0; - int ch, rv; - unsigned i; - EFI_STATUS status; - EFI_GUID varguid = { 0,0,0,{0,0,0,0,0,0,0,0} }; - EFI_GUID matchguid = { 0,0,0,{0,0,0,0,0,0,0,0} }; - uint32_t uuid_status; - CHAR16 *varname; - CHAR16 *newnm; - CHAR16 varnamearg[128]; - UINTN varalloc; - UINTN varsz; - - while ((ch = getopt(argc, argv, "ag:lv:")) != -1) { - switch (ch) { - case 'a': - aflag = 1; - break; - case 'g': - gflag = 1; - uuid_from_string(optarg, (uuid_t *)&matchguid, - &uuid_status); - if (uuid_status != uuid_s_ok) { - printf("uid %s could not be parsed\n", optarg); - return (CMD_ERROR); - } - break; - case 'l': - lflag = 1; - break; - case 'v': - vflag = 1; - if (strlen(optarg) >= nitems(varnamearg)) { - printf("Variable %s is longer than %zd characters\n", - optarg, nitems(varnamearg)); - return (CMD_ERROR); - } - for (i = 0; i < strlen(optarg); i++) - varnamearg[i] = optarg[i]; - varnamearg[i] = 0; - break; - default: - printf("Invalid argument %c\n", ch); - return (CMD_ERROR); - } - } - - if (aflag && (gflag || vflag)) { - printf("-a isn't compatible with -v or -u\n"); - return (CMD_ERROR); - } - - if (aflag && optind < argc) { - printf("-a doesn't take any args"); - return (CMD_ERROR); - } - - if (optind == argc) - aflag = 1; - - argc -= optind; - argv += optind; - - pager_open(); - if (vflag && gflag) { - rv = efi_print_var(varnamearg, &matchguid, lflag); - pager_close(); - return (rv); - } - - if (argc == 2) { - optarg = argv[0]; - if (strlen(optarg) >= nitems(varnamearg)) { - printf("Variable %s is longer than %zd characters\n", - optarg, nitems(varnamearg)); - pager_close(); - return (CMD_ERROR); - } - for (i = 0; i < strlen(optarg); i++) - varnamearg[i] = optarg[i]; - varnamearg[i] = 0; - optarg = argv[1]; - uuid_from_string(optarg, (uuid_t *)&matchguid, - &uuid_status); - if (uuid_status != uuid_s_ok) { - printf("uid %s could not be parsed\n", optarg); - pager_close(); - return (CMD_ERROR); - } - rv = efi_print_var(varnamearg, &matchguid, lflag); - pager_close(); - return (rv); - } - - if (argc > 0) { - printf("Too many args %d\n", argc); - pager_close(); - return (CMD_ERROR); - } - - /* - * Initiate the search -- note the standard takes pain - * to specify the initial call must be a poiner to a NULL - * character. - */ - varalloc = 1024; - varname = malloc(varalloc); - if (varname == NULL) { - printf("Can't allocate memory to get variables\n"); - pager_close(); - return (CMD_ERROR); - } - varname[0] = 0; - while (1) { - varsz = varalloc; - status = RS->GetNextVariableName(&varsz, varname, &varguid); - if (status == EFI_BUFFER_TOO_SMALL) { - varalloc = varsz; - newnm = malloc(varalloc); - if (newnm == NULL) { - printf("Can't allocate memory to get variables\n"); - free(varname); - pager_close(); - return (CMD_ERROR); - } - memcpy(newnm, varname, varsz); - free(varname); - varname = newnm; - continue; /* Try again with bigger buffer */ - } - if (status != EFI_SUCCESS) - break; - if (aflag) { - if (efi_print_var(varname, &varguid, lflag) != CMD_OK) - break; - continue; - } - if (vflag) { - if (wcscmp(varnamearg, varname) == 0) { - if (efi_print_var(varname, &varguid, lflag) != CMD_OK) - break; - continue; - } - } - if (gflag) { - if (memcmp(&varguid, &matchguid, sizeof(varguid)) == 0) { - if (efi_print_var(varname, &varguid, lflag) != CMD_OK) - break; - continue; - } - } - } - free(varname); - pager_close(); - - return (CMD_OK); -} - -COMMAND_SET(efiset, "efi-set", "set EFI variables", command_efi_set); - -static int -command_efi_set(int argc, char *argv[]) -{ - char *uuid, *var, *val; - CHAR16 wvar[128]; - EFI_GUID guid; - uint32_t status; - EFI_STATUS err; - - if (argc != 4) { - printf("efi-set uuid var new-value\n"); - return (CMD_ERROR); - } - uuid = argv[1]; - var = argv[2]; - val = argv[3]; - uuid_from_string(uuid, (uuid_t *)&guid, &status); - if (status != uuid_s_ok) { - printf("Invalid uuid %s %d\n", uuid, status); - return (CMD_ERROR); - } - cpy8to16(var, wvar, sizeof(wvar)); - err = RS->SetVariable(wvar, &guid, - EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS, - strlen(val) + 1, val); - if (EFI_ERROR(err)) { - printf("Failed to set variable: error %lu\n", EFI_ERROR_CODE(err)); - return (CMD_ERROR); - } - return (CMD_OK); -} - -COMMAND_SET(efiunset, "efi-unset", "delete / unset EFI variables", command_efi_unset); - -static int -command_efi_unset(int argc, char *argv[]) -{ - char *uuid, *var; - CHAR16 wvar[128]; - EFI_GUID guid; - uint32_t status; - EFI_STATUS err; - - if (argc != 3) { - printf("efi-unset uuid var\n"); - return (CMD_ERROR); - } - uuid = argv[1]; - var = argv[2]; - uuid_from_string(uuid, (uuid_t *)&guid, &status); - if (status != uuid_s_ok) { - printf("Invalid uuid %s\n", uuid); - return (CMD_ERROR); - } - cpy8to16(var, wvar, sizeof(wvar)); - err = RS->SetVariable(wvar, &guid, 0, 0, NULL); - if (EFI_ERROR(err)) { - printf("Failed to unset variable: error %lu\n", EFI_ERROR_CODE(err)); - return (CMD_ERROR); - } - return (CMD_OK); -} - #ifdef LOADER_FDT_SUPPORT extern int command_fdt_internal(int argc, char *argv[]); @@ -1093,18 +799,43 @@ COMMAND_SET(fdt, "fdt", "flattened device tree handling", command_fdt); static void efi_zfs_probe(void) { - EFI_HANDLE h; - u_int unit; - int i; - char dname[SPECNAMELEN + 1]; - uint64_t guid; - - unit = 0; - h = efi_find_handle(&efipart_dev, 0); - for (i = 0; h != NULL; h = efi_find_handle(&efipart_dev, ++i)) { - snprintf(dname, sizeof(dname), "%s%d:", efipart_dev.dv_name, i); - if (zfs_probe_dev(dname, &guid) == 0) - (void)efi_handle_update_dev(h, &zfs_dev, unit++, guid); + pdinfo_list_t *hdi; + pdinfo_t *hd, *pd = NULL; + EFI_GUID imgid = LOADED_IMAGE_PROTOCOL; + EFI_LOADED_IMAGE *img; + EFI_HANDLE boot_disk = NULL; + char devname[SPECNAMELEN + 1]; + uint64_t *guidp = NULL; + + BS->HandleProtocol(IH, &imgid, (VOID**)&img); + + /* Find the handle for the boot disk. */ + hdi = efiblk_get_pdinfo_list(&efipart_hddev); + STAILQ_FOREACH(hd, hdi, pd_link) { + STAILQ_FOREACH(pd, &hd->pd_part, pd_link) { + if (pd->pd_handle == img->DeviceHandle) + boot_disk = hd->pd_handle; + } + } + + /* + * We provide non-NULL guid pointer if the disk was used for boot, + * and reset after the first found pool. + * Technically this solution is not very correct, we assume the boot + * pool is the first pool on this disk. + */ + + STAILQ_FOREACH(hd, hdi, pd_link) { + if (hd->pd_handle == boot_disk) + guidp = &pool_guid; + + STAILQ_FOREACH(pd, &hd->pd_part, pd_link) { + snprintf(devname, sizeof(devname), "%s%dp%d:", + efipart_hddev.dv_name, hd->pd_unit, pd->pd_unit); + (void) zfs_probe_dev(devname, guidp); + if (guidp != NULL && pool_guid != 0) + guidp = NULL; + } } } #endif diff --git a/sys/boot/forth/beastie.4th.8 b/sys/boot/forth/beastie.4th.8 index 9f77d5db297..e99f65474b4 100644 --- a/sys/boot/forth/beastie.4th.8 +++ b/sys/boot/forth/beastie.4th.8 @@ -34,9 +34,9 @@ The file that goes by the name of .Nm is a set of commands designed to draw the ASCII art FreeBSD mascot -.Nd known simply as -.Ic beastie -.Nd to the right of the boot loader menu. +\(en known simply as +.Em beastie +\(en to the right of the boot loader menu. The commands of .Nm by themselves are not enough for most uses. diff --git a/sys/boot/forth/loader.4th b/sys/boot/forth/loader.4th index 013a033b1fc..9486237b8a9 100644 --- a/sys/boot/forth/loader.4th +++ b/sys/boot/forth/loader.4th @@ -46,9 +46,9 @@ include /boot/support.4th include /boot/color.4th include /boot/delay.4th include /boot/check-password.4th -s" efi-boot" environment? [if] [if] +s" efi-version" getenv? [if] include /boot/efi.4th -[then] [then] +[then] only forth definitions diff --git a/sys/boot/geli/Makefile b/sys/boot/geli/Makefile index f302c8b240f..527d1c6a546 100644 --- a/sys/boot/geli/Makefile +++ b/sys/boot/geli/Makefile @@ -24,10 +24,6 @@ WARNS?= 0 .PATH: ${.CURDIR}/../../../lib/libc/string SRCS+= bcmp.c bcopy.c bzero.c -# need explicit_bzero for crypto -.PATH: ${.CURDIR}/../../../sys/libkern -SRCS+= explicit_bzero.c - # Our password input method SRCS+= pwgets.c @@ -43,6 +39,7 @@ SRCS+= md5c.c # AES implementation from sys/crypto .PATH: ${SRCTOP}/sys/crypto/rijndael CFLAGS+= -I${.CURDIR}/../../ +CFLAGS+= -I${.CURDIR}/../common/ # Remove asserts CFLAGS+= -DNDEBUG SRCS+= rijndael-alg-fst.c rijndael-api-fst.c rijndael-api.c diff --git a/sys/boot/geli/geliboot.c b/sys/boot/geli/geliboot.c index f9a128cb667..93264ecc8b9 100644 --- a/sys/boot/geli/geliboot.c +++ b/sys/boot/geli/geliboot.c @@ -27,17 +27,75 @@ * $FreeBSD$ */ +#include "geliboot_internal.h" #include "geliboot.h" SLIST_HEAD(geli_list, geli_entry) geli_head = SLIST_HEAD_INITIALIZER(geli_head); struct geli_list *geli_headp; +typedef u_char geli_ukey[G_ELI_USERKEYLEN]; + +static geli_ukey saved_keys[GELI_MAX_KEYS]; +static unsigned int nsaved_keys = 0; + +/* + * Copy keys from local storage to the keybuf struct. + * Destroy the local storage when finished. + */ +void +geli_fill_keybuf(struct keybuf *fkeybuf) +{ + unsigned int i; + + for (i = 0; i < nsaved_keys; i++) { + fkeybuf->kb_ents[i].ke_type = KEYBUF_TYPE_GELI; + memcpy(fkeybuf->kb_ents[i].ke_data, saved_keys[i], + G_ELI_USERKEYLEN); + } + fkeybuf->kb_nents = nsaved_keys; + explicit_bzero(saved_keys, sizeof(saved_keys)); +} + +/* + * Copy keys from a keybuf struct into local storage. + * Zero out the keybuf. + */ +void +geli_save_keybuf(struct keybuf *skeybuf) +{ + unsigned int i; + + for (i = 0; i < skeybuf->kb_nents && i < GELI_MAX_KEYS; i++) { + memcpy(saved_keys[i], skeybuf->kb_ents[i].ke_data, + G_ELI_USERKEYLEN); + explicit_bzero(skeybuf->kb_ents[i].ke_data, + G_ELI_USERKEYLEN); + skeybuf->kb_ents[i].ke_type = KEYBUF_TYPE_NONE; + } + nsaved_keys = skeybuf->kb_nents; + skeybuf->kb_nents = 0; +} + +static void +save_key(geli_ukey key) +{ + + /* + * If we run out of key space, the worst that will happen is + * it will ask the user for the password again. + */ + if (nsaved_keys < GELI_MAX_KEYS) { + memcpy(saved_keys[nsaved_keys], key, G_ELI_USERKEYLEN); + nsaved_keys++; + } +} + static int geli_same_device(struct geli_entry *ge, struct dsk *dskp) { - if (geli_e->dsk->drive == dskp->drive && - dskp->part == 255 && geli_e->dsk->part == dskp->slice) { + if (ge->dsk->drive == dskp->drive && + dskp->part == 255 && ge->dsk->part == dskp->slice) { /* * Sometimes slice = slice, and sometimes part = slice * If the incoming struct dsk has part=255, it means look at @@ -47,15 +105,39 @@ geli_same_device(struct geli_entry *ge, struct dsk *dskp) } /* Is this the same device? */ - if (geli_e->dsk->drive != dskp->drive || - geli_e->dsk->slice != dskp->slice || - geli_e->dsk->part != dskp->part) { + if (ge->dsk->drive != dskp->drive || + ge->dsk->slice != dskp->slice || + ge->dsk->part != dskp->part) { return (1); } return (0); } +static int +geli_findkey(struct geli_entry *ge, struct dsk *dskp, u_char *mkey) +{ + u_int keynum; + int i; + + if (ge->keybuf_slot >= 0) { + if (g_eli_mkey_decrypt(&ge->md, saved_keys[ge->keybuf_slot], + mkey, &keynum) == 0) { + return (0); + } + } + + for (i = 0; i < nsaved_keys; i++) { + if (g_eli_mkey_decrypt(&ge->md, saved_keys[i], mkey, + &keynum) == 0) { + ge->keybuf_slot = i; + return (0); + } + } + + return (1); +} + void geli_init(void) { @@ -123,6 +205,7 @@ geli_taste(int read_func(void *vdev, void *priv, off_t off, void *buf, if (dskp->part == 255) { geli_e->dsk->part = dskp->slice; } + geli_e->keybuf_slot = -1; geli_e->md = md; eli_metadata_softc(&geli_e->sc, &md, DEV_BSIZE, @@ -138,18 +221,27 @@ geli_taste(int read_func(void *vdev, void *priv, off_t off, void *buf, * Attempt to decrypt the device */ int -geli_attach(struct dsk *dskp, const char *passphrase) +geli_attach(struct dsk *dskp, const char *passphrase, const u_char *mkeyp) { u_char key[G_ELI_USERKEYLEN], mkey[G_ELI_DATAIVKEYLEN], *mkp; u_int keynum; struct hmac_ctx ctx; int error; + if (mkeyp != NULL) { + memcpy(&mkey, mkeyp, G_ELI_DATAIVKEYLEN); + explicit_bzero(mkeyp, G_ELI_DATAIVKEYLEN); + } + SLIST_FOREACH_SAFE(geli_e, &geli_head, entries, geli_e_tmp) { if (geli_same_device(geli_e, dskp) != 0) { continue; } + if (mkeyp != NULL || geli_findkey(geli_e, dskp, mkey) == 0) { + goto found_key; + } + g_eli_crypto_hmac_init(&ctx, NULL, 0); /* * Prepare Derived-Key from the user passphrase. @@ -173,23 +265,29 @@ geli_attach(struct dsk *dskp, const char *passphrase) sizeof(geli_e->md.md_salt), passphrase, geli_e->md.md_iterations); g_eli_crypto_hmac_update(&ctx, dkey, sizeof(dkey)); - bzero(&dkey, sizeof(dkey)); + explicit_bzero(dkey, sizeof(dkey)); } g_eli_crypto_hmac_final(&ctx, key, 0); error = g_eli_mkey_decrypt(&geli_e->md, key, mkey, &keynum); - bzero(&key, sizeof(key)); if (error == -1) { - bzero(&mkey, sizeof(mkey)); - printf("Bad GELI key: %d\n", error); + explicit_bzero(mkey, sizeof(mkey)); + explicit_bzero(key, sizeof(key)); + printf("Bad GELI key: bad password?\n"); return (error); } else if (error != 0) { - bzero(&mkey, sizeof(mkey)); - printf("Failed to decrypt GELI master key: %d\n", error); + explicit_bzero(mkey, sizeof(mkey)); + explicit_bzero(key, sizeof(key)); + printf("Failed to decrypt GELI master key: %d\n", error); return (error); - } + } else { + /* Add key to keychain */ + save_key(key); + explicit_bzero(&key, sizeof(key)); + } +found_key: /* Store the keys */ bcopy(mkey, geli_e->sc.sc_mkey, sizeof(geli_e->sc.sc_mkey)); bcopy(mkey, geli_e->sc.sc_ivkey, sizeof(geli_e->sc.sc_ivkey)); @@ -203,7 +301,7 @@ geli_attach(struct dsk *dskp, const char *passphrase) g_eli_crypto_hmac(mkp, G_ELI_MAXKEYLEN, "\x10", 1, geli_e->sc.sc_ekey, 0); } - bzero(&mkey, sizeof(mkey)); + explicit_bzero(mkey, sizeof(mkey)); /* Initialize the per-sector IV. */ switch (geli_e->sc.sc_ealgo) { @@ -231,7 +329,7 @@ is_geli(struct dsk *dskp) return (0); } } - + return (1); } @@ -279,13 +377,13 @@ geli_read(struct dsk *dskp, off_t offset, u_char *buf, size_t bytes) geli_e->sc.sc_ekeylen, iv); if (error != 0) { - bzero(&gkey, sizeof(gkey)); + explicit_bzero(&gkey, sizeof(gkey)); printf("Failed to decrypt in geli_read()!"); return (error); } pbuf += secsize; } - bzero(&gkey, sizeof(gkey)); + explicit_bzero(&gkey, sizeof(gkey)); return (0); } @@ -293,6 +391,27 @@ geli_read(struct dsk *dskp, off_t offset, u_char *buf, size_t bytes) return (1); } +int +geli_havekey(struct dsk *dskp) +{ + u_char mkey[G_ELI_DATAIVKEYLEN]; + + SLIST_FOREACH_SAFE(geli_e, &geli_head, entries, geli_e_tmp) { + if (geli_same_device(geli_e, dskp) != 0) { + continue; + } + + if (geli_findkey(geli_e, dskp, mkey) == 0) { + if (geli_attach(dskp, NULL, mkey) == 0) { + return (0); + } + } + } + explicit_bzero(mkey, sizeof(mkey)); + + return (1); +} + int geli_passphrase(char *pw, int disk, int parttype, int part, struct dsk *dskp) { @@ -302,14 +421,14 @@ geli_passphrase(char *pw, int disk, int parttype, int part, struct dsk *dskp) for (i = 0; i < 3; i++) { /* Try cached passphrase */ if (i == 0 && pw[0] != '\0') { - if (geli_attach(dskp, pw) == 0) { + if (geli_attach(dskp, pw, NULL) == 0) { return (0); } } printf("GELI Passphrase for disk%d%c%d: ", disk, parttype, part); pwgets(pw, GELI_PW_MAXLEN); printf("\n"); - if (geli_attach(dskp, pw) == 0) { + if (geli_attach(dskp, pw, NULL) == 0) { return (0); } } diff --git a/sys/boot/geli/geliboot.h b/sys/boot/geli/geliboot.h index 83df1529571..0d12eab8790 100644 --- a/sys/boot/geli/geliboot.h +++ b/sys/boot/geli/geliboot.h @@ -27,31 +27,11 @@ * $FreeBSD$ */ -#include -#include +#include #ifndef _GELIBOOT_H_ #define _GELIBOOT_H_ -#define _STRING_H_ -#define _STRINGS_H_ -#define _STDIO_H_ -#include -#include - -/* Pull in the md5, sha256, and sha512 implementations */ -#include -#include -#include - -/* Pull in AES implementation */ -#include - -/* AES-XTS implementation */ -#define _STAND -#define STAND_H /* We don't want stand.h in {gpt,zfs,gptzfs}boot */ -#include - #ifndef DEV_BSIZE #define DEV_BSIZE 512 #endif @@ -63,30 +43,26 @@ #define MIN(a,b) (((a) < (b)) ? (a) : (b)) #endif +#define GELI_MAX_KEYS 64 #define GELI_PW_MAXLEN 256 -extern void pwgets(char *buf, int n); - -struct geli_entry { - struct dsk *dsk; - off_t part_end; - struct g_eli_softc sc; - struct g_eli_metadata md; - SLIST_ENTRY(geli_entry) entries; -} *geli_e, *geli_e_tmp; -int geli_count; +extern void pwgets(char *buf, int n); void geli_init(void); int geli_taste(int read_func(void *vdev, void *priv, off_t off, void *buf, size_t bytes), struct dsk *dsk, daddr_t lastsector); -int geli_attach(struct dsk *dskp, const char *passphrase); +int geli_attach(struct dsk *dskp, const char *passphrase, const u_char *mkeyp); int is_geli(struct dsk *dsk); int geli_read(struct dsk *dsk, off_t offset, u_char *buf, size_t bytes); int geli_decrypt(u_int algo, u_char *data, size_t datasize, const u_char *key, size_t keysize, const uint8_t* iv); +int geli_havekey(struct dsk *dskp); int geli_passphrase(char *pw, int disk, int parttype, int part, struct dsk *dskp); int geliboot_crypt(u_int algo, int enc, u_char *data, size_t datasize, const u_char *key, size_t keysize, u_char *iv); +void geli_fill_keybuf(struct keybuf *keybuf); +void geli_save_keybuf(struct keybuf *keybuf); + #endif /* _GELIBOOT_H_ */ diff --git a/sys/boot/geli/geliboot_crypto.c b/sys/boot/geli/geliboot_crypto.c index 23d58ffebd1..c3db73f4955 100644 --- a/sys/boot/geli/geliboot_crypto.c +++ b/sys/boot/geli/geliboot_crypto.c @@ -31,6 +31,7 @@ #include #include +#include "geliboot_internal.h" #include "geliboot.h" int @@ -110,7 +111,7 @@ g_eli_crypto_cipher(u_int algo, int enc, u_char *data, size_t datasize, { u_char iv[keysize]; - bzero(iv, sizeof(iv)); + explicit_bzero(iv, sizeof(iv)); return (geliboot_crypt(algo, enc, data, datasize, key, keysize, iv)); } diff --git a/sys/boot/geli/geliboot_internal.h b/sys/boot/geli/geliboot_internal.h new file mode 100644 index 00000000000..ee93c244b0e --- /dev/null +++ b/sys/boot/geli/geliboot_internal.h @@ -0,0 +1,69 @@ +/*- + * Copyright (c) 2015 Allan Jude + * Copyright (c) 2005-2011 Pawel Jakub Dawidek + * 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 + * documentation and/or other materials provided with the distribution. + * + * 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. + * + * $FreeBSD$ + */ + +#ifndef _GELIBOOT_INTERNAL_H_ +#define _GELIBOOT_INTERNAL_H_ + +#define _STRING_H_ +#define _STRINGS_H_ +#define _STDIO_H_ + +#include +#include + +#include +#include + +#include + +/* Pull in the md5, sha256, and sha512 implementations */ +#include +#include +#include + +/* Pull in AES implementation */ +#include + +/* AES-XTS implementation */ +#define _STAND +#define STAND_H /* We don't want stand.h in {gpt,zfs,gptzfs}boot */ +#include + +struct geli_entry { + struct dsk *dsk; + off_t part_end; + struct g_eli_softc sc; + struct g_eli_metadata md; + int keybuf_slot; + SLIST_ENTRY(geli_entry) entries; +} *geli_e, *geli_e_tmp; + +static int geli_count; + +#endif /* _GELIBOOT_INTERNAL_H_ */ diff --git a/sys/boot/geli/pwgets.c b/sys/boot/geli/pwgets.c index aca6c3c7619..f43ebe8b3e6 100644 --- a/sys/boot/geli/pwgets.c +++ b/sys/boot/geli/pwgets.c @@ -60,14 +60,6 @@ pwgets(char *buf, int n) putchar('\b'); } break; - case 'r'&037: { - char *p; - - putchar('\n'); - for (p = buf; p < lp; ++p) - putchar(*p); - break; - } case 'u'&037: case 'w'&037: lp = buf; diff --git a/sys/boot/i386/boot2/Makefile b/sys/boot/i386/boot2/Makefile index 5f248b924c0..96946454fbf 100644 --- a/sys/boot/i386/boot2/Makefile +++ b/sys/boot/i386/boot2/Makefile @@ -25,7 +25,6 @@ BOOT2_UFS?= UFS1_AND_UFS2 CFLAGS= -fomit-frame-pointer \ -mrtd \ -mregparm=3 \ - -DUSE_XREAD \ -D${BOOT2_UFS} \ -DFLAGS=${BOOT_BOOT1_FLAGS} \ -DSIOPRT=${BOOT_COMCONSOLE_PORT} \ @@ -40,8 +39,6 @@ CFLAGS= -fomit-frame-pointer \ CFLAGS.gcc+= -Os \ -fno-asynchronous-unwind-tables \ - -fno-guess-branch-probability \ - -fno-unit-at-a-time \ --param max-inline-insns-single=100 .if ${COMPILER_TYPE} == "gcc" && ${COMPILER_VERSION} <= 40201 CFLAGS.gcc+= -mno-align-long-strings @@ -68,7 +65,7 @@ boot1.out: boot1.o ${LD} ${LD_FLAGS} -e start -Ttext ${ORG1} -o ${.TARGET} boot1.o CLEANFILES+= boot2 boot2.ld boot2.ldr boot2.bin boot2.out boot2.o \ - boot2.s boot2.s.tmp boot2.h sio.o + boot2.h sio.o BOOT2SIZE= 7680 @@ -90,16 +87,8 @@ boot2.bin: boot2.out boot2.out: ${BTXCRT} boot2.o sio.o ${LD} ${LD_FLAGS} -Ttext ${ORG2} -o ${.TARGET} ${.ALLSRC} -boot2.o: boot2.s - ${CC} ${ACFLAGS} -c boot2.s - SRCS= boot2.c boot2.h -boot2.s: boot2.c boot2.h ${.CURDIR}/../../common/ufsread.c - ${CC} ${CFLAGS} -S -o boot2.s.tmp ${.CURDIR}/boot2.c - sed -e '/align/d' -e '/nop/d' < boot2.s.tmp > boot2.s - rm -f boot2.s.tmp - boot2.h: boot1.out ${NM} -t d ${.ALLSRC} | awk '/([0-9])+ T xread/ \ { x = $$1 - ORG1; \ diff --git a/sys/boot/i386/boot2/boot2.c b/sys/boot/i386/boot2/boot2.c index 3d8c4074a14..cc5d76f86da 100644 --- a/sys/boot/i386/boot2/boot2.c +++ b/sys/boot/i386/boot2/boot2.c @@ -143,7 +143,7 @@ strcmp(const char *s1, const char *s2) #define UFS_SMALL_CGBASE #include "ufsread.c" -static inline int +static int xfsread(ufs_ino_t inode, void *buf, size_t nbyte) { if ((size_t)fsread(inode, buf, nbyte) != nbyte) { diff --git a/sys/boot/i386/btx/lib/btxv86.h b/sys/boot/i386/btx/lib/btxv86.h index 27f6b340424..f04ce5e3092 100644 --- a/sys/boot/i386/btx/lib/btxv86.h +++ b/sys/boot/i386/btx/lib/btxv86.h @@ -23,6 +23,14 @@ #include #include +/* + * Memory buffer space for real mode IO. + * Just one page is not much, but the space is rather limited. + * See ../btx/btx.S for details. + */ +#define V86_IO_BUFFER 0x8000 +#define V86_IO_BUFFER_SIZE 0x1000 + #define V86_ADDR 0x10000 /* Segment:offset address */ #define V86_CALLF 0x20000 /* Emulate far call */ #define V86_FLAGS 0x40000 /* Return flags */ diff --git a/sys/boot/i386/common/bootargs.h b/sys/boot/i386/common/bootargs.h index e6674e18303..df558072f37 100644 --- a/sys/boot/i386/common/bootargs.h +++ b/sys/boot/i386/common/bootargs.h @@ -64,10 +64,28 @@ struct bootargs */ }; +#ifdef LOADER_GELI_SUPPORT +#include +#endif + struct geli_boot_args { uint32_t size; - char gelipw[256]; + union { + char gelipw[256]; + struct { + char notapw; /* + * single null byte to stop keybuf + * being interpreted as a password + */ + uint32_t keybuf_sentinel; +#ifdef LOADER_GELI_SUPPORT + struct keybuf *keybuf; +#else + void *keybuf; +#endif + }; + }; }; #endif /*__ASSEMBLER__*/ diff --git a/sys/boot/i386/common/drv.c b/sys/boot/i386/common/drv.c index cc75d1ba6d5..a805c41f9c4 100644 --- a/sys/boot/i386/common/drv.c +++ b/sys/boot/i386/common/drv.c @@ -25,9 +25,6 @@ __FBSDID("$FreeBSD$"); #include "util.h" #include "drv.h" #include "edd.h" -#ifdef USE_XREAD -#include "xreadorg.h" -#endif static struct edd_params params; @@ -50,9 +47,7 @@ drvsize(struct dsk *dskp) return (params.sectors); } -#ifndef USE_XREAD static struct edd_packet packet; -#endif int drvread(struct dsk *dskp, void *buf, daddr_t lba, unsigned nblk) @@ -61,7 +56,6 @@ drvread(struct dsk *dskp, void *buf, daddr_t lba, unsigned nblk) 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); @@ -73,15 +67,6 @@ drvread(struct dsk *dskp, void *buf, daddr_t lba, unsigned nblk) 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", diff --git a/sys/boot/i386/gptboot/Makefile b/sys/boot/i386/gptboot/Makefile index dc447c2b924..b259f4b3bf8 100644 --- a/sys/boot/i386/gptboot/Makefile +++ b/sys/boot/i386/gptboot/Makefile @@ -42,6 +42,7 @@ CFLAGS.gcc+= --param max-inline-insns-single=100 .if !defined(LOADER_NO_GELI_SUPPORT) CFLAGS+= -DLOADER_GELI_SUPPORT CFLAGS+= -I${.CURDIR}/../../geli +CFLAGS+= -I${.CURDIR}/../../.. LIBGELIBOOT= ${.OBJDIR}/../../geli/libgeliboot.a .PATH: ${.CURDIR}/../../../opencrypto OPENCRYPTO_XTS= xform_aes_xts.o diff --git a/sys/boot/i386/gptboot/gptboot.c b/sys/boot/i386/gptboot/gptboot.c index 14438e6659c..dd06f0c5939 100644 --- a/sys/boot/i386/gptboot/gptboot.c +++ b/sys/boot/i386/gptboot/gptboot.c @@ -84,7 +84,9 @@ static struct dsk dsk; static char kname[1024]; static int comspeed = SIOSPD; static struct bootinfo bootinfo; +#ifdef LOADER_GELI_SUPPORT static struct geli_boot_args geliargs; +#endif static vm_offset_t high_heap_base; static uint32_t bios_basemem, bios_extmem, high_heap_size; @@ -101,7 +103,7 @@ static char *heap_end; void exit(int); static void load(void); -static int parse(char *, int *); +static int parse_cmds(char *, int *); static int dskread(void *, daddr_t, unsigned); void *malloc(size_t n); void free(void *ptr); @@ -137,6 +139,7 @@ free(void *ptr) #ifdef LOADER_GELI_SUPPORT #include "geliboot.c" static char gelipw[GELI_PW_MAXLEN]; +static struct keybuf *gelibuf; #endif static inline int @@ -251,7 +254,8 @@ gptinit(void) #ifdef LOADER_GELI_SUPPORT if (geli_taste(vdev_read, &dsk, (gpttable[curent].ent_lba_end - gpttable[curent].ent_lba_start)) == 0) { - if (geli_passphrase(&gelipw, dsk.unit, 'p', curent + 1, &dsk) != 0) { + if (geli_havekey(&dsk) != 0 && geli_passphrase(&gelipw, + dsk.unit, 'p', curent + 1, &dsk) != 0) { printf("%s: unable to decrypt GELI key\n", BOOTPROG); return (-1); } @@ -316,7 +320,7 @@ main(void) } if (*cmd != '\0') { memcpy(cmdtmp, cmd, sizeof(cmdtmp)); - if (parse(cmdtmp, &dskupdated)) + if (parse_cmds(cmdtmp, &dskupdated)) break; if (dskupdated && gptinit() != 0) break; @@ -366,7 +370,7 @@ main(void) getstr(cmd, sizeof(cmd)); else if (!OPT_CHECK(RBX_QUIET)) putchar('\n'); - if (parse(cmd, &dskupdated)) { + if (parse_cmds(cmd, &dskupdated)) { putchar('\a'); continue; } @@ -476,20 +480,26 @@ load(void) bootinfo.bi_esymtab = VTOP(p); bootinfo.bi_kernelname = VTOP(kname); bootinfo.bi_bios_dev = dsk.drive; - geliargs.size = sizeof(geliargs); #ifdef LOADER_GELI_SUPPORT - bcopy(gelipw, geliargs.gelipw, sizeof(geliargs.gelipw)); - bzero(gelipw, sizeof(gelipw)); -#else - geliargs.gelipw[0] = '\0'; + geliargs.size = sizeof(geliargs); + explicit_bzero(gelipw, sizeof(gelipw)); + gelibuf = malloc(sizeof(struct keybuf) + (GELI_MAX_KEYS * sizeof(struct keybuf_ent))); + geli_fill_keybuf(gelibuf); + geliargs.notapw = '\0'; + geliargs.keybuf_sentinel = KEYBUF_SENTINEL; + geliargs.keybuf = gelibuf; #endif __exec((caddr_t)addr, RB_BOOTINFO | (opts & RBX_MASK), MAKEBOOTDEV(dev_maj[dsk.type], dsk.part + 1, dsk.unit, 0xff), - KARGS_FLAGS_EXTARG, 0, 0, VTOP(&bootinfo), geliargs); + KARGS_FLAGS_EXTARG, 0, 0, VTOP(&bootinfo) +#ifdef LOADER_GELI_SUPPORT + , geliargs +#endif + ); } static int -parse(char *cmdstr, int *dskupdated) +parse_cmds(char *cmdstr, int *dskupdated) { char *arg = cmdstr; char *ep, *p, *q; diff --git a/sys/boot/i386/gptzfsboot/Makefile b/sys/boot/i386/gptzfsboot/Makefile index f46bf303793..dc2058d450b 100644 --- a/sys/boot/i386/gptzfsboot/Makefile +++ b/sys/boot/i386/gptzfsboot/Makefile @@ -33,11 +33,13 @@ CFLAGS= -DBOOTPROG=\"gptzfsboot\" \ -I${.CURDIR}/../btx/lib -I. \ -I${.CURDIR}/../boot2 \ -I${.CURDIR}/../../.. \ - -Wall -Waggregate-return -Wbad-function-cast -Wno-cast-align \ + -Wall -Waggregate-return -Wbad-function-cast \ -Wmissing-declarations -Wmissing-prototypes -Wnested-externs \ -Wpointer-arith -Wshadow -Wstrict-prototypes -Wwrite-strings \ -Winline -Wno-pointer-sign +NO_WCAST_ALIGN= + .if ${COMPILER_TYPE} == "clang" || \ (${COMPILER_TYPE} == "gcc" && ${COMPILER_VERSION} > 40201) CFLAGS+= -Wno-tentative-definition-incomplete-type diff --git a/sys/boot/i386/libi386/bioscd.c b/sys/boot/i386/libi386/bioscd.c index 1d445ac26cb..ba3be09c877 100644 --- a/sys/boot/i386/libi386/bioscd.c +++ b/sys/boot/i386/libi386/bioscd.c @@ -309,9 +309,6 @@ bc_realstrategy(void *devdata, int rw, daddr_t dblk, size_t size, return (0); } -/* Max number of sectors to bounce-buffer at a time. */ -#define CD_BOUNCEBUF 8 - /* return negative value for an error, otherwise blocks read */ static int bc_read(int unit, daddr_t dblk, int blks, caddr_t dest) @@ -339,8 +336,9 @@ bc_read(int unit, daddr_t dblk, int blks, caddr_t dest) * physical memory so we have to arrange a suitable * bounce buffer. */ - x = min(CD_BOUNCEBUF, (unsigned)blks); - bbuf = alloca(x * BIOSCD_SECSIZE); + x = V86_IO_BUFFER_SIZE / BIOSCD_SECSIZE; + x = min(x, (unsigned)blks); + bbuf = PTOV(V86_IO_BUFFER); maxfer = x; } else { bbuf = NULL; diff --git a/sys/boot/i386/libi386/biosdisk.c b/sys/boot/i386/libi386/biosdisk.c index 2081d06b040..188b8ebb9de 100644 --- a/sys/boot/i386/libi386/biosdisk.c +++ b/sys/boot/i386/libi386/biosdisk.c @@ -39,6 +39,7 @@ __FBSDID("$FreeBSD$"); */ #include +#include #include #include #include @@ -136,7 +137,6 @@ static int bd_open(struct open_file *f, ...); static int bd_close(struct open_file *f); static int bd_ioctl(struct open_file *f, u_long cmd, void *data); static int bd_print(int verbose); -static void bd_cleanup(void); #ifdef LOADER_GELI_SUPPORT static enum isgeli { @@ -159,7 +159,7 @@ struct devsw biosdisk = { bd_close, bd_ioctl, bd_print, - bd_cleanup + NULL }; /* @@ -230,13 +230,6 @@ bd_init(void) return(0); } -static void -bd_cleanup(void) -{ - - disk_cleanup(&biosdisk); -} - /* * Try to detect a device supported by the legacy int13 BIOS */ @@ -302,15 +295,28 @@ bd_int13probe(struct bdinfo *bd) if (!V86_CY(v86.efl)) { uint64_t total; - if (params.sectors != 0) - bd->bd_sectors = params.sectors; + /* + * Sector size must be a multiple of 512 bytes. + * An alternate test would be to check power of 2, + * powerof2(params.sector_size). + */ + if (params.sector_size % BIOSDISK_SECSIZE) + bd->bd_sectorsize = BIOSDISK_SECSIZE; + else + bd->bd_sectorsize = params.sector_size; + + total = bd->bd_sectorsize * params.sectors; + if (params.sectors != 0) { + /* Only update if we did not overflow. */ + if (total > params.sectors) + bd->bd_sectors = params.sectors; + } total = (uint64_t)params.cylinders * params.heads * params.sectors_per_track; if (bd->bd_sectors < total) bd->bd_sectors = total; - bd->bd_sectorsize = params.sector_size; ret = 1; } DEBUG("unit 0x%x flags %x, sectors %llu, sectorsize %u", @@ -350,9 +356,7 @@ bd_print(int verbose) dev.d_partition = -1; if (disk_open(&dev, bdinfo[i].bd_sectorsize * bdinfo[i].bd_sectors, - bdinfo[i].bd_sectorsize, - (bdinfo[i].bd_flags & BD_FLOPPY) ? - DISK_F_NOCACHE: 0) == 0) { + bdinfo[i].bd_sectorsize) == 0) { snprintf(line, sizeof(line), " disk%d", i); ret = disk_print(&dev, line, verbose); disk_close(&dev); @@ -377,8 +381,10 @@ static int bd_open(struct open_file *f, ...) { struct disk_devdesc *dev, rdev; + struct disk_devdesc disk; int err, g_err; va_list ap; + uint64_t size; va_start(ap, f); dev = va_arg(ap, struct disk_devdesc *); @@ -389,9 +395,34 @@ bd_open(struct open_file *f, ...) BD(dev).bd_open++; if (BD(dev).bd_bcache == NULL) BD(dev).bd_bcache = bcache_allocate(); + + /* + * Read disk size from partition. + * This is needed to work around buggy BIOS systems returning + * wrong (truncated) disk media size. + * During bd_probe() we tested if the mulitplication of bd_sectors + * would overflow so it should be safe to perform here. + */ + disk.d_dev = dev->d_dev; + disk.d_type = dev->d_type; + disk.d_unit = dev->d_unit; + disk.d_opendata = NULL; + disk.d_slice = -1; + disk.d_partition = -1; + disk.d_offset = 0; + if (disk_open(&disk, BD(dev).bd_sectors * BD(dev).bd_sectorsize, + BD(dev).bd_sectorsize) == 0) { + + if (disk_ioctl(&disk, DIOCGMEDIASIZE, &size) == 0) { + size /= BD(dev).bd_sectorsize; + if (size > BD(dev).bd_sectors) + BD(dev).bd_sectors = size; + } + disk_close(&disk); + } + err = disk_open(dev, BD(dev).bd_sectors * BD(dev).bd_sectorsize, - BD(dev).bd_sectorsize, (BD(dev).bd_flags & BD_FLOPPY) ? - DISK_F_NOCACHE: 0); + BD(dev).bd_sectorsize); #ifdef LOADER_GELI_SUPPORT static char gelipw[GELI_PW_MAXLEN]; @@ -441,6 +472,11 @@ bd_open(struct open_file *f, ...) } if (geli_taste(bios_read, &dskp, entry->part.end - entry->part.start) == 0) { + if (geli_havekey(&dskp) == 0) { + geli_status[dev->d_unit][dskp.slice] = ISGELI_YES; + geli_part++; + continue; + } if ((passphrase = getenv("kern.geom.eli.passphrase")) != NULL) { /* Use the cached passphrase */ @@ -453,6 +489,7 @@ bd_open(struct open_file *f, ...) bzero(gelipw, sizeof(gelipw)); geli_status[dev->d_unit][dskp.slice] = ISGELI_YES; geli_part++; + continue; } } else geli_status[dev->d_unit][dskp.slice] = ISGELI_NO; @@ -486,14 +523,20 @@ static int bd_ioctl(struct open_file *f, u_long cmd, void *data) { struct disk_devdesc *dev; + int rc; dev = (struct disk_devdesc *)f->f_devdata; + + rc = disk_ioctl(dev, cmd, data); + if (rc != ENOTTY) + return (rc); + switch (cmd) { case DIOCGSECTORSIZE: *(u_int *)data = BD(dev).bd_sectorsize; break; case DIOCGMEDIASIZE: - *(off_t *)data = BD(dev).bd_sectors * BD(dev).bd_sectorsize; + *(uint64_t *)data = BD(dev).bd_sectors * BD(dev).bd_sectorsize; break; default: return (ENOTTY); @@ -521,7 +564,8 @@ bd_realstrategy(void *devdata, int rw, daddr_t dblk, size_t size, char *buf, size_t *rsize) { struct disk_devdesc *dev = (struct disk_devdesc *)devdata; - int blks, remaining; + uint64_t disk_blocks; + int blks, rc; #ifdef BD_SUPPORT_FRAGS /* XXX: sector size */ char fragbuf[BIOSDISK_SECSIZE]; size_t fragsize; @@ -533,19 +577,43 @@ bd_realstrategy(void *devdata, int rw, daddr_t dblk, size_t size, #endif DEBUG("open_disk %p", dev); + + /* + * Check the value of the size argument. We do have quite small + * heap (64MB), but we do not know good upper limit, so we check against + * INT_MAX here. This will also protect us against possible overflows + * while translating block count to bytes. + */ + if (size > INT_MAX) { + DEBUG("too large read: %zu bytes", size); + return (EIO); + } + blks = size / BD(dev).bd_sectorsize; + if (dblk > dblk + blks) + return (EIO); + if (rsize) *rsize = 0; + /* Get disk blocks, this value is either for whole disk or for partition */ + if (disk_ioctl(dev, DIOCGMEDIASIZE, &disk_blocks)) { + /* DIOCGMEDIASIZE does return bytes. */ + disk_blocks /= BD(dev).bd_sectorsize; + } else { + /* We should not get here. Just try to survive. */ + disk_blocks = BD(dev).bd_sectors - dev->d_offset; + } + + /* Validate source block address. */ + if (dblk < dev->d_offset || dblk >= dev->d_offset + disk_blocks) + return (EIO); + /* - * Perform partial read to prevent read-ahead crossing - * the end of disk - or any 32 bit aliases of the end. - * Signed arithmetic is used to handle wrap-around cases - * like we do for TCP sequence numbers. + * Truncate if we are crossing disk or partition end. */ - remaining = (int)(BD(dev).bd_sectors - dblk); /* truncate */ - if (remaining > 0 && remaining < blks) { - blks = remaining; + if (dblk + blks >= dev->d_offset + disk_blocks) { + blks = dev->d_offset + disk_blocks - dblk; size = blks * BD(dev).bd_sectorsize; DEBUG("short read %d", blks); } @@ -554,8 +622,12 @@ bd_realstrategy(void *devdata, int rw, daddr_t dblk, size_t size, case F_READ: DEBUG("read %d from %lld to %p", blks, dblk, buf); - if (blks && bd_read(dev, dblk, blks, buf)) { - DEBUG("read error"); + if (blks && (rc = bd_read(dev, dblk, blks, buf))) { + /* Filter out floppy controller errors */ + if (BD(dev).bd_flags != BD_FLOPPY || rc != 0x20) { + printf("read %d from %lld to %p, error: 0x%x", blks, dblk, + buf, rc); + } return (EIO); } #ifdef BD_SUPPORT_FRAGS /* XXX: sector size */ @@ -592,9 +664,6 @@ bd_realstrategy(void *devdata, int rw, daddr_t dblk, size_t size, return (0); } -/* Max number of sectors to bounce-buffer if the request crosses a 64k boundary */ -#define FLOPPY_BOUNCEBUF 18 - static int bd_edd_io(struct disk_devdesc *dev, daddr_t dblk, int blks, caddr_t dest, int write) @@ -617,7 +686,9 @@ bd_edd_io(struct disk_devdesc *dev, daddr_t dblk, int blks, caddr_t dest, v86.ds = VTOPSEG(&packet); v86.esi = VTOPOFF(&packet); v86int(); - return (V86_CY(v86.efl)); + if (V86_CY(v86.efl)) + return (v86.eax >> 8); + return (0); } static int @@ -651,14 +722,16 @@ bd_chs_io(struct disk_devdesc *dev, daddr_t dblk, int blks, caddr_t dest, v86.es = VTOPSEG(dest); v86.ebx = VTOPOFF(dest); v86int(); - return (V86_CY(v86.efl)); + if (V86_CY(v86.efl)) + return (v86.eax >> 8); + return (0); } static int bd_io(struct disk_devdesc *dev, daddr_t dblk, int blks, caddr_t dest, int write) { u_int x, sec, result, resid, retry, maxfer; - caddr_t p, xp, bbuf, breg; + caddr_t p, xp, bbuf; /* Just in case some idiot actually tries to read/write -1 blocks... */ if (blks < 0) @@ -680,17 +753,12 @@ bd_io(struct disk_devdesc *dev, daddr_t dblk, int blks, caddr_t dest, int write) * as we need to. Use the bottom half unless there is a break * there, in which case we use the top half. */ - x = min(FLOPPY_BOUNCEBUF, (unsigned)blks); - bbuf = alloca(x * 2 * BD(dev).bd_sectorsize); - if (((u_int32_t)VTOP(bbuf) & 0xffff0000) == - ((u_int32_t)VTOP(bbuf + x * BD(dev).bd_sectorsize) & 0xffff0000)) { - breg = bbuf; - } else { - breg = bbuf + x * BD(dev).bd_sectorsize; - } + x = V86_IO_BUFFER_SIZE / BD(dev).bd_sectorsize; + x = min(x, (unsigned)blks); + bbuf = PTOV(V86_IO_BUFFER); maxfer = x; /* limit transfers to bounce region size */ } else { - breg = bbuf = NULL; + bbuf = NULL; maxfer = 0; } @@ -705,14 +773,14 @@ bd_io(struct disk_devdesc *dev, daddr_t dblk, int blks, caddr_t dest, int write) x = min(x, maxfer); /* fit bounce buffer */ /* where do we transfer to? */ - xp = bbuf == NULL ? p : breg; + xp = bbuf == NULL ? p : bbuf; /* * Put your Data In, Put your Data out, * Put your Data In, and shake it all about */ if (write && bbuf != NULL) - bcopy(p, breg, x * BD(dev).bd_sectorsize); + bcopy(p, bbuf, x * BD(dev).bd_sectorsize); /* * Loop retrying the operation a couple of times. The BIOS @@ -743,10 +811,10 @@ bd_io(struct disk_devdesc *dev, daddr_t dblk, int blks, caddr_t dest, int write) DEBUG("Read %d sector(s) from %lld to %p (0x%x) %s", x, dblk, p, VTOP(p), result ? "failed" : "ok"); if (result) { - return(-1); + return (result); } if (!write && bbuf != NULL) - bcopy(breg, p, x * BD(dev).bd_sectorsize); + bcopy(bbuf, p, x * BD(dev).bd_sectorsize); p += (x * BD(dev).bd_sectorsize); dblk += x; resid -= x; @@ -888,8 +956,7 @@ bd_getdev(struct i386_devdesc *d) if (biosdev == -1) /* not a BIOS device */ return(-1); if (disk_open(dev, BD(dev).bd_sectors * BD(dev).bd_sectorsize, - BD(dev).bd_sectorsize,(BD(dev).bd_flags & BD_FLOPPY) ? - DISK_F_NOCACHE: 0) != 0) /* oops, not a viable device */ + BD(dev).bd_sectorsize) != 0) /* oops, not a viable device */ return (-1); else disk_close(dev); diff --git a/sys/boot/i386/libi386/bootinfo32.c b/sys/boot/i386/libi386/bootinfo32.c index d4344278351..494688fd7cd 100644 --- a/sys/boot/i386/libi386/bootinfo32.c +++ b/sys/boot/i386/libi386/bootinfo32.c @@ -32,10 +32,18 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include "bootstrap.h" #include "libi386.h" #include "btxv86.h" +#ifdef LOADER_GELI_SUPPORT +#include "geliboot.h" + +static const size_t keybuf_size = sizeof(struct keybuf) + + (GELI_MAX_KEYS * sizeof(struct keybuf_ent)); +#endif + static struct bootinfo bi; /* @@ -146,11 +154,15 @@ bi_load32(char *args, int *howtop, int *bootdevp, vm_offset_t *bip, vm_offset_t int bootdevnr, i, howto; char *kernelname; const char *kernelpath; +#ifdef LOADER_GELI_SUPPORT + char buf[keybuf_size]; + struct keybuf *keybuf = (struct keybuf *)buf; +#endif howto = bi_getboothowto(args); - /* - * Allow the environment variable 'rootdev' to override the supplied device + /* + * Allow the environment variable 'rootdev' to override the supplied device * This should perhaps go to MI code and/or have $rootdev tested/set by * MI code before launching the kernel. */ @@ -185,7 +197,7 @@ bi_load32(char *args, int *howtop, int *bootdevp, vm_offset_t *bip, vm_offset_t case DEVT_NET: case DEVT_ZFS: break; - + default: printf("WARNING - don't know how to boot from device type %d\n", rootdev->d_type); } @@ -221,6 +233,11 @@ bi_load32(char *args, int *howtop, int *bootdevp, vm_offset_t *bip, vm_offset_t file_addmetadata(kfp, MODINFOMD_ENVP, sizeof envp, &envp); file_addmetadata(kfp, MODINFOMD_KERNEND, sizeof kernend, &kernend); bios_addsmapdata(kfp); +#ifdef LOADER_GELI_SUPPORT + geli_fill_keybuf(keybuf); + file_addmetadata(kfp, MODINFOMD_KEYBUF, keybuf_size, buf); + bzero(buf, sizeof(buf)); +#endif /* Figure out the size and location of the metadata */ *modulep = addr; diff --git a/sys/boot/i386/libi386/bootinfo64.c b/sys/boot/i386/libi386/bootinfo64.c index 751e806e1b8..02fcf723ba9 100644 --- a/sys/boot/i386/libi386/bootinfo64.c +++ b/sys/boot/i386/libi386/bootinfo64.c @@ -40,6 +40,13 @@ __FBSDID("$FreeBSD$"); #include "libi386.h" #include "btxv86.h" +#ifdef LOADER_GELI_SUPPORT +#include "geliboot.h" + +static const size_t keybuf_size = sizeof(struct keybuf) + + (GELI_MAX_KEYS * sizeof(struct keybuf_ent)); +#endif + /* * Copy module-related data into the load area, where it can be * used as a directory for loaded modules. @@ -189,6 +196,10 @@ bi_load64(char *args, vm_offset_t addr, vm_offset_t *modulep, vm_offset_t size; char *rootdevname; int howto; +#ifdef LOADER_GELI_SUPPORT + char buf[keybuf_size]; + struct keybuf *keybuf = (struct keybuf *)buf; +#endif if (!bi_checkcpu()) { printf("CPU doesn't support long mode\n"); @@ -197,8 +208,8 @@ bi_load64(char *args, vm_offset_t addr, vm_offset_t *modulep, howto = bi_getboothowto(args); - /* - * Allow the environment variable 'rootdev' to override the supplied device + /* + * Allow the environment variable 'rootdev' to override the supplied device * This should perhaps go to MI code and/or have $rootdev tested/set by * MI code before launching the kernel. */ @@ -238,6 +249,12 @@ bi_load64(char *args, vm_offset_t addr, vm_offset_t *modulep, if (add_smap != 0) bios_addsmapdata(kfp); +#ifdef LOADER_GELI_SUPPORT + geli_fill_keybuf(keybuf); + file_addmetadata(kfp, MODINFOMD_KEYBUF, keybuf_size, buf); + bzero(buf, sizeof(buf)); +#endif + size = bi_copymodules64(0); /* copy our environment */ diff --git a/sys/boot/i386/libi386/pxe.c b/sys/boot/i386/libi386/pxe.c index 4ccdd01ce8d..31c89c202ca 100644 --- a/sys/boot/i386/libi386/pxe.c +++ b/sys/boot/i386/libi386/pxe.c @@ -49,7 +49,7 @@ __FBSDID("$FreeBSD$"); /* * Allocate the PXE buffers statically instead of sticking grimy fingers into - * BTX's private data area. The scratch buffer is used to send information to + * BTX's private data area. The scratch buffer is used to send information to * the PXE BIOS, and the data buffer is used to receive data from the PXE BIOS. */ #define PXE_BUFFER_SIZE 0x2000 @@ -57,11 +57,11 @@ __FBSDID("$FreeBSD$"); static char scratch_buffer[PXE_BUFFER_SIZE]; static char data_buffer[PXE_BUFFER_SIZE]; -static pxenv_t *pxenv_p = NULL; /* PXENV+ */ -static pxe_t *pxe_p = NULL; /* !PXE */ -static BOOTPLAYER bootplayer; /* PXE Cached information. */ +static pxenv_t *pxenv_p = NULL; /* PXENV+ */ +static pxe_t *pxe_p = NULL; /* !PXE */ +static BOOTPLAYER bootplayer; /* PXE Cached information. */ -static int pxe_debug = 0; +static int pxe_debug = 0; static int pxe_sock = -1; static int pxe_opens = 0; @@ -72,7 +72,7 @@ static void bangpxe_call(int func); static int pxe_init(void); static int pxe_strategy(void *devdata, int flag, daddr_t dblk, - size_t size, char *buf, size_t *rsize); + size_t size, char *buf, size_t *rsize); static int pxe_open(struct open_file *f, ...); static int pxe_close(struct open_file *f); static int pxe_print(int verbose); @@ -84,15 +84,11 @@ static int pxe_netif_match(struct netif *nif, void *machdep_hint); static int pxe_netif_probe(struct netif *nif, void *machdep_hint); static void pxe_netif_init(struct iodesc *desc, void *machdep_hint); static int pxe_netif_get(struct iodesc *desc, void *pkt, size_t len, - time_t timeout); + time_t timeout); static int pxe_netif_put(struct iodesc *desc, void *pkt, size_t len); static void pxe_netif_end(struct netif *nif); -#ifdef OLD_NFSV2 -int nfs_getrootfh(struct iodesc*, char*, u_char*); -#else int nfs_getrootfh(struct iodesc*, char*, uint32_t*, u_char*); -#endif extern struct netif_stats pxe_st[]; extern u_int16_t __bangpxeseg; @@ -101,9 +97,10 @@ extern void __bangpxeentry(void); extern u_int16_t __pxenvseg; extern u_int16_t __pxenvoff; extern void __pxenventry(void); +extern struct in_addr servip; struct netif_dif pxe_ifs[] = { -/* dif_unit dif_nsel dif_stats dif_private */ +/* dif_unit dif_nsel dif_stats dif_private */ {0, 1, &pxe_st[0], 0} }; @@ -127,12 +124,12 @@ struct netif_driver *netif_drivers[] = { }; struct devsw pxedisk = { - "pxe", + "pxe", DEVT_NET, pxe_init, - pxe_strategy, - pxe_open, - pxe_close, + pxe_strategy, + pxe_open, + pxe_close, noioctl, pxe_print, pxe_cleanup @@ -140,8 +137,8 @@ struct devsw pxedisk = { /* * This function is called by the loader to enable PXE support if we - * are booted by PXE. The passed in pointer is a pointer to the - * PXENV+ structure. + * are booted by PXE. The passed in pointer is a pointer to the PXENV+ + * structure. */ void pxe_enable(void *pxeinfo) @@ -152,22 +149,22 @@ pxe_enable(void *pxeinfo) pxe_call = NULL; } -/* +/* * return true if pxe structures are found/initialized, - * also figures out our IP information via the pxe cached info struct + * also figures out our IP information via the pxe cached info struct */ static int pxe_init(void) { - t_PXENV_GET_CACHED_INFO *gci_p; - int counter; + t_PXENV_GET_CACHED_INFO *gci_p; + int counter; uint8_t checksum; uint8_t *checkptr; - - if(pxenv_p == NULL) + + if (pxenv_p == NULL) return (0); - /* look for "PXENV+" */ + /* look for "PXENV+" */ if (bcmp((void *)pxenv_p->Signature, S_SIZE("PXENV+"))) { pxenv_p = NULL; return (0); @@ -175,16 +172,16 @@ pxe_init(void) /* make sure the size is something we can handle */ if (pxenv_p->Length > sizeof(*pxenv_p)) { - printf("PXENV+ structure too large, ignoring\n"); + printf("PXENV+ structure too large, ignoring\n"); pxenv_p = NULL; return (0); } - - /* + + /* * do byte checksum: * add up each byte in the structure, the total should be 0 */ - checksum = 0; + checksum = 0; checkptr = (uint8_t *) pxenv_p; for (counter = 0; counter < pxenv_p->Length; counter++) checksum += *checkptr++; @@ -194,7 +191,6 @@ pxe_init(void) return (0); } - /* * PXENV+ passed, so use that if !PXE is not available or * the checksum fails. @@ -209,7 +205,7 @@ pxe_init(void) checksum = 0; checkptr = (uint8_t *)pxe_p; for (counter = 0; counter < pxe_p->StructLength; - counter++) + counter++) checksum += *checkptr++; if (checksum != 0) { pxe_p = NULL; @@ -221,19 +217,19 @@ pxe_init(void) } printf("\nPXE version %d.%d, real mode entry point ", - (uint8_t) (pxenv_p->Version >> 8), - (uint8_t) (pxenv_p->Version & 0xFF)); + (uint8_t) (pxenv_p->Version >> 8), + (uint8_t) (pxenv_p->Version & 0xFF)); if (pxe_call == bangpxe_call) printf("@%04x:%04x\n", - pxe_p->EntryPointSP.segment, - pxe_p->EntryPointSP.offset); + pxe_p->EntryPointSP.segment, + pxe_p->EntryPointSP.offset); else printf("@%04x:%04x\n", - pxenv_p->RMEntry.segment, pxenv_p->RMEntry.offset); + pxenv_p->RMEntry.segment, pxenv_p->RMEntry.offset); gci_p = (t_PXENV_GET_CACHED_INFO *) scratch_buffer; bzero(gci_p, sizeof(*gci_p)); - gci_p->PacketType = PXENV_PACKET_TYPE_BINL_REPLY; + gci_p->PacketType = PXENV_PACKET_TYPE_BINL_REPLY; pxe_call(PXENV_GET_CACHED_INFO); if (gci_p->Status != 0) { pxe_perror(gci_p->Status); @@ -241,7 +237,7 @@ pxe_init(void) return (0); } bcopy(PTOV((gci_p->Buffer.segment << 4) + gci_p->Buffer.offset), - &bootplayer, gci_p->BufferSize); + &bootplayer, gci_p->BufferSize); return (1); } @@ -256,94 +252,121 @@ pxe_strategy(void *devdata, int flag, daddr_t dblk, size_t size, static int pxe_open(struct open_file *f, ...) { - va_list args; - char *devname; /* Device part of file name (or NULL). */ - char temp[FNAME_SIZE]; - int error = 0; - int i; - - va_start(args, f); - devname = va_arg(args, char*); - va_end(args); - - /* On first open, do netif open, mount, etc. */ - if (pxe_opens == 0) { - /* Find network interface. */ - if (pxe_sock < 0) { - pxe_sock = netif_open(devname); - if (pxe_sock < 0) { - printf("pxe_open: netif_open() failed\n"); - return (ENXIO); - } - if (pxe_debug) - printf("pxe_open: netif_open() succeeded\n"); - } - if (rootip.s_addr == 0) { - /* - * Do a bootp/dhcp request to find out where our - * NFS/TFTP server is. Even if we dont get back - * the proper information, fall back to the server - * which brought us to life and a default rootpath. - */ - bootp(pxe_sock, BOOTP_PXE); - if (rootip.s_addr == 0) - rootip.s_addr = bootplayer.sip; - - netproto = NET_NFS; - if (tftpip.s_addr != 0) { - netproto = NET_TFTP; - rootip.s_addr = tftpip.s_addr; - } + va_list args; + char *devname; /* Device part of file name (or NULL). */ + char temp[FNAME_SIZE]; + int error = 0; + int i; - if (netproto == NET_NFS && !rootpath[0]) - strcpy(rootpath, PXENFSROOTPATH); + va_start(args, f); + devname = va_arg(args, char*); + va_end(args); + + /* On first open, do netif open, mount, etc. */ + if (pxe_opens == 0) { + /* Find network interface. */ + if (pxe_sock < 0) { + pxe_sock = netif_open(devname); + if (pxe_sock < 0) { + printf("pxe_open: netif_open() failed\n"); + return (ENXIO); + } + if (pxe_debug) + printf("pxe_open: netif_open() succeeded\n"); + + if (socktodesc(pxe_sock) == NULL) { + printf("pxe_open: bad socket %d\n", pxe_sock); + return (ENXIO); + } - for (i = 0; rootpath[i] != '\0' && i < FNAME_SIZE; i++) - if (rootpath[i] == ':') - break; - if (i && i != FNAME_SIZE && rootpath[i] == ':') { - rootpath[i++] = '\0'; - if (inet_addr(&rootpath[0]) != INADDR_NONE) - rootip.s_addr = inet_addr(&rootpath[0]); - bcopy(&rootpath[i], &temp[0], strlen(&rootpath[i])+1); - bcopy(&temp[0], &rootpath[0], strlen(&rootpath[i])+1); - } - setenv("boot.netif.ip", inet_ntoa(myip), 1); - setenv("boot.netif.netmask", intoa(netmask), 1); - setenv("boot.netif.gateway", inet_ntoa(gateip), 1); - setenv("boot.netif.server", inet_ntoa(rootip), 1); - if (bootplayer.Hardware == ETHER_TYPE) { - sprintf(temp, "%6D", bootplayer.CAddr, ":"); - setenv("boot.netif.hwaddr", temp, 1); - } - if (intf_mtu != 0) { - char mtu[16]; - sprintf(mtu, "%u", intf_mtu); - setenv("boot.netif.mtu", mtu, 1); - } - printf("pxe_open: server addr: %s\n", inet_ntoa(rootip)); - printf("pxe_open: server path: %s\n", rootpath); - printf("pxe_open: gateway ip: %s\n", inet_ntoa(gateip)); - - if (netproto == NET_TFTP) { - setenv("boot.tftproot.server", inet_ntoa(rootip), 1); - setenv("boot.tftproot.path", rootpath, 1); - } else if (netproto == NET_NFS) { - setenv("boot.nfsroot.server", inet_ntoa(rootip), 1); - setenv("boot.nfsroot.path", rootpath, 1); } - setenv("dhcp.host-name", hostname, 1); + if (rootip.s_addr == 0) { + /* + * Try to extract the RFC1048 data from PXE. + * If fail do a bootp/dhcp request to find out where our + * NFS/TFTP server is. Even if we dont get back + * the proper information, fall back to the server + * which brought us to life and a default rootpath. + */ + + if (dhcp_try_rfc1048(bootplayer.vendor.d, BOOTP_DHCPVEND) < 0) { + if (pxe_debug) + printf("pxe_open: no RFC1048 data in PXE Cache\n"); + bootp(pxe_sock, BOOTP_PXE); + } else if (pxe_debug) { + printf("pxe_open: loaded RFC1048 data from PXE Cache\n"); + } + +#ifdef LOADER_TFTP_SUPPORT + bootp(pxe_sock, BOOTP_PXE); +#endif + if (rootip.s_addr == 0) + rootip.s_addr = bootplayer.sip; + if (gateip.s_addr == 0) + gateip.s_addr = bootplayer.gip; + if (myip.s_addr == 0) + myip.s_addr = bootplayer.yip; + if (servip.s_addr == 0) + servip = rootip; + + netproto = NET_NFS; + if (tftpip.s_addr != 0) { + netproto = NET_TFTP; + rootip.s_addr = tftpip.s_addr; + } + + if (netproto == NET_NFS && !rootpath[0]) + strcpy(rootpath, PXENFSROOTPATH); + + for (i = 0; rootpath[i] != '\0' && i < FNAME_SIZE; i++) + if (rootpath[i] == ':') + break; + if (i && i != FNAME_SIZE && rootpath[i] == ':') { + rootpath[i++] = '\0'; + if (inet_addr(&rootpath[0]) != INADDR_NONE) + rootip.s_addr = inet_addr(&rootpath[0]); + bcopy(&rootpath[i], &temp[0], strlen(&rootpath[i]) + 1); + bcopy(&temp[0], &rootpath[0], strlen(&rootpath[i]) + 1); + } + setenv("boot.netif.ip", inet_ntoa(myip), 1); + setenv("boot.netif.netmask", intoa(netmask), 1); + setenv("boot.netif.gateway", inet_ntoa(gateip), 1); + setenv("boot.netif.server", inet_ntoa(rootip), 1); + if (bootplayer.Hardware == ETHER_TYPE) { + sprintf(temp, "%6D", bootplayer.CAddr, ":"); + setenv("boot.netif.hwaddr", temp, 1); + } + if (intf_mtu != 0) { + char mtu[16]; + snprintf(sizeof(mtu), mtu, "%u", intf_mtu); + setenv("boot.netif.mtu", mtu, 1); + } + printf("pxe_open: server addr: %s\n", inet_ntoa(rootip)); + printf("pxe_open: server path: %s\n", rootpath); + printf("pxe_open: gateway ip: %s\n", inet_ntoa(gateip)); + printf("pxe_open: my ip: %s\n", inet_ntoa(myip)); + printf("pxe_open: netmask: %s\n", intoa(netmask)); + printf("pxe_open: servip: %s\n", inet_ntoa(servip)); + + if (netproto == NET_TFTP) { + setenv("boot.tftproot.server", inet_ntoa(rootip), 1); + setenv("boot.tftproot.path", rootpath, 1); + } else if (netproto == NET_NFS) { + setenv("boot.nfsroot.server", inet_ntoa(rootip), 1); + setenv("boot.nfsroot.path", rootpath, 1); + } + setenv("dhcp.host-name", hostname, 1); - setenv("pxeboot.ip", inet_ntoa(myip), 1); - if (bootplayer.Hardware == ETHER_TYPE) { - sprintf(temp, "%6D", bootplayer.CAddr, ":"); - setenv("pxeboot.hwaddr", temp, 1); + setenv("pxeboot.ip", inet_ntoa(myip), 1); + if (bootplayer.Hardware == ETHER_TYPE) { + sprintf(temp, "%6D", bootplayer.CAddr, ":"); + setenv("pxeboot.hwaddr", temp, 1); + } } } - } - pxe_opens++; - f->f_devdata = &pxe_sock; - return (error); + pxe_opens++; + f->f_devdata = &pxe_sock; + return (error); } static int @@ -351,35 +374,35 @@ pxe_close(struct open_file *f) { #ifdef PXE_DEBUG - if (pxe_debug) - printf("pxe_close: opens=%d\n", pxe_opens); + if (pxe_debug) + printf("pxe_close: opens=%d\n", pxe_opens); #endif - /* On last close, do netif close, etc. */ - f->f_devdata = NULL; - /* Extra close call? */ - if (pxe_opens <= 0) - return (0); - pxe_opens--; - /* Not last close? */ - if (pxe_opens > 0) - return(0); + /* On last close, do netif close, etc. */ + f->f_devdata = NULL; + /* Extra close call? */ + if (pxe_opens <= 0) + return (0); + pxe_opens--; + /* Not last close? */ + if (pxe_opens > 0) + return (0); - if (netproto == NET_NFS) { - /* get an NFS filehandle for our root filesystem */ - pxe_setnfshandle(rootpath); - } + if (netproto == NET_NFS) { + /* get an NFS filehandle for our root filesystem */ + pxe_setnfshandle(rootpath); + } - if (pxe_sock >= 0) { + if (pxe_sock >= 0) { #ifdef PXE_DEBUG if (pxe_debug) - printf("pxe_close: calling netif_close()\n"); + printf("pxe_close: calling netif_close()\n"); #endif netif_close(pxe_sock); pxe_sock = -1; - } - return (0); + } + return (0); } static int @@ -406,9 +429,9 @@ pxe_cleanup(void) { #ifdef PXE_DEBUG t_PXENV_UNLOAD_STACK *unload_stack_p = - (t_PXENV_UNLOAD_STACK *)scratch_buffer; + (t_PXENV_UNLOAD_STACK *)scratch_buffer; t_PXENV_UNDI_SHUTDOWN *undi_shutdown_p = - (t_PXENV_UNDI_SHUTDOWN *)scratch_buffer; + (t_PXENV_UNDI_SHUTDOWN *)scratch_buffer; #endif if (pxe_call == NULL) @@ -419,12 +442,12 @@ pxe_cleanup(void) #ifdef PXE_DEBUG if (pxe_debug && undi_shutdown_p->Status != 0) printf("pxe_cleanup: UNDI_SHUTDOWN failed %x\n", - undi_shutdown_p->Status); + undi_shutdown_p->Status); #endif pxe_call(PXENV_UNLOAD_STACK); -#ifdef PXE_DEBUG +#ifdef PXE_DEBUG if (pxe_debug && unload_stack_p->Status != 0) printf("pxe_cleanup: UNLOAD_STACK failed %x\n", unload_stack_p->Status); @@ -441,56 +464,6 @@ pxe_perror(int err) * Reach inside the libstand NFS code and dig out an NFS handle * for the root filesystem. */ -#ifdef OLD_NFSV2 -struct nfs_iodesc { - struct iodesc *iodesc; - off_t off; - u_char fh[NFS_FHSIZE]; - /* structure truncated here */ -}; -extern struct nfs_iodesc nfs_root_node; -extern int rpc_port; - -static void -pxe_rpcmountcall() -{ - struct iodesc *d; - int error; - - if (!(d = socktodesc(pxe_sock))) - return; - d->myport = htons(--rpc_port); - d->destip = rootip; - if ((error = nfs_getrootfh(d, rootpath, nfs_root_node.fh)) != 0) - printf("NFS MOUNT RPC error: %d\n", error); - nfs_root_node.iodesc = d; -} - -static void -pxe_setnfshandle(char *rootpath) -{ - int i; - u_char *fh; - char buf[2 * NFS_FHSIZE + 3], *cp; - - /* - * If NFS files were never opened, we need to do mount call - * ourselves. Use nfs_root_node.iodesc as flag indicating - * previous NFS usage. - */ - if (nfs_root_node.iodesc == NULL) - pxe_rpcmountcall(); - - fh = &nfs_root_node.fh[0]; - buf[0] = 'X'; - cp = &buf[1]; - for (i = 0; i < NFS_FHSIZE; i++, cp += 2) - sprintf(cp, "%02x", fh[i]); - sprintf(cp, "X"); - setenv("boot.nfsroot.nfshandle", buf, 1); -} -#else /* !OLD_NFSV2 */ - #define NFS_V3MAXFHSIZE 64 struct nfs_iodesc { @@ -511,10 +484,10 @@ pxe_rpcmountcall() if (!(d = socktodesc(pxe_sock))) return; - d->myport = htons(--rpc_port); - d->destip = rootip; + d->myport = htons(--rpc_port); + d->destip = rootip; if ((error = nfs_getrootfh(d, rootpath, &nfs_root_node.fhsize, - nfs_root_node.fh)) != 0) { + nfs_root_node.fh)) != 0) { printf("NFS MOUNT RPC error: %d\n", error); nfs_root_node.fhsize = 0; } @@ -546,7 +519,6 @@ pxe_setnfshandle(char *rootpath) sprintf(buf, "%d", nfs_root_node.fhsize); setenv("boot.nfsroot.nfshandlelen", buf, 1); } -#endif /* OLD_NFSV2 */ void pxenv_call(int func) @@ -578,13 +550,13 @@ bangpxe_call(int func) if (pxe_debug) printf("bangpxe_call %x\n", func); #endif - + bzero(&v86, sizeof(v86)); bzero(data_buffer, sizeof(data_buffer)); __bangpxeseg = pxe_p->EntryPointSP.segment; __bangpxeoff = pxe_p->EntryPointSP.offset; - + v86.ctl = V86_ADDR | V86_CALLF | V86_FLAGS; v86.edx = VTOPSEG(scratch_buffer); v86.eax = VTOPOFF(scratch_buffer); @@ -595,21 +567,12 @@ bangpxe_call(int func) } -time_t -getsecs(void) -{ - time_t n = 0; - time(&n); - return n; -} - static int pxe_netif_match(struct netif *nif, void *machdep_hint) { return 1; } - static int pxe_netif_probe(struct netif *nif, void *machdep_hint) { @@ -666,7 +629,7 @@ sendudp(struct iodesc *h, void *pkt, size_t len) { t_PXENV_UDP_WRITE *udpwrite_p = (t_PXENV_UDP_WRITE *)scratch_buffer; bzero(udpwrite_p, sizeof(*udpwrite_p)); - + udpwrite_p->ip = h->destip.s_addr; udpwrite_p->dst_port = h->destport; udpwrite_p->src_port = h->myport; @@ -686,7 +649,7 @@ sendudp(struct iodesc *h, void *pkt, size_t len) delay(1000); #endif if (udpwrite_p->status != 0) { - /* XXX: This happens a lot. It shouldn't. */ + /* XXX: This happens a lot. It shouldn't. */ if (udpwrite_p->status != 1) printf("sendudp failed %x\n", udpwrite_p->status); return -1; @@ -699,10 +662,10 @@ readudp(struct iodesc *h, void *pkt, size_t len, time_t timeout) { t_PXENV_UDP_READ *udpread_p = (t_PXENV_UDP_READ *)scratch_buffer; struct udphdr *uh = NULL; - + uh = (struct udphdr *) pkt - 1; bzero(udpread_p, sizeof(*udpread_p)); - + udpread_p->dest_ip = h->myip.s_addr; udpread_p->d_port = h->myport; udpread_p->buffer_size = len; @@ -716,7 +679,7 @@ readudp(struct iodesc *h, void *pkt, size_t len, time_t timeout) delay(1000); #endif if (udpread_p->status != 0) { - /* XXX: This happens a lot. It shouldn't. */ + /* XXX: This happens a lot. It shouldn't. */ if (udpread_p->status != 1) printf("readudp failed %x\n", udpread_p->status); return -1; diff --git a/sys/boot/i386/libi386/pxe.h b/sys/boot/i386/libi386/pxe.h index 97295620752..62b6aa79cca 100644 --- a/sys/boot/i386/libi386/pxe.h +++ b/sys/boot/i386/libi386/pxe.h @@ -175,8 +175,8 @@ typedef struct { uint16_t PktFilter; # define FLTR_DIRECTED 0x0001 # define FLTR_BRDCST 0x0002 -# define FLTR_PRMSCS 0x0003 -# define FLTR_SRC_RTG 0x0004 +# define FLTR_PRMSCS 0x0004 +# define FLTR_SRC_RTG 0x0008 t_PXENV_UNDI_MCAST_ADDRESS R_Mcast_Buf; } PACKED t_PXENV_UNDI_OPEN; diff --git a/sys/boot/i386/libi386/time.c b/sys/boot/i386/libi386/time.c index c27dcf6b5db..7636ace5ff9 100644 --- a/sys/boot/i386/libi386/time.c +++ b/sys/boot/i386/libi386/time.c @@ -32,6 +32,7 @@ __FBSDID("$FreeBSD$"); #include "bootstrap.h" #include "libi386.h" +time_t getsecs(void); static int bios_seconds(void); /* @@ -91,6 +92,14 @@ time(time_t *t) return(now); } +time_t +getsecs(void) +{ + time_t n = 0; + time(&n); + return n; +} + /* * Use the BIOS Wait function to pause for (period) microseconds. * diff --git a/sys/boot/i386/loader/Makefile b/sys/boot/i386/loader/Makefile index 2f2e9c10f14..31bf9834ddb 100644 --- a/sys/boot/i386/loader/Makefile +++ b/sys/boot/i386/loader/Makefile @@ -61,6 +61,7 @@ CFLAGS+= -DLOADER_NANDFS_SUPPORT .endif .if !defined(LOADER_NO_GELI_SUPPORT) CFLAGS+= -DLOADER_GELI_SUPPORT +CFLAGS+= -I${.CURDIR}/../../geli LIBGELIBOOT= ${.OBJDIR}/../../geli/libgeliboot.a .PATH: ${.CURDIR}/../../../opencrypto SRCS+= xform_aes_xts.c diff --git a/sys/boot/i386/loader/main.c b/sys/boot/i386/loader/main.c index 9b034ab96b8..919165f5f3e 100644 --- a/sys/boot/i386/loader/main.c +++ b/sys/boot/i386/loader/main.c @@ -39,6 +39,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include "bootstrap.h" #include "common/bootargs.h" @@ -69,6 +70,7 @@ static int isa_inb(int port); static void isa_outb(int port, int value); void exit(int code); #ifdef LOADER_GELI_SUPPORT +#include "geliboot.h" struct geli_boot_args *gargs; #endif #ifdef LOADER_ZFS_SUPPORT @@ -173,9 +175,13 @@ main(void) if ((kargs->bootflags & KARGS_FLAGS_EXTARG) != 0) { zargs = (struct zfs_boot_args *)(kargs + 1); if (zargs != NULL && zargs->size >= offsetof(struct zfs_boot_args, gelipw)) { + if (zargs->size >= offsetof(struct zfs_boot_args, keybuf_sentinel) && + zargs->keybuf_sentinel == KEYBUF_SENTINEL) { + geli_save_keybuf(zargs->keybuf); + } if (zargs->gelipw[0] != '\0') { setenv("kern.geom.eli.passphrase", zargs->gelipw, 1); - bzero(zargs->gelipw, sizeof(zargs->gelipw)); + explicit_bzero(zargs->gelipw, sizeof(zargs->gelipw)); } } } @@ -185,9 +191,12 @@ main(void) if ((kargs->bootflags & KARGS_FLAGS_EXTARG) != 0) { gargs = (struct geli_boot_args *)(kargs + 1); if (gargs != NULL && gargs->size >= offsetof(struct geli_boot_args, gelipw)) { + if (gargs->keybuf_sentinel == KEYBUF_SENTINEL) { + geli_save_keybuf(gargs->keybuf); + } if (gargs->gelipw[0] != '\0') { setenv("kern.geom.eli.passphrase", gargs->gelipw, 1); - bzero(gargs->gelipw, sizeof(gargs->gelipw)); + explicit_bzero(gargs->gelipw, sizeof(gargs->gelipw)); } } } diff --git a/sys/boot/i386/zfsboot/zfsboot.c b/sys/boot/i386/zfsboot/zfsboot.c index bb64384fadc..fe73f97ef4e 100644 --- a/sys/boot/i386/zfsboot/zfsboot.c +++ b/sys/boot/i386/zfsboot/zfsboot.c @@ -121,7 +121,7 @@ static struct dmadat *dmadat; void exit(int); void reboot(void); static void load(void); -static int parse(void); +static int parse_cmd(void); static void bios_getmem(void); void *malloc(size_t n); void free(void *ptr); @@ -159,6 +159,7 @@ strdup(const char *s) #ifdef LOADER_GELI_SUPPORT #include "geliboot.c" static char gelipw[GELI_PW_MAXLEN]; +static struct keybuf *gelibuf; #endif #include "zfsimpl.c" @@ -502,7 +503,8 @@ probe_drive(struct dsk *dsk) elba--; } if (geli_taste(vdev_read, dsk, elba) == 0) { - if (geli_passphrase(&gelipw, dsk->unit, ':', 0, dsk) == 0) { + if (geli_havekey(dsk) == 0 || geli_passphrase(&gelipw, dsk->unit, + ':', 0, dsk) == 0) { if (vdev_probe(vdev_read, dsk, NULL) == 0) { return; } @@ -559,7 +561,8 @@ probe_drive(struct dsk *dsk) #ifdef LOADER_GELI_SUPPORT else if (geli_taste(vdev_read, dsk, ent->ent_lba_end - ent->ent_lba_start) == 0) { - if (geli_passphrase(&gelipw, dsk->unit, 'p', dsk->slice, dsk) == 0) { + if (geli_havekey(dsk) == 0 || geli_passphrase(&gelipw, + dsk->unit, 'p', dsk->slice, dsk) == 0) { /* * This slice has GELI, check it for ZFS. */ @@ -597,7 +600,8 @@ probe_drive(struct dsk *dsk) #ifdef LOADER_GELI_SUPPORT else if (geli_taste(vdev_read, dsk, dp[i].dp_size - dp[i].dp_start) == 0) { - if (geli_passphrase(&gelipw, dsk->unit, 's', i, dsk) == 0) { + if (geli_havekey(dsk) == 0 || geli_passphrase(&gelipw, dsk->unit, + 's', i, dsk) == 0) { /* * This slice has GELI, check it for ZFS. */ @@ -729,7 +733,7 @@ main(void) */ nextboot = 1; memcpy(cmddup, cmd, sizeof(cmd)); - if (parse()) { + if (parse_cmd()) { printf("failed to parse pad2 area of primary vdev\n"); reboot(); } @@ -756,11 +760,11 @@ main(void) if (*cmd) { /* - * Note that parse() is destructive to cmd[] and we also want + * Note that parse_cmd() is destructive to cmd[] and we also want * to honor RBX_QUIET option that could be present in cmd[]. */ memcpy(cmddup, cmd, sizeof(cmd)); - if (parse()) + if (parse_cmd()) autoboot = 0; if (!OPT_CHECK(RBX_QUIET)) printf("%s: %s\n", PATH_CONFIG, cmddup); @@ -810,7 +814,7 @@ main(void) else if (!autoboot || !OPT_CHECK(RBX_QUIET)) putchar('\n'); autoboot = 0; - if (parse()) + if (parse_cmd()) putchar('\a'); else load(); @@ -925,8 +929,12 @@ load(void) zfsargs.root = zfsmount.rootobj; zfsargs.primary_pool = primary_spa->spa_guid; #ifdef LOADER_GELI_SUPPORT - bcopy(gelipw, zfsargs.gelipw, sizeof(zfsargs.gelipw)); - bzero(gelipw, sizeof(gelipw)); + explicit_bzero(gelipw, sizeof(gelipw)); + gelibuf = malloc(sizeof(struct keybuf) + (GELI_MAX_KEYS * sizeof(struct keybuf_ent))); + geli_fill_keybuf(gelibuf); + zfsargs.notapw = '\0'; + zfsargs.keybuf_sentinel = KEYBUF_SENTINEL; + zfsargs.keybuf = gelibuf; #else zfsargs.gelipw[0] = '\0'; #endif @@ -979,7 +987,7 @@ zfs_mount_ds(char *dsname) } static int -parse(void) +parse_cmd(void) { char *arg = cmd; char *ep, *p, *q; diff --git a/sys/boot/mips/beri/boot2/Makefile b/sys/boot/mips/beri/boot2/Makefile index f9950a96b87..be2dc0a6bb5 100644 --- a/sys/boot/mips/beri/boot2/Makefile +++ b/sys/boot/mips/beri/boot2/Makefile @@ -52,7 +52,7 @@ CFLAGS= -ffreestanding \ -I${.CURDIR}/../../../.. \ -D_KERNEL \ -Wall \ - -G0 -Xassembler -G0 \ + -G0 \ -fno-pic -mno-abicalls \ -msoft-float \ -g @@ -71,7 +71,7 @@ LDFLAGS= -nostdlib \ CFLAGS+= -I${.CURDIR}/../common flashboot.elf: relocate.o start.o boot2.o altera_jtag_uart.o cfi.o sdcard.o - ${LD} ${_LDFLAGS} -T ${.CURDIR}/flashboot.ldscript -o ${.TARGET} \ + ${CC} ${LDFLAGS} -T ${.CURDIR}/flashboot.ldscript -o ${.TARGET} \ ${.ALLSRC} ${LIBSTAND} flashboot: flashboot.elf ${OBJCOPY} -S -O binary ${.TARGET}.elf ${.TARGET} @@ -79,7 +79,7 @@ flashboot.md5: flashboot md5 flashboot > flashboot.md5 jtagboot: start.o boot2.o altera_jtag_uart.o cfi.o sdcard.o - ${LD} ${_LDFLAGS} -T ${.CURDIR}/jtagboot.ldscript -o ${.TARGET} \ + ${CC} ${LDFLAGS} -T ${.CURDIR}/jtagboot.ldscript -o ${.TARGET} \ ${.ALLSRC} ${LIBSTAND} jtagboot.md5: jtagboot md5 jtagboot > jtagboot.md5 diff --git a/sys/boot/mips/beri/common/common.ldscript b/sys/boot/mips/beri/common/common.ldscript index ac3b0760129..6266646cfc3 100644 --- a/sys/boot/mips/beri/common/common.ldscript +++ b/sys/boot/mips/beri/common/common.ldscript @@ -73,5 +73,4 @@ __cheri_sdcard_vaddr__ = __mips64_xkphys_uncached__ + __cheri_sdcard_base__; __kernel_base__ = 0x100000; __kernel_vaddr__ = __mips64_xkphys_cached__ + __kernel_base__; -OUTPUT_FORMAT("elf64-tradbigmips"); OUTPUT_ARCH(mips) diff --git a/sys/boot/mips/beri/loader/beri_disk_cfi.c b/sys/boot/mips/beri/loader/beri_disk_cfi.c index ce172f6d7a9..ffccce7959b 100644 --- a/sys/boot/mips/beri/loader/beri_disk_cfi.c +++ b/sys/boot/mips/beri/loader/beri_disk_cfi.c @@ -44,7 +44,6 @@ __FBSDID("$FreeBSD$"); static int beri_cfi_disk_init(void); static int beri_cfi_disk_open(struct open_file *, ...); static int beri_cfi_disk_close(struct open_file *); -static void beri_cfi_disk_cleanup(void); static int beri_cfi_disk_strategy(void *, int, daddr_t, size_t, char *, size_t *); static int beri_cfi_disk_print(int); @@ -58,7 +57,7 @@ struct devsw beri_cfi_disk = { .dv_close = beri_cfi_disk_close, .dv_ioctl = noioctl, .dv_print = beri_cfi_disk_print, - .dv_cleanup = beri_cfi_disk_cleanup, + .dv_cleanup = NULL, }; static int @@ -100,7 +99,7 @@ beri_cfi_disk_open(struct open_file *f, ...) if (dev->d_unit != 0) return (EIO); - return (disk_open(dev, cfi_get_mediasize(), cfi_get_sectorsize(), 0)); + return (disk_open(dev, cfi_get_mediasize(), cfi_get_sectorsize())); } static int @@ -131,8 +130,7 @@ beri_cfi_disk_print(int verbose) dev.d_unit = 0; dev.d_slice = -1; dev.d_partition = -1; - if (disk_open(&dev, cfi_get_mediasize(), - cfi_get_sectorsize(), 0) == 0) { + if (disk_open(&dev, cfi_get_mediasize(), cfi_get_sectorsize()) == 0) { snprintf(line, sizeof(line), " cfi%d", 0); ret = disk_print(&dev, line, verbose); disk_close(&dev); @@ -140,10 +138,3 @@ beri_cfi_disk_print(int verbose) return (ret); } - -static void -beri_cfi_disk_cleanup(void) -{ - - disk_cleanup(&beri_cfi_disk); -} diff --git a/sys/boot/mips/beri/loader/beri_disk_sdcard.c b/sys/boot/mips/beri/loader/beri_disk_sdcard.c index b95e22d8e44..aab7a664b59 100644 --- a/sys/boot/mips/beri/loader/beri_disk_sdcard.c +++ b/sys/boot/mips/beri/loader/beri_disk_sdcard.c @@ -44,7 +44,6 @@ __FBSDID("$FreeBSD$"); static int beri_sdcard_disk_init(void); static int beri_sdcard_disk_open(struct open_file *, ...); static int beri_sdcard_disk_close(struct open_file *); -static void beri_sdcard_disk_cleanup(void); static int beri_sdcard_disk_strategy(void *, int, daddr_t, size_t, char *, size_t *); static int beri_sdcard_disk_print(int); @@ -58,7 +57,7 @@ struct devsw beri_sdcard_disk = { .dv_close = beri_sdcard_disk_close, .dv_ioctl = noioctl, .dv_print = beri_sdcard_disk_print, - .dv_cleanup = beri_sdcard_disk_cleanup, + .dv_cleanup = NULL, }; static int @@ -106,7 +105,7 @@ beri_sdcard_disk_open(struct open_file *f, ...) if (dev->d_unit != 0) return (EIO); return (disk_open(dev, altera_sdcard_get_mediasize(), - altera_sdcard_get_sectorsize(), 0)); + altera_sdcard_get_sectorsize())); } static int @@ -138,17 +137,10 @@ beri_sdcard_disk_print(int verbose) dev.d_slice = -1; dev.d_partition = -1; if (disk_open(&dev, altera_sdcard_get_mediasize(), - altera_sdcard_get_sectorsize(), 0) == 0) { + altera_sdcard_get_sectorsize()) == 0) { snprintf(line, sizeof(line), " sdcard%d", 0); ret = disk_print(&dev, line, verbose); disk_close(&dev); } return (ret); } - -static void -beri_sdcard_disk_cleanup(void) -{ - - disk_cleanup(&beri_sdcard_disk); -} diff --git a/sys/boot/mips/beri/loader/loader.ldscript b/sys/boot/mips/beri/loader/loader.ldscript index f3d286ae61e..deb4865c28e 100644 --- a/sys/boot/mips/beri/loader/loader.ldscript +++ b/sys/boot/mips/beri/loader/loader.ldscript @@ -44,7 +44,6 @@ __loader_base_vaddr__ = __mips64_xkphys_cached__ + __loader_base__; __loader_end__ = 0x100000; __loader_end_vaddr__ = __mips64_xkphys_cached__ + __loader_end__; -OUTPUT_FORMAT("elf64-tradbigmips"); OUTPUT_ARCH(mips) ENTRY(start) SECTIONS diff --git a/sys/boot/sparc64/loader/Makefile b/sys/boot/sparc64/loader/Makefile index 5cdbdbbfcc3..ad48be461ce 100644 --- a/sys/boot/sparc64/loader/Makefile +++ b/sys/boot/sparc64/loader/Makefile @@ -82,6 +82,9 @@ CFLAGS+= -I${.CURDIR}/../../ofw/libofw/ # where to get libstand from CFLAGS+= -I${.CURDIR}/../../../../lib/libstand/ +# Need sys/ for crypto/intake.h +CFLAGS+= -I${SRCTOP}/sys + DPADD= ${LIBFICL} ${LIBZFSBOOT} ${LIBOFW} ${LIBSTAND} LDADD= ${LIBFICL} ${LIBZFSBOOT} ${LIBOFW} -lstand diff --git a/sys/boot/uboot/lib/disk.c b/sys/boot/uboot/lib/disk.c index f5092f6c1d5..6ca1f9d61f5 100644 --- a/sys/boot/uboot/lib/disk.c +++ b/sys/boot/uboot/lib/disk.c @@ -139,7 +139,6 @@ stor_cleanup(void) for (i = 0; i < stor_info_no; i++) if (stor_info[i].opened > 0) ub_dev_close(stor_info[i].handle); - disk_cleanup(&uboot_storage); } static int @@ -203,7 +202,7 @@ stor_opendev(struct disk_devdesc *dev) SI(dev).opened++; } return (disk_open(dev, SI(dev).blocks * SI(dev).bsize, - SI(dev).bsize, 0)); + SI(dev).bsize)); } static int @@ -282,7 +281,7 @@ stor_ioctl(struct open_file *f, u_long cmd, void *data) *(u_int *)data = SI(dev).bsize; break; case DIOCGMEDIASIZE: - *(off_t *)data = SI(dev).bsize * SI(dev).blocks; + *(uint64_t *)data = SI(dev).bsize * SI(dev).blocks; break; default: return (ENOTTY); diff --git a/sys/boot/usb/storage/umass_loader.c b/sys/boot/usb/storage/umass_loader.c index efbd914a579..3414201a33d 100644 --- a/sys/boot/usb/storage/umass_loader.c +++ b/sys/boot/usb/storage/umass_loader.c @@ -116,7 +116,7 @@ umass_disk_open_sub(struct disk_devdesc *dev) if (usb_msc_read_capacity(umass_uaa.device, 0, &nblock, &blocksize) != 0) return (EINVAL); - return (disk_open(dev, ((uint64_t)nblock + 1) * (uint64_t)blocksize, blocksize, 0)); + return (disk_open(dev, ((uint64_t)nblock + 1) * (uint64_t)blocksize, blocksize)); } static int @@ -137,20 +137,30 @@ umass_disk_open(struct open_file *f,...) } static int -umass_disk_ioctl(struct open_file *f __unused, u_long cmd, void *buf) +umass_disk_ioctl(struct open_file *f, u_long cmd, void *buf) { + struct disk_devdesc *dev; uint32_t nblock; uint32_t blocksize; + int rc; + + dev = (struct disk_devdesc *)(f->f_devdata); + if (dev == NULL) + return (EINVAL); + + rc = disk_ioctl(dev, cmd, buf); + if (rc != ENOTTY) + return (rc); switch (cmd) { - case IOCTL_GET_BLOCK_SIZE: - case IOCTL_GET_BLOCKS: + case DIOCGSECTORSIZE: + case DIOCGMEDIASIZE: if (usb_msc_read_capacity(umass_uaa.device, 0, &nblock, &blocksize) != 0) return (EINVAL); - if (cmd == IOCTL_GET_BLOCKS) - *(uint32_t*)buf = nblock; + if (cmd == DIOCGMEDIASIZE) + *(uint64_t*)buf = nblock; else *(uint32_t*)buf = blocksize; @@ -198,7 +208,6 @@ umass_disk_print(int verbose) static void umass_disk_cleanup(void) { - disk_cleanup(&umass_disk); usb_uninit(); } diff --git a/sys/boot/userboot/userboot/userboot_disk.c b/sys/boot/userboot/userboot/userboot_disk.c index e49393e9f08..4e617b6d252 100644 --- a/sys/boot/userboot/userboot/userboot_disk.c +++ b/sys/boot/userboot/userboot/userboot_disk.c @@ -110,7 +110,6 @@ userdisk_cleanup(void) if (userdisk_maxunit > 0) free(ud_info); - disk_cleanup(&userboot_disk); } /* @@ -141,7 +140,7 @@ userdisk_print(int verbose) dev.d_slice = -1; dev.d_partition = -1; if (disk_open(&dev, ud_info[i].mediasize, - ud_info[i].sectorsize, 0) == 0) { + ud_info[i].sectorsize) == 0) { snprintf(line, sizeof(line), " disk%d", i); ret = disk_print(&dev, line, verbose); disk_close(&dev); @@ -171,7 +170,7 @@ userdisk_open(struct open_file *f, ...) if (ud_info[dev->d_unit].ud_bcache == NULL) ud_info[dev->d_unit].ud_bcache = bcache_allocate(); return (disk_open(dev, ud_info[dev->d_unit].mediasize, - ud_info[dev->d_unit].sectorsize, 0)); + ud_info[dev->d_unit].sectorsize)); } static int diff --git a/sys/boot/zfs/libzfs.h b/sys/boot/zfs/libzfs.h index 0ce0a9c7f69..1b304998867 100644 --- a/sys/boot/zfs/libzfs.h +++ b/sys/boot/zfs/libzfs.h @@ -47,6 +47,10 @@ struct zfs_devdesc uint64_t root_guid; }; +#ifdef LOADER_GELI_SUPPORT +#include +#endif + struct zfs_boot_args { uint32_t size; @@ -55,7 +59,21 @@ struct zfs_boot_args uint64_t root; uint64_t primary_pool; uint64_t primary_vdev; - char gelipw[256]; + union { + char gelipw[256]; + struct { + char notapw; /* + * single null byte to stop keybuf + * being interpreted as a password + */ + uint32_t keybuf_sentinel; +#ifdef LOADER_GELI_SUPPORT + struct keybuf *keybuf; +#else + void *keybuf; +#endif + }; + }; }; int zfs_parsedev(struct zfs_devdesc *dev, const char *devspec, diff --git a/sys/boot/zfs/zfs.c b/sys/boot/zfs/zfs.c index c5a46efd851..062895eef79 100644 --- a/sys/boot/zfs/zfs.c +++ b/sys/boot/zfs/zfs.c @@ -417,7 +417,7 @@ struct zfs_probe_args { }; static int -zfs_diskread(void *arg, void *buf, size_t blocks, off_t offset) +zfs_diskread(void *arg, void *buf, size_t blocks, uint64_t offset) { struct zfs_probe_args *ppa; @@ -483,9 +483,11 @@ zfs_probe_dev(const char *devname, uint64_t *pool_guid) { struct ptable *table; struct zfs_probe_args pa; - off_t mediasz; + uint64_t mediasz; int ret; + if (pool_guid) + *pool_guid = 0; pa.fd = open(devname, O_RDONLY); if (pa.fd == -1) return (ENXIO); @@ -493,6 +495,7 @@ zfs_probe_dev(const char *devname, uint64_t *pool_guid) ret = zfs_probe(pa.fd, pool_guid); if (ret == 0) return (0); + /* Probe each partition */ ret = ioctl(pa.fd, DIOCGMEDIASIZE, &mediasz); if (ret == 0) @@ -508,6 +511,8 @@ zfs_probe_dev(const char *devname, uint64_t *pool_guid) } } close(pa.fd); + if (pool_guid && *pool_guid == 0) + ret = ENXIO; return (ret); } diff --git a/sys/crypto/intake.h b/sys/crypto/intake.h new file mode 100644 index 00000000000..bdded3a767f --- /dev/null +++ b/sys/crypto/intake.h @@ -0,0 +1,64 @@ +/*- + * Copyright (c) 2016 Eric McCorkle + * 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 + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + * + * $FreeBSD$ + */ + +#ifndef _INTAKE_H_ +#define _INTAKE_H_ + +#include + +/* + * This file provides an interface for providing keys to the kernel + * during boot time. + */ + +#define MAX_KEY_BITS 4096 +#define MAX_KEY_BYTES (MAX_KEY_BITS / NBBY) + +#define KEYBUF_SENTINEL 0xcee54b5d /* KEYS4BSD */ + +enum { + KEYBUF_TYPE_NONE, + KEYBUF_TYPE_GELI +}; + +struct keybuf_ent { + unsigned int ke_type; + char ke_data[MAX_KEY_BYTES]; +}; + +struct keybuf { + unsigned int kb_nents; + struct keybuf_ent kb_ents[]; +}; + +#ifdef _KERNEL +/* Get the key intake buffer */ +extern struct keybuf* get_keybuf(void); +#endif + +#endif diff --git a/sys/geom/eli/g_eli.c b/sys/geom/eli/g_eli.c index 6d734aece18..f710c45e16f 100644 --- a/sys/geom/eli/g_eli.c +++ b/sys/geom/eli/g_eli.c @@ -53,6 +53,8 @@ __FBSDID("$FreeBSD$"); #include #include +#include + FEATURE(geom_eli, "GEOM crypto module"); MALLOC_DEFINE(M_ELI, "eli data", "GEOM_ELI Data"); @@ -111,13 +113,39 @@ fetch_loader_passphrase(void * dummy) } SYSINIT(geli_fetch_loader_passphrase, SI_SUB_KMEM + 1, SI_ORDER_ANY, fetch_loader_passphrase, NULL); + static void -zero_boot_passcache(void * dummy) +zero_boot_passcache(void) { - memset(cached_passphrase, 0, sizeof(cached_passphrase)); + explicit_bzero(cached_passphrase, sizeof(cached_passphrase)); +} + +static void +zero_geli_intake_keys(void) +{ + struct keybuf *keybuf; + int i; + + if ((keybuf = get_keybuf()) != NULL) { + /* Scan the key buffer, clear all GELI keys. */ + for (i = 0; i < keybuf->kb_nents; i++) { + if (keybuf->kb_ents[i].ke_type == KEYBUF_TYPE_GELI) { + explicit_bzero(keybuf->kb_ents[i].ke_data, + sizeof(keybuf->kb_ents[i].ke_data)); + keybuf->kb_ents[i].ke_type = KEYBUF_TYPE_NONE; + } + } + } +} + +static void +zero_intake_passcache(void *dummy) +{ + zero_boot_passcache(); + zero_geli_intake_keys(); } -EVENTHANDLER_DEFINE(mountroot, zero_boot_passcache, NULL, 0); +EVENTHANDLER_DEFINE(mountroot, zero_intake_passcache, NULL, 0); static eventhandler_tag g_eli_pre_sync = NULL; @@ -997,6 +1025,7 @@ g_eli_taste(struct g_class *mp, struct g_provider *pp, int flags __unused) u_char key[G_ELI_USERKEYLEN], mkey[G_ELI_DATAIVKEYLEN]; u_int i, nkey, nkeyfiles, tries; int error; + struct keybuf *keybuf; g_trace(G_T_TOPOLOGY, "%s(%s, %s)", __func__, mp->name, pp->name); g_topology_assert(); @@ -1035,97 +1064,114 @@ g_eli_taste(struct g_class *mp, struct g_provider *pp, int flags __unused) tries = g_eli_tries; } - for (i = 0; i <= tries; i++) { - g_eli_crypto_hmac_init(&ctx, NULL, 0); - - /* - * Load all key files. - */ - nkeyfiles = g_eli_keyfiles_load(&ctx, pp->name); - - if (nkeyfiles == 0 && md.md_iterations == -1) { - /* - * No key files and no passphrase, something is - * definitely wrong here. - * geli(8) doesn't allow for such situation, so assume - * that there was really no passphrase and in that case - * key files are no properly defined in loader.conf. - */ - G_ELI_DEBUG(0, - "Found no key files in loader.conf for %s.", - pp->name); - return (NULL); - } - - /* Ask for the passphrase if defined. */ - if (md.md_iterations >= 0) { - /* Try first with cached passphrase. */ - if (i == 0) { - if (!g_eli_boot_passcache) - continue; - memcpy(passphrase, cached_passphrase, - sizeof(passphrase)); - } else { - printf("Enter passphrase for %s: ", pp->name); - cngets(passphrase, sizeof(passphrase), - g_eli_visible_passphrase); - memcpy(cached_passphrase, passphrase, - sizeof(passphrase)); - } - } - - /* - * Prepare Derived-Key from the user passphrase. - */ - if (md.md_iterations == 0) { - g_eli_crypto_hmac_update(&ctx, md.md_salt, - sizeof(md.md_salt)); - g_eli_crypto_hmac_update(&ctx, passphrase, - strlen(passphrase)); - bzero(passphrase, sizeof(passphrase)); - } else if (md.md_iterations > 0) { - u_char dkey[G_ELI_USERKEYLEN]; - - pkcs5v2_genkey(dkey, sizeof(dkey), md.md_salt, - sizeof(md.md_salt), passphrase, md.md_iterations); - bzero(passphrase, sizeof(passphrase)); - g_eli_crypto_hmac_update(&ctx, dkey, sizeof(dkey)); - bzero(dkey, sizeof(dkey)); - } - - g_eli_crypto_hmac_final(&ctx, key, 0); - - /* - * Decrypt Master-Key. - */ - error = g_eli_mkey_decrypt(&md, key, mkey, &nkey); - bzero(key, sizeof(key)); - if (error == -1) { - if (i == tries) { - G_ELI_DEBUG(0, - "Wrong key for %s. No tries left.", - pp->name); - g_eli_keyfiles_clear(pp->name); - return (NULL); - } - if (i > 0) { - G_ELI_DEBUG(0, - "Wrong key for %s. Tries left: %u.", - pp->name, tries - i); - } - /* Try again. */ - continue; - } else if (error > 0) { - G_ELI_DEBUG(0, - "Cannot decrypt Master Key for %s (error=%d).", - pp->name, error); - g_eli_keyfiles_clear(pp->name); - return (NULL); - } - g_eli_keyfiles_clear(pp->name); - G_ELI_DEBUG(1, "Using Master Key %u for %s.", nkey, pp->name); - break; - } + if ((keybuf = get_keybuf()) != NULL) { + /* Scan the key buffer, try all GELI keys. */ + for (i = 0; i < keybuf->kb_nents; i++) { + if (keybuf->kb_ents[i].ke_type == KEYBUF_TYPE_GELI) { + memcpy(key, keybuf->kb_ents[i].ke_data, + sizeof(key)); + + if (g_eli_mkey_decrypt(&md, key, + mkey, &nkey) == 0 ) { + explicit_bzero(key, sizeof(key)); + goto have_key; + } + } + } + } + + for (i = 0; i <= tries; i++) { + g_eli_crypto_hmac_init(&ctx, NULL, 0); + + /* + * Load all key files. + */ + nkeyfiles = g_eli_keyfiles_load(&ctx, pp->name); + + if (nkeyfiles == 0 && md.md_iterations == -1) { + /* + * No key files and no passphrase, something is + * definitely wrong here. + * geli(8) doesn't allow for such situation, so assume + * that there was really no passphrase and in that case + * key files are no properly defined in loader.conf. + */ + G_ELI_DEBUG(0, + "Found no key files in loader.conf for %s.", + pp->name); + return (NULL); + } + + /* Ask for the passphrase if defined. */ + if (md.md_iterations >= 0) { + /* Try first with cached passphrase. */ + if (i == 0) { + if (!g_eli_boot_passcache) + continue; + memcpy(passphrase, cached_passphrase, + sizeof(passphrase)); + } else { + printf("Enter passphrase for %s: ", pp->name); + cngets(passphrase, sizeof(passphrase), + g_eli_visible_passphrase); + memcpy(cached_passphrase, passphrase, + sizeof(passphrase)); + } + } + + /* + * Prepare Derived-Key from the user passphrase. + */ + if (md.md_iterations == 0) { + g_eli_crypto_hmac_update(&ctx, md.md_salt, + sizeof(md.md_salt)); + g_eli_crypto_hmac_update(&ctx, passphrase, + strlen(passphrase)); + explicit_bzero(passphrase, sizeof(passphrase)); + } else if (md.md_iterations > 0) { + u_char dkey[G_ELI_USERKEYLEN]; + + pkcs5v2_genkey(dkey, sizeof(dkey), md.md_salt, + sizeof(md.md_salt), passphrase, md.md_iterations); + bzero(passphrase, sizeof(passphrase)); + g_eli_crypto_hmac_update(&ctx, dkey, sizeof(dkey)); + explicit_bzero(dkey, sizeof(dkey)); + } + + g_eli_crypto_hmac_final(&ctx, key, 0); + + /* + * Decrypt Master-Key. + */ + error = g_eli_mkey_decrypt(&md, key, mkey, &nkey); + bzero(key, sizeof(key)); + if (error == -1) { + if (i == tries) { + G_ELI_DEBUG(0, + "Wrong key for %s. No tries left.", + pp->name); + g_eli_keyfiles_clear(pp->name); + return (NULL); + } + if (i > 0) { + G_ELI_DEBUG(0, + "Wrong key for %s. Tries left: %u.", + pp->name, tries - i); + } + /* Try again. */ + continue; + } else if (error > 0) { + G_ELI_DEBUG(0, + "Cannot decrypt Master Key for %s (error=%d).", + pp->name, error); + g_eli_keyfiles_clear(pp->name); + return (NULL); + } + g_eli_keyfiles_clear(pp->name); + G_ELI_DEBUG(1, "Using Master Key %u for %s.", nkey, pp->name); + break; + } +have_key: /* * We have correct key, let's attach provider. diff --git a/sys/geom/eli/g_eli.h b/sys/geom/eli/g_eli.h index 0b8b07a8ed7..035f41a187c 100644 --- a/sys/geom/eli/g_eli.h +++ b/sys/geom/eli/g_eli.h @@ -41,6 +41,7 @@ #include #include #include +#include #else #include #include @@ -139,6 +140,10 @@ #define G_ELI_CRYPTO_SW 2 #ifdef _KERNEL +#if (MAX_KEY_BYTES < G_ELI_DATAIVKEYLEN) +#error "MAX_KEY_BYTES is less than G_ELI_DATAKEYLEN" +#endif + extern int g_eli_debug; extern u_int g_eli_overwrites; extern u_int g_eli_batch; diff --git a/sys/opencrypto/crypto.c b/sys/opencrypto/crypto.c index 44fbdf8fd7a..ca9a89d4f8b 100644 --- a/sys/opencrypto/crypto.c +++ b/sys/opencrypto/crypto.c @@ -63,6 +63,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include #include @@ -74,6 +75,7 @@ __FBSDID("$FreeBSD$"); #include #include +#include #include #include /* XXX for M_XDATA */ @@ -84,6 +86,7 @@ __FBSDID("$FreeBSD$"); #if defined(__i386__) || defined(__amd64__) #include #endif +#include SDT_PROVIDER_DEFINE(opencrypto); @@ -186,6 +189,37 @@ SYSCTL_INT(_debug, OID_AUTO, crypto_timing, CTLFLAG_RW, &crypto_timing, 0, "Enable/disable crypto timing support"); #endif +/* Try to avoid directly exposing the key buffer as a symbol */ +static struct keybuf *keybuf; + +static struct keybuf empty_keybuf = { + .kb_nents = 0 +}; + +/* Obtain the key buffer from boot metadata */ +static void +keybuf_init(void) +{ + caddr_t kmdp; + + kmdp = preload_search_by_type("elf kernel"); + + if (kmdp == NULL) + kmdp = preload_search_by_type("elf64 kernel"); + + keybuf = (struct keybuf *)preload_search_info(kmdp, + MODINFO_METADATA | MODINFOMD_KEYBUF); + + if (keybuf == NULL) + keybuf = &empty_keybuf; +} + +/* It'd be nice if we could store these in some kind of secure memory... */ +struct keybuf * get_keybuf(void) { + + return (keybuf); +} + static int crypto_init(void) { @@ -238,6 +272,9 @@ crypto_init(void) error); goto bad; } + + keybuf_init(); + return 0; bad: crypto_destroy(); @@ -282,7 +319,7 @@ crypto_destroy(void) /* XXX flush queues??? */ - /* + /* * Reclaim dynamically allocated resources. */ if (crypto_drivers != NULL) diff --git a/sys/sys/linker.h b/sys/sys/linker.h index 42253a7758a..349bfeb3369 100644 --- a/sys/sys/linker.h +++ b/sys/sys/linker.h @@ -142,7 +142,7 @@ int linker_file_foreach(linker_predicate_t *_predicate, void *_context); * Lookup a symbol in a file. If deps is TRUE, look in dependencies * if not found in file. */ -caddr_t linker_file_lookup_symbol(linker_file_t _file, const char* _name, +caddr_t linker_file_lookup_symbol(linker_file_t _file, const char* _name, int _deps); /* @@ -156,7 +156,7 @@ int linker_file_lookup_set(linker_file_t _file, const char *_name, /* * List all functions in a file. */ -int linker_file_function_listall(linker_file_t, +int linker_file_function_listall(linker_file_t, linker_function_nameval_callback_t, void *); /* @@ -216,6 +216,7 @@ void *linker_hwpmc_list_objects(void); #define MODINFOMD_CTORS_ADDR 0x000a /* address of .ctors */ #define MODINFOMD_CTORS_SIZE 0x000b /* size of .ctors */ #define MODINFOMD_FW_HANDLE 0x000c /* Firmware dependent handle */ +#define MODINFOMD_KEYBUF 0x000d /* Crypto key intake buffer */ #define MODINFOMD_NOCOPY 0x8000 /* don't copy this metadata to the kernel */ #define MODINFOMD_DEPLIST (0x4001 | MODINFOMD_NOCOPY) /* depends on */ diff --git a/usr.sbin/makefs/ffs.c b/usr.sbin/makefs/ffs.c index 209588a9e44..62c3c3ea44a 100644 --- a/usr.sbin/makefs/ffs.c +++ b/usr.sbin/makefs/ffs.c @@ -977,7 +977,7 @@ ffs_write_file(union dinode *din, uint32_t ino, void *buf, fsinfo_t *fsopts) errno = bwrite(bp); if (errno != 0) goto bad_ffs_write_file; - brelse(bp); + brelse(bp, 0); if (!isfile) p += chunk; } diff --git a/usr.sbin/makefs/ffs/buf.c b/usr.sbin/makefs/ffs/buf.c index 06538f50936..15dcfe8cff1 100644 --- a/usr.sbin/makefs/ffs/buf.c +++ b/usr.sbin/makefs/ffs/buf.c @@ -1,4 +1,4 @@ -/* $NetBSD: buf.c,v 1.12 2004/06/20 22:20:18 jmc Exp $ */ +/* $NetBSD: buf.c,v 1.13 2004/06/20 22:20:18 jmc Exp $ */ /* * Copyright (c) 2001 Wasabi Systems, Inc. @@ -60,10 +60,12 @@ extern int sectorsize; /* XXX: from ffs.c & mkfs.c */ TAILQ_HEAD(buftailhead,buf) buftail; int -bread(int fd, struct fs *fs, daddr_t blkno, int size, struct buf **bpp) +bread(struct vnode *vp, daddr_t blkno, int size, struct ucred *u1 __unused, + struct buf **bpp) { off_t offset; ssize_t rv; + struct fs *fs = vp->fs; assert (fs != NULL); assert (bpp != NULL); @@ -71,7 +73,7 @@ bread(int fd, struct fs *fs, daddr_t blkno, int size, struct buf **bpp) if (debug & DEBUG_BUF_BREAD) printf("bread: fs %p blkno %lld size %d\n", fs, (long long)blkno, size); - *bpp = getblk(fd, fs, blkno, size); + *bpp = getblk(vp, blkno, size, 0, 0, 0); offset = (*bpp)->b_blkno * sectorsize; /* XXX */ if (debug & DEBUG_BUF_BREAD) printf("bread: bp %p blkno %lld offset %lld bcount %ld\n", @@ -95,7 +97,7 @@ bread(int fd, struct fs *fs, daddr_t blkno, int size, struct buf **bpp) } void -brelse(struct buf *bp) +brelse(struct buf *bp, int u1 __unused) { assert (bp != NULL); @@ -174,12 +176,16 @@ bcleanup(void) } struct buf * -getblk(int fd, struct fs *fs, daddr_t blkno, int size) +getblk(struct vnode *vp, daddr_t blkno, int size, int u1 __unused, + int u2 __unused, int u3 __unused) { static int buftailinitted; struct buf *bp; void *n; + int fd = vp->fd; + struct fs *fs = vp->fs; + blkno += vp->offset; assert (fs != NULL); if (debug & DEBUG_BUF_GETBLK) printf("getblk: fs %p blkno %lld size %d\n", fs, diff --git a/usr.sbin/makefs/ffs/buf.h b/usr.sbin/makefs/ffs/buf.h index 02c67138e3c..b082f48650e 100644 --- a/usr.sbin/makefs/ffs/buf.h +++ b/usr.sbin/makefs/ffs/buf.h @@ -1,4 +1,4 @@ -/* $NetBSD: buf.h,v 1.2 2001/11/02 03:12:49 lukem Exp $ */ +/* $NetBSD: buf.h,v 1.3 2001/11/02 03:12:49 lukem Exp $ */ /* * Copyright (c) 2001 Wasabi Systems, Inc. @@ -43,6 +43,15 @@ #include #include +struct ucred; + +struct vnode { + int fd; + void *fs; + void *v_data; + int offset; +}; + struct buf { void * b_data; long b_bufsize; @@ -56,10 +65,11 @@ struct buf { }; void bcleanup(void); -int bread(int, struct fs *, daddr_t, int, struct buf **); -void brelse(struct buf *); +int bread(struct vnode *, daddr_t, int, struct ucred *, + struct buf **); +void brelse(struct buf *, int); int bwrite(struct buf *); -struct buf * getblk(int, struct fs *, daddr_t, int); +struct buf * getblk(struct vnode *, daddr_t, int, int, int, int); #define bdwrite(bp) bwrite(bp) #define clrbuf(bp) memset((bp)->b_data, 0, (u_int)(bp)->b_bcount) diff --git a/usr.sbin/makefs/ffs/ffs_alloc.c b/usr.sbin/makefs/ffs/ffs_alloc.c index afab8699509..5147d04ba1a 100644 --- a/usr.sbin/makefs/ffs/ffs_alloc.c +++ b/usr.sbin/makefs/ffs/ffs_alloc.c @@ -297,19 +297,20 @@ ffs_alloccg(struct inode *ip, int cg, daddr_t bpref, int size) int error, frags, allocsiz, i; struct fs *fs = ip->i_fs; const int needswap = UFS_FSNEEDSWAP(fs); + struct vnode vp = { ip->i_fd, ip->i_fs, NULL, 0 }; if (fs->fs_cs(fs, cg).cs_nbfree == 0 && size == fs->fs_bsize) return (0); - error = bread(ip->i_fd, ip->i_fs, fsbtodb(fs, cgtod(fs, cg)), - (int)fs->fs_cgsize, &bp); + error = bread(&vp, fsbtodb(fs, cgtod(fs, cg)), (int)fs->fs_cgsize, + NULL, &bp); if (error) { - brelse(bp); + brelse(bp, 0); return (0); } cgp = (struct cg *)bp->b_data; if (!cg_chkmagic_swap(cgp, needswap) || (cgp->cg_cs.cs_nbfree == 0 && size == fs->fs_bsize)) { - brelse(bp); + brelse(bp, 0); return (0); } if (size == fs->fs_bsize) { @@ -332,7 +333,7 @@ ffs_alloccg(struct inode *ip, int cg, daddr_t bpref, int size) * allocated, and hacked up */ if (cgp->cg_cs.cs_nbfree == 0) { - brelse(bp); + brelse(bp, 0); return (0); } bno = ffs_alloccgblk(ip, bp, bpref); @@ -432,6 +433,7 @@ ffs_blkfree(struct inode *ip, daddr_t bno, long size) int i, error, cg, blk, frags, bbase; struct fs *fs = ip->i_fs; const int needswap = UFS_FSNEEDSWAP(fs); + struct vnode vp = { ip->i_fd, ip->i_fs, NULL, 0 }; if (size > fs->fs_bsize || fragoff(fs, size) != 0 || fragnum(fs, bno) + numfrags(fs, size) > fs->fs_frag) { @@ -444,15 +446,15 @@ ffs_blkfree(struct inode *ip, daddr_t bno, long size) (uintmax_t)ip->i_number); return; } - error = bread(ip->i_fd, ip->i_fs, fsbtodb(fs, cgtod(fs, cg)), - (int)fs->fs_cgsize, &bp); + error = bread(&vp, fsbtodb(fs, cgtod(fs, cg)), (int)fs->fs_cgsize, + NULL, &bp); if (error) { - brelse(bp); + brelse(bp, 0); return; } cgp = (struct cg *)bp->b_data; if (!cg_chkmagic_swap(cgp, needswap)) { - brelse(bp); + brelse(bp, 0); return; } cgbno = dtogd(fs, bno); diff --git a/usr.sbin/makefs/ffs/ffs_balloc.c b/usr.sbin/makefs/ffs/ffs_balloc.c index 0a048ad356b..0ce4f756a3b 100644 --- a/usr.sbin/makefs/ffs/ffs_balloc.c +++ b/usr.sbin/makefs/ffs/ffs_balloc.c @@ -89,6 +89,7 @@ ffs_balloc_ufs1(struct inode *ip, off_t offset, int bufsize, struct buf **bpp) int32_t *allocblk, allociblk[NIADDR + 1]; int32_t *allocib; const int needswap = UFS_FSNEEDSWAP(fs); + struct vnode vp = { ip->i_fd, ip->i_fs, NULL, 0 }; lbn = lblkno(fs, offset); size = blkoff(fs, offset) + bufsize; @@ -132,10 +133,10 @@ ffs_balloc_ufs1(struct inode *ip, off_t offset, int bufsize, struct buf **bpp) */ if (bpp != NULL) { - error = bread(ip->i_fd, ip->i_fs, lbn, - fs->fs_bsize, bpp); + error = bread(&vp, lbn, fs->fs_bsize, NULL, + bpp); if (error) { - brelse(*bpp); + brelse(*bpp, 0); return (error); } } @@ -158,10 +159,10 @@ ffs_balloc_ufs1(struct inode *ip, off_t offset, int bufsize, struct buf **bpp) */ if (bpp != NULL) { - error = bread(ip->i_fd, ip->i_fs, lbn, - osize, bpp); + error = bread(&vp, lbn, osize, NULL, + bpp); if (error) { - brelse(*bpp); + brelse(*bpp, 0); return (error); } } @@ -188,7 +189,7 @@ ffs_balloc_ufs1(struct inode *ip, off_t offset, int bufsize, struct buf **bpp) if (error) return (error); if (bpp != NULL) { - bp = getblk(ip->i_fd, ip->i_fs, lbn, nsize); + bp = getblk(&vp, lbn, nsize, 0, 0, 0); bp->b_blkno = fsbtodb(fs, newb); clrbuf(bp); *bpp = bp; @@ -226,7 +227,7 @@ ffs_balloc_ufs1(struct inode *ip, off_t offset, int bufsize, struct buf **bpp) return error; nb = newb; *allocblk++ = nb; - bp = getblk(ip->i_fd, ip->i_fs, indirs[1].in_lbn, fs->fs_bsize); + bp = getblk(&vp, indirs[1].in_lbn, fs->fs_bsize, 0, 0, 0); bp->b_blkno = fsbtodb(fs, nb); clrbuf(bp); /* @@ -244,10 +245,9 @@ ffs_balloc_ufs1(struct inode *ip, off_t offset, int bufsize, struct buf **bpp) */ for (i = 1;;) { - error = bread(ip->i_fd, ip->i_fs, indirs[i].in_lbn, - fs->fs_bsize, &bp); + error = bread(&vp, indirs[i].in_lbn, fs->fs_bsize, NULL, &bp); if (error) { - brelse(bp); + brelse(bp, 0); return error; } bap = (int32_t *)bp->b_data; @@ -256,20 +256,19 @@ ffs_balloc_ufs1(struct inode *ip, off_t offset, int bufsize, struct buf **bpp) break; i++; if (nb != 0) { - brelse(bp); + brelse(bp, 0); continue; } if (pref == 0) pref = ffs_blkpref_ufs1(ip, lbn, 0, (int32_t *)0); error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, &newb); if (error) { - brelse(bp); + brelse(bp, 0); return error; } nb = newb; *allocblk++ = nb; - nbp = getblk(ip->i_fd, ip->i_fs, indirs[i].in_lbn, - fs->fs_bsize); + nbp = getblk(&vp, indirs[i].in_lbn, fs->fs_bsize, 0, 0, 0); nbp->b_blkno = fsbtodb(fs, nb); clrbuf(nbp); /* @@ -278,7 +277,7 @@ ffs_balloc_ufs1(struct inode *ip, off_t offset, int bufsize, struct buf **bpp) */ if ((error = bwrite(nbp)) != 0) { - brelse(bp); + brelse(bp, 0); return error; } bap[indirs[i - 1].in_off] = ufs_rw32(nb, needswap); @@ -294,13 +293,13 @@ ffs_balloc_ufs1(struct inode *ip, off_t offset, int bufsize, struct buf **bpp) pref = ffs_blkpref_ufs1(ip, lbn, indirs[num].in_off, &bap[0]); error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, &newb); if (error) { - brelse(bp); + brelse(bp, 0); return error; } nb = newb; *allocblk++ = nb; if (bpp != NULL) { - nbp = getblk(ip->i_fd, ip->i_fs, lbn, fs->fs_bsize); + nbp = getblk(&vp, lbn, fs->fs_bsize, 0, 0, 0); nbp->b_blkno = fsbtodb(fs, nb); clrbuf(nbp); *bpp = nbp; @@ -314,11 +313,11 @@ ffs_balloc_ufs1(struct inode *ip, off_t offset, int bufsize, struct buf **bpp) bwrite(bp); return (0); } - brelse(bp); + brelse(bp, 0); if (bpp != NULL) { - error = bread(ip->i_fd, ip->i_fs, lbn, (int)fs->fs_bsize, &nbp); + error = bread(&vp, lbn, (int)fs->fs_bsize, NULL, &nbp); if (error) { - brelse(nbp); + brelse(nbp, 0); return error; } *bpp = nbp; @@ -340,6 +339,7 @@ ffs_balloc_ufs2(struct inode *ip, off_t offset, int bufsize, struct buf **bpp) int64_t *allocblk, allociblk[NIADDR + 1]; int64_t *allocib; const int needswap = UFS_FSNEEDSWAP(fs); + struct vnode vp = { ip->i_fd, ip->i_fs, NULL, 0 }; lbn = lblkno(fs, offset); size = blkoff(fs, offset) + bufsize; @@ -383,10 +383,10 @@ ffs_balloc_ufs2(struct inode *ip, off_t offset, int bufsize, struct buf **bpp) */ if (bpp != NULL) { - error = bread(ip->i_fd, ip->i_fs, lbn, - fs->fs_bsize, bpp); + error = bread(&vp, lbn, fs->fs_bsize, NULL, + bpp); if (error) { - brelse(*bpp); + brelse(*bpp, 0); return (error); } } @@ -409,10 +409,10 @@ ffs_balloc_ufs2(struct inode *ip, off_t offset, int bufsize, struct buf **bpp) */ if (bpp != NULL) { - error = bread(ip->i_fd, ip->i_fs, lbn, - osize, bpp); + error = bread(&vp, lbn, osize, NULL, + bpp); if (error) { - brelse(*bpp); + brelse(*bpp, 0); return (error); } } @@ -439,7 +439,7 @@ ffs_balloc_ufs2(struct inode *ip, off_t offset, int bufsize, struct buf **bpp) if (error) return (error); if (bpp != NULL) { - bp = getblk(ip->i_fd, ip->i_fs, lbn, nsize); + bp = getblk(&vp, lbn, nsize, 0, 0, 0); bp->b_blkno = fsbtodb(fs, newb); clrbuf(bp); *bpp = bp; @@ -477,7 +477,7 @@ ffs_balloc_ufs2(struct inode *ip, off_t offset, int bufsize, struct buf **bpp) return error; nb = newb; *allocblk++ = nb; - bp = getblk(ip->i_fd, ip->i_fs, indirs[1].in_lbn, fs->fs_bsize); + bp = getblk(&vp, indirs[1].in_lbn, fs->fs_bsize, 0, 0, 0); bp->b_blkno = fsbtodb(fs, nb); clrbuf(bp); /* @@ -495,10 +495,9 @@ ffs_balloc_ufs2(struct inode *ip, off_t offset, int bufsize, struct buf **bpp) */ for (i = 1;;) { - error = bread(ip->i_fd, ip->i_fs, indirs[i].in_lbn, - fs->fs_bsize, &bp); + error = bread(&vp, indirs[i].in_lbn, fs->fs_bsize, NULL, &bp); if (error) { - brelse(bp); + brelse(bp, 0); return error; } bap = (int64_t *)bp->b_data; @@ -507,20 +506,19 @@ ffs_balloc_ufs2(struct inode *ip, off_t offset, int bufsize, struct buf **bpp) break; i++; if (nb != 0) { - brelse(bp); + brelse(bp, 0); continue; } if (pref == 0) pref = ffs_blkpref_ufs2(ip, lbn, 0, (int64_t *)0); error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, &newb); if (error) { - brelse(bp); + brelse(bp, 0); return error; } nb = newb; *allocblk++ = nb; - nbp = getblk(ip->i_fd, ip->i_fs, indirs[i].in_lbn, - fs->fs_bsize); + nbp = getblk(&vp, indirs[i].in_lbn, fs->fs_bsize, 0, 0, 0); nbp->b_blkno = fsbtodb(fs, nb); clrbuf(nbp); /* @@ -529,7 +527,7 @@ ffs_balloc_ufs2(struct inode *ip, off_t offset, int bufsize, struct buf **bpp) */ if ((error = bwrite(nbp)) != 0) { - brelse(bp); + brelse(bp, 0); return error; } bap[indirs[i - 1].in_off] = ufs_rw64(nb, needswap); @@ -545,13 +543,13 @@ ffs_balloc_ufs2(struct inode *ip, off_t offset, int bufsize, struct buf **bpp) pref = ffs_blkpref_ufs2(ip, lbn, indirs[num].in_off, &bap[0]); error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, &newb); if (error) { - brelse(bp); + brelse(bp, 0); return error; } nb = newb; *allocblk++ = nb; if (bpp != NULL) { - nbp = getblk(ip->i_fd, ip->i_fs, lbn, fs->fs_bsize); + nbp = getblk(&vp, lbn, fs->fs_bsize, 0, 0, 0); nbp->b_blkno = fsbtodb(fs, nb); clrbuf(nbp); *bpp = nbp; @@ -565,11 +563,11 @@ ffs_balloc_ufs2(struct inode *ip, off_t offset, int bufsize, struct buf **bpp) bwrite(bp); return (0); } - brelse(bp); + brelse(bp, 0); if (bpp != NULL) { - error = bread(ip->i_fd, ip->i_fs, lbn, (int)fs->fs_bsize, &nbp); + error = bread(&vp, lbn, (int)fs->fs_bsize, NULL, &nbp); if (error) { - brelse(nbp); + brelse(nbp, 0); return error; } *bpp = nbp; -- 2.45.0