1202097Smarcel/*- 2202097Smarcel * Copyright (c) 2010 Marcel Moolenaar 3202097Smarcel * All rights reserved. 4202097Smarcel * 5202097Smarcel * Redistribution and use in source and binary forms, with or without 6202097Smarcel * modification, are permitted provided that the following conditions 7202097Smarcel * are met: 8202097Smarcel * 1. Redistributions of source code must retain the above copyright 9202097Smarcel * notice, this list of conditions and the following disclaimer. 10202097Smarcel * 2. Redistributions in binary form must reproduce the above copyright 11202097Smarcel * notice, this list of conditions and the following disclaimer in the 12202097Smarcel * documentation and/or other materials provided with the distribution. 13202097Smarcel * 14202097Smarcel * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15202097Smarcel * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16202097Smarcel * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17202097Smarcel * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18202097Smarcel * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19202097Smarcel * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20202097Smarcel * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21202097Smarcel * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22202097Smarcel * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23202097Smarcel * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24202097Smarcel * SUCH DAMAGE. 25202097Smarcel */ 26202097Smarcel 27202097Smarcel#include <sys/cdefs.h> 28202097Smarcel__FBSDID("$FreeBSD$"); 29202097Smarcel 30202097Smarcel#include <sys/param.h> 31202097Smarcel#include <sys/conf.h> 32202097Smarcel#include <sys/fcntl.h> 33202097Smarcel#include <sys/ioccom.h> 34202273Smarcel#include <sys/malloc.h> 35202097Smarcel#include <sys/priv.h> 36202097Smarcel#include <sys/proc.h> 37202097Smarcel#include <sys/systm.h> 38202097Smarcel 39202097Smarcel#include <machine/bus.h> 40202273Smarcel#include <machine/efi.h> 41202097Smarcel#include <machine/iodev.h> 42202097Smarcel 43202273Smarcelstatic int iodev_efivar_getvar(struct iodev_efivar_req *req); 44202273Smarcelstatic int iodev_efivar_nextname(struct iodev_efivar_req *req); 45202273Smarcelstatic int iodev_efivar_setvar(struct iodev_efivar_req *req); 46202273Smarcel 47202097Smarcel/* ARGSUSED */ 48202097Smarcelint 49207329Sattilioiodev_open(struct thread *td __unused) 50202097Smarcel{ 51202097Smarcel 52207329Sattilio return (0); 53202097Smarcel} 54202097Smarcel 55202097Smarcel/* ARGSUSED */ 56202097Smarcelint 57207329Sattilioiodev_close(struct thread *td __unused) 58202097Smarcel{ 59202097Smarcel 60202097Smarcel return (0); 61202097Smarcel} 62202097Smarcel 63202097Smarcelint 64207329Sattilioiodev_ioctl(u_long cmd, caddr_t data) 65202097Smarcel{ 66202273Smarcel struct iodev_efivar_req *efivar_req; 67202097Smarcel int error; 68202097Smarcel 69202097Smarcel switch (cmd) { 70202273Smarcel case IODEV_EFIVAR: 71202273Smarcel efivar_req = (struct iodev_efivar_req *)data; 72202273Smarcel efivar_req->result = 0; /* So it's well-defined */ 73202273Smarcel switch (efivar_req->access) { 74202273Smarcel case IODEV_EFIVAR_GETVAR: 75202273Smarcel error = iodev_efivar_getvar(efivar_req); 76202273Smarcel break; 77202273Smarcel case IODEV_EFIVAR_NEXTNAME: 78202273Smarcel error = iodev_efivar_nextname(efivar_req); 79202273Smarcel break; 80202273Smarcel case IODEV_EFIVAR_SETVAR: 81202273Smarcel error = iodev_efivar_setvar(efivar_req); 82202273Smarcel break; 83202273Smarcel default: 84202273Smarcel error = EINVAL; 85202273Smarcel break; 86202273Smarcel } 87202273Smarcel break; 88207329Sattilio default: 89207329Sattilio error = ENOIOCTL; 90202097Smarcel } 91202097Smarcel 92202097Smarcel return (error); 93202097Smarcel} 94202097Smarcel 95202097Smarcelstatic int 96202273Smarceliodev_efivar_getvar(struct iodev_efivar_req *req) 97202273Smarcel{ 98202273Smarcel void *data; 99202273Smarcel efi_char *name; 100202273Smarcel int error; 101202273Smarcel 102202273Smarcel if ((req->namesize & 1) != 0 || req->namesize < 4) 103202273Smarcel return (EINVAL); 104202273Smarcel if (req->datasize == 0) 105202273Smarcel return (EINVAL); 106202273Smarcel 107202273Smarcel /* 108202273Smarcel * Pre-zero the allocated memory and don't copy the last 2 bytes 109202273Smarcel * of the name. That should be the closing nul character (ucs-2) 110202273Smarcel * and if not, then we ensured a nul-terminating string. This is 111202273Smarcel * to protect the firmware and thus ourselves. 112202273Smarcel */ 113202273Smarcel name = malloc(req->namesize, M_TEMP, M_WAITOK | M_ZERO); 114202273Smarcel error = copyin(req->name, name, req->namesize - 2); 115202273Smarcel if (error) { 116202273Smarcel free(name, M_TEMP); 117202273Smarcel return (error); 118202273Smarcel } 119202273Smarcel 120202273Smarcel data = malloc(req->datasize, M_TEMP, M_WAITOK); 121202273Smarcel error = efi_var_get(name, &req->vendor, &req->attrib, &req->datasize, 122202273Smarcel data); 123202273Smarcel if (error == EOVERFLOW || error == ENOENT) { 124202273Smarcel req->result = error; 125202273Smarcel error = 0; 126202273Smarcel } 127202273Smarcel if (!error && !req->result) 128202273Smarcel error = copyout(data, req->data, req->datasize); 129202273Smarcel 130202273Smarcel free(data, M_TEMP); 131202273Smarcel free(name, M_TEMP); 132202273Smarcel return (error); 133202273Smarcel} 134202273Smarcel 135202273Smarcelstatic int 136202273Smarceliodev_efivar_nextname(struct iodev_efivar_req *req) 137202273Smarcel{ 138202273Smarcel efi_char *name; 139202273Smarcel int error; 140202273Smarcel 141202273Smarcel /* Enforce a reasonable minimum size of the name buffer. */ 142202273Smarcel if (req->namesize < 4) 143202273Smarcel return (EINVAL); 144202273Smarcel 145202273Smarcel name = malloc(req->namesize, M_TEMP, M_WAITOK); 146202273Smarcel error = copyin(req->name, name, req->namesize); 147202273Smarcel if (error) { 148202273Smarcel free(name, M_TEMP); 149202273Smarcel return (error); 150202273Smarcel } 151202273Smarcel 152202273Smarcel error = efi_var_nextname(&req->namesize, name, &req->vendor); 153202273Smarcel if (error == EOVERFLOW || error == ENOENT) { 154202273Smarcel req->result = error; 155202273Smarcel error = 0; 156202273Smarcel } 157202273Smarcel if (!error && !req->result) 158202273Smarcel error = copyout(name, req->name, req->namesize); 159202273Smarcel 160202273Smarcel free(name, M_TEMP); 161202273Smarcel return (error); 162202273Smarcel} 163202273Smarcel 164202273Smarcelstatic int 165202273Smarceliodev_efivar_setvar(struct iodev_efivar_req *req) 166202273Smarcel{ 167202273Smarcel void *data; 168202273Smarcel efi_char *name; 169202273Smarcel int error; 170202273Smarcel 171202273Smarcel if ((req->namesize & 1) != 0 || req->namesize < 4) 172202273Smarcel return (EINVAL); 173202273Smarcel 174202273Smarcel /* 175202273Smarcel * Pre-zero the allocated memory and don't copy the last 2 bytes 176202273Smarcel * of the name. That should be the closing nul character (ucs-2) 177202273Smarcel * and if not, then we ensured a nul-terminating string. This is 178202273Smarcel * to protect the firmware and thus ourselves. 179202273Smarcel */ 180202273Smarcel name = malloc(req->namesize, M_TEMP, M_WAITOK | M_ZERO); 181202273Smarcel error = copyin(req->name, name, req->namesize - 2); 182202273Smarcel if (error) { 183202273Smarcel free(name, M_TEMP); 184202273Smarcel return (error); 185202273Smarcel } 186202273Smarcel 187202273Smarcel if (req->datasize) { 188202273Smarcel data = malloc(req->datasize, M_TEMP, M_WAITOK); 189202273Smarcel error = copyin(req->data, data, req->datasize); 190202273Smarcel if (error) { 191202273Smarcel free(data, M_TEMP); 192202273Smarcel free(name, M_TEMP); 193202273Smarcel return (error); 194202273Smarcel } 195202273Smarcel } else 196202273Smarcel data = NULL; 197202273Smarcel 198202273Smarcel error = efi_var_set(name, &req->vendor, req->attrib, req->datasize, 199202273Smarcel data); 200202273Smarcel if (error == EAGAIN || error == ENOENT) { 201202273Smarcel req->result = error; 202202273Smarcel error = 0; 203202273Smarcel } 204202273Smarcel 205202273Smarcel free(data, M_TEMP); 206202273Smarcel free(name, M_TEMP); 207202273Smarcel return (error); 208202273Smarcel} 209