From owner-svn-src-head@FreeBSD.ORG Sat Jan 9 22:54:30 2010 Return-Path: Delivered-To: svn-src-head@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 134C9106568F; Sat, 9 Jan 2010 22:54:30 +0000 (UTC) (envelope-from marcel@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id F41CD8FC08; Sat, 9 Jan 2010 22:54:29 +0000 (UTC) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.3/8.14.3) with ESMTP id o09MsTYR039782; Sat, 9 Jan 2010 22:54:29 GMT (envelope-from marcel@svn.freebsd.org) Received: (from marcel@localhost) by svn.freebsd.org (8.14.3/8.14.3/Submit) id o09MsTYj039775; Sat, 9 Jan 2010 22:54:29 GMT (envelope-from marcel@svn.freebsd.org) Message-Id: <201001092254.o09MsTYj039775@svn.freebsd.org> From: Marcel Moolenaar Date: Sat, 9 Jan 2010 22:54:29 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r201941 - in head/sys/boot: common efi/include efi/libefi ia64/efi X-BeenThere: svn-src-head@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: SVN commit messages for the src tree for head/-current List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sat, 09 Jan 2010 22:54:30 -0000 Author: marcel Date: Sat Jan 9 22:54:29 2010 New Revision: 201941 URL: http://svn.freebsd.org/changeset/base/201941 Log: Remove file system support based on the simple file system protocol as this only allows us to access file systems that EFI knows about. With a loader that can only use EFI-supported file systems, we're forced to put /boot on the EFI system partition. This is suboptimal in the following ways: 1. With /boot a symlink to /efi/boot, mergemaster complains about the mismatch and there's no quick solution. 2. The EFI loader can only boot a single version of FreeBSD. There's no way to install multiple versions of FreeBSD and select one at the loader prompt. 3. ZFS maintains /boot/zfs/zpool.cache and with /boot a symlink we end up with the file on a MSDOS file system. ZFS does not have proper handling of file systems that are under Giant. Implement a disk device based on the block I/O protocol instead and pull in file system code from libstand. The disk devices are really the partitions that EFI knows about. This change is backward compatible. MFC after: 1 week Added: head/sys/boot/efi/libefi/efipart.c (contents, props changed) Deleted: head/sys/boot/efi/libefi/efifs.c Modified: head/sys/boot/common/bootstrap.h head/sys/boot/efi/include/efilib.h head/sys/boot/efi/libefi/Makefile head/sys/boot/ia64/efi/conf.c head/sys/boot/ia64/efi/version Modified: head/sys/boot/common/bootstrap.h ============================================================================== --- head/sys/boot/common/bootstrap.h Sat Jan 9 22:47:40 2010 (r201940) +++ head/sys/boot/common/bootstrap.h Sat Jan 9 22:54:29 2010 (r201941) @@ -45,6 +45,7 @@ struct devdesc #define DEVT_CD 3 #define DEVT_ZFS 4 int d_unit; + void *d_opendata; }; /* Commands and return values; nonzero return sets command_errmsg != NULL */ Modified: head/sys/boot/efi/include/efilib.h ============================================================================== --- head/sys/boot/efi/include/efilib.h Sat Jan 9 22:47:40 2010 (r201940) +++ head/sys/boot/efi/include/efilib.h Sat Jan 9 22:54:29 2010 (r201941) @@ -34,9 +34,7 @@ extern EFI_SYSTEM_TABLE *ST; extern EFI_BOOT_SERVICES *BS; extern EFI_RUNTIME_SERVICES *RS; -extern struct devsw efifs_dev; -extern struct fs_ops efifs_fsops; - +extern struct devsw efipart_dev; extern struct devsw efinet_dev; extern struct netif_driver efinetif; Modified: head/sys/boot/efi/libefi/Makefile ============================================================================== --- head/sys/boot/efi/libefi/Makefile Sat Jan 9 22:47:40 2010 (r201940) +++ head/sys/boot/efi/libefi/Makefile Sat Jan 9 22:54:29 2010 (r201941) @@ -3,8 +3,8 @@ LIB= efi INTERNALLIB= -SRCS= delay.c efi_console.c efifs.c efinet.c errno.c handles.c libefi.c \ - time.c +SRCS= delay.c efi_console.c efinet.c efipart.c errno.c handles.c \ + libefi.c time.c CFLAGS+= -I${.CURDIR}/../include CFLAGS+= -I${.CURDIR}/../include/${MACHINE_ARCH:S/amd64/i386/} Added: head/sys/boot/efi/libefi/efipart.c ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ head/sys/boot/efi/libefi/efipart.c Sat Jan 9 22:54:29 2010 (r201941) @@ -0,0 +1,265 @@ +/*- + * Copyright (c) 2010 Marcel Moolenaar + * 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 +#include +#include + +#include + +#include +#include +#include + +static EFI_GUID blkio_guid = BLOCK_IO_PROTOCOL; + +static int efipart_init(void); +static int efipart_strategy(void *, int, daddr_t, size_t, char *, size_t *); +static int efipart_open(struct open_file *, ...); +static int efipart_close(struct open_file *); +static void efipart_print(int); + +struct devsw efipart_dev = { + .dv_name = "part", + .dv_type = DEVT_DISK, + .dv_init = efipart_init, + .dv_strategy = efipart_strategy, + .dv_open = efipart_open, + .dv_close = efipart_close, + .dv_ioctl = noioctl, + .dv_print = efipart_print, + .dv_cleanup = NULL +}; + +static int +efipart_init(void) +{ + EFI_BLOCK_IO *blkio; + EFI_HANDLE *hin, *hout; + EFI_STATUS status; + UINTN sz; + u_int n, nin, nout; + int err; + + sz = 0; + status = BS->LocateHandle(ByProtocol, &blkio_guid, 0, &sz, 0); + if (status == EFI_BUFFER_TOO_SMALL) { + hin = (EFI_HANDLE *)malloc(sz * 2); + status = BS->LocateHandle(ByProtocol, &blkio_guid, 0, &sz, + hin); + if (EFI_ERROR(status)) + free(hin); + } + 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; + nout = 0; + + for (n = 0; n < nin; n++) { + status = BS->HandleProtocol(hin[n], &blkio_guid, &blkio); + if (EFI_ERROR(status)) + continue; + if (!blkio->Media->LogicalPartition) + continue; + hout[nout] = hin[n]; + nout++; + } + + err = efi_register_handles(&efipart_dev, hout, nout); + free(hin); + return (err); +} + +static void +efipart_print(int verbose) +{ + char line[80]; + EFI_BLOCK_IO *blkio; + EFI_HANDLE h; + EFI_STATUS status; + u_int unit; + + for (unit = 0, h = efi_find_handle(&efipart_dev, 0); + h != NULL; h = efi_find_handle(&efipart_dev, ++unit)) { + sprintf(line, " %s%d:", efipart_dev.dv_name, unit); + pager_output(line); + + status = BS->HandleProtocol(h, &blkio_guid, &blkio); + if (!EFI_ERROR(status)) { + sprintf(line, " %llu blocks", + (unsigned long long)(blkio->Media->LastBlock + 1)); + pager_output(line); + if (blkio->Media->RemovableMedia) + pager_output(" (removable)"); + } + pager_output("\n"); + } +} + +static int +efipart_open(struct open_file *f, ...) +{ + va_list args; + struct devdesc *dev; + EFI_BLOCK_IO *blkio; + EFI_HANDLE h; + EFI_STATUS status; + + va_start(args, f); + dev = va_arg(args, struct devdesc*); + va_end(args); + + h = efi_find_handle(&efipart_dev, dev->d_unit); + if (h == NULL) + return (EINVAL); + + status = BS->HandleProtocol(h, &blkio_guid, &blkio); + if (EFI_ERROR(status)) + return (efi_status_to_errno(status)); + + if (!blkio->Media->MediaPresent) + return (EAGAIN); + + dev->d_opendata = blkio; + return (0); +} + +static int +efipart_close(struct open_file *f) +{ + struct devdesc *dev; + + dev = (struct devdesc *)(f->f_devdata); + if (dev->d_opendata == NULL) + return (EINVAL); + + dev->d_opendata = NULL; + return (0); +} + +/* + * efipart_readwrite() + * Internal equivalent of efipart_strategy(), which operates on the + * media-native block size. This function expects all I/O requests + * to be within the media size and returns an error if such is not + * the case. + */ +static int +efipart_readwrite(EFI_BLOCK_IO *blkio, int rw, daddr_t blk, daddr_t nblks, + char *buf) +{ + EFI_STATUS status; + + if (blkio == NULL) + return (ENXIO); + if (blk < 0 || blk > blkio->Media->LastBlock) + return (EIO); + if ((blk + nblks - 1) > blkio->Media->LastBlock) + return (EIO); + + switch (rw) { + case F_READ: + status = blkio->ReadBlocks(blkio, blkio->Media->MediaId, blk, + nblks * blkio->Media->BlockSize, buf); + break; + case F_WRITE: + if (blkio->Media->ReadOnly) + return (EROFS); + status = blkio->WriteBlocks(blkio, blkio->Media->MediaId, blk, + nblks * blkio->Media->BlockSize, buf); + break; + default: + return (ENOSYS); + } + + if (EFI_ERROR(status)) + printf("%s: rw=%d, status=%lu\n", __func__, rw, status); + return (efi_status_to_errno(status)); +} + +static int +efipart_strategy(void *devdata, int rw, daddr_t blk, size_t size, char *buf, + size_t *rsize) +{ + struct devdesc *dev = (struct devdesc *)devdata; + EFI_BLOCK_IO *blkio; + off_t off; + char *blkbuf; + size_t blkoff, blksz; + int error; + + if (dev == NULL || blk < 0) + return (EINVAL); + + blkio = dev->d_opendata; + if (blkio == NULL) + return (ENXIO); + + if (size == 0 || (size % 512) != 0) + return (EIO); + + if (rsize != NULL) + *rsize = size; + + if (blkio->Media->BlockSize == 512) + return (efipart_readwrite(blkio, rw, blk, size / 512, buf)); + + /* + * The block size of the media is not 512B per sector. + */ + blkbuf = malloc(blkio->Media->BlockSize); + if (blkbuf == NULL) + return (ENOMEM); + + error = 0; + off = blk * 512; + blk = off / blkio->Media->BlockSize; + blkoff = off % blkio->Media->BlockSize; + blksz = blkio->Media->BlockSize - blkoff; + while (size > 0) { + error = efipart_readwrite(blkio, rw, blk, 1, blkbuf); + if (error) + break; + if (size < blksz) + blksz = size; + bcopy(blkbuf + blkoff, buf, blksz); + buf += blksz; + size -= blksz; + blk++; + blkoff = 0; + blksz = blkio->Media->BlockSize; + } + + free(blkbuf); + return (error); +} Modified: head/sys/boot/ia64/efi/conf.c ============================================================================== --- head/sys/boot/ia64/efi/conf.c Sat Jan 9 22:47:40 2010 (r201940) +++ head/sys/boot/ia64/efi/conf.c Sat Jan 9 22:54:29 2010 (r201941) @@ -49,15 +49,16 @@ __FBSDID("$FreeBSD$"); /* Exported for libstand */ struct devsw *devsw[] = { - &efifs_dev, + &efipart_dev, &efinet_dev, NULL }; struct fs_ops *file_system[] = { - &efifs_fsops, - &nfs_fsops, + &dosfs_fsops, &ufs_fsops, + &cd9660_fsops, + &nfs_fsops, &gzipfs_fsops, NULL }; Modified: head/sys/boot/ia64/efi/version ============================================================================== --- head/sys/boot/ia64/efi/version Sat Jan 9 22:47:40 2010 (r201940) +++ head/sys/boot/ia64/efi/version Sat Jan 9 22:54:29 2010 (r201941) @@ -3,6 +3,9 @@ $FreeBSD$ NOTE ANY CHANGES YOU MAKE TO THE BOOTBLOCKS HERE. The format of this file is important. Make sure the current version number is on line 6. +2.0: Provide devices based on the block I/O protocol, rather than the + simple file services protocol. Use the FreeBSD file system code + on top of those devices to access files. 1.2: Restructured. Has some user visible differences. 1.1: Pass the HCDP table address to the kernel via bootinfo if one is present in the EFI system table.