xref: /titanic_52/usr/src/psm/promif/ieee1275/common/prom_io.c (revision d58fda4376e4bf67072ce2e69f6f47036f9dbb68)
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, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 1994,1998,2001-2002 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 /*ARGSUSED3*/
140 ssize_t
141 prom_write(ihandle_t fd, caddr_t buf, size_t len, uint_t startblk, char devtype)
142 {
143 	cell_t ci[7];
144 	promif_owrap_t *ow;
145 #ifdef PROM_32BIT_ADDRS
146 	caddr_t obuf = NULL;
147 	static char smallbuf[256];
148 
149 	ASSERT(buf);
150 
151 	if ((uintptr_t)buf > (uint32_t)-1) {
152 		/*
153 		 * This is a hack for kernel message output.
154 		 * By avoiding calls to promplat_alloc (and
155 		 * using smallbuf instead) when memory is low
156 		 * we can print shortish kernel messages without
157 		 * deadlocking. smallbuf should be at least as
158 		 * large as the automatic buffer in
159 		 * prom_printf.c:_doprint()'s stack frame.
160 		 * promplat_alloc() can block on a mutex and so
161 		 * is called here before calling promif_preprom().
162 		 */
163 		if (len > sizeof (smallbuf)) {
164 			obuf = buf;
165 			buf = promplat_alloc(len);
166 			if (buf == NULL) {
167 				return (-1);
168 			}
169 			promplat_bcopy(obuf, buf, len);
170 		}
171 	}
172 #endif
173 
174 	ow = promif_preout();
175 	promif_preprom();
176 
177 #ifdef PROM_32BIT_ADDRS
178 
179 	if ((uintptr_t)buf > (uint32_t)-1) {
180 		/*
181 		 * If buf is small enough, use smallbuf
182 		 * instead of promplat_alloc() (see above)
183 		 * smallbuf is static, so single thread
184 		 * access to it by using it only after
185 		 * promif_preprom()
186 		 */
187 		if (len <= sizeof (smallbuf)) {
188 			promplat_bcopy(buf, smallbuf, len);
189 			buf = smallbuf;
190 		}
191 	}
192 #endif
193 
194 	ci[0] = p1275_ptr2cell("write");	/* Service name */
195 	ci[1] = (cell_t)3;			/* #argument cells */
196 	ci[2] = (cell_t)1;			/* #result cells */
197 	ci[3] = p1275_uint2cell((uint_t)fd);	/* Arg1: ihandle */
198 	ci[4] = p1275_ptr2cell(buf);		/* Arg2: buffer address */
199 	ci[5] = p1275_size2cell(len);		/* Arg3: buffer length */
200 	ci[6] = (cell_t)-1;			/* Res1: Prime result */
201 
202 	(void) p1275_cif_handler(&ci);
203 
204 	promif_postprom();
205 	promif_postout(ow);
206 
207 #ifdef PROM_32BIT_ADDRS
208 	if (obuf != NULL)
209 		promplat_free(buf, len);
210 #endif
211 
212 	return (p1275_cell2size(ci[6]));	/* Res1: actual length */
213 }
214 
215 int
216 prom_close(int fd)
217 {
218 	cell_t ci[4];
219 	promif_owrap_t *ow;
220 
221 	ci[0] = p1275_ptr2cell("close");	/* Service name */
222 	ci[1] = (cell_t)1;			/* #argument cells */
223 	ci[2] = (cell_t)0;			/* #result cells */
224 	ci[3] = p1275_uint2cell((uint_t)fd);	/* Arg1: ihandle */
225 
226 	ow = promif_preout();
227 	promif_preprom();
228 	(void) p1275_cif_handler(&ci);
229 	promif_postprom();
230 	promif_postout(ow);
231 
232 	return (0);
233 }
234