From owner-svn-src-projects@FreeBSD.ORG Sat Feb 15 14:30:20 2014 Return-Path: Delivered-To: svn-src-projects@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) (using TLSv1 with cipher ADH-AES256-SHA (256/256 bits)) (No client certificate requested) by hub.freebsd.org (Postfix) with ESMTPS id B24FDE19; Sat, 15 Feb 2014 14:30:20 +0000 (UTC) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:1900:2254:2068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mx1.freebsd.org (Postfix) with ESMTPS id 9C2D31B86; Sat, 15 Feb 2014 14:30:20 +0000 (UTC) Received: from svn.freebsd.org ([127.0.1.70]) by svn.freebsd.org (8.14.8/8.14.8) with ESMTP id s1FEUKOY045361; Sat, 15 Feb 2014 14:30:20 GMT (envelope-from andrew@svn.freebsd.org) Received: (from andrew@localhost) by svn.freebsd.org (8.14.8/8.14.8/Submit) id s1FEUKae045359; Sat, 15 Feb 2014 14:30:20 GMT (envelope-from andrew@svn.freebsd.org) Message-Id: <201402151430.s1FEUKae045359@svn.freebsd.org> From: Andrew Turner Date: Sat, 15 Feb 2014 14:30:20 +0000 (UTC) To: src-committers@freebsd.org, svn-src-projects@freebsd.org Subject: svn commit: r261923 - projects/arm64/sys/boot/efi/libefi X-SVN-Group: projects MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-projects@freebsd.org X-Mailman-Version: 2.1.17 Precedence: list List-Id: "SVN commit messages for the src " projects" tree" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sat, 15 Feb 2014 14:30:20 -0000 Author: andrew Date: Sat Feb 15 14:30:19 2014 New Revision: 261923 URL: http://svnweb.freebsd.org/changeset/base/261923 Log: Add a filesystem to read using the EFI Simple Filesystem Protocol. Added: projects/arm64/sys/boot/efi/libefi/efisimplefs.c (contents, props changed) Modified: projects/arm64/sys/boot/efi/libefi/Makefile Modified: projects/arm64/sys/boot/efi/libefi/Makefile ============================================================================== --- projects/arm64/sys/boot/efi/libefi/Makefile Sat Feb 15 13:27:45 2014 (r261922) +++ projects/arm64/sys/boot/efi/libefi/Makefile Sat Feb 15 14:30:19 2014 (r261923) @@ -3,8 +3,8 @@ LIB= efi INTERNALLIB= -SRCS= delay.c efi_console.c efinet.c efipart.c errno.c handles.c \ - libefi.c time.c +SRCS= delay.c efi_console.c efinet.c efipart.c efisimplefs.c errno.c \ + handles.c libefi.c time.c CFLAGS+= -I${.CURDIR}/../include CFLAGS+= -I${.CURDIR}/../include/${MACHINE_CPUARCH:S/amd64/i386/} Added: projects/arm64/sys/boot/efi/libefi/efisimplefs.c ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ projects/arm64/sys/boot/efi/libefi/efisimplefs.c Sat Feb 15 14:30:19 2014 (r261923) @@ -0,0 +1,386 @@ +/*- + * Copyright (c) 2014 Andrew Turner + * 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 + +static EFI_GUID sfs_guid = SIMPLE_FILE_SYSTEM_PROTOCOL; +static EFI_GUID file_info_guid = EFI_FILE_INFO_ID; + +static int efifs_open(const char *path, struct open_file *f); +static int efifs_write(struct open_file *f, void *buf, size_t size, + size_t *resid); +static int efifs_close(struct open_file *f); +static int efifs_read(struct open_file *f, void *buf, size_t size, + size_t *resid); +static off_t efifs_seek(struct open_file *f, off_t offset, int where); +static int efifs_stat(struct open_file *f, struct stat *sb); +static int efifs_readdir(struct open_file *f, struct dirent *d); + +struct fs_ops efifs_fsops = { + "efifs", + efifs_open, + efifs_close, + efifs_read, + efifs_write, + efifs_seek, + efifs_stat, + efifs_readdir +}; + +static CHAR16 * +path_to_filename(const char *path) +{ + CHAR16 *filename; + size_t len; + int i; + + len = strlen(path) + 1; + filename = malloc(len * 2); + if (filename == NULL) + return (NULL); + + for (i = 0; i < len; i++) { + if (path[i] == '/') + filename[i] = L'\\'; + else + filename[i] = path[i]; + } + + return filename; +} + +static int +efifs_open(const char *path, struct open_file *f) +{ + EFI_FILE *dev, *file; + EFI_STATUS status; + struct devdesc *devdesc; + CHAR16 *filename; + + devdesc = (struct devdesc *)(f->f_devdata); + if (devdesc->d_opendata == NULL) + return (EINVAL); + + if (f->f_dev != &efisfs_dev) + return (EINVAL); + + dev = devdesc->d_opendata; + + filename = path_to_filename(path); + if (filename == NULL) + return (ENOMEM); + + status = dev->Open(dev, &file, filename, EFI_FILE_MODE_READ, 0); + free(filename); + if (EFI_ERROR(status)) + return (efi_status_to_errno(status)); + + f->f_fsdata = file; + + return (0); +} + +static int +efifs_close(struct open_file *f) +{ + EFI_STATUS status; + EFI_FILE *file; + + file = f->f_fsdata; + if (file == NULL) + return (EINVAL); + + status = file->Close(file); + if (EFI_ERROR(status)) + return (efi_status_to_errno(status)); + + return (0); +} + +static int +efifs_read(struct open_file *f, void *buf, size_t size, size_t *resid) +{ + EFI_STATUS status; + EFI_FILE *file; + size_t read_size; + + file = f->f_fsdata; + if (file == NULL) + return (EINVAL); + + read_size = size; + status = file->Read(file, &read_size, buf); + if (EFI_ERROR(status)) + return (efi_status_to_errno(status)); + + if (resid != NULL) + *resid = (size - read_size); + + return (0); +} + +static int +efifs_write(struct open_file *f, void *buf, size_t size, size_t *resid) +{ + printf("efifs_write\n"); + + return (EINVAL); +} + +static off_t +efifs_seek(struct open_file *f, off_t offset, int where) +{ + printf("efifs_seek\n"); + + return (EINVAL); +} + +static int +efifs_stat(struct open_file *f, struct stat *sb) +{ + EFI_FILE_INFO *info; + EFI_STATUS status; + EFI_FILE *file; + UINTN infosz; + + file = f->f_fsdata; + if (file == NULL) + return (EINVAL); + + infosz = sizeof(EFI_FILE_INFO); + info = malloc(infosz); + if (info == NULL) + return (ENOMEM); + + status = file->GetInfo(file, &file_info_guid, &infosz, info); + /* Resize the buffer and try again if required */ + if (status == EFI_BUFFER_TOO_SMALL) { + EFI_FILE_INFO *tmp; + + tmp = realloc(info, infosz); + if (info == NULL) { + free(info); + return (ENOMEM); + } + info = tmp; + status = file->GetInfo(file, &file_info_guid, &infosz, info); + } + + if (EFI_ERROR(status)) + return (efi_status_to_errno(status)); + + bzero(sb, sizeof(*sb)); + + sb->st_size = info->FileSize; + sb->st_mode = S_IRUSR; + if (info->FileName[0] == 0) + sb->st_mode = S_IFDIR; + else + sb->st_mode |= + (info->Attribute & EFI_FILE_DIRECTORY) ? S_IFDIR : S_IFREG; + + return (0); +} + +static int +efifs_readdir(struct open_file *f, struct dirent *d) +{ + EFI_FILE_INFO *cur_file; + EFI_STATUS status; + EFI_FILE *file; + UINTN filesz; + int i; + + file = f->f_fsdata; + if (file == NULL) + return (EINVAL); + + filesz = sizeof(*cur_file) + sizeof(d->d_name) * 2; + cur_file = malloc(filesz); + if (cur_file == NULL) + return (ENOMEM); + + bzero(cur_file, filesz); + + status = file->Read(file, &filesz, cur_file); + if (EFI_ERROR(status)) { + free(cur_file); + return (efi_status_to_errno(status)); + } + + if (filesz == 0) { + free(cur_file); + return (ENOENT); + } + + bzero(d, sizeof(*d)); + + for (i = 0; i < sizeof(d->d_name); i++) { + d->d_name[i] = cur_file->FileName[i]; + if (cur_file->FileName[i] == L'\0') + break; + } + + free(cur_file); + + return (0); +} + + +static int efisfs_init(void); +static int efisfs_strategy(void *, int, daddr_t, size_t, char *, size_t *); +static int efisfs_open(struct open_file *, ...); +static int efisfs_close(struct open_file *); +static void efisfs_print(int); + +struct devsw efisfs_dev = { + .dv_name = "simplefs", + .dv_type = DEVT_FS, + .dv_init = efisfs_init, + .dv_strategy = efisfs_strategy, + .dv_open = efisfs_open, + .dv_close = efisfs_close, + .dv_ioctl = noioctl, + .dv_print = efisfs_print, + .dv_cleanup = NULL +}; + +static int +efisfs_init(void) +{ + EFI_FILE_IO_INTERFACE *fsio; + EFI_HANDLE *hin, *hout; + EFI_STATUS status; + UINTN sz; + u_int n, nin, nout; + int err; + + sz = 0; + hin = NULL; + status = BS->LocateHandle(ByProtocol, &sfs_guid, 0, &sz, 0); + if (status == EFI_BUFFER_TOO_SMALL) { + hin = (EFI_HANDLE *)malloc(sz * 2); + status = BS->LocateHandle(ByProtocol, &sfs_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], &sfs_guid, &fsio); + if (EFI_ERROR(status)) + continue; + if(fsio->Revision != EFI_FILE_IO_INTERFACE_REVISION) + continue; + hout[nout] = hin[n]; + nout++; + } + + err = efi_register_handles(&efisfs_dev, hout, nout); + free(hin); + return (err); +} + +static int +efisfs_strategy(void *devdata, int rw, daddr_t blk, size_t size, char *buf, + size_t *rsize) +{ + printf("efisfs_strategy\n"); + + return (ENXIO); +} + +static int +efisfs_open(struct open_file *f, ...) +{ + va_list args; + struct devdesc *dev; + EFI_FILE_IO_INTERFACE *fsio; + EFI_FILE *fileio; + EFI_HANDLE h; + EFI_STATUS status; + + va_start(args, f); + dev = va_arg(args, struct devdesc*); + va_end(args); + + h = efi_find_handle(&efisfs_dev, dev->d_unit); + if (h == NULL) + return (EINVAL); + + status = BS->HandleProtocol(h, &sfs_guid, &fsio); + if (EFI_ERROR(status)) + return (efi_status_to_errno(status)); + + if(fsio->Revision != EFI_FILE_IO_INTERFACE_REVISION) + return (EAGAIN); + + status = fsio->OpenVolume(fsio, &fileio); + if (EFI_ERROR(status)) + return (efi_status_to_errno(status)); + + dev->d_opendata = fileio; + return (0); +} + +static int +efisfs_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); +} + +static void +efisfs_print(int verbose) +{ + printf("efisfs_print\n"); +} +