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