]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - sys/ia64/ia64/iodev_machdep.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.git] / sys / ia64 / ia64 / iodev_machdep.c
1 /*-
2  * Copyright (c) 2010 Marcel Moolenaar
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  */
26
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
29
30 #include <sys/param.h>
31 #include <sys/conf.h>
32 #include <sys/fcntl.h>
33 #include <sys/ioccom.h>
34 #include <sys/malloc.h>
35 #include <sys/priv.h>
36 #include <sys/proc.h>
37 #include <sys/systm.h>
38
39 #include <machine/bus.h>
40 #include <machine/efi.h>
41 #include <machine/iodev.h>
42
43 static int iodev_efivar_getvar(struct iodev_efivar_req *req);
44 static int iodev_efivar_nextname(struct iodev_efivar_req *req);
45 static int iodev_efivar_setvar(struct iodev_efivar_req *req);
46
47 /* ARGSUSED */
48 int
49 iodev_open(struct thread *td __unused)
50 {
51
52         return (0);
53 }
54
55 /* ARGSUSED */
56 int
57 iodev_close(struct thread *td __unused)
58 {
59
60         return (0);
61 }
62
63 int
64 iodev_ioctl(u_long cmd, caddr_t data)
65 {
66         struct iodev_efivar_req *efivar_req;
67         int error;
68
69         switch (cmd) {
70         case IODEV_EFIVAR:
71                 efivar_req = (struct iodev_efivar_req *)data;
72                 efivar_req->result = 0;         /* So it's well-defined */
73                 switch (efivar_req->access) {
74                 case IODEV_EFIVAR_GETVAR:
75                         error = iodev_efivar_getvar(efivar_req);
76                         break;
77                 case IODEV_EFIVAR_NEXTNAME:
78                         error = iodev_efivar_nextname(efivar_req);
79                         break;
80                 case IODEV_EFIVAR_SETVAR:
81                         error = iodev_efivar_setvar(efivar_req);
82                         break;
83                 default:
84                         error = EINVAL;
85                         break;
86                 }
87                 break;
88         default:
89                 error = ENOIOCTL;
90         }
91
92         return (error);
93 }
94
95 static int
96 iodev_efivar_getvar(struct iodev_efivar_req *req)
97 {
98         void *data;
99         efi_char *name;
100         int error;
101
102         if ((req->namesize & 1) != 0 || req->namesize < 4)
103                 return (EINVAL);
104         if (req->datasize == 0)
105                 return (EINVAL);
106
107         /*
108          * Pre-zero the allocated memory and don't copy the last 2 bytes
109          * of the name. That should be the closing nul character (ucs-2)
110          * and if not, then we ensured a nul-terminating string. This is
111          * to protect the firmware and thus ourselves.
112          */
113         name = malloc(req->namesize, M_TEMP, M_WAITOK | M_ZERO);
114         error = copyin(req->name, name, req->namesize - 2);
115         if (error) {
116                 free(name, M_TEMP);
117                 return (error);
118         }
119
120         data = malloc(req->datasize, M_TEMP, M_WAITOK);
121         error = efi_var_get(name, &req->vendor, &req->attrib, &req->datasize,
122             data);
123         if (error == EOVERFLOW || error == ENOENT) {
124                 req->result = error;
125                 error = 0;
126         }
127         if (!error && !req->result)
128                 error = copyout(data, req->data, req->datasize);
129
130         free(data, M_TEMP);
131         free(name, M_TEMP);
132         return (error);
133 }
134
135 static int 
136 iodev_efivar_nextname(struct iodev_efivar_req *req) 
137 {
138         efi_char *name;
139         int error;
140
141         /* Enforce a reasonable minimum size of the name buffer. */
142         if (req->namesize < 4)
143                 return (EINVAL);
144
145         name = malloc(req->namesize, M_TEMP, M_WAITOK);
146         error = copyin(req->name, name, req->namesize);
147         if (error) {
148                 free(name, M_TEMP);
149                 return (error);
150         }
151
152         error = efi_var_nextname(&req->namesize, name, &req->vendor);
153         if (error == EOVERFLOW || error == ENOENT) {
154                 req->result = error;
155                 error = 0;
156         }
157         if (!error && !req->result)
158                 error = copyout(name, req->name, req->namesize);
159
160         free(name, M_TEMP);
161         return (error);
162 }
163
164 static int 
165 iodev_efivar_setvar(struct iodev_efivar_req *req) 
166 {
167         void *data;
168         efi_char *name;
169         int error;
170
171         if ((req->namesize & 1) != 0 || req->namesize < 4)
172                 return (EINVAL);
173
174         /*
175          * Pre-zero the allocated memory and don't copy the last 2 bytes
176          * of the name. That should be the closing nul character (ucs-2)
177          * and if not, then we ensured a nul-terminating string. This is
178          * to protect the firmware and thus ourselves.
179          */
180         name = malloc(req->namesize, M_TEMP, M_WAITOK | M_ZERO);
181         error = copyin(req->name, name, req->namesize - 2);
182         if (error) {
183                 free(name, M_TEMP);
184                 return (error);
185         }
186
187         if (req->datasize) {
188                 data = malloc(req->datasize, M_TEMP, M_WAITOK);
189                 error = copyin(req->data, data, req->datasize);
190                 if (error) {
191                         free(data, M_TEMP);
192                         free(name, M_TEMP);
193                         return (error);
194                 }
195         } else
196                 data = NULL;
197
198         error = efi_var_set(name, &req->vendor, req->attrib, req->datasize,
199             data);
200         if (error == EAGAIN || error == ENOENT) {
201                 req->result = error;
202                 error = 0;
203         }
204
205         free(data, M_TEMP);
206         free(name, M_TEMP);
207         return (error);
208 }