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