Subject: Console Magic redux
To: None <tech-kern@netbsd.org>
From: None <eeh@netbsd.org>
List: tech-kern
Date: 11/05/2000 16:11:50
Here we go again.

Breaking into the debugger from the console is an interesting problem.
Most serial drivers have code to check if they are the console if they
receive a BREAK and check if they are the console.  Others can have
keyboards attached and have checks for specific key sequences.

These methods are not particularly flexible or customizable.  There are
times when you don't want a machine to ignore BREAK.  It might be
desirable to have a long, obscure key sequence break into the
debugger.  And one serial driver may be used by different ports that have
different key sequences to enter the debugger.  Or different sequences
should be used by different ports.

What I'm not proposing to solve is the issue of registering console
devices.  Since that may require cascaded drivers I don't think there
is a MI solution to that.

Anyway, I'm proposing an interface to solve these issues:

void
cn_trap();

This routine usually is defined as `console_debugger()' but can be overridden
in MD header files if needed.  It does whatever is necessary to enter the
debugger, PROM, whatever.  It usually just does a Debugger(), but some
machines such as SPARCs and Sun 4s will enter the PROM on a magic sequence if
DDB is not compiled in.


int
cn_isconsole(dev_t dev);

This routine takes a dev_t and returns non-zero if that is the console device.
It can be overridden in MD header files if needed.


void
cn_check_magic(dev_t dev, int k, cnm_state_t);

It uses cn_isconsole() to determine if this device is the console or on part
of the console input stream.  If so, it checks the key sequence (k) to see if
it matches the the magic sequence.  If there is a match, it calls cn_trap().

dev		dev_t of the instance of the device that recieved a keystroke.

k		Byte read from serial line or keyboard.  Break is represented by
		the value `CNC_BREAK'.

db_state_t	This is an opaque structure provided by the device driver
		to allow db_check_magic() to keep a separate state for
		multiple input devices.

This routine is designed to be fast and should be placed in the highest
level interrupt handler so you can enter the debugger even if the machine
is wedged.


void
cn_init_magic(cnm_state_t *cnm);

Initialize a console magic state structure so it can be used.


int
cn_set_magic(char *magic);

This routine changes the magic key sequence.  A magic string is a 
null-terminated string of characters.  Certain out of band events
cannot be encoded in an 8-bit character.  These are encoded as an
escape sequence consisting of the escape character, 0x27, followed
by an escape code.  These are the defined escape codes:

	0x27	The escape character itself
	0x01	Serial BREAK
	0x02	NUL (0x00) character

It returns 0 on success.

cn_set_magic() should be used by the console driver to register
an appropriate default magic key sequence when the driver attaches.


int
cn_get_magic(char *magic, int len);

This routine is the inverse of cn_set_magic().  It extracts the magic key
sequence into a string, up to a maximum length of `len'.  It returns 0 on
success.


void
cn_destroy_magic(cnm_state_t *cnm);

Destroy a magic state structure.


kern.cnmagic sysctl variable will be added.  This takes a
string.  cn_set_magic() will be used to convert kern.cnmagic to an internal
representation.


cn_trap(), cn_isconsole(), and cn_check_magic() are all implemented as macros
and can be overridden by MD header files if needed.


Eduardo Horvath