From owner-svn-src-all@FreeBSD.ORG Fri Jan 22 03:59:05 2010 Return-Path: Delivered-To: svn-src-all@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 658941065693; Fri, 22 Jan 2010 03:59:05 +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 53B428FC1B; Fri, 22 Jan 2010 03:59:05 +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 o0M3x5fS039201; Fri, 22 Jan 2010 03:59:05 GMT (envelope-from marcel@svn.freebsd.org) Received: (from marcel@localhost) by svn.freebsd.org (8.14.3/8.14.3/Submit) id o0M3x5Y0039196; Fri, 22 Jan 2010 03:59:05 GMT (envelope-from marcel@svn.freebsd.org) Message-Id: <201001220359.o0M3x5Y0039196@svn.freebsd.org> From: Marcel Moolenaar Date: Fri, 22 Jan 2010 03:59:05 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-8@freebsd.org X-SVN-Group: stable-8 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r202777 - in stable/8/sys/ia64: ia64 include X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 22 Jan 2010 03:59:05 -0000 Author: marcel Date: Fri Jan 22 03:59:05 2010 New Revision: 202777 URL: http://svn.freebsd.org/changeset/base/202777 Log: MFC rev. 202271-202273: o Add wrappers for the RT Variable Services. o Add ioctl requests to /dev/io on ia64 for reading and writing EFI variables. Modified: stable/8/sys/ia64/ia64/efi.c stable/8/sys/ia64/ia64/iodev_machdep.c stable/8/sys/ia64/include/efi.h stable/8/sys/ia64/include/iodev.h Directory Properties: stable/8/sys/ (props changed) stable/8/sys/amd64/include/xen/ (props changed) stable/8/sys/cddl/contrib/opensolaris/ (props changed) stable/8/sys/contrib/dev/acpica/ (props changed) stable/8/sys/contrib/pf/ (props changed) stable/8/sys/dev/xen/xenpci/ (props changed) Modified: stable/8/sys/ia64/ia64/efi.c ============================================================================== --- stable/8/sys/ia64/ia64/efi.c Fri Jan 22 03:50:43 2010 (r202776) +++ stable/8/sys/ia64/ia64/efi.c Fri Jan 22 03:59:05 2010 (r202777) @@ -41,6 +41,45 @@ static struct efi_systbl *efi_systbl; static struct efi_cfgtbl *efi_cfgtbl; static struct efi_rt *efi_runtime; +static int efi_status2err[25] = { + 0, /* EFI_SUCCESS */ + ENOEXEC, /* EFI_LOAD_ERROR */ + EINVAL, /* EFI_INVALID_PARAMETER */ + ENOSYS, /* EFI_UNSUPPORTED */ + EMSGSIZE, /* EFI_BAD_BUFFER_SIZE */ + EOVERFLOW, /* EFI_BUFFER_TOO_SMALL */ + EBUSY, /* EFI_NOT_READY */ + EIO, /* EFI_DEVICE_ERROR */ + EROFS, /* EFI_WRITE_PROTECTED */ + EAGAIN, /* EFI_OUT_OF_RESOURCES */ + EIO, /* EFI_VOLUME_CORRUPTED */ + ENOSPC, /* EFI_VOLUME_FULL */ + ENXIO, /* EFI_NO_MEDIA */ + ESTALE, /* EFI_MEDIA_CHANGED */ + ENOENT, /* EFI_NOT_FOUND */ + EACCES, /* EFI_ACCESS_DENIED */ + ETIMEDOUT, /* EFI_NO_RESPONSE */ + EADDRNOTAVAIL, /* EFI_NO_MAPPING */ + ETIMEDOUT, /* EFI_TIMEOUT */ + EDOOFUS, /* EFI_NOT_STARTED */ + EALREADY, /* EFI_ALREADY_STARTED */ + ECANCELED, /* EFI_ABORTED */ + EPROTO, /* EFI_ICMP_ERROR */ + EPROTO, /* EFI_TFTP_ERROR */ + EPROTO /* EFI_PROTOCOL_ERROR */ +}; + +static int +efi_status_to_errno(efi_status status) +{ + u_long code; + int error; + + code = status & 0x3ffffffffffffffful; + error = (code < 25) ? efi_status2err[code] : EDOOFUS; + return (error); +} + void efi_boot_finish(void) { @@ -148,9 +187,38 @@ efi_reset_system(void) panic("%s: unable to reset the machine", __func__); } -efi_status +int efi_set_time(struct efi_tm *tm) { - return (efi_runtime->rt_settime(tm)); + return (efi_status_to_errno(efi_runtime->rt_settime(tm))); +} + +int +efi_var_get(efi_char *name, struct uuid *vendor, uint32_t *attrib, + size_t *datasize, void *data) +{ + efi_status status; + + status = efi_runtime->rt_getvar(name, vendor, attrib, datasize, data); + return (efi_status_to_errno(status)); +} + +int +efi_var_nextname(size_t *namesize, efi_char *name, struct uuid *vendor) +{ + efi_status status; + + status = efi_runtime->rt_scanvar(namesize, name, vendor); + return (efi_status_to_errno(status)); +} + +int +efi_var_set(efi_char *name, struct uuid *vendor, uint32_t attrib, + size_t datasize, void *data) +{ + efi_status status; + + status = efi_runtime->rt_setvar(name, vendor, attrib, datasize, data); + return (efi_status_to_errno(status)); } Modified: stable/8/sys/ia64/ia64/iodev_machdep.c ============================================================================== --- stable/8/sys/ia64/ia64/iodev_machdep.c Fri Jan 22 03:50:43 2010 (r202776) +++ stable/8/sys/ia64/ia64/iodev_machdep.c Fri Jan 22 03:59:05 2010 (r202777) @@ -31,16 +31,22 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include #include #include +#include #include static int iodev_pio_read(struct iodev_pio_req *req); static int iodev_pio_write(struct iodev_pio_req *req); +static int iodev_efivar_getvar(struct iodev_efivar_req *req); +static int iodev_efivar_nextname(struct iodev_efivar_req *req); +static int iodev_efivar_setvar(struct iodev_efivar_req *req); + /* ARGSUSED */ int ioopen(struct cdev *dev __unused, int flags __unused, int fmt __unused, @@ -69,6 +75,7 @@ int ioioctl(struct cdev *dev __unused, u_long cmd, caddr_t data, int fflag __unused, struct thread *td __unused) { + struct iodev_efivar_req *efivar_req; struct iodev_pio_req *pio_req; int error; @@ -88,6 +95,24 @@ ioioctl(struct cdev *dev __unused, u_lon break; } break; + case IODEV_EFIVAR: + efivar_req = (struct iodev_efivar_req *)data; + efivar_req->result = 0; /* So it's well-defined */ + switch (efivar_req->access) { + case IODEV_EFIVAR_GETVAR: + error = iodev_efivar_getvar(efivar_req); + break; + case IODEV_EFIVAR_NEXTNAME: + error = iodev_efivar_nextname(efivar_req); + break; + case IODEV_EFIVAR_SETVAR: + error = iodev_efivar_setvar(efivar_req); + break; + default: + error = EINVAL; + break; + } + break; } return (error); @@ -158,3 +183,118 @@ iodev_pio_write(struct iodev_pio_req *re return (0); } + +static int +iodev_efivar_getvar(struct iodev_efivar_req *req) +{ + void *data; + efi_char *name; + int error; + + if ((req->namesize & 1) != 0 || req->namesize < 4) + return (EINVAL); + if (req->datasize == 0) + return (EINVAL); + + /* + * Pre-zero the allocated memory and don't copy the last 2 bytes + * of the name. That should be the closing nul character (ucs-2) + * and if not, then we ensured a nul-terminating string. This is + * to protect the firmware and thus ourselves. + */ + name = malloc(req->namesize, M_TEMP, M_WAITOK | M_ZERO); + error = copyin(req->name, name, req->namesize - 2); + if (error) { + free(name, M_TEMP); + return (error); + } + + data = malloc(req->datasize, M_TEMP, M_WAITOK); + error = efi_var_get(name, &req->vendor, &req->attrib, &req->datasize, + data); + if (error == EOVERFLOW || error == ENOENT) { + req->result = error; + error = 0; + } + if (!error && !req->result) + error = copyout(data, req->data, req->datasize); + + free(data, M_TEMP); + free(name, M_TEMP); + return (error); +} + +static int +iodev_efivar_nextname(struct iodev_efivar_req *req) +{ + efi_char *name; + int error; + + /* Enforce a reasonable minimum size of the name buffer. */ + if (req->namesize < 4) + return (EINVAL); + + name = malloc(req->namesize, M_TEMP, M_WAITOK); + error = copyin(req->name, name, req->namesize); + if (error) { + free(name, M_TEMP); + return (error); + } + + error = efi_var_nextname(&req->namesize, name, &req->vendor); + if (error == EOVERFLOW || error == ENOENT) { + req->result = error; + error = 0; + } + if (!error && !req->result) + error = copyout(name, req->name, req->namesize); + + free(name, M_TEMP); + return (error); +} + +static int +iodev_efivar_setvar(struct iodev_efivar_req *req) +{ + void *data; + efi_char *name; + int error; + + if ((req->namesize & 1) != 0 || req->namesize < 4) + return (EINVAL); + + /* + * Pre-zero the allocated memory and don't copy the last 2 bytes + * of the name. That should be the closing nul character (ucs-2) + * and if not, then we ensured a nul-terminating string. This is + * to protect the firmware and thus ourselves. + */ + name = malloc(req->namesize, M_TEMP, M_WAITOK | M_ZERO); + error = copyin(req->name, name, req->namesize - 2); + if (error) { + free(name, M_TEMP); + return (error); + } + + if (req->datasize) { + data = malloc(req->datasize, M_TEMP, M_WAITOK); + error = copyin(req->data, data, req->datasize); + if (error) { + free(data, M_TEMP); + free(name, M_TEMP); + return (error); + } + } else + data = NULL; + + error = efi_var_set(name, &req->vendor, req->attrib, req->datasize, + data); + if (error == EAGAIN || error == ENOENT) { + req->result = error; + error = 0; + } + + free(data, M_TEMP); + free(name, M_TEMP); + return (error); +} Modified: stable/8/sys/ia64/include/efi.h ============================================================================== --- stable/8/sys/ia64/include/efi.h Fri Jan 22 03:50:43 2010 (r202776) +++ stable/8/sys/ia64/include/efi.h Fri Jan 22 03:59:05 2010 (r202777) @@ -158,6 +158,9 @@ void efi_get_time(struct efi_tm *); struct efi_md *efi_md_first(void); struct efi_md *efi_md_next(struct efi_md *); void efi_reset_system(void); -efi_status efi_set_time(struct efi_tm *); +int efi_set_time(struct efi_tm *); +int efi_var_get(efi_char *, struct uuid *, uint32_t *, size_t *, void *); +int efi_var_nextname(size_t *, efi_char *, struct uuid *); +int efi_var_set(efi_char *, struct uuid *, uint32_t, size_t, void *); #endif /* _MACHINE_EFI_H_ */ Modified: stable/8/sys/ia64/include/iodev.h ============================================================================== --- stable/8/sys/ia64/include/iodev.h Fri Jan 22 03:50:43 2010 (r202776) +++ stable/8/sys/ia64/include/iodev.h Fri Jan 22 03:59:05 2010 (r202777) @@ -29,6 +29,8 @@ #ifndef _MACHINE_IODEV_H_ #define _MACHINE_IODEV_H_ +#include + struct iodev_pio_req { u_int access; #define IODEV_PIO_READ 0 @@ -40,6 +42,22 @@ struct iodev_pio_req { #define IODEV_PIO _IOWR('I', 0, struct iodev_pio_req) +struct iodev_efivar_req { + u_int access; +#define IODEV_EFIVAR_GETVAR 0 +#define IODEV_EFIVAR_NEXTNAME 1 +#define IODEV_EFIVAR_SETVAR 2 + u_int result; /* errno value */ + size_t namesize; + u_short *name; /* UCS-2 */ + struct uuid vendor; + uint32_t attrib; + size_t datasize; + void *data; +}; + +#define IODEV_EFIVAR _IOWR('I', 1, struct iodev_efivar_req) + #ifdef _KERNEL d_open_t ioopen;