xref: /titanic_44/usr/src/cmd/mdb/common/kmdb/kmdb_promif.c (revision 80148899834a4078a2bd348504aa2d6de9752837)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5c7d88479Slq150181  * Common Development and Distribution License (the "License").
6c7d88479Slq150181  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
21de81e71eSTim Marsland 
227c478bd9Sstevel@tonic-gate /*
23de81e71eSTim Marsland  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
247c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate  */
267c478bd9Sstevel@tonic-gate 
277c478bd9Sstevel@tonic-gate #include <sys/types.h>
287c478bd9Sstevel@tonic-gate #include <sys/termios.h>
297c478bd9Sstevel@tonic-gate #include <sys/promif.h>
301ae08745Sheppo #ifdef sun4v
311ae08745Sheppo #include <sys/promif_impl.h>
321ae08745Sheppo #endif
337c478bd9Sstevel@tonic-gate #include <unistd.h>
347c478bd9Sstevel@tonic-gate #include <string.h>
357c478bd9Sstevel@tonic-gate #include <stdlib.h>
367c478bd9Sstevel@tonic-gate 
377c478bd9Sstevel@tonic-gate #include <kmdb/kmdb_promif_impl.h>
387c478bd9Sstevel@tonic-gate #include <kmdb/kmdb_kdi.h>
397c478bd9Sstevel@tonic-gate #include <kmdb/kmdb_dpi.h>
407c478bd9Sstevel@tonic-gate #include <mdb/mdb_debug.h>
417c478bd9Sstevel@tonic-gate #include <mdb/mdb_err.h>
427c478bd9Sstevel@tonic-gate #include <mdb/mdb_frame.h>
437c478bd9Sstevel@tonic-gate #include <mdb/mdb_string.h>
447c478bd9Sstevel@tonic-gate #include <mdb/mdb.h>
457c478bd9Sstevel@tonic-gate 
467c478bd9Sstevel@tonic-gate #define	KMDB_PROM_DEF_CONS_MODE	"9600,n,1,-,-"
477c478bd9Sstevel@tonic-gate 
487c478bd9Sstevel@tonic-gate #define	KMDB_PROM_READBUF_SIZE	1024
497c478bd9Sstevel@tonic-gate 
507c478bd9Sstevel@tonic-gate static char kmdb_prom_readbuf[KMDB_PROM_READBUF_SIZE];
517c478bd9Sstevel@tonic-gate static int kmdb_prom_readbuf_head;
527c478bd9Sstevel@tonic-gate static int kmdb_prom_readbuf_tail;
537c478bd9Sstevel@tonic-gate 
54ae115bc7Smrj static int
kmdb_prom_getchar(int wait)55ae115bc7Smrj kmdb_prom_getchar(int wait)
567c478bd9Sstevel@tonic-gate {
57ae115bc7Smrj 	struct cons_polledio *pio = mdb.m_pio;
58ae115bc7Smrj 	uintptr_t ischar;
59ae115bc7Smrj 	uintptr_t getchar;
60ae115bc7Smrj 	uintptr_t arg;
61ae115bc7Smrj 
62ae115bc7Smrj 	if (pio == NULL || pio->cons_polledio_getchar == NULL) {
637c478bd9Sstevel@tonic-gate 		int c;
64ae115bc7Smrj 		while ((c = prom_mayget()) == -1) {
65ae115bc7Smrj 			if (!wait)
66ae115bc7Smrj 				return (-1);
67ae115bc7Smrj 		}
68ae115bc7Smrj 		return (c);
697c478bd9Sstevel@tonic-gate 	}
707c478bd9Sstevel@tonic-gate 
71ae115bc7Smrj 	ischar = (uintptr_t)pio->cons_polledio_ischar;
72ae115bc7Smrj 	getchar = (uintptr_t)pio->cons_polledio_getchar;
73ae115bc7Smrj 	arg = (uintptr_t)pio->cons_polledio_argument;
74ae115bc7Smrj 
75ae115bc7Smrj 	if (!wait && ischar != NULL && !kmdb_dpi_call(ischar, 1, &arg))
76ae115bc7Smrj 		return (-1);
77ae115bc7Smrj 
78ae115bc7Smrj 	return ((int)kmdb_dpi_call(getchar, 1, &arg));
797c478bd9Sstevel@tonic-gate }
807c478bd9Sstevel@tonic-gate 
81c7bf3205Sjohnlev static ssize_t
kmdb_prom_polled_write(caddr_t buf,size_t len)827c478bd9Sstevel@tonic-gate kmdb_prom_polled_write(caddr_t buf, size_t len)
837c478bd9Sstevel@tonic-gate {
847c478bd9Sstevel@tonic-gate 	uintptr_t args[2];
857c478bd9Sstevel@tonic-gate 	int i;
867c478bd9Sstevel@tonic-gate 
877c478bd9Sstevel@tonic-gate 	args[0] = (uintptr_t)mdb.m_pio->cons_polledio_argument;
887c478bd9Sstevel@tonic-gate 
897c478bd9Sstevel@tonic-gate 	for (i = 0; i < len; i++) {
907c478bd9Sstevel@tonic-gate 		args[1] = *buf++;
917c478bd9Sstevel@tonic-gate 		(void) kmdb_dpi_call(
927c478bd9Sstevel@tonic-gate 		    (uintptr_t)mdb.m_pio->cons_polledio_putchar, 2, args);
937c478bd9Sstevel@tonic-gate 	}
947c478bd9Sstevel@tonic-gate 
957c478bd9Sstevel@tonic-gate 	return (len);
967c478bd9Sstevel@tonic-gate }
977c478bd9Sstevel@tonic-gate 
987c478bd9Sstevel@tonic-gate static ssize_t
kmdb_prom_reader(caddr_t buf,size_t len,int wait)99ae115bc7Smrj kmdb_prom_reader(caddr_t buf, size_t len, int wait)
1007c478bd9Sstevel@tonic-gate {
1017c478bd9Sstevel@tonic-gate 	int nread = 0;
1027c478bd9Sstevel@tonic-gate 	int c;
1037c478bd9Sstevel@tonic-gate 
104ae115bc7Smrj 	while (nread < len) {
105ae115bc7Smrj 		if ((c = kmdb_prom_getchar(wait)) == -1)
106ae115bc7Smrj 			break;
1077c478bd9Sstevel@tonic-gate 
1087c478bd9Sstevel@tonic-gate 		*buf++ = (char)c;
1097c478bd9Sstevel@tonic-gate 		nread++;
110ae115bc7Smrj 		wait = 0;
1117c478bd9Sstevel@tonic-gate 	}
1127c478bd9Sstevel@tonic-gate 
1137c478bd9Sstevel@tonic-gate 	return (nread);
1147c478bd9Sstevel@tonic-gate }
1157c478bd9Sstevel@tonic-gate 
1167c478bd9Sstevel@tonic-gate static ssize_t
kmdb_prom_writer(caddr_t buf,size_t len)1177c478bd9Sstevel@tonic-gate kmdb_prom_writer(caddr_t buf, size_t len)
1187c478bd9Sstevel@tonic-gate {
1197c478bd9Sstevel@tonic-gate 	if (mdb.m_pio != NULL && mdb.m_pio->cons_polledio_putchar != NULL)
1207c478bd9Sstevel@tonic-gate 		return (kmdb_prom_polled_write(buf, len));
1217c478bd9Sstevel@tonic-gate 
1227c478bd9Sstevel@tonic-gate 	return (kmdb_prom_obp_writer(buf, len));
1237c478bd9Sstevel@tonic-gate }
1247c478bd9Sstevel@tonic-gate 
1257c478bd9Sstevel@tonic-gate /*
1267c478bd9Sstevel@tonic-gate  * Due to the nature of kmdb, we don't have signals.  This prevents us from
127c7bf3205Sjohnlev  * receiving asynchronous notification when the user would like to abort active
128c7bf3205Sjohnlev  * dcmds.  Whereas mdb can simply declare a SIGINT handler, we must
1297c478bd9Sstevel@tonic-gate  * occasionally poll the input stream, looking for pending ^C characters.  To
1307c478bd9Sstevel@tonic-gate  * give the illusion of asynchronous interrupt delivery, this polling is
131c7bf3205Sjohnlev  * triggered from several commonly-used functions, such as kmdb_prom_write and
132c7bf3205Sjohnlev  * the *read and *write target ops.  When an interrupt check is triggered, we
133c7bf3205Sjohnlev  * read through pending input, looking for interrupt characters.  If we find
134c7bf3205Sjohnlev  * one, we deliver an interrupt immediately.
135c7bf3205Sjohnlev  *
136c7bf3205Sjohnlev  * In a read context, we can deliver the interrupt character directly back to
137c7bf3205Sjohnlev  * the termio handler rather than raising an interrupt.
1387c478bd9Sstevel@tonic-gate  *
1397c478bd9Sstevel@tonic-gate  * OBP doesn't have an "unget" facility.  Any character read for interrupt
1407c478bd9Sstevel@tonic-gate  * checking is gone forever, unless we save it.  Loss of these characters
1417c478bd9Sstevel@tonic-gate  * would prevent us from supporting typeahead.  We like typeahead, so we're
1427c478bd9Sstevel@tonic-gate  * going to save characters gathered during interrupt checking.  As with
1437c478bd9Sstevel@tonic-gate  * ungetc(3c), however, we can only store a finite number of characters in
1447c478bd9Sstevel@tonic-gate  * our typeahead buffer.  Characters read beyond that will be silently dropped
1457c478bd9Sstevel@tonic-gate  * after they undergo interrupt processing.
1467c478bd9Sstevel@tonic-gate  *
1477c478bd9Sstevel@tonic-gate  * The typeahead facility is implemented as a ring buffer, stored in
148c7bf3205Sjohnlev  * kmdb_prom_readbuf.
1497c478bd9Sstevel@tonic-gate  */
150c7bf3205Sjohnlev static size_t
kmdb_prom_drain_readbuf(void * buf,size_t len)1517c478bd9Sstevel@tonic-gate kmdb_prom_drain_readbuf(void *buf, size_t len)
1527c478bd9Sstevel@tonic-gate {
1537c478bd9Sstevel@tonic-gate 	size_t n, tailread;
1547c478bd9Sstevel@tonic-gate 
1557c478bd9Sstevel@tonic-gate 	/*
1567c478bd9Sstevel@tonic-gate 	 * If head > tail, life is easy - we can simply read as much as we need
1577c478bd9Sstevel@tonic-gate 	 * in one gulp.
1587c478bd9Sstevel@tonic-gate 	 */
1597c478bd9Sstevel@tonic-gate 	if (kmdb_prom_readbuf_head > kmdb_prom_readbuf_tail) {
1607c478bd9Sstevel@tonic-gate 		n = MIN(kmdb_prom_readbuf_head - kmdb_prom_readbuf_tail, len);
1617c478bd9Sstevel@tonic-gate 		bcopy(kmdb_prom_readbuf + kmdb_prom_readbuf_tail, buf, n);
1627c478bd9Sstevel@tonic-gate 		kmdb_prom_readbuf_tail += n;
1637c478bd9Sstevel@tonic-gate 		return (n);
1647c478bd9Sstevel@tonic-gate 
1657c478bd9Sstevel@tonic-gate 	} else if (kmdb_prom_readbuf_head == kmdb_prom_readbuf_tail) {
1667c478bd9Sstevel@tonic-gate 		return (0);
1677c478bd9Sstevel@tonic-gate 	}
1687c478bd9Sstevel@tonic-gate 
1697c478bd9Sstevel@tonic-gate 	/*
1707c478bd9Sstevel@tonic-gate 	 * The consumable slots wrap around zero (there are slots from tail to
1717c478bd9Sstevel@tonic-gate 	 * zero, and from zero to head).  We have to read them in two parts.
1727c478bd9Sstevel@tonic-gate 	 */
1737c478bd9Sstevel@tonic-gate 	n = MIN(KMDB_PROM_READBUF_SIZE - kmdb_prom_readbuf_tail, len);
1747c478bd9Sstevel@tonic-gate 	bcopy(kmdb_prom_readbuf + kmdb_prom_readbuf_tail, buf, n);
1757c478bd9Sstevel@tonic-gate 	kmdb_prom_readbuf_tail = (kmdb_prom_readbuf_tail + n) %
1767c478bd9Sstevel@tonic-gate 	    KMDB_PROM_READBUF_SIZE;
1777c478bd9Sstevel@tonic-gate 
1787c478bd9Sstevel@tonic-gate 	if (n == len) {
1797c478bd9Sstevel@tonic-gate 		/*
1807c478bd9Sstevel@tonic-gate 		 * We filled the passed buffer from the first part, so there's
1817c478bd9Sstevel@tonic-gate 		 * no need to read the second.
1827c478bd9Sstevel@tonic-gate 		 */
1837c478bd9Sstevel@tonic-gate 		return (n);
1847c478bd9Sstevel@tonic-gate 	} else {
1857c478bd9Sstevel@tonic-gate 		tailread = n;
1867c478bd9Sstevel@tonic-gate 	}
1877c478bd9Sstevel@tonic-gate 
1887c478bd9Sstevel@tonic-gate 	n = MIN(kmdb_prom_readbuf_head, len - tailread);
1897c478bd9Sstevel@tonic-gate 	buf = (void *)((uintptr_t)buf + tailread);
1907c478bd9Sstevel@tonic-gate 	bcopy(kmdb_prom_readbuf, buf, n);
1917c478bd9Sstevel@tonic-gate 
1927c478bd9Sstevel@tonic-gate 	kmdb_prom_readbuf_tail = (kmdb_prom_readbuf_tail + n) %
1937c478bd9Sstevel@tonic-gate 	    KMDB_PROM_READBUF_SIZE;
1947c478bd9Sstevel@tonic-gate 
1957c478bd9Sstevel@tonic-gate 	return (tailread + n);
1967c478bd9Sstevel@tonic-gate }
1977c478bd9Sstevel@tonic-gate 
1987c478bd9Sstevel@tonic-gate static void
check_int(char * buf,size_t len)1997c478bd9Sstevel@tonic-gate check_int(char *buf, size_t len)
2007c478bd9Sstevel@tonic-gate {
2017c478bd9Sstevel@tonic-gate 	int i;
2027c478bd9Sstevel@tonic-gate 
2037c478bd9Sstevel@tonic-gate 	for (i = 0; i < len; i++) {
204c7bf3205Sjohnlev 		if (buf[i] == CTRL('c')) {
2057c478bd9Sstevel@tonic-gate 			kmdb_prom_readbuf_tail = kmdb_prom_readbuf_head;
2067c478bd9Sstevel@tonic-gate 			if (mdb.m_intr == 0)
2077c478bd9Sstevel@tonic-gate 				longjmp(mdb.m_frame->f_pcb, MDB_ERR_SIGINT);
2087c478bd9Sstevel@tonic-gate 			else
2097c478bd9Sstevel@tonic-gate 				mdb.m_pend++;
2107c478bd9Sstevel@tonic-gate 		}
2117c478bd9Sstevel@tonic-gate 	}
2127c478bd9Sstevel@tonic-gate }
2137c478bd9Sstevel@tonic-gate 
214c7bf3205Sjohnlev /*
215c7bf3205Sjohnlev  * Attempt to refill the ring buffer from the input stream.  This called from
216c7bf3205Sjohnlev  * two contexts:
217c7bf3205Sjohnlev  *
218c7bf3205Sjohnlev  * Direct read: read the input into our buffer until input is exhausted, or the
219c7bf3205Sjohnlev  * buffer is full.
220c7bf3205Sjohnlev  *
221c7bf3205Sjohnlev  * Interrupt check: called 'asynchronously' from the normal read routines; read
222c7bf3205Sjohnlev  * the input into our buffer until it is exhausted, discarding input if the
223c7bf3205Sjohnlev  * buffer is full.  In this case we look ahead for any interrupt characters,
224c7bf3205Sjohnlev  * delivering an interrupt directly if we find one.
225c7bf3205Sjohnlev  */
226c7bf3205Sjohnlev static void
kmdb_prom_fill_readbuf(int check_for_int,int wait)227ae115bc7Smrj kmdb_prom_fill_readbuf(int check_for_int, int wait)
2287c478bd9Sstevel@tonic-gate {
2297c478bd9Sstevel@tonic-gate 	int oldhead, left, n;
2307c478bd9Sstevel@tonic-gate 
2317c478bd9Sstevel@tonic-gate 	/*
2327c478bd9Sstevel@tonic-gate 	 * Calculate the number of slots left before we wrap around to the
2337c478bd9Sstevel@tonic-gate 	 * beginning again.
2347c478bd9Sstevel@tonic-gate 	 */
2357c478bd9Sstevel@tonic-gate 	left = KMDB_PROM_READBUF_SIZE - kmdb_prom_readbuf_head;
2367c478bd9Sstevel@tonic-gate 	if (kmdb_prom_readbuf_tail == 0)
2377c478bd9Sstevel@tonic-gate 		left--;
2387c478bd9Sstevel@tonic-gate 
2397c478bd9Sstevel@tonic-gate 	if (kmdb_prom_readbuf_head == kmdb_prom_readbuf_tail ||
2407c478bd9Sstevel@tonic-gate 	    (kmdb_prom_readbuf_head > kmdb_prom_readbuf_tail && left > 0)) {
2417c478bd9Sstevel@tonic-gate 		/*
2427c478bd9Sstevel@tonic-gate 		 * head > tail, so we have to read in two parts - the slots
2437c478bd9Sstevel@tonic-gate 		 * from head until we wrap back around to zero, and the ones
2447c478bd9Sstevel@tonic-gate 		 * from zero to tail.  We handle the first part here, and let
2457c478bd9Sstevel@tonic-gate 		 * the common code handle the second.
2467c478bd9Sstevel@tonic-gate 		 */
2477c478bd9Sstevel@tonic-gate 		if ((n = kmdb_prom_reader(kmdb_prom_readbuf +
248ae115bc7Smrj 		    kmdb_prom_readbuf_head, left, wait)) <= 0)
2497c478bd9Sstevel@tonic-gate 			return;
2507c478bd9Sstevel@tonic-gate 
2517c478bd9Sstevel@tonic-gate 		oldhead = kmdb_prom_readbuf_head;
2527c478bd9Sstevel@tonic-gate 		kmdb_prom_readbuf_head = (kmdb_prom_readbuf_head + n) %
2537c478bd9Sstevel@tonic-gate 		    KMDB_PROM_READBUF_SIZE;
2547c478bd9Sstevel@tonic-gate 
255c7bf3205Sjohnlev 		if (check_for_int)
2567c478bd9Sstevel@tonic-gate 			check_int(kmdb_prom_readbuf + oldhead, n);
2577c478bd9Sstevel@tonic-gate 
2587c478bd9Sstevel@tonic-gate 		if (n != left)
2597c478bd9Sstevel@tonic-gate 			return;
2607c478bd9Sstevel@tonic-gate 	}
2617c478bd9Sstevel@tonic-gate 
2627c478bd9Sstevel@tonic-gate 	left = kmdb_prom_readbuf_tail - kmdb_prom_readbuf_head - 1;
2637c478bd9Sstevel@tonic-gate 	if (left > 0) {
2647c478bd9Sstevel@tonic-gate 		if ((n = kmdb_prom_reader(kmdb_prom_readbuf +
265ae115bc7Smrj 		    kmdb_prom_readbuf_head, left, wait)) <= 0)
2667c478bd9Sstevel@tonic-gate 			return;
2677c478bd9Sstevel@tonic-gate 
2687c478bd9Sstevel@tonic-gate 		oldhead = kmdb_prom_readbuf_head;
2697c478bd9Sstevel@tonic-gate 		kmdb_prom_readbuf_head = (kmdb_prom_readbuf_head + n) %
2707c478bd9Sstevel@tonic-gate 		    KMDB_PROM_READBUF_SIZE;
2717c478bd9Sstevel@tonic-gate 
272c7bf3205Sjohnlev 		if (check_for_int)
2737c478bd9Sstevel@tonic-gate 			check_int(kmdb_prom_readbuf + oldhead, n);
2747c478bd9Sstevel@tonic-gate 
2757c478bd9Sstevel@tonic-gate 		if (n != left)
2767c478bd9Sstevel@tonic-gate 			return;
2777c478bd9Sstevel@tonic-gate 	}
2787c478bd9Sstevel@tonic-gate 
279c7bf3205Sjohnlev 	if (check_for_int) {
2807c478bd9Sstevel@tonic-gate 		char c;
2817c478bd9Sstevel@tonic-gate 
282ae115bc7Smrj 		while (kmdb_prom_reader(&c, 1, 0) == 1)
2837c478bd9Sstevel@tonic-gate 			check_int(&c, 1);
2847c478bd9Sstevel@tonic-gate 	}
2857c478bd9Sstevel@tonic-gate }
2867c478bd9Sstevel@tonic-gate 
2877c478bd9Sstevel@tonic-gate void
kmdb_prom_check_interrupt(void)2887c478bd9Sstevel@tonic-gate kmdb_prom_check_interrupt(void)
2897c478bd9Sstevel@tonic-gate {
290ae115bc7Smrj 	kmdb_prom_fill_readbuf(1, 0);
2917c478bd9Sstevel@tonic-gate }
2927c478bd9Sstevel@tonic-gate 
2937c478bd9Sstevel@tonic-gate /*
2947c478bd9Sstevel@tonic-gate  * OBP reads are always non-blocking.  If there are characters available,
2957c478bd9Sstevel@tonic-gate  * we'll return as many as we can.  If nothing is available, we'll spin
2967c478bd9Sstevel@tonic-gate  * until one shows up.
2977c478bd9Sstevel@tonic-gate  */
2987c478bd9Sstevel@tonic-gate ssize_t
kmdb_prom_read(void * buf,size_t len,struct termios * tio)2997c478bd9Sstevel@tonic-gate kmdb_prom_read(void *buf, size_t len, struct termios *tio)
3007c478bd9Sstevel@tonic-gate {
3017c478bd9Sstevel@tonic-gate 	size_t totread = 0;
3027c478bd9Sstevel@tonic-gate 	size_t thisread;
3037c478bd9Sstevel@tonic-gate 	char *c = (char *)buf;
304ae115bc7Smrj 	int wait = 1;
3057c478bd9Sstevel@tonic-gate 
3067c478bd9Sstevel@tonic-gate 	for (;;) {
307ae115bc7Smrj 		kmdb_prom_fill_readbuf(0, wait);
3087c478bd9Sstevel@tonic-gate 		thisread = kmdb_prom_drain_readbuf(c, len);
3097c478bd9Sstevel@tonic-gate 		len -= thisread;
3107c478bd9Sstevel@tonic-gate 		totread += thisread;
3117c478bd9Sstevel@tonic-gate 		c += thisread;
3127c478bd9Sstevel@tonic-gate 
3137c478bd9Sstevel@tonic-gate 		/* wait until something shows up */
3147c478bd9Sstevel@tonic-gate 		if (totread == 0)
3157c478bd9Sstevel@tonic-gate 			continue;
3167c478bd9Sstevel@tonic-gate 
317ae115bc7Smrj 		wait = 0;
318ae115bc7Smrj 
3197c478bd9Sstevel@tonic-gate 		/*
3207c478bd9Sstevel@tonic-gate 		 * We're done if we've exhausted available input or if we've
3217c478bd9Sstevel@tonic-gate 		 * filled the provided buffer.
3227c478bd9Sstevel@tonic-gate 		 */
3237c478bd9Sstevel@tonic-gate 		if (len == 0 || thisread == 0)
3247c478bd9Sstevel@tonic-gate 			break;
3257c478bd9Sstevel@tonic-gate 	}
3267c478bd9Sstevel@tonic-gate 
3277c478bd9Sstevel@tonic-gate 	if (tio->c_iflag & ICRNL) {
3287c478bd9Sstevel@tonic-gate 		char *cbuf = buf;
3297c478bd9Sstevel@tonic-gate 		int i;
3307c478bd9Sstevel@tonic-gate 
3317c478bd9Sstevel@tonic-gate 		for (i = 0; i < totread; i++) {
3327c478bd9Sstevel@tonic-gate 			if (cbuf[i] == '\r')
3337c478bd9Sstevel@tonic-gate 				cbuf[i] = '\n';
3347c478bd9Sstevel@tonic-gate 		}
3357c478bd9Sstevel@tonic-gate 	}
3367c478bd9Sstevel@tonic-gate 
3377c478bd9Sstevel@tonic-gate 	if (tio->c_lflag & ECHO)
3387c478bd9Sstevel@tonic-gate 		(void) kmdb_prom_write(buf, totread, tio);
3397c478bd9Sstevel@tonic-gate 
3407c478bd9Sstevel@tonic-gate 	return (totread);
3417c478bd9Sstevel@tonic-gate }
3427c478bd9Sstevel@tonic-gate 
3437c478bd9Sstevel@tonic-gate /*ARGSUSED*/
3447c478bd9Sstevel@tonic-gate ssize_t
kmdb_prom_write(const void * bufp,size_t len,struct termios * tio)3457c478bd9Sstevel@tonic-gate kmdb_prom_write(const void *bufp, size_t len, struct termios *tio)
3467c478bd9Sstevel@tonic-gate {
3477c478bd9Sstevel@tonic-gate 	caddr_t buf = (caddr_t)bufp;
3487c478bd9Sstevel@tonic-gate 	size_t left = len;
3497c478bd9Sstevel@tonic-gate 	char *nl = "\r\n";
3507c478bd9Sstevel@tonic-gate 	char *c;
3517c478bd9Sstevel@tonic-gate 
3527c478bd9Sstevel@tonic-gate 	kmdb_prom_check_interrupt();
3537c478bd9Sstevel@tonic-gate 
3547c478bd9Sstevel@tonic-gate 	if (!(tio->c_oflag & ONLCR))
3557c478bd9Sstevel@tonic-gate 		return (kmdb_prom_writer(buf, left));
3567c478bd9Sstevel@tonic-gate 
3577c478bd9Sstevel@tonic-gate 	/* translate every \n into \r\n */
3587c478bd9Sstevel@tonic-gate 	while ((c = strnchr(buf, '\n', left)) != NULL) {
3597c478bd9Sstevel@tonic-gate 		if (c != buf) {
3607c478bd9Sstevel@tonic-gate 			size_t sz = (size_t)(c - buf);
3617c478bd9Sstevel@tonic-gate 			(void) kmdb_prom_writer(buf, sz);
3627c478bd9Sstevel@tonic-gate 			left -= sz;
3637c478bd9Sstevel@tonic-gate 		}
3647c478bd9Sstevel@tonic-gate 
3657c478bd9Sstevel@tonic-gate 		buf = c + 1;
3667c478bd9Sstevel@tonic-gate 		left--;
3677c478bd9Sstevel@tonic-gate 
3687c478bd9Sstevel@tonic-gate 		(void) kmdb_prom_writer(nl, 2);
3697c478bd9Sstevel@tonic-gate 	}
3707c478bd9Sstevel@tonic-gate 
3717c478bd9Sstevel@tonic-gate 	if (*buf != '\0')
3727c478bd9Sstevel@tonic-gate 		(void) kmdb_prom_writer(buf, left);
3737c478bd9Sstevel@tonic-gate 
3747c478bd9Sstevel@tonic-gate 	return (len);
3757c478bd9Sstevel@tonic-gate }
3767c478bd9Sstevel@tonic-gate 
3777c478bd9Sstevel@tonic-gate static char *
kmdb_get_ttyio_mode(kmdb_auxv_t * kav,char * devname)3787c478bd9Sstevel@tonic-gate kmdb_get_ttyio_mode(kmdb_auxv_t *kav, char *devname)
3797c478bd9Sstevel@tonic-gate {
3807c478bd9Sstevel@tonic-gate 	char *modepname, *modepval;
3817c478bd9Sstevel@tonic-gate 
3827c478bd9Sstevel@tonic-gate 	modepname = mdb_alloc(strlen(devname) + 5 + 1, UM_SLEEP);
383*80148899SSurya Prakki 	(void) strcpy(modepname, devname);
384*80148899SSurya Prakki 	(void) strcat(modepname, "-mode");
3857c478bd9Sstevel@tonic-gate 
386c7d88479Slq150181 	modepval = kmdb_prom_get_ddi_prop(kav, modepname);
3877c478bd9Sstevel@tonic-gate 
3887c478bd9Sstevel@tonic-gate 	strfree(modepname);
3897c478bd9Sstevel@tonic-gate 
3907c478bd9Sstevel@tonic-gate 	return (modepval);
3917c478bd9Sstevel@tonic-gate }
3927c478bd9Sstevel@tonic-gate 
3937c478bd9Sstevel@tonic-gate static int
termios_setispeed(struct termios * tip,speed_t s)3947c478bd9Sstevel@tonic-gate termios_setispeed(struct termios *tip, speed_t s)
3957c478bd9Sstevel@tonic-gate {
3967c478bd9Sstevel@tonic-gate 	if (s > (2 * CBAUD + 1))
3977c478bd9Sstevel@tonic-gate 		return (-1);
3987c478bd9Sstevel@tonic-gate 
3997c478bd9Sstevel@tonic-gate 	if ((s << IBSHIFT) > CIBAUD) {
4007c478bd9Sstevel@tonic-gate 		tip->c_cflag |= CIBAUDEXT;
4017c478bd9Sstevel@tonic-gate 		s -= ((CIBAUD >> IBSHIFT) + 1);
4027c478bd9Sstevel@tonic-gate 	} else
4037c478bd9Sstevel@tonic-gate 		tip->c_cflag &= ~CIBAUDEXT;
4047c478bd9Sstevel@tonic-gate 
4057c478bd9Sstevel@tonic-gate 	tip->c_cflag = (tip->c_cflag & ~CIBAUD) | ((s << IBSHIFT) & CIBAUD);
4067c478bd9Sstevel@tonic-gate 
4077c478bd9Sstevel@tonic-gate 	return (0);
4087c478bd9Sstevel@tonic-gate }
4097c478bd9Sstevel@tonic-gate 
4107c478bd9Sstevel@tonic-gate static int
termios_setospeed(struct termios * tip,speed_t s)4117c478bd9Sstevel@tonic-gate termios_setospeed(struct termios *tip, speed_t s)
4127c478bd9Sstevel@tonic-gate {
4137c478bd9Sstevel@tonic-gate 	if (s > (2 * CBAUD + 1))
4147c478bd9Sstevel@tonic-gate 		return (-1);
4157c478bd9Sstevel@tonic-gate 
4167c478bd9Sstevel@tonic-gate 	if (s > CBAUD) {
4177c478bd9Sstevel@tonic-gate 		tip->c_cflag |= CBAUDEXT;
4187c478bd9Sstevel@tonic-gate 		s -= (CBAUD + 1);
4197c478bd9Sstevel@tonic-gate 	} else
4207c478bd9Sstevel@tonic-gate 		tip->c_cflag &= ~CBAUDEXT;
4217c478bd9Sstevel@tonic-gate 
4227c478bd9Sstevel@tonic-gate 	tip->c_cflag = (tip->c_cflag & ~CBAUD) | (s & CBAUD);
4237c478bd9Sstevel@tonic-gate 
4247c478bd9Sstevel@tonic-gate 	return (0);
4257c478bd9Sstevel@tonic-gate }
4267c478bd9Sstevel@tonic-gate 
4277c478bd9Sstevel@tonic-gate static int
kmdb_parse_mode(const char * mode,struct termios * tip,int in)4287c478bd9Sstevel@tonic-gate kmdb_parse_mode(const char *mode, struct termios *tip, int in)
4297c478bd9Sstevel@tonic-gate {
4307c478bd9Sstevel@tonic-gate 	static const uint_t baudmap[] = {
4317c478bd9Sstevel@tonic-gate 		0, 50, 75, 110, 134, 150, 200, 300, 600, 1200,
4327c478bd9Sstevel@tonic-gate 		1800, 2400, 4800, 9600, 19200, 38400, 57600,
433de81e71eSTim Marsland 		76800, 115200, 153600, 230400, 307200, 460800, 921600
4347c478bd9Sstevel@tonic-gate 	};
4357c478bd9Sstevel@tonic-gate 	static const uint_t bitsmap[] = { CS6, CS6, CS7, CS8 };
4367c478bd9Sstevel@tonic-gate 	char *m = strdup(mode);
4377c478bd9Sstevel@tonic-gate 	char *w;
4387c478bd9Sstevel@tonic-gate 	int rc = -1;
4397c478bd9Sstevel@tonic-gate 	speed_t speed;
4407c478bd9Sstevel@tonic-gate 	int baud, i;
4417c478bd9Sstevel@tonic-gate 
4427c478bd9Sstevel@tonic-gate 	/*
4437c478bd9Sstevel@tonic-gate 	 * termios supports different baud rates and flow control types for
4447c478bd9Sstevel@tonic-gate 	 * input and output, but it requires character width, parity, and stop
4457c478bd9Sstevel@tonic-gate 	 * bits to be equal in input and output.  obp allows them to be
4467c478bd9Sstevel@tonic-gate 	 * different, but we're going to (silently) assume that nobody will use
4477c478bd9Sstevel@tonic-gate 	 * it that way.
4487c478bd9Sstevel@tonic-gate 	 */
4497c478bd9Sstevel@tonic-gate 
4507c478bd9Sstevel@tonic-gate 	/* baud rate - see baudmap above */
4517c478bd9Sstevel@tonic-gate 	if ((w = strtok(m, ",")) == NULL)
4527c478bd9Sstevel@tonic-gate 		goto parse_mode_bail;
4537c478bd9Sstevel@tonic-gate 
4547c478bd9Sstevel@tonic-gate 	baud = strtol(w, NULL, 10);
4557c478bd9Sstevel@tonic-gate 	speed = 0;
4567c478bd9Sstevel@tonic-gate 	for (i = 0; i < sizeof (baudmap) / sizeof (baudmap[0]); i++) {
4577c478bd9Sstevel@tonic-gate 		if (baudmap[i] == baud) {
4587c478bd9Sstevel@tonic-gate 			speed = i;
4597c478bd9Sstevel@tonic-gate 			break;
4607c478bd9Sstevel@tonic-gate 		}
4617c478bd9Sstevel@tonic-gate 	}
4627c478bd9Sstevel@tonic-gate 	if (speed == 0)
4637c478bd9Sstevel@tonic-gate 		goto parse_mode_bail;
4647c478bd9Sstevel@tonic-gate 
4657c478bd9Sstevel@tonic-gate 	if (in == 1)
4667c478bd9Sstevel@tonic-gate 		(void) termios_setispeed(tip, speed);
4677c478bd9Sstevel@tonic-gate 	else
4687c478bd9Sstevel@tonic-gate 		(void) termios_setospeed(tip, speed);
4697c478bd9Sstevel@tonic-gate 
4707c478bd9Sstevel@tonic-gate 	/* character width (bits) - 5, 6, 7, or 8 */
4717c478bd9Sstevel@tonic-gate 	if ((w = strtok(NULL, ",")) == NULL || strlen(w) != 1 || *w < '5' ||
4727c478bd9Sstevel@tonic-gate 	    *w > '8')
4737c478bd9Sstevel@tonic-gate 		goto parse_mode_bail;
4747c478bd9Sstevel@tonic-gate 	tip->c_cflag = (tip->c_cflag & ~CSIZE) | bitsmap[*w - '5'];
4757c478bd9Sstevel@tonic-gate 
4767c478bd9Sstevel@tonic-gate 	/* parity - `n' (none), `e' (even), or `o' (odd) */
4777c478bd9Sstevel@tonic-gate 	if ((w = strtok(NULL, ",")) == NULL || strlen(w) != 1 ||
4787c478bd9Sstevel@tonic-gate 	    strchr("neo", *w) == NULL)
4797c478bd9Sstevel@tonic-gate 		goto parse_mode_bail;
4807c478bd9Sstevel@tonic-gate 
4817c478bd9Sstevel@tonic-gate 	tip->c_cflag = (tip->c_cflag & ~(PARENB|PARODD));
4827c478bd9Sstevel@tonic-gate 	switch (*w) {
4837c478bd9Sstevel@tonic-gate 	case 'n':
4847c478bd9Sstevel@tonic-gate 		/* nothing */
4857c478bd9Sstevel@tonic-gate 		break;
4867c478bd9Sstevel@tonic-gate 	case 'e':
4877c478bd9Sstevel@tonic-gate 		tip->c_cflag |= PARENB;
4887c478bd9Sstevel@tonic-gate 		break;
4897c478bd9Sstevel@tonic-gate 	case 'o':
4907c478bd9Sstevel@tonic-gate 		tip->c_cflag |= PARENB|PARODD;
4917c478bd9Sstevel@tonic-gate 		break;
4927c478bd9Sstevel@tonic-gate 	}
4937c478bd9Sstevel@tonic-gate 
4947c478bd9Sstevel@tonic-gate 	/*
4957c478bd9Sstevel@tonic-gate 	 * stop bits - 1, or 2.  obp can, in theory, support 1.5 bits,
4967c478bd9Sstevel@tonic-gate 	 * but we can't.  how many angels can dance on half of a bit?
4977c478bd9Sstevel@tonic-gate 	 */
4987c478bd9Sstevel@tonic-gate 	if ((w = strtok(NULL, ",")) == NULL || strlen(w) != 1 || *w < '1' ||
4997c478bd9Sstevel@tonic-gate 	    *w > '2')
5007c478bd9Sstevel@tonic-gate 		goto parse_mode_bail;
5017c478bd9Sstevel@tonic-gate 
5027c478bd9Sstevel@tonic-gate 	if (*w == '1')
5037c478bd9Sstevel@tonic-gate 		tip->c_cflag &= ~CSTOPB;
5047c478bd9Sstevel@tonic-gate 	else
5057c478bd9Sstevel@tonic-gate 		tip->c_cflag |= CSTOPB;
5067c478bd9Sstevel@tonic-gate 
5077c478bd9Sstevel@tonic-gate 	/* flow control - `-' (none), `h' (h/w), or `s' (s/w - XON/XOFF) */
5087c478bd9Sstevel@tonic-gate 	if ((w = strtok(NULL, ",")) == NULL || strlen(w) != 1 ||
5097c478bd9Sstevel@tonic-gate 	    strchr("-hs", *w) == NULL)
5107c478bd9Sstevel@tonic-gate 		goto parse_mode_bail;
5117c478bd9Sstevel@tonic-gate 
5127c478bd9Sstevel@tonic-gate 	tip->c_cflag &= ~(CRTSXOFF|CRTSCTS);
5137c478bd9Sstevel@tonic-gate 	tip->c_iflag &= ~(IXON|IXANY|IXOFF);
5147c478bd9Sstevel@tonic-gate 
5157c478bd9Sstevel@tonic-gate 	switch (*w) {
5167c478bd9Sstevel@tonic-gate 	case 'h':
5177c478bd9Sstevel@tonic-gate 		tip->c_cflag |= (in == 1 ? CRTSXOFF : CRTSCTS);
5187c478bd9Sstevel@tonic-gate 		break;
5197c478bd9Sstevel@tonic-gate 
5207c478bd9Sstevel@tonic-gate 	case 's':
5217c478bd9Sstevel@tonic-gate 		tip->c_iflag |= (in == 1 ? IXOFF : IXON);
5227c478bd9Sstevel@tonic-gate 		break;
5237c478bd9Sstevel@tonic-gate 	}
5247c478bd9Sstevel@tonic-gate 
5257c478bd9Sstevel@tonic-gate 	rc = 0;
5267c478bd9Sstevel@tonic-gate 
5277c478bd9Sstevel@tonic-gate parse_mode_bail:
5287c478bd9Sstevel@tonic-gate 	strfree(m);
5297c478bd9Sstevel@tonic-gate 
5307c478bd9Sstevel@tonic-gate 	return (rc);
5317c478bd9Sstevel@tonic-gate }
5327c478bd9Sstevel@tonic-gate 
5337c478bd9Sstevel@tonic-gate #ifdef __sparc
5347c478bd9Sstevel@tonic-gate #define	ATTACHED_TERM_TYPE	"sun"
5357c478bd9Sstevel@tonic-gate #else
5367c478bd9Sstevel@tonic-gate #define	ATTACHED_TERM_TYPE	"sun-color"
5377c478bd9Sstevel@tonic-gate #endif
5387c478bd9Sstevel@tonic-gate 
5397c478bd9Sstevel@tonic-gate static void
kmdb_prom_term_init(kmdb_auxv_t * kav,kmdb_promif_t * pif)5407c478bd9Sstevel@tonic-gate kmdb_prom_term_init(kmdb_auxv_t *kav, kmdb_promif_t *pif)
5417c478bd9Sstevel@tonic-gate {
5427c478bd9Sstevel@tonic-gate 	const char ccs[NCCS] = { 0x03, 0x1c, 0x08, 0x15, 0x04, 0x00, 0x00,
5437c478bd9Sstevel@tonic-gate 	    0x00, 0x11, 0x13, 0x1a, 0x19, 0x12, 0x0f, 0x17, 0x16 };
5447c478bd9Sstevel@tonic-gate 	char *conin = NULL, *conout = NULL;
5457c478bd9Sstevel@tonic-gate 
5467c478bd9Sstevel@tonic-gate 	if (kmdb_prom_stdout_is_framebuffer(kav))
5477c478bd9Sstevel@tonic-gate 		pif->pif_oterm = ATTACHED_TERM_TYPE;
5487c478bd9Sstevel@tonic-gate 
5497c478bd9Sstevel@tonic-gate 	bzero(&pif->pif_tios, sizeof (struct termios));
5507c478bd9Sstevel@tonic-gate 
5517c478bd9Sstevel@tonic-gate 	/* output device characteristics */
552c7d88479Slq150181 	if ((conout = kmdb_prom_get_ddi_prop(kav, "output-device")) ==
5537c478bd9Sstevel@tonic-gate 	    NULL || strcmp(conout, "screen") == 0) {
5547c478bd9Sstevel@tonic-gate 		(void) kmdb_parse_mode(KMDB_PROM_DEF_CONS_MODE,
5557c478bd9Sstevel@tonic-gate 		    &pif->pif_tios, 0);
5567c478bd9Sstevel@tonic-gate 	} else if (*conout == '/') {
5577c478bd9Sstevel@tonic-gate 		/*
5587c478bd9Sstevel@tonic-gate 		 * We're not going to be able to get characteristics for a
5597c478bd9Sstevel@tonic-gate 		 * device that's specified as a path, so don't even try.
5607c478bd9Sstevel@tonic-gate 		 * Conveniently, this allows us to avoid chattering on
5617c478bd9Sstevel@tonic-gate 		 * Serengetis.
5627c478bd9Sstevel@tonic-gate 		 */
5637c478bd9Sstevel@tonic-gate 		(void) kmdb_parse_mode(KMDB_PROM_DEF_CONS_MODE,
5647c478bd9Sstevel@tonic-gate 		    &pif->pif_tios, 0);
5657c478bd9Sstevel@tonic-gate 	} else {
5667c478bd9Sstevel@tonic-gate 		char *mode = kmdb_get_ttyio_mode(kav, conout);
5677c478bd9Sstevel@tonic-gate 
5687c478bd9Sstevel@tonic-gate #ifdef __sparc
5697c478bd9Sstevel@tonic-gate 		/*
5707c478bd9Sstevel@tonic-gate 		 * Some platforms (Starfire) define a value of `ttya' for
5717c478bd9Sstevel@tonic-gate 		 * output-device, but neglect to provide a specific property
5727c478bd9Sstevel@tonic-gate 		 * with the characteristics.  We'll provide a default value.
5737c478bd9Sstevel@tonic-gate 		 */
5747c478bd9Sstevel@tonic-gate 		if (mode == NULL && strcmp(conout, "ttya") == 0) {
5757c478bd9Sstevel@tonic-gate 			(void) kmdb_parse_mode(KMDB_PROM_DEF_CONS_MODE,
5767c478bd9Sstevel@tonic-gate 			    &pif->pif_tios, 0);
5777c478bd9Sstevel@tonic-gate 		} else
5787c478bd9Sstevel@tonic-gate #endif
5797c478bd9Sstevel@tonic-gate 		{
5807c478bd9Sstevel@tonic-gate 			if (mode == NULL || kmdb_parse_mode(mode,
5817c478bd9Sstevel@tonic-gate 			    &pif->pif_tios, 0) < 0) {
5827c478bd9Sstevel@tonic-gate 				/*
5837c478bd9Sstevel@tonic-gate 				 * Either we couldn't retrieve the
5847c478bd9Sstevel@tonic-gate 				 * characteristics for this console, or they
5857c478bd9Sstevel@tonic-gate 				 * weren't parseable.  The console hasn't been
5867c478bd9Sstevel@tonic-gate 				 * set up yet, so we can't warn.  We'll have to
5877c478bd9Sstevel@tonic-gate 				 * silently fall back to the default
5887c478bd9Sstevel@tonic-gate 				 * characteristics.
5897c478bd9Sstevel@tonic-gate 				 */
5907c478bd9Sstevel@tonic-gate 				(void) kmdb_parse_mode(KMDB_PROM_DEF_CONS_MODE,
5917c478bd9Sstevel@tonic-gate 				    &pif->pif_tios, 0);
5927c478bd9Sstevel@tonic-gate 			}
5937c478bd9Sstevel@tonic-gate 		}
5947c478bd9Sstevel@tonic-gate 
5957c478bd9Sstevel@tonic-gate 		if (mode != NULL)
596c7d88479Slq150181 			kmdb_prom_free_ddi_prop(mode);
5977c478bd9Sstevel@tonic-gate 	}
5987c478bd9Sstevel@tonic-gate 
5997c478bd9Sstevel@tonic-gate 	/* input device characteristics */
600c7d88479Slq150181 	if ((conin = kmdb_prom_get_ddi_prop(kav, "input-device")) == NULL ||
6017c478bd9Sstevel@tonic-gate 	    strcmp(conin, "keyboard") == 0) {
6027c478bd9Sstevel@tonic-gate 		(void) kmdb_parse_mode(KMDB_PROM_DEF_CONS_MODE,
6037c478bd9Sstevel@tonic-gate 		    &pif->pif_tios, 1);
6047c478bd9Sstevel@tonic-gate 	} else if (*conin == '/') {
6057c478bd9Sstevel@tonic-gate 		/* See similar case in output-device above */
6067c478bd9Sstevel@tonic-gate 		(void) kmdb_parse_mode(KMDB_PROM_DEF_CONS_MODE,
6077c478bd9Sstevel@tonic-gate 		    &pif->pif_tios, 1);
6087c478bd9Sstevel@tonic-gate 	} else {
6097c478bd9Sstevel@tonic-gate 		char *mode = kmdb_get_ttyio_mode(kav, conin);
6107c478bd9Sstevel@tonic-gate 
6117c478bd9Sstevel@tonic-gate #ifdef __sparc
6127c478bd9Sstevel@tonic-gate 		/*
6137c478bd9Sstevel@tonic-gate 		 * Some platforms (Starfire) define a value of `ttya' for
6147c478bd9Sstevel@tonic-gate 		 * input-device, but neglect to provide a specific property
6157c478bd9Sstevel@tonic-gate 		 * with the characteristics.  We'll provide a default value.
6167c478bd9Sstevel@tonic-gate 		 */
6177c478bd9Sstevel@tonic-gate 		if (mode == NULL && strcmp(conin, "ttya") == 0) {
6187c478bd9Sstevel@tonic-gate 			(void) kmdb_parse_mode(KMDB_PROM_DEF_CONS_MODE,
6197c478bd9Sstevel@tonic-gate 			    &pif->pif_tios, 1);
6207c478bd9Sstevel@tonic-gate 		} else
6217c478bd9Sstevel@tonic-gate #endif
6227c478bd9Sstevel@tonic-gate 		{
6237c478bd9Sstevel@tonic-gate 			if (mode == NULL || kmdb_parse_mode(mode,
6247c478bd9Sstevel@tonic-gate 			    &pif->pif_tios, 1) < 0) {
6257c478bd9Sstevel@tonic-gate 				/*
6267c478bd9Sstevel@tonic-gate 				 * Either we couldn't retrieve the
6277c478bd9Sstevel@tonic-gate 				 * characteristics for this console, or they
6287c478bd9Sstevel@tonic-gate 				 * weren't parseable.  The console hasn't been
6297c478bd9Sstevel@tonic-gate 				 * set up yet, so we can't warn.  We'll have to
6307c478bd9Sstevel@tonic-gate 				 * silently fall back to the default
6317c478bd9Sstevel@tonic-gate 				 * characteristics.
6327c478bd9Sstevel@tonic-gate 				 */
6337c478bd9Sstevel@tonic-gate 				(void) kmdb_parse_mode(KMDB_PROM_DEF_CONS_MODE,
6347c478bd9Sstevel@tonic-gate 				    &pif->pif_tios, 1);
6357c478bd9Sstevel@tonic-gate 			}
6367c478bd9Sstevel@tonic-gate 		}
6377c478bd9Sstevel@tonic-gate 
6387c478bd9Sstevel@tonic-gate 		if (mode != NULL)
639c7d88479Slq150181 			kmdb_prom_free_ddi_prop(mode);
6407c478bd9Sstevel@tonic-gate 	}
6417c478bd9Sstevel@tonic-gate 
6427c478bd9Sstevel@tonic-gate 	/* various characteristics of the prom read/write interface */
6437c478bd9Sstevel@tonic-gate 	pif->pif_tios.c_iflag |= ICRNL;
6447c478bd9Sstevel@tonic-gate 	pif->pif_tios.c_lflag |= ECHO;
6457c478bd9Sstevel@tonic-gate 	bcopy(ccs, &pif->pif_tios.c_cc, sizeof (ccs));
6467c478bd9Sstevel@tonic-gate 
6477c478bd9Sstevel@tonic-gate 	if (conin != NULL)
648c7d88479Slq150181 		kmdb_prom_free_ddi_prop(conin);
6497c478bd9Sstevel@tonic-gate 	if (conout != NULL)
650c7d88479Slq150181 		kmdb_prom_free_ddi_prop(conout);
6517c478bd9Sstevel@tonic-gate }
6527c478bd9Sstevel@tonic-gate 
6537c478bd9Sstevel@tonic-gate char *
kmdb_prom_term_type(void)6547c478bd9Sstevel@tonic-gate kmdb_prom_term_type(void)
6557c478bd9Sstevel@tonic-gate {
6567c478bd9Sstevel@tonic-gate 	return (mdb.m_promif->pif_oterm);
6577c478bd9Sstevel@tonic-gate }
6587c478bd9Sstevel@tonic-gate 
6597c478bd9Sstevel@tonic-gate int
kmdb_prom_term_ctl(int req,void * arg)6607c478bd9Sstevel@tonic-gate kmdb_prom_term_ctl(int req, void *arg)
6617c478bd9Sstevel@tonic-gate {
6627c478bd9Sstevel@tonic-gate 	switch (req) {
6637c478bd9Sstevel@tonic-gate 	case TCGETS: {
6647c478bd9Sstevel@tonic-gate 		struct termios *ti = arg;
6657c478bd9Sstevel@tonic-gate 		bcopy(&mdb.m_promif->pif_tios, ti, sizeof (struct termios));
6667c478bd9Sstevel@tonic-gate 		return (0);
6677c478bd9Sstevel@tonic-gate 	}
6687c478bd9Sstevel@tonic-gate 	case TIOCGWINSZ:
6697c478bd9Sstevel@tonic-gate 		/*
6707c478bd9Sstevel@tonic-gate 		 * When kmdb is used over a serial console, we have no idea how
6717c478bd9Sstevel@tonic-gate 		 * large the terminal window is.  When we're invoked on a local
6727c478bd9Sstevel@tonic-gate 		 * console, however, we do, and need to share that information
6737c478bd9Sstevel@tonic-gate 		 * with the debugger in order to contradict potentially
6747c478bd9Sstevel@tonic-gate 		 * incorrect sizing information retrieved from the terminfo
6757c478bd9Sstevel@tonic-gate 		 * database.  One specific case where this happens is with the
6767c478bd9Sstevel@tonic-gate 		 * Intel console, which is 80x25.  The terminfo entry for
6777c478bd9Sstevel@tonic-gate 		 * sun-color -- the default terminal type for local Intel
6787c478bd9Sstevel@tonic-gate 		 * consoles -- was cloned from sun, which has a height of 34
6797c478bd9Sstevel@tonic-gate 		 * rows.
6807c478bd9Sstevel@tonic-gate 		 */
6817c478bd9Sstevel@tonic-gate 		if (mdb.m_promif->pif_oterm != NULL) {
6827c478bd9Sstevel@tonic-gate 			struct winsize *wsz = arg;
6837c478bd9Sstevel@tonic-gate 			wsz->ws_row = KMDB_PIF_WINSIZE_ROWS;
6847c478bd9Sstevel@tonic-gate 			wsz->ws_col = KMDB_PIF_WINSIZE_COLS;
6857c478bd9Sstevel@tonic-gate 			wsz->ws_xpixel = wsz->ws_ypixel = 0;
6867c478bd9Sstevel@tonic-gate 			return (0);
6877c478bd9Sstevel@tonic-gate 		}
6887c478bd9Sstevel@tonic-gate 
6897c478bd9Sstevel@tonic-gate 		return (set_errno(ENOTSUP));
6907c478bd9Sstevel@tonic-gate 	default:
6917c478bd9Sstevel@tonic-gate 		return (set_errno(EINVAL));
6927c478bd9Sstevel@tonic-gate 	}
6937c478bd9Sstevel@tonic-gate }
6947c478bd9Sstevel@tonic-gate 
6957c478bd9Sstevel@tonic-gate int
kmdb_prom_vtop(uintptr_t virt,physaddr_t * pap)6967c478bd9Sstevel@tonic-gate kmdb_prom_vtop(uintptr_t virt, physaddr_t *pap)
6977c478bd9Sstevel@tonic-gate {
6987c478bd9Sstevel@tonic-gate 	physaddr_t pa;
6997c478bd9Sstevel@tonic-gate 	int rc = kmdb_kdi_vtop(virt, &pa);
7007c478bd9Sstevel@tonic-gate 
7017c478bd9Sstevel@tonic-gate #ifdef	__sparc
7027c478bd9Sstevel@tonic-gate 	if (rc < 0 && errno == EAGAIN)
7037c478bd9Sstevel@tonic-gate 		rc = kmdb_prom_translate_virt(virt, &pa);
7047c478bd9Sstevel@tonic-gate #endif
7057c478bd9Sstevel@tonic-gate 
7067c478bd9Sstevel@tonic-gate 	if (rc == 0 && pap != NULL)
7077c478bd9Sstevel@tonic-gate 		*pap = pa;
7087c478bd9Sstevel@tonic-gate 
7097c478bd9Sstevel@tonic-gate 	return (rc);
7107c478bd9Sstevel@tonic-gate }
7117c478bd9Sstevel@tonic-gate 
7127c478bd9Sstevel@tonic-gate void
kmdb_prom_debugger_entry(void)7137c478bd9Sstevel@tonic-gate kmdb_prom_debugger_entry(void)
7147c478bd9Sstevel@tonic-gate {
7157c478bd9Sstevel@tonic-gate 	/*
7167c478bd9Sstevel@tonic-gate 	 * While kmdb_prom_debugger_entry and kmdb_prom_debugger_exit are not
7177c478bd9Sstevel@tonic-gate 	 * guaranteed to be called an identical number of times (an intentional
7187c478bd9Sstevel@tonic-gate 	 * debugger fault will cause an additional entry call without a matching
7197c478bd9Sstevel@tonic-gate 	 * exit call), we must ensure that the polled I/O entry and exit calls
7207c478bd9Sstevel@tonic-gate 	 * match.
7217c478bd9Sstevel@tonic-gate 	 */
7227c478bd9Sstevel@tonic-gate 	if (mdb.m_pio == NULL) {
7237c478bd9Sstevel@tonic-gate 		mdb.m_pio = kmdb_kdi_get_polled_io();
7247c478bd9Sstevel@tonic-gate 
7257c478bd9Sstevel@tonic-gate 		if (mdb.m_pio != NULL &&
7267c478bd9Sstevel@tonic-gate 		    mdb.m_pio->cons_polledio_enter != NULL) {
7277c478bd9Sstevel@tonic-gate 			(void) kmdb_dpi_call(
7287c478bd9Sstevel@tonic-gate 			    (uintptr_t)mdb.m_pio->cons_polledio_enter, 1,
7297c478bd9Sstevel@tonic-gate 			    (uintptr_t *)&mdb.m_pio->cons_polledio_argument);
7307c478bd9Sstevel@tonic-gate 		}
7317c478bd9Sstevel@tonic-gate 	}
7327c478bd9Sstevel@tonic-gate }
7337c478bd9Sstevel@tonic-gate 
7347c478bd9Sstevel@tonic-gate void
kmdb_prom_debugger_exit(void)7357c478bd9Sstevel@tonic-gate kmdb_prom_debugger_exit(void)
7367c478bd9Sstevel@tonic-gate {
7377c478bd9Sstevel@tonic-gate 	if (mdb.m_pio != NULL && mdb.m_pio->cons_polledio_exit != NULL) {
7387c478bd9Sstevel@tonic-gate 		(void) kmdb_dpi_call((uintptr_t)mdb.m_pio->cons_polledio_exit,
7397c478bd9Sstevel@tonic-gate 		    1, (uintptr_t *)&mdb.m_pio->cons_polledio_argument);
7407c478bd9Sstevel@tonic-gate 	}
7417c478bd9Sstevel@tonic-gate 
7427c478bd9Sstevel@tonic-gate 	mdb.m_pio = NULL;
7437c478bd9Sstevel@tonic-gate }
7447c478bd9Sstevel@tonic-gate 
7457c478bd9Sstevel@tonic-gate #ifdef DEBUG
7467c478bd9Sstevel@tonic-gate /*
7477c478bd9Sstevel@tonic-gate  * The prom_* files use ASSERT, which is #defined as assfail().
7487c478bd9Sstevel@tonic-gate  * We need to redirect that to our assert function.
7497c478bd9Sstevel@tonic-gate  */
7507c478bd9Sstevel@tonic-gate int
kmdb_prom_assfail(const char * assertion,const char * file,int line)7517c478bd9Sstevel@tonic-gate kmdb_prom_assfail(const char *assertion, const char *file, int line)
7527c478bd9Sstevel@tonic-gate {
7537c478bd9Sstevel@tonic-gate 	(void) mdb_dassert(assertion, file, line);
7547c478bd9Sstevel@tonic-gate 	/*NOTREACHED*/
7557c478bd9Sstevel@tonic-gate 	return (0);
7567c478bd9Sstevel@tonic-gate }
7577c478bd9Sstevel@tonic-gate #endif
7587c478bd9Sstevel@tonic-gate 
7597c478bd9Sstevel@tonic-gate /*
7607c478bd9Sstevel@tonic-gate  * Begin the initialization of the debugger/PROM interface.  Initialization is
7617c478bd9Sstevel@tonic-gate  * performed in two steps due to interlocking dependencies between promif and
7627c478bd9Sstevel@tonic-gate  * both the memory allocator and mdb_create.  The first phase is performed
7637c478bd9Sstevel@tonic-gate  * before either of the others have been initialized, and thus must neither
7647c478bd9Sstevel@tonic-gate  * attempt to allocate memory nor access/write to `mdb'.
7657c478bd9Sstevel@tonic-gate  */
7667c478bd9Sstevel@tonic-gate void
kmdb_prom_init_begin(char * pgmname,kmdb_auxv_t * kav)7677c478bd9Sstevel@tonic-gate kmdb_prom_init_begin(char *pgmname, kmdb_auxv_t *kav)
7687c478bd9Sstevel@tonic-gate {
7691ae08745Sheppo #ifdef sun4v
7701ae08745Sheppo 	if (kav->kav_domaining)
7711ae08745Sheppo 		kmdb_prom_init_promif(pgmname, kav);
7721ae08745Sheppo 	else
7737c478bd9Sstevel@tonic-gate 		prom_init(pgmname, kav->kav_romp);
7741ae08745Sheppo #else
7751ae08745Sheppo 	prom_init(pgmname, kav->kav_romp);
7761ae08745Sheppo #endif
7777c478bd9Sstevel@tonic-gate 
7787c478bd9Sstevel@tonic-gate 	/* Initialize the interrupt ring buffer */
7797c478bd9Sstevel@tonic-gate 	kmdb_prom_readbuf_head = kmdb_prom_readbuf_tail;
7807c478bd9Sstevel@tonic-gate 
7817c478bd9Sstevel@tonic-gate #if defined(__i386) || defined(__amd64)
7827c478bd9Sstevel@tonic-gate 	kmdb_sysp = kav->kav_romp;
7837c478bd9Sstevel@tonic-gate #endif
7847c478bd9Sstevel@tonic-gate }
7857c478bd9Sstevel@tonic-gate 
7861ae08745Sheppo #ifdef sun4v
7871ae08745Sheppo void
kmdb_prom_init_promif(char * pgmname,kmdb_auxv_t * kav)7881ae08745Sheppo kmdb_prom_init_promif(char *pgmname, kmdb_auxv_t *kav)
7891ae08745Sheppo {
7901ae08745Sheppo 	ASSERT(kav->kav_domaining);
7911ae08745Sheppo 	cif_init(pgmname, kav->kav_promif_root,
7921ae08745Sheppo 	    kav->kav_promif_in, kav->kav_promif_out,
7931ae08745Sheppo 	    kav->kav_promif_pin, kav->kav_promif_pout,
7941ae08745Sheppo 	    kav->kav_promif_chosennode, kav->kav_promif_optionsnode);
7951ae08745Sheppo }
7961ae08745Sheppo #endif
7971ae08745Sheppo 
7987c478bd9Sstevel@tonic-gate /*
7997c478bd9Sstevel@tonic-gate  * Conclude the initialization of the debugger/PROM interface.  Memory
8007c478bd9Sstevel@tonic-gate  * allocation and the global `mdb' object are now available.
8017c478bd9Sstevel@tonic-gate  */
8027c478bd9Sstevel@tonic-gate void
kmdb_prom_init_finish(kmdb_auxv_t * kav)8037c478bd9Sstevel@tonic-gate kmdb_prom_init_finish(kmdb_auxv_t *kav)
8047c478bd9Sstevel@tonic-gate {
8057c478bd9Sstevel@tonic-gate 	mdb.m_promif = mdb_zalloc(sizeof (kmdb_promif_t), UM_SLEEP);
8067c478bd9Sstevel@tonic-gate 	kmdb_prom_term_init(kav, mdb.m_promif);
8077c478bd9Sstevel@tonic-gate }
808