kmdb_promif.c revision de81e71e031139a0a7f13b7bf64152c3faa76698
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#ifdef sun4v
#include <sys/promif_impl.h>
#endif
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <kmdb/kmdb_promif_impl.h>
#include <kmdb/kmdb_kdi.h>
#include <kmdb/kmdb_dpi.h>
#include <mdb/mdb_debug.h>
#include <mdb/mdb_frame.h>
#include <mdb/mdb_string.h>
#define KMDB_PROM_DEF_CONS_MODE "9600,n,1,-,-"
#define KMDB_PROM_READBUF_SIZE 1024
static char kmdb_prom_readbuf[KMDB_PROM_READBUF_SIZE];
static int kmdb_prom_readbuf_head;
static int kmdb_prom_readbuf_tail;
static int
kmdb_prom_getchar(int wait)
{
int c;
while ((c = prom_mayget()) == -1) {
if (!wait)
return (-1);
}
return (c);
}
return (-1);
}
static ssize_t
{
int i;
for (i = 0; i < len; i++) {
(void) kmdb_dpi_call(
}
return (len);
}
static ssize_t
{
int nread = 0;
int c;
break;
*buf++ = (char)c;
nread++;
wait = 0;
}
return (nread);
}
static ssize_t
{
}
/*
* Due to the nature of kmdb, we don't have signals. This prevents us from
* receiving asynchronous notification when the user would like to abort active
* dcmds. Whereas mdb can simply declare a SIGINT handler, we must
* occasionally poll the input stream, looking for pending ^C characters. To
* give the illusion of asynchronous interrupt delivery, this polling is
* triggered from several commonly-used functions, such as kmdb_prom_write and
* the *read and *write target ops. When an interrupt check is triggered, we
* read through pending input, looking for interrupt characters. If we find
* one, we deliver an interrupt immediately.
*
* In a read context, we can deliver the interrupt character directly back to
* the termio handler rather than raising an interrupt.
*
* OBP doesn't have an "unget" facility. Any character read for interrupt
* checking is gone forever, unless we save it. Loss of these characters
* would prevent us from supporting typeahead. We like typeahead, so we're
* going to save characters gathered during interrupt checking. As with
* ungetc(3c), however, we can only store a finite number of characters in
* our typeahead buffer. Characters read beyond that will be silently dropped
* after they undergo interrupt processing.
*
* The typeahead facility is implemented as a ring buffer, stored in
* kmdb_prom_readbuf.
*/
static size_t
{
/*
* If head > tail, life is easy - we can simply read as much as we need
* in one gulp.
*/
kmdb_prom_readbuf_tail += n;
return (n);
} else if (kmdb_prom_readbuf_head == kmdb_prom_readbuf_tail) {
return (0);
}
/*
* The consumable slots wrap around zero (there are slots from tail to
* zero, and from zero to head). We have to read them in two parts.
*/
kmdb_prom_readbuf_tail = (kmdb_prom_readbuf_tail + n) %
if (n == len) {
/*
* We filled the passed buffer from the first part, so there's
* no need to read the second.
*/
return (n);
} else {
tailread = n;
}
kmdb_prom_readbuf_tail = (kmdb_prom_readbuf_tail + n) %
return (tailread + n);
}
static void
{
int i;
for (i = 0; i < len; i++) {
else
}
}
}
/*
* Attempt to refill the ring buffer from the input stream. This called from
* two contexts:
*
* Direct read: read the input into our buffer until input is exhausted, or the
* buffer is full.
*
* Interrupt check: called 'asynchronously' from the normal read routines; read
* the input into our buffer until it is exhausted, discarding input if the
* buffer is full. In this case we look ahead for any interrupt characters,
* delivering an interrupt directly if we find one.
*/
static void
{
/*
* Calculate the number of slots left before we wrap around to the
* beginning again.
*/
if (kmdb_prom_readbuf_tail == 0)
left--;
if (kmdb_prom_readbuf_head == kmdb_prom_readbuf_tail ||
/*
* head > tail, so we have to read in two parts - the slots
* from head until we wrap back around to zero, and the ones
* from zero to tail. We handle the first part here, and let
* the common code handle the second.
*/
if ((n = kmdb_prom_reader(kmdb_prom_readbuf +
return;
kmdb_prom_readbuf_head = (kmdb_prom_readbuf_head + n) %
if (check_for_int)
if (n != left)
return;
}
if (left > 0) {
if ((n = kmdb_prom_reader(kmdb_prom_readbuf +
return;
kmdb_prom_readbuf_head = (kmdb_prom_readbuf_head + n) %
if (check_for_int)
if (n != left)
return;
}
if (check_for_int) {
char c;
check_int(&c, 1);
}
}
void
{
kmdb_prom_fill_readbuf(1, 0);
}
/*
* OBP reads are always non-blocking. If there are characters available,
* we'll return as many as we can. If nothing is available, we'll spin
* until one shows up.
*/
{
char *c = (char *)buf;
int wait = 1;
for (;;) {
c += thisread;
/* wait until something shows up */
if (totread == 0)
continue;
wait = 0;
/*
* We're done if we've exhausted available input or if we've
* filled the provided buffer.
*/
break;
}
int i;
for (i = 0; i < totread; i++) {
if (cbuf[i] == '\r')
cbuf[i] = '\n';
}
}
return (totread);
}
/*ARGSUSED*/
{
char *nl = "\r\n";
char *c;
/* translate every \n into \r\n */
if (c != buf) {
}
buf = c + 1;
left--;
}
if (*buf != '\0')
return (len);
}
static char *
{
return (modepval);
}
static int
{
return (-1);
} else
return (0);
}
static int
{
return (-1);
if (s > CBAUD) {
s -= (CBAUD + 1);
} else
return (0);
}
static int
{
0, 50, 75, 110, 134, 150, 200, 300, 600, 1200,
1800, 2400, 4800, 9600, 19200, 38400, 57600,
76800, 115200, 153600, 230400, 307200, 460800, 921600
};
char *w;
int rc = -1;
int baud, i;
/*
* termios supports different baud rates and flow control types for
* input and output, but it requires character width, parity, and stop
* bits to be equal in input and output. obp allows them to be
* different, but we're going to (silently) assume that nobody will use
* it that way.
*/
/* baud rate - see baudmap above */
goto parse_mode_bail;
speed = 0;
speed = i;
break;
}
}
if (speed == 0)
goto parse_mode_bail;
if (in == 1)
else
/* character width (bits) - 5, 6, 7, or 8 */
*w > '8')
goto parse_mode_bail;
/* parity - `n' (none), `e' (even), or `o' (odd) */
goto parse_mode_bail;
switch (*w) {
case 'n':
/* nothing */
break;
case 'e':
break;
case 'o':
break;
}
/*
* stop bits - 1, or 2. obp can, in theory, support 1.5 bits,
* but we can't. how many angels can dance on half of a bit?
*/
*w > '2')
goto parse_mode_bail;
if (*w == '1')
else
goto parse_mode_bail;
switch (*w) {
case 'h':
break;
case 's':
break;
}
rc = 0;
strfree(m);
return (rc);
}
#ifdef __sparc
#define ATTACHED_TERM_TYPE "sun"
#else
#define ATTACHED_TERM_TYPE "sun-color"
#endif
static void
{
0x00, 0x11, 0x13, 0x1a, 0x19, 0x12, 0x0f, 0x17, 0x16 };
/* output device characteristics */
} else if (*conout == '/') {
/*
* We're not going to be able to get characteristics for a
* device that's specified as a path, so don't even try.
* Conveniently, this allows us to avoid chattering on
* Serengetis.
*/
} else {
#ifdef __sparc
/*
* Some platforms (Starfire) define a value of `ttya' for
* output-device, but neglect to provide a specific property
* with the characteristics. We'll provide a default value.
*/
} else
#endif
{
/*
* Either we couldn't retrieve the
* characteristics for this console, or they
* weren't parseable. The console hasn't been
* set up yet, so we can't warn. We'll have to
* silently fall back to the default
* characteristics.
*/
}
}
}
/* input device characteristics */
} else if (*conin == '/') {
/* See similar case in output-device above */
} else {
#ifdef __sparc
/*
* Some platforms (Starfire) define a value of `ttya' for
* input-device, but neglect to provide a specific property
* with the characteristics. We'll provide a default value.
*/
} else
#endif
{
/*
* Either we couldn't retrieve the
* characteristics for this console, or they
* weren't parseable. The console hasn't been
* set up yet, so we can't warn. We'll have to
* silently fall back to the default
* characteristics.
*/
}
}
}
}
char *
kmdb_prom_term_type(void)
{
}
int
{
switch (req) {
case TCGETS: {
return (0);
}
case TIOCGWINSZ:
/*
* When kmdb is used over a serial console, we have no idea how
* large the terminal window is. When we're invoked on a local
* console, however, we do, and need to share that information
* with the debugger in order to contradict potentially
* incorrect sizing information retrieved from the terminfo
* database. One specific case where this happens is with the
* Intel console, which is 80x25. The terminfo entry for
* sun-color -- the default terminal type for local Intel
* consoles -- was cloned from sun, which has a height of 34
* rows.
*/
return (0);
}
default:
}
}
int
{
#ifdef __sparc
#endif
return (rc);
}
void
kmdb_prom_debugger_entry(void)
{
/*
* While kmdb_prom_debugger_entry and kmdb_prom_debugger_exit are not
* guaranteed to be called an identical number of times (an intentional
* debugger fault will cause an additional entry call without a matching
* exit call), we must ensure that the polled I/O entry and exit calls
* match.
*/
(void) kmdb_dpi_call(
}
}
}
void
kmdb_prom_debugger_exit(void)
{
}
}
#ifdef DEBUG
/*
* The prom_* files use ASSERT, which is #defined as assfail().
* We need to redirect that to our assert function.
*/
int
{
/*NOTREACHED*/
return (0);
}
#endif
/*
* performed in two steps due to interlocking dependencies between promif and
* both the memory allocator and mdb_create. The first phase is performed
* before either of the others have been initialized, and thus must neither
*/
void
{
#ifdef sun4v
if (kav->kav_domaining)
else
#else
#endif
/* Initialize the interrupt ring buffer */
#endif
}
#ifdef sun4v
void
{
}
#endif
/*
* allocation and the global `mdb' object are now available.
*/
void
{
}