svn commit: r202273 - in head/sys/ia64: ia64 include

Marcel Moolenaar marcel at FreeBSD.org
Thu Jan 14 02:48:40 UTC 2010


Author: marcel
Date: Thu Jan 14 02:48:39 2010
New Revision: 202273
URL: http://svn.freebsd.org/changeset/base/202273

Log:
  Add ioctl requests to /dev/io on ia64 for reading and writing
  EFI variables. The primary reason for this is that it allows
  sysinstall(8) to add a boot menu item for the newly installed
  FreeBSD image.

Modified:
  head/sys/ia64/ia64/iodev_machdep.c
  head/sys/ia64/include/iodev.h

Modified: head/sys/ia64/ia64/iodev_machdep.c
==============================================================================
--- head/sys/ia64/ia64/iodev_machdep.c	Thu Jan 14 02:38:46 2010	(r202272)
+++ head/sys/ia64/ia64/iodev_machdep.c	Thu Jan 14 02:48:39 2010	(r202273)
@@ -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: head/sys/ia64/include/iodev.h
==============================================================================
--- head/sys/ia64/include/iodev.h	Thu Jan 14 02:38:46 2010	(r202272)
+++ head/sys/ia64/include/iodev.h	Thu Jan 14 02:48:39 2010	(r202273)
@@ -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;


More information about the svn-src-head mailing list