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_impl.h>
30 #include <sys/systm.h>
31 #include <sys/hypervisor_api.h>
32 #ifndef _KMDB
33 #include <sys/kmem.h>
34 #endif
35 
36 #define	PROM_REG_TO_UNIT_ADDR(r)	((r) & ~(0xful << 28))
37 
38 static pnode_t instance_to_package(ihandle_t ih);
39 
40 /* cached copies of IO params */
41 static phandle_t pstdin;
42 static phandle_t pstdout;
43 
44 static ihandle_t istdin;
45 static ihandle_t istdout;
46 
47 int
48 promif_instance_to_package(void *p)
49 {
50 	cell_t		*ci = (cell_t *)p;
51 	ihandle_t	ih;
52 	phandle_t	ph;
53 
54 	ih = p1275_cell2ihandle(ci[3]);
55 
56 	ph = instance_to_package(ih);
57 
58 	ci[4] = p1275_phandle2cell(ph);
59 
60 	return (0);
61 }
62 
63 int
64 promif_write(void *p)
65 {
66 	cell_t	*ci = (cell_t *)p;
67 	uint_t	fd;
68 	char	*buf;
69 	size_t	len;
70 	size_t	rlen;
71 
72 	ASSERT(ci[1] == 3);
73 
74 	fd  = p1275_cell2uint(ci[3]);
75 	buf = p1275_cell2ptr(ci[4]);
76 	len = p1275_cell2size(ci[5]);
77 
78 	/* only support stdout (console) */
79 	ASSERT(fd == istdout);
80 
81 	for (rlen = 0; rlen < len; rlen++) {
82 		while (hv_cnputchar((uint8_t)buf[rlen]) == H_EWOULDBLOCK)
83 			/* try forever */;
84 	}
85 
86 	/* return the length written */
87 	ci[6] = p1275_size2cell(rlen);
88 
89 	return (0);
90 }
91 
92 int
93 promif_read(void *p)
94 {
95 	cell_t	*ci = (cell_t *)p;
96 	uint_t	fd;
97 	char	*buf;
98 	size_t	len;
99 	size_t	rlen;
100 
101 	ASSERT(ci[1] == 3);
102 
103 	/* unpack arguments */
104 	fd  = p1275_cell2uint(ci[3]);
105 	buf = p1275_cell2ptr(ci[4]);
106 	len = p1275_cell2size(ci[5]);
107 
108 	/* only support stdin (console) */
109 	ASSERT(fd == istdin);
110 
111 	for (rlen = 0; rlen < len; rlen++) {
112 		if (hv_cngetchar((uint8_t *)&buf[rlen]) != H_EOK)
113 			break;
114 	}
115 
116 	/* return the length read */
117 	ci[6] = p1275_size2cell(rlen);
118 
119 	return (0);
120 }
121 
122 static pnode_t
123 instance_to_package(ihandle_t ih)
124 {
125 	/* only support stdin and stdout */
126 	ASSERT((ih == istdin) || (ih == istdout));
127 
128 	if (ih == istdin)
129 		return (pstdin);
130 
131 	if (ih == istdout)
132 		return (pstdout);
133 
134 	return (OBP_BADNODE);
135 }
136 
137 #ifdef _KMDB
138 
139 void
140 promif_io_init(ihandle_t in, ihandle_t out, phandle_t pin, phandle_t pout)
141 {
142 	istdin = in;
143 	istdout = out;
144 	pstdin = pin;
145 	pstdout = pout;
146 }
147 
148 #else
149 
150 void
151 promif_io_init(void)
152 {
153 	/*
154 	 * Cache the mapping between the stdin and stdout
155 	 * ihandles and their respective phandles.
156 	 */
157 	pstdin = prom_stdin_node();
158 	pstdout = prom_stdout_node();
159 
160 	istdin = prom_stdin_ihandle();
161 	istdout = prom_stdout_ihandle();
162 }
163 
164 int
165 promif_instance_to_path(void *p)
166 {
167 	cell_t		*ci = (cell_t *)p;
168 	pnode_t		node;
169 	ihandle_t	ih;
170 	char		*buf;
171 	int		rlen;
172 	char		*regval;
173 	uint_t		*csaddr;
174 	char		name[OBP_MAXPROPNAME];
175 	char		scratch[OBP_MAXPATHLEN];
176 	int		rvlen;
177 
178 	ih = p1275_cell2ihandle(ci[3]);
179 	buf = p1275_cell2ptr(ci[4]);
180 
181 	ci[6] = p1275_uint2cell(0);
182 
183 	node = instance_to_package(ih);
184 
185 	*buf = '\0';
186 
187 	while (node != prom_rootnode()) {
188 		if (prom_getprop(node, OBP_NAME, name) == -1) {
189 			prom_printf("instance_to_path: no name property "
190 			    "node=0x%x\n", node);
191 			return (-1);
192 		}
193 
194 		/* construct the unit address from the 'reg' property */
195 		if ((rlen = prom_getproplen(node, OBP_REG)) == -1)
196 			return (-1);
197 
198 		regval = kmem_zalloc(rlen, KM_SLEEP);
199 
200 		(void) prom_getprop(node, OBP_REG, regval);
201 
202 		csaddr = (uint_t *)regval;
203 
204 		(void) prom_sprintf(scratch, "/%s@%lx%s", name,
205 		    PROM_REG_TO_UNIT_ADDR(*csaddr), buf);
206 
207 		kmem_free(regval, rlen);
208 
209 		(void) prom_strcpy(buf, scratch);
210 
211 		node = prom_parentnode(node);
212 	}
213 
214 	rvlen = prom_strlen(buf);
215 	ci[6] = p1275_uint2cell(rvlen);
216 
217 	return (0);
218 }
219 
220 #endif	/* _KMDB */
221