Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 22 Jan 2010 03:59:05 +0000 (UTC)
From:      Marcel Moolenaar <marcel@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-8@freebsd.org
Subject:   svn commit: r202777 - in stable/8/sys/ia64: ia64 include
Message-ID:  <201001220359.o0M3x5Y0039196@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
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 <sys/conf.h>
 #include <sys/fcntl.h>
 #include <sys/ioccom.h>
+#include <sys/malloc.h>
 #include <sys/priv.h>
 #include <sys/proc.h>
 #include <sys/systm.h>
 
 #include <machine/bus.h>
+#include <machine/efi.h>
 #include <machine/iodev.h>
 
 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 <sys/uuid.h>
+
 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;



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201001220359.o0M3x5Y0039196>