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 2008 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 #include <sys/promif_impl.h>
28 #include <sys/systm.h>
29 #include <sys/hypervisor_api.h>
30 #include <sys/consdev.h>
31 #ifndef _KMDB
32 #include <sys/kmem.h>
33 #endif
34
35 /*
36 * Definitions for using Polled I/O.
37 *
38 * The usage of Polled I/O is different when we are in kmdb. In that case,
39 * we can not directly invoke the polled I/O functions and we have to use
40 * the kmdb DPI interface. Also we don't need to enter/exit the polled I/O
41 * mode because this is already managed by kmdb when entering/exiting the
42 * debugger.
43 *
44 * When we are not in kmdb then we can directly call the polled I/O functions
45 * but we have to enter the polled I/O mode first. After using polled I/O
46 * functions we have to exit the polled I/O mode. Note that entering/exiting
47 * the polled I/O mode is time consuming so this should be avoided when
48 * possible.
49 */
50 #ifdef _KMDB
51 extern struct cons_polledio *kmdb_kdi_get_polled_io(void);
52 extern uintptr_t kmdb_dpi_call(uintptr_t, uint_t, const uintptr_t *);
53
54 #define PROMIF_PIO (kmdb_kdi_get_polled_io())
55
56 #define PROMIF_PIO_CALL1(fn, arg) \
57 (kmdb_dpi_call((uintptr_t)fn, 1, (uintptr_t *)&arg))
58
59 #define PROMIF_PIO_CALL2(fn, arg1, arg2) \
60 { \
61 uintptr_t args[2]; \
62 args[0] = (uintptr_t)arg1; \
63 args[1] = (uintptr_t)arg2; \
64 (void) (kmdb_dpi_call((uintptr_t)fn, 2, (uintptr_t *)args)); \
65 }
66
67 #define PROMIF_PIO_ENTER(pio)
68 #define PROMIF_PIO_EXIT(pio)
69
70 #else /* _KMDB */
71
72 #define PROMIF_PIO (cons_polledio)
73 #define PROMIF_PIO_CALL1(fn, arg) (fn(arg))
74 #define PROMIF_PIO_CALL2(fn, arg1, arg2) (fn(arg1, arg2))
75
76 #define PROMIF_PIO_ENTER(pio) \
77 if (pio->cons_polledio_enter != NULL) { \
78 pio->cons_polledio_enter(pio->cons_polledio_argument); \
79 }
80
81 #define PROMIF_PIO_EXIT(pio) \
82 if (pio->cons_polledio_exit != NULL) { \
83 pio->cons_polledio_exit(pio->cons_polledio_argument); \
84 }
85
86 #endif /* _KMDB */
87
88 #define PROM_REG_TO_UNIT_ADDR(r) ((r) & ~(0xful << 28))
89
90 static pnode_t instance_to_package(ihandle_t ih);
91
92 /* cached copies of IO params */
93 static phandle_t pstdin;
94 static phandle_t pstdout;
95
96 static ihandle_t istdin;
97 static ihandle_t istdout;
98
99 static struct cons_polledio *promif_polledio = NULL;
100
101 int
promif_instance_to_package(void * p)102 promif_instance_to_package(void *p)
103 {
104 cell_t *ci = (cell_t *)p;
105 ihandle_t ih;
106 phandle_t ph;
107
108 ih = p1275_cell2ihandle(ci[3]);
109
110 ph = instance_to_package(ih);
111
112 ci[4] = p1275_phandle2cell(ph);
113
114 return (0);
115 }
116
117 /* This function is not used but it is convenient for debugging I/O problems */
118 static void
119 /* LINTED */
promif_hv_print(char * str)120 promif_hv_print(char *str)
121 {
122 size_t i, len = strlen(str);
123
124 for (i = 0; i < len; i++) {
125 while (hv_cnputchar((uint8_t)str[i]) == H_EWOULDBLOCK)
126 /* try forever */;
127 }
128 }
129
130 static void
promif_pio_enter(void)131 promif_pio_enter(void)
132 {
133 ASSERT(promif_polledio == NULL);
134
135 promif_polledio = PROMIF_PIO;
136 ASSERT(promif_polledio != NULL);
137
138 PROMIF_PIO_ENTER(promif_polledio);
139 }
140
141 static void
promif_pio_exit(void)142 promif_pio_exit(void)
143 {
144 ASSERT(promif_polledio != NULL);
145
146 PROMIF_PIO_EXIT(promif_polledio);
147 promif_polledio = NULL;
148 }
149
150 static int
promif_do_read(char * buf,size_t len,boolean_t wait)151 promif_do_read(char *buf, size_t len, boolean_t wait)
152 {
153 int rlen;
154 int (*getchar)(cons_polledio_arg_t);
155 boolean_t (*ischar)(cons_polledio_arg_t);
156 cons_polledio_arg_t arg;
157
158 promif_pio_enter();
159
160 if ((ischar = promif_polledio->cons_polledio_ischar) == NULL)
161 return (0);
162 if ((getchar = promif_polledio->cons_polledio_getchar) == NULL)
163 return (0);
164
165 arg = promif_polledio->cons_polledio_argument;
166
167 for (rlen = 0; rlen < len; ) {
168 if (PROMIF_PIO_CALL1(ischar, arg)) {
169 buf[rlen] = PROMIF_PIO_CALL1(getchar, arg);
170 rlen++;
171 continue;
172 }
173
174 if (!wait)
175 break;
176 }
177
178 promif_pio_exit();
179
180 return (rlen);
181 }
182
183 static int
promif_do_write(char * buf,size_t len)184 promif_do_write(char *buf, size_t len)
185 {
186 int rlen;
187 void (*putchar)(cons_polledio_arg_t, uchar_t);
188 cons_polledio_arg_t arg;
189
190 promif_pio_enter();
191
192 if ((putchar = promif_polledio->cons_polledio_putchar) == NULL)
193 return (0);
194
195 arg = promif_polledio->cons_polledio_argument;
196
197 for (rlen = 0; rlen < len; rlen++)
198 PROMIF_PIO_CALL2(putchar, arg, buf[rlen]);
199
200 promif_pio_exit();
201
202 return (rlen);
203 }
204
205 char
promif_getchar(void)206 promif_getchar(void)
207 {
208 char c;
209
210 (void) promif_do_read(&c, 1, B_TRUE);
211 return (c);
212 }
213
214 int
promif_write(void * p)215 promif_write(void *p)
216 {
217 cell_t *ci = (cell_t *)p;
218 uint_t fd;
219 char *buf;
220 size_t len;
221 size_t rlen;
222
223 ASSERT(ci[1] == 3);
224
225 fd = p1275_cell2uint(ci[3]);
226 buf = p1275_cell2ptr(ci[4]);
227 len = p1275_cell2size(ci[5]);
228
229 /* only support stdout (console) */
230 VERIFY(fd == istdout);
231
232 rlen = promif_do_write(buf, len);
233
234 /* return the length written */
235 ci[6] = p1275_size2cell(rlen);
236
237 return (0);
238 }
239
240 int
promif_read(void * p)241 promif_read(void *p)
242 {
243 cell_t *ci = (cell_t *)p;
244 uint_t fd;
245 char *buf;
246 size_t len;
247 size_t rlen;
248
249 ASSERT(ci[1] == 3);
250
251 /* unpack arguments */
252 fd = p1275_cell2uint(ci[3]);
253 buf = p1275_cell2ptr(ci[4]);
254 len = p1275_cell2size(ci[5]);
255
256 /* only support stdin (console) */
257 VERIFY(fd == istdin);
258
259 rlen = promif_do_read(buf, len, B_FALSE);
260
261 /* return the length read */
262 ci[6] = p1275_size2cell(rlen);
263
264 return (0);
265 }
266
267 static pnode_t
instance_to_package(ihandle_t ih)268 instance_to_package(ihandle_t ih)
269 {
270 /* only support stdin and stdout */
271 ASSERT((ih == istdin) || (ih == istdout));
272
273 if (ih == istdin)
274 return (pstdin);
275
276 if (ih == istdout)
277 return (pstdout);
278
279 return (OBP_BADNODE);
280 }
281
282 #ifdef _KMDB
283
284 void
promif_io_init(ihandle_t in,ihandle_t out,phandle_t pin,phandle_t pout)285 promif_io_init(ihandle_t in, ihandle_t out, phandle_t pin, phandle_t pout)
286 {
287 istdin = in;
288 istdout = out;
289 pstdin = pin;
290 pstdout = pout;
291 }
292
293 #else
294
295 void
promif_io_init(void)296 promif_io_init(void)
297 {
298 /*
299 * Cache the mapping between the stdin and stdout
300 * ihandles and their respective phandles.
301 */
302 pstdin = prom_stdin_node();
303 pstdout = prom_stdout_node();
304
305 istdin = prom_stdin_ihandle();
306 istdout = prom_stdout_ihandle();
307 }
308
309 int
promif_instance_to_path(void * p)310 promif_instance_to_path(void *p)
311 {
312 cell_t *ci = (cell_t *)p;
313 pnode_t node;
314 ihandle_t ih;
315 char *buf;
316 int rlen;
317 char *regval;
318 uint_t *csaddr;
319 char name[OBP_MAXPROPNAME];
320 char scratch[OBP_MAXPATHLEN];
321 int rvlen;
322
323 ih = p1275_cell2ihandle(ci[3]);
324 buf = p1275_cell2ptr(ci[4]);
325
326 ci[6] = p1275_uint2cell(0);
327
328 node = instance_to_package(ih);
329
330 *buf = '\0';
331
332 while (node != prom_rootnode()) {
333 if (prom_getprop(node, OBP_NAME, name) == -1) {
334 prom_printf("instance_to_path: no name property "
335 "node=0x%x\n", node);
336 return (-1);
337 }
338
339 /* construct the unit address from the 'reg' property */
340 if ((rlen = prom_getproplen(node, OBP_REG)) == -1)
341 return (-1);
342
343 /*
344 * Make sure we don't get dispatched onto a different
345 * cpu if we happen to sleep. See kern_postprom().
346 */
347 thread_affinity_set(curthread, CPU->cpu_id);
348 regval = kmem_zalloc(rlen, KM_SLEEP);
349
350 (void) prom_getprop(node, OBP_REG, regval);
351
352 csaddr = (uint_t *)regval;
353
354 (void) prom_sprintf(scratch, "/%s@%lx%s", name,
355 PROM_REG_TO_UNIT_ADDR(*csaddr), buf);
356
357 kmem_free(regval, rlen);
358 thread_affinity_clear(curthread);
359
360 (void) prom_strcpy(buf, scratch);
361
362 node = prom_parentnode(node);
363 }
364
365 rvlen = prom_strlen(buf);
366 ci[6] = p1275_uint2cell(rvlen);
367
368 return (0);
369 }
370
371 #endif /* _KMDB */
372