xref: /illumos-gate/usr/src/psm/promif/ieee1275/common/prom_io.c (revision 2b24ab6b3865caeede9eeb9db6b83e1d89dcd1ea)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 #include <sys/promif.h>
30 #include <sys/promimpl.h>
31 
32 /*
33  *  Returns 0 on error. Otherwise returns a handle.
34  */
35 int
36 prom_open(char *path)
37 {
38 	cell_t ci[5];
39 	promif_owrap_t *ow;
40 #ifdef PROM_32BIT_ADDRS
41 	char *opath = NULL;
42 	size_t len;
43 
44 	if ((uintptr_t)path > (uint32_t)-1) {
45 		opath = path;
46 		len = prom_strlen(opath) + 1; /* include terminating NUL */
47 		path = promplat_alloc(len);
48 		if (path == NULL)
49 			return (0);
50 		(void) prom_strcpy(path, opath);
51 	}
52 #endif
53 
54 	ow = promif_preout();
55 	promif_preprom();
56 	ci[0] = p1275_ptr2cell("open");		/* Service name */
57 	ci[1] = (cell_t)1;			/* #argument cells */
58 	ci[2] = (cell_t)1;			/* #result cells */
59 	ci[3] = p1275_ptr2cell(path);		/* Arg1: Pathname */
60 	ci[4] = (cell_t)0;			/* Res1: Prime result */
61 
62 	(void) p1275_cif_handler(&ci);
63 
64 	promif_postprom();
65 	promif_postout(ow);
66 
67 #ifdef PROM_32BIT_ADDRS
68 	if (opath != NULL)
69 		promplat_free(path, len);
70 #endif
71 
72 	return (p1275_cell2int(ci[4]));		/* Res1: ihandle */
73 }
74 
75 
76 int
77 prom_seek(int fd, unsigned long long offset)
78 {
79 	cell_t ci[7];
80 
81 	ci[0] = p1275_ptr2cell("seek");		/* Service name */
82 	ci[1] = (cell_t)3;			/* #argument cells */
83 	ci[2] = (cell_t)1;			/* #result cells */
84 	ci[3] = p1275_uint2cell((uint_t)fd);	/* Arg1: ihandle */
85 	ci[4] = p1275_ull2cell_high(offset);	/* Arg2: pos.hi */
86 	ci[5] = p1275_ull2cell_low(offset);	/* Arg3: pos.lo */
87 	ci[6] = (cell_t)-1;			/* Res1: Prime result */
88 
89 	promif_preprom();
90 	(void) p1275_cif_handler(&ci);
91 	promif_postprom();
92 
93 	return (p1275_cell2int(ci[6]));		/* Res1: actual */
94 }
95 
96 /*ARGSUSED3*/
97 ssize_t
98 prom_read(ihandle_t fd, caddr_t buf, size_t len, uint_t startblk, char devtype)
99 {
100 	cell_t ci[7];
101 	promif_owrap_t *ow;
102 #ifdef PROM_32BIT_ADDRS
103 	caddr_t obuf = NULL;
104 
105 	if ((uintptr_t)buf > (uint32_t)-1) {
106 		obuf = buf;
107 		buf = promplat_alloc(len);
108 		if (buf == NULL)
109 			return (-1);
110 	}
111 #endif
112 
113 	ow = promif_preout();
114 	promif_preprom();
115 
116 	ci[0] = p1275_ptr2cell("read");		/* Service name */
117 	ci[1] = (cell_t)3;			/* #argument cells */
118 	ci[2] = (cell_t)1;			/* #result cells */
119 	ci[3] = p1275_size2cell((uint_t)fd);	/* Arg1: ihandle */
120 	ci[4] = p1275_ptr2cell(buf);		/* Arg2: buffer address */
121 	ci[5] = p1275_uint2cell(len);		/* Arg3: buffer length */
122 	ci[6] = (cell_t)-1;			/* Res1: Prime result */
123 
124 	(void) p1275_cif_handler(&ci);
125 
126 	promif_postprom();
127 	promif_postout(ow);
128 
129 #ifdef PROM_32BIT_ADDRS
130 	if (obuf != NULL) {
131 		promplat_bcopy(buf, obuf, len);
132 		promplat_free(buf, len);
133 	}
134 #endif
135 
136 	return (p1275_cell2size(ci[6]));	/* Res1: actual length */
137 }
138 
139 /*
140  * prom_write is the only prom_*() function we have to intercept
141  * because all the other prom_*() io interfaces eventually call
142  * into prom_write().
143  */
144 /*ARGSUSED3*/
145 ssize_t
146 prom_write(ihandle_t fd, caddr_t buf, size_t len, uint_t startblk, char devtype)
147 {
148 	cell_t ci[7];
149 	promif_owrap_t *ow;
150 	ssize_t rlen;
151 
152 #ifdef PROM_32BIT_ADDRS
153 	caddr_t obuf = NULL;
154 	static char smallbuf[256];
155 
156 	ASSERT(buf);
157 
158 	if ((uintptr_t)buf > (uint32_t)-1) {
159 		/*
160 		 * This is a hack for kernel message output.
161 		 * By avoiding calls to promplat_alloc (and
162 		 * using smallbuf instead) when memory is low
163 		 * we can print shortish kernel messages without
164 		 * deadlocking. smallbuf should be at least as
165 		 * large as the automatic buffer in
166 		 * prom_printf.c:_doprint()'s stack frame.
167 		 * promplat_alloc() can block on a mutex and so
168 		 * is called here before calling promif_preprom().
169 		 */
170 
171 		if (len > sizeof (smallbuf)) {
172 			obuf = buf;
173 			buf = promplat_alloc(len);
174 			if (buf == NULL) {
175 				return (-1);
176 			}
177 			promplat_bcopy(obuf, buf, len);
178 		}
179 	}
180 #endif
181 
182 	ow = promif_preout();
183 	promif_preprom();
184 
185 #ifdef PROM_32BIT_ADDRS
186 
187 	if ((uintptr_t)buf > (uint32_t)-1) {
188 		/*
189 		 * If buf is small enough, use smallbuf
190 		 * instead of promplat_alloc() (see above)
191 		 * smallbuf is static, so single thread
192 		 * access to it by using it only after
193 		 * promif_preprom()
194 		 */
195 		if (len <= sizeof (smallbuf)) {
196 			promplat_bcopy(buf, smallbuf, len);
197 			buf = smallbuf;
198 		}
199 	}
200 #endif
201 	/*
202 	 * If the callback address is set, attempt to redirect
203 	 * console output back into kernel terminal emulator.
204 	 */
205 	if (promif_redirect != NULL &&
206 	    fd == prom_stdout_ihandle()) {
207 		/*
208 		 * even if we're re-directing output to the kernel
209 		 * console device, we still have to call promif_preout()
210 		 * and promif_preprom() because these functions make sure
211 		 * that the console device is powered up before sending
212 		 * output to it.
213 		 */
214 		rlen = promif_redirect(promif_redirect_arg,
215 		    (uchar_t *)buf, len);
216 	} else {
217 		ci[0] = p1275_ptr2cell("write");	/* Service name */
218 		ci[1] = (cell_t)3;			/* #argument cells */
219 		ci[2] = (cell_t)1;			/* #result cells */
220 		ci[3] = p1275_uint2cell((uint_t)fd);	/* Arg1: ihandle */
221 		ci[4] = p1275_ptr2cell(buf);		/* Arg2: buffer addr */
222 		ci[5] = p1275_size2cell(len);		/* Arg3: buffer len */
223 		ci[6] = (cell_t)-1;			/* Res1: Prime result */
224 
225 		(void) p1275_cif_handler(&ci);
226 		rlen = p1275_cell2size(ci[6]);		/* Res1: actual len */
227 	}
228 
229 	promif_postprom();
230 	promif_postout(ow);
231 
232 #ifdef PROM_32BIT_ADDRS
233 	if (obuf != NULL)
234 		promplat_free(buf, len);
235 #endif
236 
237 	return (rlen);
238 }
239 
240 int
241 prom_close(int fd)
242 {
243 	cell_t ci[4];
244 	promif_owrap_t *ow;
245 
246 	ci[0] = p1275_ptr2cell("close");	/* Service name */
247 	ci[1] = (cell_t)1;			/* #argument cells */
248 	ci[2] = (cell_t)0;			/* #result cells */
249 	ci[3] = p1275_uint2cell((uint_t)fd);	/* Arg1: ihandle */
250 
251 	ow = promif_preout();
252 	promif_preprom();
253 	(void) p1275_cif_handler(&ci);
254 	promif_postprom();
255 	promif_postout(ow);
256 
257 	return (0);
258 }
259