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 (c) 1991, 2010, Oracle and/or its affiliates. All rights reserved.
24  */
25 
26 #include <sys/promif.h>
27 #include <sys/promimpl.h>
28 
29 /*
30  *  Returns 0 on error. Otherwise returns a handle.
31  */
32 int
prom_open(char * path)33 prom_open(char *path)
34 {
35 	cell_t ci[5];
36 	promif_owrap_t *ow;
37 #ifdef PROM_32BIT_ADDRS
38 	char *opath = NULL;
39 	size_t len;
40 
41 	if ((uintptr_t)path > (uint32_t)-1) {
42 		opath = path;
43 		len = prom_strlen(opath) + 1; /* include terminating NUL */
44 		path = promplat_alloc(len);
45 		if (path == NULL)
46 			return (0);
47 		(void) prom_strcpy(path, opath);
48 	}
49 #endif
50 
51 	ow = promif_preout();
52 	promif_preprom();
53 	ci[0] = p1275_ptr2cell("open");		/* Service name */
54 	ci[1] = (cell_t)1;			/* #argument cells */
55 	ci[2] = (cell_t)1;			/* #result cells */
56 	ci[3] = p1275_ptr2cell(path);		/* Arg1: Pathname */
57 	ci[4] = (cell_t)0;			/* Res1: Prime result */
58 
59 	(void) p1275_cif_handler(&ci);
60 
61 	promif_postprom();
62 	promif_postout(ow);
63 
64 #ifdef PROM_32BIT_ADDRS
65 	if (opath != NULL)
66 		promplat_free(path, len);
67 #endif
68 
69 	return (p1275_cell2int(ci[4]));		/* Res1: ihandle */
70 }
71 
72 
73 int
prom_seek(int fd,unsigned long long offset)74 prom_seek(int fd, unsigned long long offset)
75 {
76 	cell_t ci[7];
77 
78 	ci[0] = p1275_ptr2cell("seek");		/* Service name */
79 	ci[1] = (cell_t)3;			/* #argument cells */
80 	ci[2] = (cell_t)1;			/* #result cells */
81 	ci[3] = p1275_uint2cell((uint_t)fd);	/* Arg1: ihandle */
82 	ci[4] = p1275_ull2cell_high(offset);	/* Arg2: pos.hi */
83 	ci[5] = p1275_ull2cell_low(offset);	/* Arg3: pos.lo */
84 	ci[6] = (cell_t)-1;			/* Res1: Prime result */
85 
86 	promif_preprom();
87 	(void) p1275_cif_handler(&ci);
88 	promif_postprom();
89 
90 	return (p1275_cell2int(ci[6]));		/* Res1: actual */
91 }
92 
93 /*ARGSUSED3*/
94 ssize_t
prom_read(ihandle_t fd,caddr_t buf,size_t len,uint_t startblk,char devtype)95 prom_read(ihandle_t fd, caddr_t buf, size_t len, uint_t startblk, char devtype)
96 {
97 	cell_t ci[7];
98 	promif_owrap_t *ow;
99 #ifdef PROM_32BIT_ADDRS
100 	caddr_t obuf = NULL;
101 
102 	if ((uintptr_t)buf > (uint32_t)-1) {
103 		obuf = buf;
104 		buf = promplat_alloc(len);
105 		if (buf == NULL)
106 			return (-1);
107 	}
108 #endif
109 
110 	ow = promif_preout();
111 	promif_preprom();
112 
113 	ci[0] = p1275_ptr2cell("read");		/* Service name */
114 	ci[1] = (cell_t)3;			/* #argument cells */
115 	ci[2] = (cell_t)1;			/* #result cells */
116 	ci[3] = p1275_size2cell((uint_t)fd);	/* Arg1: ihandle */
117 	ci[4] = p1275_ptr2cell(buf);		/* Arg2: buffer address */
118 	ci[5] = p1275_uint2cell(len);		/* Arg3: buffer length */
119 	ci[6] = (cell_t)-1;			/* Res1: Prime result */
120 
121 	(void) p1275_cif_handler(&ci);
122 
123 	promif_postprom();
124 	promif_postout(ow);
125 
126 #ifdef PROM_32BIT_ADDRS
127 	if (obuf != NULL) {
128 		promplat_bcopy(buf, obuf, len);
129 		promplat_free(buf, len);
130 	}
131 #endif
132 
133 	return (p1275_cell2size(ci[6]));	/* Res1: actual length */
134 }
135 
136 /*
137  * prom_write is the only prom_*() function we have to intercept
138  * because all the other prom_*() io interfaces eventually call
139  * into prom_write().
140  */
141 /*ARGSUSED3*/
142 ssize_t
prom_write(ihandle_t fd,caddr_t buf,size_t len,uint_t startblk,char devtype)143 prom_write(ihandle_t fd, caddr_t buf, size_t len, uint_t startblk, char devtype)
144 {
145 	cell_t ci[7];
146 	promif_owrap_t *ow;
147 	ssize_t rlen;
148 
149 #ifdef PROM_32BIT_ADDRS
150 	caddr_t obuf = NULL;
151 	static char smallbuf[256];
152 
153 	ASSERT(buf);
154 #endif
155 
156 	/*
157 	 * If the callback address is set, attempt to redirect
158 	 * console output back into kernel terminal emulator.
159 	 */
160 	if (promif_redirect != NULL && fd == prom_stdout_ihandle()) {
161 		ow = promif_preout();
162 		rlen = promif_redirect(promif_redirect_arg, (uchar_t *)buf,
163 		    len);
164 		promif_postout(ow);
165 		return (rlen);
166 	}
167 
168 #ifdef PROM_32BIT_ADDRS
169 	if ((uintptr_t)buf > (uint32_t)-1) {
170 		/*
171 		 * This is a hack for kernel message output.
172 		 * By avoiding calls to promplat_alloc (and
173 		 * using smallbuf instead) when memory is low
174 		 * we can print shortish kernel messages without
175 		 * deadlocking. smallbuf should be at least as
176 		 * large as the automatic buffer in
177 		 * prom_printf.c:_doprint()'s stack frame.
178 		 * promplat_alloc() can block on a mutex and so
179 		 * is called here before calling promif_preprom().
180 		 */
181 		if (len > sizeof (smallbuf)) {
182 			obuf = buf;
183 			buf = promplat_alloc(len);
184 			if (buf == NULL) {
185 				return (-1);
186 			}
187 			promplat_bcopy(obuf, buf, len);
188 		}
189 	}
190 #endif
191 
192 	/*
193 	 * Normally we'd call promif_preprom() just before
194 	 * calling into the prom (to enforce single-threaded
195 	 * access) but here we need to call it before accessing
196 	 * smallbuf, since smallbuf is statically allocated and
197 	 * hence can only be accessed by one thread at a time.
198 	 */
199 	ow = promif_preout();
200 	promif_preprom();
201 
202 #ifdef PROM_32BIT_ADDRS
203 	if ((uintptr_t)buf > (uint32_t)-1) {
204 		/*
205 		 * If buf is small enough, use smallbuf
206 		 * instead of promplat_alloc() (see above)
207 		 * smallbuf is static, so single thread
208 		 * access to it by using it only after
209 		 * promif_preprom()
210 		 */
211 		if (len <= sizeof (smallbuf)) {
212 			promplat_bcopy(buf, smallbuf, len);
213 			buf = smallbuf;
214 		}
215 	}
216 #endif
217 
218 	ci[0] = p1275_ptr2cell("write");	/* Service name */
219 	ci[1] = (cell_t)3;			/* #argument cells */
220 	ci[2] = (cell_t)1;			/* #result cells */
221 	ci[3] = p1275_uint2cell((uint_t)fd);	/* Arg1: ihandle */
222 	ci[4] = p1275_ptr2cell(buf);		/* Arg2: buffer addr */
223 	ci[5] = p1275_size2cell(len);		/* Arg3: buffer len */
224 	ci[6] = (cell_t)-1;			/* Res1: Prime result */
225 
226 	(void) p1275_cif_handler(&ci);
227 	rlen = p1275_cell2size(ci[6]);		/* Res1: actual len */
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
prom_close(int fd)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