xref: /openbsd-src/sys/arch/sparc64/sparc64/openprom.c (revision 47c47feae40d23b370daf5f162f0e605e186b16a)
1 /*	$OpenBSD: openprom.c,v 1.23 2022/10/16 01:22:39 jsg Exp $	*/
2 /*	$NetBSD: openprom.c,v 1.4 2002/01/10 06:21:53 briggs Exp $ */
3 
4 /*
5  * Copyright (c) 1992, 1993
6  *	The Regents of the University of California.  All rights reserved.
7  *
8  * This software was developed by the Computer Systems Engineering group
9  * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
10  * contributed to Berkeley.
11  *
12  * All advertising materials mentioning features or use of this software
13  * must display the following acknowledgement:
14  *	This product includes software developed by the University of
15  *	California, Lawrence Berkeley Laboratory.
16  *
17  * Redistribution and use in source and binary forms, with or without
18  * modification, are permitted provided that the following conditions
19  * are met:
20  * 1. Redistributions of source code must retain the above copyright
21  *    notice, this list of conditions and the following disclaimer.
22  * 2. Redistributions in binary form must reproduce the above copyright
23  *    notice, this list of conditions and the following disclaimer in the
24  *    documentation and/or other materials provided with the distribution.
25  * 3. Neither the name of the University nor the names of its contributors
26  *    may be used to endorse or promote products derived from this software
27  *    without specific prior written permission.
28  *
29  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
30  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
31  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
32  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
33  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
34  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
35  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
36  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
37  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
38  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
39  * SUCH DAMAGE.
40  *
41  *	@(#)openprom.c	8.1 (Berkeley) 6/11/93
42  */
43 
44 #include <sys/param.h>
45 #include <sys/systm.h>
46 #include <sys/errno.h>
47 #include <sys/fcntl.h>
48 #include <sys/ioctl.h>
49 #include <sys/malloc.h>
50 #include <sys/conf.h>
51 #include <sys/device.h>
52 
53 #include <machine/openpromio.h>
54 #include <machine/autoconf.h>
55 #include <machine/conf.h>
56 #include <machine/mdesc.h>
57 
58 #include <dev/clock_subr.h>
59 #include <dev/ofw/openfirm.h>
60 
61 extern todr_chip_handle_t todr_handle;
62 
63 #define OPROMMAXPARAM		32
64 
65 static	int lastnode;			/* speed hack */
66 extern	int optionsnode;		/* node ID of ROM's options */
67 
68 static int openpromcheckid(int, int);
69 static int openpromgetstr(int, char *, char **);
70 
71 int
openpromopen(dev_t dev,int flags,int mode,struct proc * p)72 openpromopen(dev_t dev, int flags, int mode, struct proc *p)
73 {
74 
75 	return (0);
76 }
77 
78 int
openpromclose(dev_t dev,int flags,int mode,struct proc * p)79 openpromclose(dev_t dev, int flags, int mode, struct proc *p)
80 {
81 
82 	return (0);
83 }
84 
85 int
openpromread(dev_t dev,struct uio * uio,int flags)86 openpromread(dev_t dev, struct uio *uio, int flags)
87 {
88 #ifdef SUN4V
89 	int error;
90 	size_t data_len, len;
91 	caddr_t data, v;
92 
93 	switch (minor(dev)) {
94 	case 1:
95 		data = mdesc;
96 		data_len = mdesc_len;
97 		break;
98 	case 2:
99 		data = pri;
100 		data_len = pri_len;
101 		break;
102 	default:
103 		data = NULL;
104 		data_len = 0;
105 		break;
106 	}
107 
108 	if (data == NULL || data_len == 0)
109 		return (ENXIO);
110 
111 	if (uio->uio_offset < 0)
112 		return (EINVAL);
113 
114 	while (uio->uio_resid > 0) {
115 		if (uio->uio_offset >= data_len)
116 			break;
117 
118 		v = data + uio->uio_offset;
119 		len = data_len - uio->uio_offset;
120 		if (len > uio->uio_resid)
121 			len = uio->uio_resid;
122 
123 		error = uiomove(v, len, uio);
124 		if (error)
125 			return (error);
126 	}
127 
128 	return (0);
129 #else
130 	return (ENXIO);
131 #endif
132 }
133 
134 /*
135  * Verify target ID is valid (exists in the OPENPROM tree), as
136  * listed from node ID sid forward.
137  */
138 static int
openpromcheckid(int sid,int tid)139 openpromcheckid(int sid, int tid)
140 {
141 	for (; sid != 0; sid = OF_peer(sid))
142 		if (sid == tid || openpromcheckid(OF_child(sid), tid))
143 			return (1);
144 
145 	return (0);
146 }
147 
148 static int
openpromgetstr(int len,char * user,char ** cpp)149 openpromgetstr(int len, char *user, char **cpp)
150 {
151 	int error;
152 	char *cp;
153 
154 	/* Reject obvious bogus requests */
155 	if ((u_int)len > (8 * 1024) - 1)
156 		return (ENAMETOOLONG);
157 
158 	*cpp = cp = malloc(len + 1, M_TEMP, M_WAITOK);
159 	error = copyin(user, cp, len);
160 	cp[len] = '\0';
161 	return (error);
162 }
163 
164 int
openpromioctl(dev_t dev,u_long cmd,caddr_t data,int flags,struct proc * p)165 openpromioctl(dev_t dev, u_long cmd, caddr_t data, int flags, struct proc *p)
166 {
167 	struct opiocdesc *op;
168 	int node, len, ok, error, s;
169 	char *name, *value, *nextprop;
170 
171 	/* All too easy... */
172 	if (cmd == OPIOCGETOPTNODE) {
173 		*(int *)data = optionsnode;
174 		return (0);
175 	}
176 
177 	/* Verify node id */
178 	op = (struct opiocdesc *)data;
179 	node = op->op_nodeid;
180 	if (node != 0 && node != lastnode && node != optionsnode) {
181 		/* Not an easy one, must search for it */
182 		s = splhigh();
183 		ok = openpromcheckid(findroot(), node);
184 		splx(s);
185 		if (!ok)
186 			return (EINVAL);
187 		lastnode = node;
188 	}
189 
190 	name = value = NULL;
191 	error = 0;
192 	switch (cmd) {
193 
194 	case OPIOCGET:
195 		if ((flags & FREAD) == 0)
196 			return (EBADF);
197 		if (node == 0)
198 			return (EINVAL);
199 		error = openpromgetstr(op->op_namelen, op->op_name, &name);
200 		if (error)
201 			break;
202 		s = splhigh();
203 		len = getproplen(node, name);
204 		splx(s);
205 		if (len > op->op_buflen) {
206 			error = ENOMEM;
207 			break;
208 		}
209 		op->op_buflen = len;
210 		/* -1 means no entry; 0 means no value */
211 		if (len <= 0)
212 			break;
213 		value = malloc(len, M_TEMP, M_WAITOK);
214 		s = splhigh();
215 		error = getprop(node, name, 1, &len, (void **)&value);
216 		splx(s);
217 		if (error != 0)
218 			break;
219 		error = copyout(value, op->op_buf, len);
220 		break;
221 
222 	case OPIOCSET:
223 		if ((flags & FWRITE) == 0)
224 			return (EBADF);
225 		if (node == 0)
226 			return (EINVAL);
227 		error = openpromgetstr(op->op_namelen, op->op_name, &name);
228 		if (error)
229 			break;
230 		error = openpromgetstr(op->op_buflen, op->op_buf, &value);
231 		if (error)
232 			break;
233 		s = splhigh();
234 		/*
235 		 * Make sure we can write to nvram, which on many
236 		 * machines lives on the clock chip (and shares its
237 		 * address space with the clock).
238 		 */
239 		if (todr_handle)
240 			todr_wenable(todr_handle, 1);
241 		len = OF_setprop(node, name, value, op->op_buflen + 1);
242 		if (todr_handle)
243 			todr_wenable(todr_handle, 0);
244 		splx(s);
245 		if (len != op->op_buflen)
246 			error = EINVAL;
247 		break;
248 
249 	case OPIOCNEXTPROP:
250 		if ((flags & FREAD) == 0)
251 			return (EBADF);
252 		if (node == 0)
253 			return (EINVAL);
254 		error = openpromgetstr(op->op_namelen, op->op_name, &name);
255 		if (error)
256 			break;
257 		if (op->op_buflen <= 0) {
258 			error = ENAMETOOLONG;
259 			break;
260 		}
261 		value = nextprop = malloc(OPROMMAXPARAM, M_TEMP,
262 		    M_WAITOK | M_CANFAIL);
263 		if (nextprop == NULL) {
264 			error = ENOMEM;
265 			break;
266 		}
267 		s = splhigh();
268 		error = OF_nextprop(node, name, nextprop);
269 		splx(s);
270 		if (error == -1) {
271 			error = EINVAL;
272 			break;
273 		}
274 		if (error == 0) {
275 			char nul = '\0';
276 
277 			op->op_buflen = 0;
278 			error = copyout(&nul, op->op_buf, sizeof(char));
279 			break;
280 		}
281 		len = strlen(nextprop);
282 		if (len > op->op_buflen)
283 			len = op->op_buflen;
284 		else
285 			op->op_buflen = len;
286 		error = copyout(nextprop, op->op_buf, len);
287 		break;
288 
289 	case OPIOCGETNEXT:
290 		if ((flags & FREAD) == 0)
291 			return (EBADF);
292 		s = splhigh();
293 		node = nextsibling(node);
294 		splx(s);
295 		*(int *)data = lastnode = node;
296 		break;
297 
298 	case OPIOCGETCHILD:
299 		if ((flags & FREAD) == 0)
300 			return (EBADF);
301 		if (node == 0)
302 			return (EINVAL);
303 		s = splhigh();
304 		node = firstchild(node);
305 		splx(s);
306 		*(int *)data = lastnode = node;
307 		break;
308 
309 	default:
310 		return (ENOTTY);
311 	}
312 
313 	free(name, M_TEMP, 0);
314 	free(value, M_TEMP, 0);
315 
316 	return (error);
317 }
318