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;
_______________________________________________
[email protected] mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "[email protected]"

Reply via email to