Add dumb console driver and related bits.
dcons(4): very simple console and gdb port driver dcons_crom(4): FireWire attachment dconschat(8): User interface to dcons Tested with: i386, i386-PAE, and sparc64.
This commit is contained in:
parent
ed7d11555d
commit
869093b15d
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=121468
@ -50,6 +50,8 @@ ttyd0 "/usr/libexec/getty std.9600" vt100 on secure
|
|||||||
ttyd1 "/usr/libexec/getty std.9600" dialup off secure
|
ttyd1 "/usr/libexec/getty std.9600" dialup off secure
|
||||||
ttyd2 "/usr/libexec/getty std.9600" dialup off secure
|
ttyd2 "/usr/libexec/getty std.9600" dialup off secure
|
||||||
ttyd3 "/usr/libexec/getty std.9600" dialup off secure
|
ttyd3 "/usr/libexec/getty std.9600" dialup off secure
|
||||||
|
# Dumb console
|
||||||
|
dcons "/usr/libexec/getty std.9600" vt100 off secure
|
||||||
# Pseudo terminals
|
# Pseudo terminals
|
||||||
ttyp0 none network
|
ttyp0 none network
|
||||||
ttyp1 none network
|
ttyp1 none network
|
||||||
|
@ -48,6 +48,8 @@ ttyd0 "/usr/libexec/getty std.9600" dialup off secure
|
|||||||
ttyd1 "/usr/libexec/getty std.9600" dialup off secure
|
ttyd1 "/usr/libexec/getty std.9600" dialup off secure
|
||||||
ttyd2 "/usr/libexec/getty std.9600" dialup off secure
|
ttyd2 "/usr/libexec/getty std.9600" dialup off secure
|
||||||
ttyd3 "/usr/libexec/getty std.9600" dialup off secure
|
ttyd3 "/usr/libexec/getty std.9600" dialup off secure
|
||||||
|
# Dumb console
|
||||||
|
dcons "/usr/libexec/getty std.9600" vt100 off secure
|
||||||
# Pseudo terminals
|
# Pseudo terminals
|
||||||
ttyp0 none network
|
ttyp0 none network
|
||||||
ttyp1 none network
|
ttyp1 none network
|
||||||
|
@ -48,6 +48,8 @@ ttyd0 "/usr/libexec/getty std.9600" dialup off secure
|
|||||||
ttyd1 "/usr/libexec/getty std.9600" dialup off secure
|
ttyd1 "/usr/libexec/getty std.9600" dialup off secure
|
||||||
ttyd2 "/usr/libexec/getty std.9600" dialup off secure
|
ttyd2 "/usr/libexec/getty std.9600" dialup off secure
|
||||||
ttyd3 "/usr/libexec/getty std.9600" dialup off secure
|
ttyd3 "/usr/libexec/getty std.9600" dialup off secure
|
||||||
|
# Dumb console
|
||||||
|
dcons "/usr/libexec/getty std.9600" vt100 off secure
|
||||||
# Pseudo terminals
|
# Pseudo terminals
|
||||||
ttyp0 none network
|
ttyp0 none network
|
||||||
ttyp1 none network
|
ttyp1 none network
|
||||||
|
@ -48,6 +48,8 @@ ttyu0 "/usr/libexec/getty std.9600" vt100 on secure
|
|||||||
ttyu1 "/usr/libexec/getty std.9600" dialup off secure
|
ttyu1 "/usr/libexec/getty std.9600" dialup off secure
|
||||||
ttyu2 "/usr/libexec/getty std.9600" dialup off secure
|
ttyu2 "/usr/libexec/getty std.9600" dialup off secure
|
||||||
ttyu3 "/usr/libexec/getty std.9600" dialup off secure
|
ttyu3 "/usr/libexec/getty std.9600" dialup off secure
|
||||||
|
# Dumb console
|
||||||
|
dcons "/usr/libexec/getty std.9600" vt100 off secure
|
||||||
# Pseudo terminals.
|
# Pseudo terminals.
|
||||||
ttyp0 none network
|
ttyp0 none network
|
||||||
ttyp1 none network
|
ttyp1 none network
|
||||||
|
@ -52,6 +52,8 @@ ttyu0 "/usr/libexec/getty std.9600" vt100 on secure
|
|||||||
ttyu1 "/usr/libexec/getty std.9600" vt100 on secure
|
ttyu1 "/usr/libexec/getty std.9600" vt100 on secure
|
||||||
ttyu2 "/usr/libexec/getty std.9600" vt100 off secure
|
ttyu2 "/usr/libexec/getty std.9600" vt100 off secure
|
||||||
ttyu3 "/usr/libexec/getty std.9600" vt100 off secure
|
ttyu3 "/usr/libexec/getty std.9600" vt100 off secure
|
||||||
|
# Dumb console
|
||||||
|
dcons "/usr/libexec/getty std.9600" vt100 off secure
|
||||||
# Pseudo terminals
|
# Pseudo terminals
|
||||||
ttyp0 none network
|
ttyp0 none network
|
||||||
ttyp1 none network
|
ttyp1 none network
|
||||||
|
@ -41,6 +41,8 @@ MAN= aac.4 \
|
|||||||
cue.4 \
|
cue.4 \
|
||||||
da.4 \
|
da.4 \
|
||||||
dc.4 \
|
dc.4 \
|
||||||
|
dcons.4 \
|
||||||
|
dcons_crom.4 \
|
||||||
ddb.4 \
|
ddb.4 \
|
||||||
de.4 \
|
de.4 \
|
||||||
devctl.4 \
|
devctl.4 \
|
||||||
|
112
share/man/man4/dcons.4
Normal file
112
share/man/man4/dcons.4
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
.\" Copyright (c) 2003 Hidetoshi Shimokawa
|
||||||
|
.\" All rights reserved.
|
||||||
|
.\"
|
||||||
|
.\" Redistribution and use in source and binary forms, with or without
|
||||||
|
.\" modification, are permitted provided that the following conditions
|
||||||
|
.\" are met:
|
||||||
|
.\" 1. Redistributions of source code must retain the above copyright
|
||||||
|
.\" notice, this list of conditions and the following disclaimer.
|
||||||
|
.\" 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
.\" notice, this list of conditions and the following disclaimer in the
|
||||||
|
.\" documentation and/or other materials provided with the distribution.
|
||||||
|
.\"
|
||||||
|
.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
.\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
.\" DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
|
||||||
|
.\" INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
.\" (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
.\" SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||||
|
.\" STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||||
|
.\" ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
.\" POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
.\"
|
||||||
|
.\" $FreeBSD$
|
||||||
|
.\"
|
||||||
|
.\"
|
||||||
|
.Dd February 11, 2003
|
||||||
|
.Dt DCONS 4
|
||||||
|
.Os
|
||||||
|
.Sh NAME
|
||||||
|
.Nm dcons
|
||||||
|
.Nd dumb console device driver
|
||||||
|
.Sh SYNOPSIS
|
||||||
|
.Cd device dcons
|
||||||
|
.Pp
|
||||||
|
.Cd options DDB
|
||||||
|
.Cd options ALT_BREAK_TO_DEBUGGER
|
||||||
|
.Pp
|
||||||
|
.Cd device firewire
|
||||||
|
.Sh DESCRIPTION
|
||||||
|
The
|
||||||
|
.Nm
|
||||||
|
device is the simple console device which just reads from and writes to
|
||||||
|
an allocated buffer for input and output respectivly.
|
||||||
|
It is no use by itself and it is supposed that the buffer is accessed
|
||||||
|
via a bus like
|
||||||
|
.Xr FireWire 4
|
||||||
|
for interaction.
|
||||||
|
.Pp
|
||||||
|
The buffer consists of 4 channels.
|
||||||
|
There are 2 ports, one for console tty and other is GDB ports then each port
|
||||||
|
has a input channel and a output channel.
|
||||||
|
The physical address of the buffer is sometimes neccesary to acess the buffer.
|
||||||
|
You can get the address by
|
||||||
|
.Xr sysctl 8
|
||||||
|
or
|
||||||
|
.Xr dmesg 8
|
||||||
|
.
|
||||||
|
.Sh EXAMPLE
|
||||||
|
If you want to run
|
||||||
|
.Xr getty 8
|
||||||
|
on dcons, insert following line into
|
||||||
|
.Xr /etc/ttys 5
|
||||||
|
and
|
||||||
|
send a HUP signal to
|
||||||
|
.Xr init 8
|
||||||
|
using
|
||||||
|
.Xr kill 1 .
|
||||||
|
.Bd -literal -offset indent
|
||||||
|
dcons "/usr/libexec/getty std.9600" vt100 on secure
|
||||||
|
.Ed
|
||||||
|
.Pp
|
||||||
|
You can use either of the following commands to obtain physical
|
||||||
|
address of the buffer.
|
||||||
|
.Bd -literal -offset indent
|
||||||
|
% sysctl kern.dcons.paddr
|
||||||
|
kern.dcons.paddr: 4732704
|
||||||
|
% dmesg | grep dcons: | tail -1
|
||||||
|
dcons: virtual 0xc0483720 physical 0x483720 quad 0x120dc8
|
||||||
|
.Ed
|
||||||
|
.Pp
|
||||||
|
In this example, the buffer is located at 4732704 in decimal
|
||||||
|
and 0x483720 in hex.
|
||||||
|
.Pp
|
||||||
|
Once
|
||||||
|
.Xr fwochi 4
|
||||||
|
device is initialized to allow physical access,
|
||||||
|
the buffer can be accessed from another host via FireWire bus using
|
||||||
|
.Xr fwchat 8
|
||||||
|
application. See
|
||||||
|
.Xr fwchat 8
|
||||||
|
for more details.
|
||||||
|
.Pp
|
||||||
|
.Sh FILES
|
||||||
|
.Bl -tag -width indent -compact
|
||||||
|
.It Pa /dev/dcons
|
||||||
|
.It Pa /dev/dconsctl
|
||||||
|
.It Pa /etc/ttys
|
||||||
|
.El
|
||||||
|
.Sh SEE ALSO
|
||||||
|
.Xr ddb 4 ,
|
||||||
|
.Xr firewire 4 ,
|
||||||
|
.Xr fwohci 4 ,
|
||||||
|
.Xr fwchat 8 ,
|
||||||
|
.Xr fwcontrol 8 ,
|
||||||
|
.Xr ttys 5
|
||||||
|
.Sh AUTHORS
|
||||||
|
.An Hidetoshi Shimokawa Aq simokawa@FreeBSD.org
|
||||||
|
.Sh BUGS
|
||||||
|
This driver is still under development.
|
||||||
|
.Pp
|
59
share/man/man4/dcons_crom.4
Normal file
59
share/man/man4/dcons_crom.4
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
.\" Copyright (c) 2003 Hidetoshi Shimokawa
|
||||||
|
.\" All rights reserved.
|
||||||
|
.\"
|
||||||
|
.\" Redistribution and use in source and binary forms, with or without
|
||||||
|
.\" modification, are permitted provided that the following conditions
|
||||||
|
.\" are met:
|
||||||
|
.\" 1. Redistributions of source code must retain the above copyright
|
||||||
|
.\" notice, this list of conditions and the following disclaimer.
|
||||||
|
.\" 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
.\" notice, this list of conditions and the following disclaimer in the
|
||||||
|
.\" documentation and/or other materials provided with the distribution.
|
||||||
|
.\"
|
||||||
|
.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
.\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
.\" DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
|
||||||
|
.\" INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
.\" (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
.\" SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||||
|
.\" STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||||
|
.\" ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
.\" POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
.\"
|
||||||
|
.\" $FreeBSD$
|
||||||
|
.\"
|
||||||
|
.\"
|
||||||
|
.Dd June 16, 2003
|
||||||
|
.Dt DCONS_CROM 4
|
||||||
|
.Os
|
||||||
|
.Sh NAME
|
||||||
|
.Nm dcons_crom
|
||||||
|
.Nd Configuration ROM stub for
|
||||||
|
.Xr dcons 4
|
||||||
|
.Sh SYNOPSIS
|
||||||
|
.Cd device dcons_crom
|
||||||
|
.Cd device dcons
|
||||||
|
.Cd device firewire
|
||||||
|
.Pp
|
||||||
|
.Sh DESCRIPTION
|
||||||
|
The
|
||||||
|
.Nm
|
||||||
|
exposes buffer address of
|
||||||
|
.Xr dcons 4
|
||||||
|
via Configuration ROM which is accessed by
|
||||||
|
.Xr FireWire 4
|
||||||
|
.
|
||||||
|
.El
|
||||||
|
.Sh SEE ALSO
|
||||||
|
.Xr dcons 4 ,
|
||||||
|
.Xr firewire 4 ,
|
||||||
|
.Xr fwohci 4 ,
|
||||||
|
.Xr fwchat 8 ,
|
||||||
|
.Xr fwcontrol 8 ,
|
||||||
|
.Sh AUTHORS
|
||||||
|
.An Hidetoshi Shimokawa Aq simokawa@FreeBSD.org
|
||||||
|
.Sh BUGS
|
||||||
|
This driver is still under development.
|
||||||
|
.Pp
|
@ -2241,11 +2241,21 @@ makeoptions UKBD_DFLT_KEYMAP=it.iso
|
|||||||
options UVSCOM_DEFAULT_OPKTSIZE=8 # default output packet size
|
options UVSCOM_DEFAULT_OPKTSIZE=8 # default output packet size
|
||||||
|
|
||||||
#####################################################################
|
#####################################################################
|
||||||
# Firewire support
|
# FireWire support
|
||||||
|
|
||||||
device firewire # Firewire bus code
|
device firewire # FireWire bus code
|
||||||
device sbp # SCSI over Firewire (Requires scbus and da)
|
device sbp # SCSI over Firewire (Requires scbus and da)
|
||||||
device fwe # Ethernet over Firewire (non-standard!)
|
device fwe # Ethernet over FireWire (non-standard!)
|
||||||
|
|
||||||
|
#####################################################################
|
||||||
|
# dcons support (Dumb Console Device)
|
||||||
|
|
||||||
|
device dcons # dumb console driver
|
||||||
|
device dcons_crom # FireWire attachment
|
||||||
|
options DCONS_BUF_SIZE=16384 # buffer size
|
||||||
|
options DCONS_POLL_HZ=100 # polling rate
|
||||||
|
options DCONS_FORCE_CONSOLE=0 # force to be the primary console
|
||||||
|
options DCONS_FORCE_GDB=1 # force to be the gdb device
|
||||||
|
|
||||||
#####################################################################
|
#####################################################################
|
||||||
# crypto subsystem
|
# crypto subsystem
|
||||||
|
@ -351,6 +351,8 @@ dev/cs/if_cs.c optional cs
|
|||||||
dev/cs/if_cs_isa.c optional cs isa
|
dev/cs/if_cs_isa.c optional cs isa
|
||||||
dev/cs/if_cs_pccard.c optional cs card
|
dev/cs/if_cs_pccard.c optional cs card
|
||||||
dev/cs/if_cs_pccard.c optional cs pccard
|
dev/cs/if_cs_pccard.c optional cs pccard
|
||||||
|
dev/dcons/dcons.c optional dcons
|
||||||
|
dev/dcons/dcons_crom.c optional dcons_crom
|
||||||
dev/digi/digi.c optional digi
|
dev/digi/digi.c optional digi
|
||||||
dev/digi/digi_isa.c optional digi isa
|
dev/digi/digi_isa.c optional digi isa
|
||||||
dev/digi/digi_pci.c optional digi pci
|
dev/digi/digi_pci.c optional digi pci
|
||||||
|
@ -673,3 +673,9 @@ AH_SUPPORT_AR5212 opt_ah.h
|
|||||||
AH_DEBUG opt_ah.h
|
AH_DEBUG opt_ah.h
|
||||||
AH_DEBUG_ALQ opt_ah.h
|
AH_DEBUG_ALQ opt_ah.h
|
||||||
AH_ASSERT opt_ah.h
|
AH_ASSERT opt_ah.h
|
||||||
|
|
||||||
|
# dcons options
|
||||||
|
DCONS_BUF_SIZE opt_dcons.h
|
||||||
|
DCONS_POLL_HZ opt_dcons.h
|
||||||
|
DCONS_FORCE_CONSOLE opt_dcons.h
|
||||||
|
DCONS_FORCE_GDB opt_dcons.h
|
||||||
|
648
sys/dev/dcons/dcons.c
Normal file
648
sys/dev/dcons/dcons.c
Normal file
@ -0,0 +1,648 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2003
|
||||||
|
* Hidetoshi Shimokawa. All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. All advertising materials mentioning features or use of this software
|
||||||
|
* must display the following acknowledgement:
|
||||||
|
*
|
||||||
|
* This product includes software developed by Hidetoshi Shimokawa.
|
||||||
|
*
|
||||||
|
* 4. Neither the name of the author nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||||
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||||
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
* SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* $Id: dcons.c,v 1.65 2003/10/24 03:24:55 simokawa Exp $
|
||||||
|
* $FreeBSD$
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <sys/param.h>
|
||||||
|
#include <sys/kernel.h>
|
||||||
|
#include <sys/systm.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/conf.h>
|
||||||
|
#include <sys/cons.h>
|
||||||
|
#include <sys/consio.h>
|
||||||
|
#include <sys/tty.h>
|
||||||
|
#include <sys/malloc.h>
|
||||||
|
#include <sys/proc.h>
|
||||||
|
#include <sys/ucred.h>
|
||||||
|
|
||||||
|
#include <machine/bus.h>
|
||||||
|
|
||||||
|
#include <dev/dcons/dcons.h>
|
||||||
|
|
||||||
|
#include <ddb/ddb.h>
|
||||||
|
#include <sys/reboot.h>
|
||||||
|
|
||||||
|
#include <sys/sysctl.h>
|
||||||
|
|
||||||
|
#include "opt_ddb.h"
|
||||||
|
#include "opt_comconsole.h"
|
||||||
|
#include "opt_dcons.h"
|
||||||
|
|
||||||
|
#ifndef DCONS_POLL_HZ
|
||||||
|
#define DCONS_POLL_HZ 100
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef DCONS_BUF_SIZE
|
||||||
|
#define DCONS_BUF_SIZE (16*1024)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef DCONS_FORCE_CONSOLE
|
||||||
|
#define DCONS_FORCE_CONSOLE 0 /* mostly for FreeBSD-4 */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef DCONS_FORCE_GDB
|
||||||
|
#define DCONS_FORCE_GDB 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if __FreeBSD_version >= 500101
|
||||||
|
#define CONS_NODEV 1 /* for latest current */
|
||||||
|
static struct consdev gdbconsdev;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define CDEV_MAJOR 184
|
||||||
|
|
||||||
|
static d_open_t dcons_open;
|
||||||
|
static d_close_t dcons_close;
|
||||||
|
static d_ioctl_t dcons_ioctl;
|
||||||
|
|
||||||
|
static struct cdevsw dcons_cdevsw = {
|
||||||
|
#if __FreeBSD_version >= 500104
|
||||||
|
.d_open = dcons_open,
|
||||||
|
.d_close = dcons_close,
|
||||||
|
.d_read = ttyread,
|
||||||
|
.d_write = ttywrite,
|
||||||
|
.d_ioctl = dcons_ioctl,
|
||||||
|
.d_poll = ttypoll,
|
||||||
|
.d_name = "dcons",
|
||||||
|
.d_maj = CDEV_MAJOR,
|
||||||
|
#else
|
||||||
|
/* open */ dcons_open,
|
||||||
|
/* close */ dcons_close,
|
||||||
|
/* read */ ttyread,
|
||||||
|
/* write */ ttywrite,
|
||||||
|
/* ioctl */ dcons_ioctl,
|
||||||
|
/* poll */ ttypoll,
|
||||||
|
/* mmap */ nommap,
|
||||||
|
/* strategy */ nostrategy,
|
||||||
|
/* name */ "dcons",
|
||||||
|
/* major */ CDEV_MAJOR,
|
||||||
|
/* dump */ nodump,
|
||||||
|
/* psize */ nopsize,
|
||||||
|
/* flags */ 0,
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifndef KLD_MODULE
|
||||||
|
static char bssbuf[DCONS_BUF_SIZE]; /* buf in bss */
|
||||||
|
#endif
|
||||||
|
struct dcons_buf *dcons_buf;
|
||||||
|
size_t dcons_bufsize;
|
||||||
|
bus_dma_tag_t dcons_dma_tag = NULL;
|
||||||
|
bus_dmamap_t dcons_dma_map = NULL;
|
||||||
|
|
||||||
|
static int poll_hz = DCONS_POLL_HZ;
|
||||||
|
SYSCTL_NODE(_kern, OID_AUTO, dcons, CTLFLAG_RD, 0, "Dumb Console");
|
||||||
|
SYSCTL_INT(_kern_dcons, OID_AUTO, poll_hz, CTLFLAG_RW, &poll_hz, 0,
|
||||||
|
"dcons polling rate");
|
||||||
|
|
||||||
|
static int drv_init = 0;
|
||||||
|
static struct callout dcons_callout;
|
||||||
|
|
||||||
|
/* per device data */
|
||||||
|
static struct dcons_softc {
|
||||||
|
dev_t dev;
|
||||||
|
struct dcons_ch o, i;
|
||||||
|
int brk_state;
|
||||||
|
#define DC_GDB 1
|
||||||
|
int flags;
|
||||||
|
} sc[DCONS_NPORT];
|
||||||
|
static void dcons_tty_start(struct tty *);
|
||||||
|
static int dcons_tty_param(struct tty *, struct termios *);
|
||||||
|
static void dcons_timeout(void *);
|
||||||
|
static int dcons_drv_init(int);
|
||||||
|
static int dcons_getc(struct dcons_softc *);
|
||||||
|
static int dcons_checkc(struct dcons_softc *);
|
||||||
|
static void dcons_putc(struct dcons_softc *, int);
|
||||||
|
|
||||||
|
static cn_probe_t dcons_cnprobe;
|
||||||
|
static cn_init_t dcons_cninit;
|
||||||
|
static cn_getc_t dcons_cngetc;
|
||||||
|
static cn_checkc_t dcons_cncheckc;
|
||||||
|
static cn_putc_t dcons_cnputc;
|
||||||
|
|
||||||
|
CONS_DRIVER(dcons, dcons_cnprobe, dcons_cninit, NULL, dcons_cngetc,
|
||||||
|
dcons_cncheckc, dcons_cnputc, NULL);
|
||||||
|
|
||||||
|
#if __FreeBSD_version < 500000
|
||||||
|
#define THREAD proc
|
||||||
|
#else
|
||||||
|
#define THREAD thread
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static int
|
||||||
|
dcons_open(dev_t dev, int flag, int mode, struct THREAD *td)
|
||||||
|
{
|
||||||
|
struct tty *tp;
|
||||||
|
int unit, error, s;
|
||||||
|
|
||||||
|
unit = minor(dev);
|
||||||
|
if (unit != 0)
|
||||||
|
return (ENXIO);
|
||||||
|
|
||||||
|
tp = dev->si_tty = ttymalloc(dev->si_tty);
|
||||||
|
tp->t_oproc = dcons_tty_start;
|
||||||
|
tp->t_param = dcons_tty_param;
|
||||||
|
tp->t_stop = nottystop;
|
||||||
|
tp->t_dev = dev;
|
||||||
|
|
||||||
|
error = 0;
|
||||||
|
|
||||||
|
s = spltty();
|
||||||
|
if ((tp->t_state & TS_ISOPEN) == 0) {
|
||||||
|
tp->t_state |= TS_CARR_ON;
|
||||||
|
ttychars(tp);
|
||||||
|
tp->t_iflag = TTYDEF_IFLAG;
|
||||||
|
tp->t_oflag = TTYDEF_OFLAG;
|
||||||
|
tp->t_cflag = TTYDEF_CFLAG|CLOCAL;
|
||||||
|
tp->t_lflag = TTYDEF_LFLAG;
|
||||||
|
tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED;
|
||||||
|
ttsetwater(tp);
|
||||||
|
} else if ((tp->t_state & TS_XCLUDE) && suser(td)) {
|
||||||
|
splx(s);
|
||||||
|
return (EBUSY);
|
||||||
|
}
|
||||||
|
splx(s);
|
||||||
|
|
||||||
|
error = (*linesw[tp->t_line].l_open)(dev, tp);
|
||||||
|
|
||||||
|
return (error);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
dcons_close(dev_t dev, int flag, int mode, struct THREAD *td)
|
||||||
|
{
|
||||||
|
int unit;
|
||||||
|
struct tty *tp;
|
||||||
|
|
||||||
|
unit = minor(dev);
|
||||||
|
if (unit != 0)
|
||||||
|
return (ENXIO);
|
||||||
|
|
||||||
|
tp = dev->si_tty;
|
||||||
|
if (tp->t_state & TS_ISOPEN) {
|
||||||
|
(*linesw[tp->t_line].l_close)(tp, flag);
|
||||||
|
ttyclose(tp);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
dcons_ioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct THREAD *td)
|
||||||
|
{
|
||||||
|
int unit;
|
||||||
|
struct tty *tp;
|
||||||
|
int error;
|
||||||
|
|
||||||
|
unit = minor(dev);
|
||||||
|
if (unit != 0)
|
||||||
|
return (ENXIO);
|
||||||
|
|
||||||
|
tp = dev->si_tty;
|
||||||
|
error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, td);
|
||||||
|
if (error != ENOIOCTL)
|
||||||
|
return (error);
|
||||||
|
|
||||||
|
error = ttioctl(tp, cmd, data, flag);
|
||||||
|
if (error != ENOIOCTL)
|
||||||
|
return (error);
|
||||||
|
|
||||||
|
return (ENOTTY);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
dcons_tty_param(struct tty *tp, struct termios *t)
|
||||||
|
{
|
||||||
|
tp->t_ispeed = t->c_ispeed;
|
||||||
|
tp->t_ospeed = t->c_ospeed;
|
||||||
|
tp->t_cflag = t->c_cflag;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
dcons_tty_start(struct tty *tp)
|
||||||
|
{
|
||||||
|
struct dcons_softc *dc;
|
||||||
|
int s;
|
||||||
|
|
||||||
|
dc = (struct dcons_softc *)tp->t_dev->si_drv1;
|
||||||
|
s = spltty();
|
||||||
|
if (tp->t_state & (TS_TIMEOUT | TS_TTSTOP)) {
|
||||||
|
ttwwakeup(tp);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
tp->t_state |= TS_BUSY;
|
||||||
|
while (tp->t_outq.c_cc != 0)
|
||||||
|
dcons_putc(dc, getc(&tp->t_outq));
|
||||||
|
tp->t_state &= ~TS_BUSY;
|
||||||
|
|
||||||
|
ttwwakeup(tp);
|
||||||
|
splx(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
dcons_timeout(void *v)
|
||||||
|
{
|
||||||
|
struct tty *tp;
|
||||||
|
struct dcons_softc *dc;
|
||||||
|
int i, c, polltime;
|
||||||
|
|
||||||
|
for (i = 0; i < DCONS_NPORT; i ++) {
|
||||||
|
dc = &sc[i];
|
||||||
|
tp = dc->dev->si_tty;
|
||||||
|
while ((c = dcons_checkc(dc)) != -1)
|
||||||
|
if (tp->t_state & TS_ISOPEN)
|
||||||
|
(*linesw[tp->t_line].l_rint)(c, tp);
|
||||||
|
}
|
||||||
|
polltime = hz / poll_hz;
|
||||||
|
if (polltime < 1)
|
||||||
|
polltime = 1;
|
||||||
|
callout_reset(&dcons_callout, polltime, dcons_timeout, tp);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
dcons_cnprobe(struct consdev *cp)
|
||||||
|
{
|
||||||
|
#if __FreeBSD_version >= 501109
|
||||||
|
sprintf(cp->cn_name, "dcons");
|
||||||
|
#else
|
||||||
|
cp->cn_dev = makedev(CDEV_MAJOR, DCONS_CON);
|
||||||
|
#endif
|
||||||
|
#if DCONS_FORCE_CONSOLE
|
||||||
|
cp->cn_pri = CN_REMOTE;
|
||||||
|
#else
|
||||||
|
cp->cn_pri = CN_NORMAL;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
dcons_cninit(struct consdev *cp)
|
||||||
|
{
|
||||||
|
dcons_drv_init(0);
|
||||||
|
#if CONS_NODEV
|
||||||
|
cp->cn_arg
|
||||||
|
#else
|
||||||
|
cp->cn_dev->si_drv1
|
||||||
|
#endif
|
||||||
|
= (void *)&sc[DCONS_CON]; /* share port0 with unit0 */
|
||||||
|
}
|
||||||
|
|
||||||
|
#if CONS_NODEV
|
||||||
|
static int
|
||||||
|
dcons_cngetc(struct consdev *cp)
|
||||||
|
{
|
||||||
|
return(dcons_getc((struct dcons_softc *)cp->cn_arg));
|
||||||
|
}
|
||||||
|
static int
|
||||||
|
dcons_cncheckc(struct consdev *cp)
|
||||||
|
{
|
||||||
|
return(dcons_checkc((struct dcons_softc *)cp->cn_arg));
|
||||||
|
}
|
||||||
|
static void
|
||||||
|
dcons_cnputc(struct consdev *cp, int c)
|
||||||
|
{
|
||||||
|
dcons_putc((struct dcons_softc *)cp->cn_arg, c);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
static int
|
||||||
|
dcons_cngetc(dev_t dev)
|
||||||
|
{
|
||||||
|
return(dcons_getc((struct dcons_softc *)dev->si_drv1));
|
||||||
|
}
|
||||||
|
static int
|
||||||
|
dcons_cncheckc(dev_t dev)
|
||||||
|
{
|
||||||
|
return(dcons_checkc((struct dcons_softc *)dev->si_drv1));
|
||||||
|
}
|
||||||
|
static void
|
||||||
|
dcons_cnputc(dev_t dev, int c)
|
||||||
|
{
|
||||||
|
dcons_putc((struct dcons_softc *)dev->si_drv1, c);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static int
|
||||||
|
dcons_getc(struct dcons_softc *dc)
|
||||||
|
{
|
||||||
|
int c;
|
||||||
|
|
||||||
|
while ((c = dcons_checkc(dc)) == -1);
|
||||||
|
|
||||||
|
return (c & 0xff);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
dcons_checkc(struct dcons_softc *dc)
|
||||||
|
{
|
||||||
|
unsigned char c;
|
||||||
|
u_int32_t ptr, pos, gen, next_gen;
|
||||||
|
struct dcons_ch *ch;
|
||||||
|
|
||||||
|
ch = &dc->i;
|
||||||
|
|
||||||
|
if (dcons_dma_tag != NULL)
|
||||||
|
bus_dmamap_sync(dcons_dma_tag, dcons_dma_map,
|
||||||
|
BUS_DMASYNC_POSTREAD);
|
||||||
|
ptr = ntohl(*ch->ptr);
|
||||||
|
gen = ptr >> DCONS_GEN_SHIFT;
|
||||||
|
pos = ptr & DCONS_POS_MASK;
|
||||||
|
if (gen == ch->gen && pos == ch->pos)
|
||||||
|
return (-1);
|
||||||
|
|
||||||
|
next_gen = DCONS_NEXT_GEN(ch->gen);
|
||||||
|
/* XXX sanity check */
|
||||||
|
if ((gen != ch->gen && gen != next_gen)
|
||||||
|
|| (gen == ch->gen && pos < ch->pos)) {
|
||||||
|
/* generation skipped !! */
|
||||||
|
/* XXX discard */
|
||||||
|
ch->gen = gen;
|
||||||
|
ch->pos = pos;
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
c = ch->buf[ch->pos];
|
||||||
|
ch->pos ++;
|
||||||
|
if (ch->pos >= ch->size) {
|
||||||
|
ch->gen = next_gen;
|
||||||
|
ch->pos = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if DDB && ALT_BREAK_TO_DEBUGGER
|
||||||
|
switch (dc->brk_state) {
|
||||||
|
case STATE1:
|
||||||
|
if (c == KEY_TILDE)
|
||||||
|
dc->brk_state = STATE2;
|
||||||
|
else
|
||||||
|
dc->brk_state = STATE0;
|
||||||
|
break;
|
||||||
|
case STATE2:
|
||||||
|
dc->brk_state = STATE0;
|
||||||
|
if (c == KEY_CTRLB) {
|
||||||
|
#if DCONS_FORCE_GDB
|
||||||
|
if (dc->flags & DC_GDB)
|
||||||
|
boothowto |= RB_GDB;
|
||||||
|
#endif
|
||||||
|
breakpoint();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (c == KEY_CR)
|
||||||
|
dc->brk_state = STATE1;
|
||||||
|
#endif
|
||||||
|
return (c);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
dcons_putc(struct dcons_softc *dc, int c)
|
||||||
|
{
|
||||||
|
struct dcons_ch *ch;
|
||||||
|
|
||||||
|
ch = &dc->o;
|
||||||
|
|
||||||
|
ch->buf[ch->pos] = c;
|
||||||
|
ch->pos ++;
|
||||||
|
if (ch->pos >= ch->size) {
|
||||||
|
ch->gen = DCONS_NEXT_GEN(ch->gen);
|
||||||
|
ch->pos = 0;
|
||||||
|
}
|
||||||
|
*ch->ptr = DCONS_MAKE_PTR(ch);
|
||||||
|
if (dcons_dma_tag != NULL)
|
||||||
|
bus_dmamap_sync(dcons_dma_tag, dcons_dma_map,
|
||||||
|
BUS_DMASYNC_PREWRITE);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
dcons_init_port(int port, int offset, int size)
|
||||||
|
{
|
||||||
|
int osize;
|
||||||
|
struct dcons_softc *dc;
|
||||||
|
|
||||||
|
dc = &sc[port];
|
||||||
|
|
||||||
|
osize = size * 3 / 4;
|
||||||
|
|
||||||
|
dc->o.size = osize;
|
||||||
|
dc->i.size = size - osize;
|
||||||
|
dc->o.buf = (char *)dcons_buf + offset;
|
||||||
|
dc->i.buf = dc->o.buf + osize;
|
||||||
|
dc->o.gen = dc->i.gen = 0;
|
||||||
|
dc->o.pos = dc->i.pos = 0;
|
||||||
|
dc->o.ptr = &dcons_buf->optr[port];
|
||||||
|
dc->i.ptr = &dcons_buf->iptr[port];
|
||||||
|
dc->brk_state = STATE0;
|
||||||
|
dcons_buf->osize[port] = htonl(osize);
|
||||||
|
dcons_buf->isize[port] = htonl(size - osize);
|
||||||
|
dcons_buf->ooffset[port] = htonl(offset);
|
||||||
|
dcons_buf->ioffset[port] = htonl(offset + osize);
|
||||||
|
dcons_buf->optr[port] = DCONS_MAKE_PTR(&dc->o);
|
||||||
|
dcons_buf->iptr[port] = DCONS_MAKE_PTR(&dc->i);
|
||||||
|
|
||||||
|
return(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
dcons_drv_init(int stage)
|
||||||
|
{
|
||||||
|
int size, size0, offset;
|
||||||
|
|
||||||
|
if (drv_init)
|
||||||
|
return(drv_init);
|
||||||
|
|
||||||
|
drv_init = -1;
|
||||||
|
|
||||||
|
dcons_bufsize = DCONS_BUF_SIZE;
|
||||||
|
|
||||||
|
#ifndef KLD_MODULE
|
||||||
|
if (stage == 0) /* XXX or cold */
|
||||||
|
/*
|
||||||
|
* DCONS_FORCE_CONSOLE == 1 and statically linked.
|
||||||
|
* called from cninit(). can't use contigmalloc yet .
|
||||||
|
*/
|
||||||
|
dcons_buf = (struct dcons_buf *) bssbuf;
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
/*
|
||||||
|
* DCONS_FORCE_CONSOLE == 0 or kernel module case.
|
||||||
|
* if the module is loaded after boot,
|
||||||
|
* dcons_buf could be non-continuous.
|
||||||
|
*/
|
||||||
|
dcons_buf = (struct dcons_buf *) contigmalloc(dcons_bufsize,
|
||||||
|
M_DEVBUF, 0, 0x10000, 0xffffffff, PAGE_SIZE, 0ul);
|
||||||
|
|
||||||
|
offset = DCONS_HEADER_SIZE;
|
||||||
|
size = (dcons_bufsize - offset);
|
||||||
|
size0 = size * 3 / 4;
|
||||||
|
|
||||||
|
dcons_init_port(0, offset, size0);
|
||||||
|
offset += size0;
|
||||||
|
dcons_init_port(1, offset, size - size0);
|
||||||
|
dcons_buf->version = htonl(DCONS_VERSION);
|
||||||
|
dcons_buf->magic = ntohl(DCONS_MAGIC);
|
||||||
|
|
||||||
|
#if DDB && DCONS_FORCE_GDB
|
||||||
|
#if CONS_NODEV
|
||||||
|
gdbconsdev.cn_arg = (void *)&sc[DCONS_GDB];
|
||||||
|
#if __FreeBSD_version >= 501109
|
||||||
|
sprintf(gdbconsdev.cn_name, "dgdb");
|
||||||
|
#endif
|
||||||
|
gdb_arg = &gdbconsdev;
|
||||||
|
#else
|
||||||
|
gdbdev = makedev(CDEV_MAJOR, DCONS_GDB);
|
||||||
|
#endif
|
||||||
|
gdb_getc = dcons_cngetc;
|
||||||
|
gdb_putc = dcons_cnputc;
|
||||||
|
#endif
|
||||||
|
drv_init = 1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int
|
||||||
|
dcons_attach_port(int port, char *name, int flags)
|
||||||
|
{
|
||||||
|
struct dcons_softc *dc;
|
||||||
|
struct tty *tp;
|
||||||
|
|
||||||
|
dc = &sc[port];
|
||||||
|
dc->flags = flags;
|
||||||
|
dc->dev = make_dev(&dcons_cdevsw, port,
|
||||||
|
UID_ROOT, GID_WHEEL, 0600, name);
|
||||||
|
tp = ttymalloc(NULL);
|
||||||
|
|
||||||
|
dc->dev->si_drv1 = (void *)dc;
|
||||||
|
dc->dev->si_tty = tp;
|
||||||
|
|
||||||
|
tp->t_oproc = dcons_tty_start;
|
||||||
|
tp->t_param = dcons_tty_param;
|
||||||
|
tp->t_stop = nottystop;
|
||||||
|
tp->t_dev = dc->dev;
|
||||||
|
|
||||||
|
return(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
dcons_attach(void)
|
||||||
|
{
|
||||||
|
int polltime;
|
||||||
|
|
||||||
|
dcons_attach_port(DCONS_CON, "dcons", 0);
|
||||||
|
dcons_attach_port(DCONS_GDB, "dgdb", DC_GDB);
|
||||||
|
#if __FreeBSD_version < 500000
|
||||||
|
callout_init(&dcons_callout);
|
||||||
|
#else
|
||||||
|
callout_init(&dcons_callout, 0);
|
||||||
|
#endif
|
||||||
|
polltime = hz / poll_hz;
|
||||||
|
if (polltime < 1)
|
||||||
|
polltime = 1;
|
||||||
|
callout_reset(&dcons_callout, polltime, dcons_timeout, NULL);
|
||||||
|
return(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
dcons_detach(int port)
|
||||||
|
{
|
||||||
|
struct tty *tp;
|
||||||
|
struct dcons_softc *dc;
|
||||||
|
|
||||||
|
dc = &sc[port];
|
||||||
|
|
||||||
|
tp = dc->dev->si_tty;
|
||||||
|
|
||||||
|
if (tp->t_state & TS_ISOPEN) {
|
||||||
|
printf("dcons: still opened\n");
|
||||||
|
(*linesw[tp->t_line].l_close)(tp, 0);
|
||||||
|
tp->t_gen++;
|
||||||
|
ttyclose(tp);
|
||||||
|
ttwakeup(tp);
|
||||||
|
ttwwakeup(tp);
|
||||||
|
}
|
||||||
|
/* XXX
|
||||||
|
* must wait until all device are closed.
|
||||||
|
*/
|
||||||
|
tsleep((void *)dc, PWAIT, "dcodtc", hz/4);
|
||||||
|
destroy_dev(dc->dev);
|
||||||
|
|
||||||
|
return(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* cnXXX works only for FreeBSD-5 */
|
||||||
|
static int
|
||||||
|
dcons_modevent(module_t mode, int type, void *data)
|
||||||
|
{
|
||||||
|
int err = 0, ret;
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case MOD_LOAD:
|
||||||
|
ret = dcons_drv_init(1);
|
||||||
|
dcons_attach();
|
||||||
|
#if __FreeBSD_version >= 500000
|
||||||
|
if (ret == 0) {
|
||||||
|
dcons_cnprobe(&dcons_consdev);
|
||||||
|
dcons_cninit(&dcons_consdev);
|
||||||
|
cnadd(&dcons_consdev);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
case MOD_UNLOAD:
|
||||||
|
printf("dcons: unload\n");
|
||||||
|
callout_stop(&dcons_callout);
|
||||||
|
#if DDB && DCONS_FORCE_GDB
|
||||||
|
#if CONS_NODEV
|
||||||
|
gdb_arg = NULL;
|
||||||
|
#else
|
||||||
|
gdbdev = NODEV;
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
#if __FreeBSD_version >= 500000
|
||||||
|
cnremove(&dcons_consdev);
|
||||||
|
#endif
|
||||||
|
dcons_detach(DCONS_CON);
|
||||||
|
dcons_detach(DCONS_GDB);
|
||||||
|
dcons_buf->magic = 0;
|
||||||
|
|
||||||
|
contigfree(dcons_buf, DCONS_BUF_SIZE, M_DEVBUF);
|
||||||
|
|
||||||
|
break;
|
||||||
|
case MOD_SHUTDOWN:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
DEV_MODULE(dcons, dcons_modevent, NULL);
|
||||||
|
MODULE_VERSION(dcons, DCONS_VERSION);
|
97
sys/dev/dcons/dcons.h
Normal file
97
sys/dev/dcons/dcons.h
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2002
|
||||||
|
* Hidetoshi Shimokawa. All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. All advertising materials mentioning features or use of this software
|
||||||
|
* must display the following acknowledgement:
|
||||||
|
*
|
||||||
|
* This product includes software developed by Hidetoshi Shimokawa.
|
||||||
|
*
|
||||||
|
* 4. Neither the name of the author nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||||
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||||
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
* SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* $Id: dcons.h,v 1.15 2003/10/23 15:05:31 simokawa Exp $
|
||||||
|
* $FreeBSD$
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef _KERNEL
|
||||||
|
#define V volatile
|
||||||
|
#else
|
||||||
|
#define V
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define DCONS_NPORT 2
|
||||||
|
#define DCONS_CON 0
|
||||||
|
#define DCONS_GDB 1
|
||||||
|
|
||||||
|
struct dcons_buf {
|
||||||
|
#define DCONS_VERSION 2
|
||||||
|
V u_int32_t version;
|
||||||
|
V u_int32_t ooffset[DCONS_NPORT];
|
||||||
|
V u_int32_t ioffset[DCONS_NPORT];
|
||||||
|
V u_int32_t osize[DCONS_NPORT];
|
||||||
|
V u_int32_t isize[DCONS_NPORT];
|
||||||
|
#define DCONS_MAGIC 0x64636f6e /* "dcon" */
|
||||||
|
V u_int32_t magic;
|
||||||
|
#define DCONS_GEN_SHIFT (24)
|
||||||
|
#define DCONS_GEN_MASK (0xff)
|
||||||
|
#define DCONS_POS_MASK ((1<< DCONS_GEN_SHIFT) - 1)
|
||||||
|
V u_int32_t optr[DCONS_NPORT];
|
||||||
|
V u_int32_t iptr[DCONS_NPORT];
|
||||||
|
V char buf[0];
|
||||||
|
};
|
||||||
|
|
||||||
|
#define DCONS_CSR_VAL_VER 0x64636f /* "dco" */
|
||||||
|
#define DCONS_CSR_KEY_HI 0x3a
|
||||||
|
#define DCONS_CSR_KEY_LO 0x3b
|
||||||
|
|
||||||
|
#define DCONS_HEADER_SIZE sizeof(struct dcons_buf)
|
||||||
|
#define DCONS_MAKE_PTR(x) htonl(((x)->gen << DCONS_GEN_SHIFT) | (x)->pos)
|
||||||
|
#define DCONS_NEXT_GEN(x) (((x) + 1) & DCONS_GEN_MASK)
|
||||||
|
|
||||||
|
struct dcons_ch {
|
||||||
|
u_int32_t size;
|
||||||
|
u_int32_t gen;
|
||||||
|
u_int32_t pos;
|
||||||
|
#ifdef _KERNEL
|
||||||
|
V u_int32_t *ptr;
|
||||||
|
V char *buf;
|
||||||
|
#else
|
||||||
|
off_t buf;
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
#define KEY_CTRLB 2 /* ^B */
|
||||||
|
#define KEY_CR 13 /* CR '\r' */
|
||||||
|
#define KEY_TILDE 126 /* ~ */
|
||||||
|
#define STATE0 0
|
||||||
|
#define STATE1 1
|
||||||
|
#define STATE2 2
|
||||||
|
|
||||||
|
#ifdef _KERNEL
|
||||||
|
extern struct dcons_buf *dcons_buf;
|
||||||
|
extern size_t dcons_bufsize;
|
||||||
|
extern bus_dma_tag_t dcons_dma_tag;
|
||||||
|
extern bus_dmamap_t dcons_dma_map;
|
||||||
|
#endif
|
224
sys/dev/dcons/dcons_crom.c
Normal file
224
sys/dev/dcons/dcons_crom.c
Normal file
@ -0,0 +1,224 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2003
|
||||||
|
* Hidetoshi Shimokawa. All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. All advertising materials mentioning features or use of this software
|
||||||
|
* must display the following acknowledgement:
|
||||||
|
*
|
||||||
|
* This product includes software developed by Hidetoshi Shimokawa.
|
||||||
|
*
|
||||||
|
* 4. Neither the name of the author nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||||
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||||
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
* SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* $Id: dcons_crom.c,v 1.8 2003/10/23 15:47:21 simokawa Exp $
|
||||||
|
* $FreeBSD$
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <sys/param.h>
|
||||||
|
#include <sys/kernel.h>
|
||||||
|
#include <sys/systm.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/conf.h>
|
||||||
|
#include <sys/malloc.h>
|
||||||
|
|
||||||
|
#include <sys/bus.h>
|
||||||
|
#include <machine/bus.h>
|
||||||
|
|
||||||
|
#include <dev/firewire/firewire.h>
|
||||||
|
#include <dev/firewire/firewirereg.h>
|
||||||
|
#include <dev/firewire/iec13213.h>
|
||||||
|
#include <dev/dcons/dcons.h>
|
||||||
|
|
||||||
|
static bus_addr_t dcons_paddr;
|
||||||
|
|
||||||
|
#ifndef CSRVAL_VENDOR_PRIVATE
|
||||||
|
#define NEED_NEW_DRIVER
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define ADDR_HI(x) (((x) >> 24) & 0xffffff)
|
||||||
|
#define ADDR_LO(x) ((x) & 0xffffff)
|
||||||
|
|
||||||
|
struct dcons_crom_softc {
|
||||||
|
struct firewire_dev_comm fd;
|
||||||
|
struct crom_chunk unit;
|
||||||
|
struct crom_chunk spec;
|
||||||
|
struct crom_chunk ver;
|
||||||
|
bus_dma_tag_t dma_tag;
|
||||||
|
bus_dmamap_t dma_map;
|
||||||
|
bus_addr_t bus_addr;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void
|
||||||
|
dcons_crom_identify(driver_t *driver, device_t parent)
|
||||||
|
{
|
||||||
|
BUS_ADD_CHILD(parent, 0, "dcons_crom", device_get_unit(parent));
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
dcons_crom_probe(device_t dev)
|
||||||
|
{
|
||||||
|
device_t pa;
|
||||||
|
|
||||||
|
pa = device_get_parent(dev);
|
||||||
|
if(device_get_unit(dev) != device_get_unit(pa)){
|
||||||
|
return(ENXIO);
|
||||||
|
}
|
||||||
|
|
||||||
|
device_set_desc(dev, "dcons configuration ROM");
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef NEED_NEW_DRIVER
|
||||||
|
static void
|
||||||
|
dcons_crom_post_busreset(void *arg)
|
||||||
|
{
|
||||||
|
struct dcons_crom_softc *sc;
|
||||||
|
struct crom_src *src;
|
||||||
|
struct crom_chunk *root;
|
||||||
|
|
||||||
|
sc = (struct dcons_crom_softc *) arg;
|
||||||
|
src = sc->fd.fc->crom_src;
|
||||||
|
root = sc->fd.fc->crom_root;
|
||||||
|
|
||||||
|
bzero(&sc->unit, sizeof(struct crom_chunk));
|
||||||
|
|
||||||
|
crom_add_chunk(src, root, &sc->unit, CROM_UDIR);
|
||||||
|
crom_add_entry(&sc->unit, CSRKEY_SPEC, CSRVAL_VENDOR_PRIVATE);
|
||||||
|
crom_add_simple_text(src, &sc->unit, &sc->spec, "FreeBSD");
|
||||||
|
crom_add_entry(&sc->unit, CSRKEY_VER, DCONS_CSR_VAL_VER);
|
||||||
|
crom_add_simple_text(src, &sc->unit, &sc->ver, "dcons");
|
||||||
|
crom_add_entry(&sc->unit, DCONS_CSR_KEY_HI, ADDR_HI(dcons_paddr));
|
||||||
|
crom_add_entry(&sc->unit, DCONS_CSR_KEY_LO, ADDR_LO(dcons_paddr));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static void
|
||||||
|
dmamap_cb(void *arg, bus_dma_segment_t *segments, int seg, int error)
|
||||||
|
{
|
||||||
|
bus_addr_t *ptr;
|
||||||
|
|
||||||
|
if (error)
|
||||||
|
printf("dcons_dmamap_cb: error=%d\n", error);
|
||||||
|
|
||||||
|
ptr = (bus_addr_t *) arg;
|
||||||
|
*ptr = segments[0].ds_addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
dcons_crom_attach(device_t dev)
|
||||||
|
{
|
||||||
|
#ifdef NEED_NEW_DRIVER
|
||||||
|
printf("dcons_crom: you need newer firewire driver\n");
|
||||||
|
return (-1);
|
||||||
|
#else
|
||||||
|
struct dcons_crom_softc *sc;
|
||||||
|
|
||||||
|
sc = (struct dcons_crom_softc *) device_get_softc(dev);
|
||||||
|
sc->fd.fc = device_get_ivars(dev);
|
||||||
|
sc->fd.dev = dev;
|
||||||
|
sc->fd.post_explore = NULL;
|
||||||
|
sc->fd.post_busreset = (void *) dcons_crom_post_busreset;
|
||||||
|
|
||||||
|
/* map dcons buffer */
|
||||||
|
bus_dma_tag_create(
|
||||||
|
/*parent*/ sc->fd.fc->dmat,
|
||||||
|
/*alignment*/ sizeof(u_int32_t),
|
||||||
|
/*boundary*/ 0,
|
||||||
|
/*lowaddr*/ BUS_SPACE_MAXADDR,
|
||||||
|
/*highaddr*/ BUS_SPACE_MAXADDR,
|
||||||
|
/*filter*/NULL, /*filterarg*/NULL,
|
||||||
|
/*maxsize*/ dcons_bufsize,
|
||||||
|
/*nsegments*/ 1,
|
||||||
|
/*maxsegsz*/ BUS_SPACE_MAXSIZE_32BIT,
|
||||||
|
/*flags*/ BUS_DMA_ALLOCNOW,
|
||||||
|
#if __FreeBSD_version >= 501102
|
||||||
|
/*lockfunc*/busdma_lock_mutex,
|
||||||
|
/*lockarg*/&Giant,
|
||||||
|
#endif
|
||||||
|
&sc->dma_tag);
|
||||||
|
bus_dmamap_create(sc->dma_tag, 0, &sc->dma_map);
|
||||||
|
bus_dmamap_load(sc->dma_tag, sc->dma_map,
|
||||||
|
(void *)dcons_buf, dcons_bufsize,
|
||||||
|
dmamap_cb, &sc->bus_addr, 0);
|
||||||
|
bus_dmamap_sync(sc->dma_tag, sc->dma_map, BUS_DMASYNC_PREWRITE);
|
||||||
|
device_printf(sc->fd.dev,
|
||||||
|
#if __FreeBSD_version < 500000
|
||||||
|
"bus_addr 0x%x\n", sc->bus_addr);
|
||||||
|
#else
|
||||||
|
"bus_addr 0x%jx\n", (uintmax_t)sc->bus_addr);
|
||||||
|
#endif
|
||||||
|
if (dcons_paddr != 0) {
|
||||||
|
/* XXX */
|
||||||
|
device_printf(sc->fd.dev, "dcons_paddr is already set\n");
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
dcons_dma_tag = sc->dma_tag;
|
||||||
|
dcons_dma_map = sc->dma_map;
|
||||||
|
dcons_paddr = sc->bus_addr;
|
||||||
|
return (0);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
dcons_crom_detach(device_t dev)
|
||||||
|
{
|
||||||
|
struct dcons_crom_softc *sc;
|
||||||
|
|
||||||
|
sc = (struct dcons_crom_softc *) device_get_softc(dev);
|
||||||
|
sc->fd.post_busreset = NULL;
|
||||||
|
|
||||||
|
/* XXX */
|
||||||
|
if (dcons_dma_tag == sc->dma_tag)
|
||||||
|
dcons_dma_tag = NULL;
|
||||||
|
|
||||||
|
bus_dmamap_unload(sc->dma_tag, sc->dma_map);
|
||||||
|
bus_dmamap_destroy(sc->dma_tag, sc->dma_map);
|
||||||
|
bus_dma_tag_destroy(sc->dma_tag);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static devclass_t dcons_crom_devclass;
|
||||||
|
|
||||||
|
static device_method_t dcons_crom_methods[] = {
|
||||||
|
/* device interface */
|
||||||
|
DEVMETHOD(device_identify, dcons_crom_identify),
|
||||||
|
DEVMETHOD(device_probe, dcons_crom_probe),
|
||||||
|
DEVMETHOD(device_attach, dcons_crom_attach),
|
||||||
|
DEVMETHOD(device_detach, dcons_crom_detach),
|
||||||
|
{ 0, 0 }
|
||||||
|
};
|
||||||
|
|
||||||
|
static driver_t dcons_crom_driver = {
|
||||||
|
"dcons_crom",
|
||||||
|
dcons_crom_methods,
|
||||||
|
sizeof(struct dcons_crom_softc),
|
||||||
|
};
|
||||||
|
|
||||||
|
DRIVER_MODULE(dcons_crom, firewire, dcons_crom_driver,
|
||||||
|
dcons_crom_devclass, 0, 0);
|
||||||
|
MODULE_VERSION(dcons_crom, 1);
|
||||||
|
MODULE_DEPEND(dcons_crom, dcons,
|
||||||
|
DCONS_VERSION, DCONS_VERSION, DCONS_VERSION);
|
||||||
|
MODULE_DEPEND(dcons_crom, firewire, 1, 1, 1);
|
@ -32,6 +32,8 @@ SUBDIR= accf_data \
|
|||||||
${_cryptodev} \
|
${_cryptodev} \
|
||||||
cue \
|
cue \
|
||||||
dc \
|
dc \
|
||||||
|
dcons \
|
||||||
|
dcons_crom \
|
||||||
de \
|
de \
|
||||||
digi \
|
digi \
|
||||||
dummynet \
|
dummynet \
|
||||||
|
18
sys/modules/dcons/Makefile
Normal file
18
sys/modules/dcons/Makefile
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
# $Id: Makefile,v 1.6 2003/10/24 15:41:26 simokawa Exp $
|
||||||
|
# $FreeBSD$
|
||||||
|
|
||||||
|
.PATH: ${.CURDIR}/../../dev/dcons
|
||||||
|
|
||||||
|
KMOD = dcons
|
||||||
|
SRCS = dcons.c dcons.h \
|
||||||
|
opt_dcons.h opt_ddb.h opt_comconsole.h
|
||||||
|
|
||||||
|
opt_ddb.h:
|
||||||
|
echo "#define DDB 1" > $@
|
||||||
|
|
||||||
|
opt_comconsole.h:
|
||||||
|
echo "#define ALT_BREAK_TO_DEBUGGER 1" > $@
|
||||||
|
|
||||||
|
CFLAGS+= -I${.CURDIR}/../..
|
||||||
|
|
||||||
|
.include <bsd.kmod.mk>
|
14
sys/modules/dcons_crom/Makefile
Normal file
14
sys/modules/dcons_crom/Makefile
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
# $Id: Makefile,v 1.6 2003/10/24 15:43:24 simokawa Exp $
|
||||||
|
# $FreeBSD$
|
||||||
|
|
||||||
|
.PATH: ${.CURDIR}/../../dev/dcons
|
||||||
|
|
||||||
|
KMOD = dcons_crom
|
||||||
|
SRCS = dcons_crom.c dcons.h \
|
||||||
|
bus_if.h device_if.h
|
||||||
|
|
||||||
|
#KMODDEPS = firewire dcons
|
||||||
|
|
||||||
|
CFLAGS+= -I${.CURDIR}/../..
|
||||||
|
|
||||||
|
.include <bsd.kmod.mk>
|
@ -25,6 +25,7 @@ SUBDIR= IPXrouted \
|
|||||||
crunch \
|
crunch \
|
||||||
ctm \
|
ctm \
|
||||||
daemon \
|
daemon \
|
||||||
|
dconschat \
|
||||||
devinfo \
|
devinfo \
|
||||||
digictl \
|
digictl \
|
||||||
diskinfo \
|
diskinfo \
|
||||||
|
12
usr.sbin/dconschat/Makefile
Normal file
12
usr.sbin/dconschat/Makefile
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
# $FreeBSD$
|
||||||
|
|
||||||
|
PROG= dconschat
|
||||||
|
SRCS= dconschat.c
|
||||||
|
MAN= dconschat.8
|
||||||
|
|
||||||
|
CFLAGS+= -I${.CURDIR}/../../sys
|
||||||
|
|
||||||
|
DPADD= ${LIBKVM}
|
||||||
|
LDADD= -lkvm
|
||||||
|
|
||||||
|
.include <bsd.prog.mk>
|
229
usr.sbin/dconschat/dconschat.8
Normal file
229
usr.sbin/dconschat/dconschat.8
Normal file
@ -0,0 +1,229 @@
|
|||||||
|
.\" Copyright (c) 2003 Hidetoshi Shimokawa
|
||||||
|
.\" All rights reserved.
|
||||||
|
.\"
|
||||||
|
.\" Redistribution and use in source and binary forms, with or without
|
||||||
|
.\" modification, are permitted provided that the following conditions
|
||||||
|
.\" are met:
|
||||||
|
.\" 1. Redistributions of source code must retain the above copyright
|
||||||
|
.\" notice, this list of conditions and the following disclaimer.
|
||||||
|
.\" 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
.\" notice, this list of conditions and the following disclaimer in the
|
||||||
|
.\" documentation and/or other materials provided with the distribution.
|
||||||
|
.\"
|
||||||
|
.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
.\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
.\" DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
|
||||||
|
.\" INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
.\" (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
.\" SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||||
|
.\" STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||||
|
.\" ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
.\" POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
.\"
|
||||||
|
.\" $FreeBSD$
|
||||||
|
.\"
|
||||||
|
.\"
|
||||||
|
.Dd February 11, 2003
|
||||||
|
.Dt DCONSCHAT 8
|
||||||
|
.Os
|
||||||
|
.Sh NAME
|
||||||
|
.Nm dconschat
|
||||||
|
.Nd user interface to dcons
|
||||||
|
.Sh SYNOPSIS
|
||||||
|
.Nm
|
||||||
|
.Op Fl brvwRT1
|
||||||
|
.Op Fl h Ar hz
|
||||||
|
.Op Fl C Ar console_port
|
||||||
|
.Op Fl G Ar gdb_port
|
||||||
|
.Op Fl M Ar core
|
||||||
|
.Op Fl N Ar system
|
||||||
|
.Nm
|
||||||
|
.Op Fl brvwR1
|
||||||
|
.Op Fl h Ar hz
|
||||||
|
.Op Fl C Ar console_port
|
||||||
|
.Op Fl G Ar gdb_port
|
||||||
|
.Op Fl a Ar address
|
||||||
|
.Op Fl u Ar bus_num
|
||||||
|
.Fl t Ar target_eui64
|
||||||
|
.Sh DESCRIPTION
|
||||||
|
The
|
||||||
|
.Nm
|
||||||
|
utility is designed to provide a way for users to access
|
||||||
|
.Xr dcons 4
|
||||||
|
(dumb console device) on a local or remote system.
|
||||||
|
The
|
||||||
|
.Nm
|
||||||
|
interacts with
|
||||||
|
.Xr dcons 4
|
||||||
|
using
|
||||||
|
.Xr kvm 3
|
||||||
|
or
|
||||||
|
.Xr firewire 4
|
||||||
|
and interact with a user over tty or TCP/IP.
|
||||||
|
To access remote
|
||||||
|
.Xr dcons 4
|
||||||
|
using
|
||||||
|
.Xr firewire 4 ,
|
||||||
|
you have to specify target EUI64 address by
|
||||||
|
.Fl t
|
||||||
|
option.
|
||||||
|
.Pp
|
||||||
|
The
|
||||||
|
.Nm
|
||||||
|
and
|
||||||
|
.Xr dcons 4
|
||||||
|
communicate using 2 port, one for console port and the other for
|
||||||
|
remote gdb port.
|
||||||
|
Users are supposed to access
|
||||||
|
.Nm
|
||||||
|
using tty, telnet and gdb.
|
||||||
|
You can specify listen ports for console and gdb port by
|
||||||
|
.Fl C
|
||||||
|
and
|
||||||
|
.Fl G
|
||||||
|
options respectively. The port number 0 has special meaning that
|
||||||
|
current tty(stdin/out) is used instead of TCP/IP.
|
||||||
|
A negative port number will disable the port.
|
||||||
|
To quit dconschat, send a CR + '~' + '.' sequence to the console port
|
||||||
|
or send signal to the process.
|
||||||
|
.Pp
|
||||||
|
By analogy with
|
||||||
|
.Xr pty 4
|
||||||
|
device, the
|
||||||
|
.Xr dcons 4
|
||||||
|
acts as a slave device and
|
||||||
|
.Nm
|
||||||
|
acts as a master device with
|
||||||
|
.Xr telnetd 8 .
|
||||||
|
.Pp
|
||||||
|
.Bl -tag -width indent
|
||||||
|
.It Fl b
|
||||||
|
Translate Ctrl-C to ALT_BREAK(CR + '~' + Ctrl-B) on gdb port.
|
||||||
|
.It Fl r
|
||||||
|
Replay old buffer on connection.
|
||||||
|
.It Fl v
|
||||||
|
Verbose debug output. Multiple '-v' increase verbosity.
|
||||||
|
.It Fl w
|
||||||
|
Listen on wildcard address rather than localhost.
|
||||||
|
.It Fl R
|
||||||
|
Read-only. Don't write anything on dcons buffer.
|
||||||
|
.It Fl T
|
||||||
|
Enable ad hoc workaround for telnet protocol to
|
||||||
|
remove unnecessary byte sequences.
|
||||||
|
It should be set when you access dconschat using telnet.
|
||||||
|
.It Fl 1
|
||||||
|
One-Shot. Read available buffer then exit. This implies
|
||||||
|
.Fl r
|
||||||
|
option.
|
||||||
|
.It Fl h Ar hz
|
||||||
|
Specify polling rate. The default value is 100.
|
||||||
|
.It Fl C Ar console_port
|
||||||
|
Specify console port. The default value is 0(stdin/stdout).
|
||||||
|
.It Fl G Ar gdb_port
|
||||||
|
Specify gdb port.. The default value is -1(disabled).
|
||||||
|
.It Fl M Ar core
|
||||||
|
Specify core file.
|
||||||
|
.It Fl N Ar system
|
||||||
|
Specify system file such as /boot/kernel/kernel.
|
||||||
|
.It Fl t Ar target_eui64
|
||||||
|
Specify the 64bit extended unique identifier of the target and use FireWire to access remote
|
||||||
|
.Xr dcons 4 .
|
||||||
|
.It Fl a Ar address
|
||||||
|
Specify the physical/IO address of the dcons buffer. See
|
||||||
|
.Xr dcons 4
|
||||||
|
for details.
|
||||||
|
If this option is not specified,
|
||||||
|
.Nm
|
||||||
|
tries to get the address from the Configuration ROM on the target.
|
||||||
|
You are supposed to enable
|
||||||
|
.Xr dcons_crom 4
|
||||||
|
on the target to omit this option.
|
||||||
|
.It Fl u Ar bus_num
|
||||||
|
Specify FireWire bus number. The default is 0.
|
||||||
|
.El
|
||||||
|
.Sh EXAMPLE
|
||||||
|
To use
|
||||||
|
.Nm
|
||||||
|
with FireWire for remote
|
||||||
|
.Xr dcons ,
|
||||||
|
you have to specify the eui64 of the target.
|
||||||
|
You can obtain EUI64 by running
|
||||||
|
.Xr fwcontorl 4
|
||||||
|
without options.
|
||||||
|
The first EUI64 is of the host running fwcontrol and others on the
|
||||||
|
bus follow.
|
||||||
|
.Bd -literal -offset indent
|
||||||
|
# fwcontrol
|
||||||
|
2 devices (info_len=2)
|
||||||
|
node EUI64 status
|
||||||
|
1 0x7766554433221100 0
|
||||||
|
0 0x0011223344556677 1
|
||||||
|
.Ed
|
||||||
|
.Pp
|
||||||
|
The EUI64 doesn't change unless you change the hardware
|
||||||
|
as the ethernet address.
|
||||||
|
.Pp
|
||||||
|
Now we can run the
|
||||||
|
.Nm .
|
||||||
|
.Bd -literal -offset indent
|
||||||
|
# dconschat -br -G 12345 -t 0x00112233445566677
|
||||||
|
.Ed
|
||||||
|
.Pp
|
||||||
|
You'll get console output of the target and login prompt if a getty is
|
||||||
|
running on dcons. You can break to DDB with ALT_BREAK (CR + '~' + Ctrl-B)
|
||||||
|
if DDB and ALT_BREAK_TO_DEBUGGER is enabled in the target kernel.
|
||||||
|
To quit the session, type CR + '~' + '.' in the console port.
|
||||||
|
.Pp
|
||||||
|
Using gdb port is almost the same as remote gdb over serial line except
|
||||||
|
using TCP/IP instead of /dev/cu*. See
|
||||||
|
"On-line Kernel Debugging Using Remote GDB"
|
||||||
|
section of The FreeBSD Developers Handbook.
|
||||||
|
.Bd -literal -offset indent
|
||||||
|
% gdb -k kernel.debug
|
||||||
|
(kgdb) target remote :12345
|
||||||
|
.Ed
|
||||||
|
.Pp
|
||||||
|
Once gdb is attached and you specified '-b' option to dconschat,
|
||||||
|
typing "Ctrl-C" on gdb causes break to debugger.
|
||||||
|
.Pp
|
||||||
|
The following command get console log from crash dump:
|
||||||
|
.Bd -literal -offset indent
|
||||||
|
# dconschat -1 -M vmcore.0 -N kernel.0
|
||||||
|
.Ed
|
||||||
|
.Pp
|
||||||
|
If you want access to the console using telnet, try the following:
|
||||||
|
.Bd -literal -offset indent
|
||||||
|
# dconschat -rTC 5555 &
|
||||||
|
# telnet localhost 5555
|
||||||
|
.Ed
|
||||||
|
.Pp
|
||||||
|
You may want to keep logging console output of several machines. Conserve-com
|
||||||
|
in the ports collection should help you. Insert the following lines
|
||||||
|
in the conserver.cf
|
||||||
|
.Bd -literal -offset indent
|
||||||
|
local:|/usr/sbin/dconschat -rh 25::&:
|
||||||
|
remote:|/usr/sbin/dconschat -rh 25 -t 0x00112233445566677::&:
|
||||||
|
.Ed
|
||||||
|
.Sh FILES
|
||||||
|
.Bl -tag -width indent
|
||||||
|
.It Pa /dev/fwmem0.0
|
||||||
|
.It Pa /dev/mem
|
||||||
|
.It Pa /dev/kmem
|
||||||
|
.El
|
||||||
|
.Sh SEE ALSO
|
||||||
|
.Xr gdb 1 ,
|
||||||
|
.Xr telnet 1 ,
|
||||||
|
.Xr kvm 3 ,
|
||||||
|
.Xr dcons 4 ,
|
||||||
|
.Xr dcons_crom 4 ,
|
||||||
|
.Xr ddb 4 ,
|
||||||
|
.Xr firewire 4 ,
|
||||||
|
.Xr fwohci 4 ,
|
||||||
|
.Xr fwcontrol 8
|
||||||
|
.Sh AUTHORS
|
||||||
|
.An Hidetoshi Shimokawa Aq simokawa@FreeBSD.org
|
||||||
|
.Sh BUGS
|
||||||
|
This utility is still under development.
|
||||||
|
.Pp
|
959
usr.sbin/dconschat/dconschat.c
Normal file
959
usr.sbin/dconschat/dconschat.c
Normal file
@ -0,0 +1,959 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2003
|
||||||
|
* Hidetoshi Shimokawa. All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. All advertising materials mentioning features or use of this software
|
||||||
|
* must display the following acknowledgement:
|
||||||
|
*
|
||||||
|
* This product includes software developed by Hidetoshi Shimokawa.
|
||||||
|
*
|
||||||
|
* 4. Neither the name of the author nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||||
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||||
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
* SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* $Id: dconschat.c,v 1.76 2003/10/23 06:21:13 simokawa Exp $
|
||||||
|
* $FreeBSD$
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <sys/param.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/uio.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <termios.h>
|
||||||
|
#include <dev/dcons/dcons.h>
|
||||||
|
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <netdb.h>
|
||||||
|
#include <err.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/event.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
#include <arpa/telnet.h>
|
||||||
|
|
||||||
|
#include <sys/ioccom.h>
|
||||||
|
#include <dev/firewire/firewire.h>
|
||||||
|
#include <dev/firewire/iec13213.h>
|
||||||
|
|
||||||
|
#include <kvm.h>
|
||||||
|
#include <nlist.h>
|
||||||
|
|
||||||
|
#include <sys/errno.h>
|
||||||
|
|
||||||
|
#define DCONS_POLL_HZ 100
|
||||||
|
|
||||||
|
#define RETRY 3
|
||||||
|
|
||||||
|
#ifdef CSRVAL_VENDOR_PRIVATE
|
||||||
|
#define USE_CROM 1
|
||||||
|
#else
|
||||||
|
#define USE_CROM 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int verbose = 0;
|
||||||
|
int tc_set = 0;
|
||||||
|
|
||||||
|
#define IS_CONSOLE(p) ((p)->port == 0)
|
||||||
|
#define IS_GDB(p) ((p)->port == 1)
|
||||||
|
|
||||||
|
static struct dcons_state {
|
||||||
|
int fd;
|
||||||
|
kvm_t *kd;
|
||||||
|
int kq;
|
||||||
|
off_t paddr;
|
||||||
|
#define F_READY (1 << 1)
|
||||||
|
#define F_RD_ONLY (1 << 2)
|
||||||
|
#define F_ALT_BREAK (1 << 3)
|
||||||
|
#define F_TELNET (1 << 4)
|
||||||
|
#define F_USE_CROM (1 << 5)
|
||||||
|
#define F_ONE_SHOT (1 << 6)
|
||||||
|
#define F_REPLAY (1 << 7)
|
||||||
|
int flags;
|
||||||
|
enum {
|
||||||
|
TYPE_KVM,
|
||||||
|
TYPE_FW
|
||||||
|
} type;
|
||||||
|
int escape_state;
|
||||||
|
struct dcons_port {
|
||||||
|
int port;
|
||||||
|
struct dcons_ch o;
|
||||||
|
struct dcons_ch i;
|
||||||
|
u_int32_t optr;
|
||||||
|
u_int32_t iptr;
|
||||||
|
int s;
|
||||||
|
int infd;
|
||||||
|
int outfd;
|
||||||
|
struct addrinfo *res;
|
||||||
|
int skip_read;
|
||||||
|
} port[DCONS_NPORT];
|
||||||
|
struct timespec to;
|
||||||
|
struct timespec zero;
|
||||||
|
struct termios tsave;
|
||||||
|
} sc;
|
||||||
|
|
||||||
|
static int
|
||||||
|
dread(struct dcons_state *dc, void *buf, size_t n, off_t offset)
|
||||||
|
{
|
||||||
|
switch (dc->type) {
|
||||||
|
case TYPE_FW:
|
||||||
|
return (pread(dc->fd, buf, n, offset));
|
||||||
|
case TYPE_KVM:
|
||||||
|
return (kvm_read(dc->kd, offset, buf, n));
|
||||||
|
}
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
dwrite(struct dcons_state *dc, void *buf, size_t n, off_t offset)
|
||||||
|
{
|
||||||
|
if ((dc->flags & F_RD_ONLY) != 0)
|
||||||
|
return (n);
|
||||||
|
|
||||||
|
switch (dc->type) {
|
||||||
|
case TYPE_FW:
|
||||||
|
return (pwrite(dc->fd, buf, n, offset));
|
||||||
|
case TYPE_KVM:
|
||||||
|
return (kvm_write(dc->kd, offset, buf, n));
|
||||||
|
}
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
dconschat_cleanup(int sig)
|
||||||
|
{
|
||||||
|
struct dcons_state *dc;
|
||||||
|
|
||||||
|
dc = ≻
|
||||||
|
if (tc_set != 0)
|
||||||
|
tcsetattr(STDIN_FILENO, TCSADRAIN, &dc->tsave);
|
||||||
|
|
||||||
|
if (sig > 0)
|
||||||
|
printf("\ndconschat exiting with signal %d ...\n", sig);
|
||||||
|
else
|
||||||
|
printf("\ndconschat exiting...\n");
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if USE_CROM
|
||||||
|
static int
|
||||||
|
dconschat_get_crom(struct dcons_state *dc)
|
||||||
|
{
|
||||||
|
off_t addr;
|
||||||
|
int i, state = 0;
|
||||||
|
u_int32_t buf, hi = 0, lo = 0;
|
||||||
|
struct csrreg *reg;
|
||||||
|
|
||||||
|
reg = (struct csrreg *)&buf;
|
||||||
|
addr = 0xffff;
|
||||||
|
addr = (addr << 32) | 0xf0000400;
|
||||||
|
for (i = 20; i < 0x400; i += 4) {
|
||||||
|
if (dread(dc, &buf, 4, addr + i) < 0) {
|
||||||
|
if (verbose)
|
||||||
|
warn("crom read faild");
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
buf = ntohl(buf);
|
||||||
|
if (verbose)
|
||||||
|
printf("%d %02x %06x\n", state, reg->key, reg->val);
|
||||||
|
switch (state) {
|
||||||
|
case 0:
|
||||||
|
if (reg->key == CSRKEY_SPEC &&
|
||||||
|
reg->val == CSRVAL_VENDOR_PRIVATE)
|
||||||
|
state = 1;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
if (reg->key == CSRKEY_VER &&
|
||||||
|
reg->val == DCONS_CSR_VAL_VER)
|
||||||
|
state = 2;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
if (reg->key == DCONS_CSR_KEY_HI)
|
||||||
|
hi = reg->val;
|
||||||
|
else if (reg->key == DCONS_CSR_KEY_LO) {
|
||||||
|
lo = reg->val;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* not found */
|
||||||
|
return (-1);
|
||||||
|
out:
|
||||||
|
if (verbose)
|
||||||
|
printf("addr: %06x %06x\n", hi, lo);
|
||||||
|
dc->paddr = ((off_t)hi << 24) | lo;
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static void
|
||||||
|
dconschat_ready(struct dcons_state *dc, int ready, char *reason)
|
||||||
|
{
|
||||||
|
static char oldreason[64] = "";
|
||||||
|
int old;
|
||||||
|
|
||||||
|
old = (dc->flags & F_READY) ? 1 : 0;
|
||||||
|
|
||||||
|
if (ready) {
|
||||||
|
dc->flags |= F_READY;
|
||||||
|
if (ready != old)
|
||||||
|
printf("[dcons connected]\r\n");
|
||||||
|
oldreason[0] = 0;
|
||||||
|
} else {
|
||||||
|
dc->flags &= ~F_READY;
|
||||||
|
if (strncmp(oldreason, reason, sizeof(oldreason)) != 0) {
|
||||||
|
printf("[dcons disconnected (%s)]\r\n", reason);
|
||||||
|
strlcpy(oldreason, reason, sizeof(oldreason));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
dconschat_fetch_header(struct dcons_state *dc)
|
||||||
|
{
|
||||||
|
char ebuf[64];
|
||||||
|
struct dcons_buf dbuf;
|
||||||
|
int j;
|
||||||
|
|
||||||
|
#if USE_CROM
|
||||||
|
if (dc->paddr == 0 && (dc->flags & F_USE_CROM) != 0) {
|
||||||
|
if (dconschat_get_crom(dc)) {
|
||||||
|
dconschat_ready(dc, 0, "get crom failed");
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (dread(dc, &dbuf, DCONS_HEADER_SIZE, dc->paddr) < 0) {
|
||||||
|
dconschat_ready(dc, 0, "read header failed");
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
if (dbuf.magic != htonl(DCONS_MAGIC)) {
|
||||||
|
if ((dc->flags & F_USE_CROM) !=0)
|
||||||
|
dc->paddr = 0;
|
||||||
|
snprintf(ebuf, sizeof(ebuf), "wrong magic 0x%08x", dbuf.magic);
|
||||||
|
dconschat_ready(dc, 0, ebuf);
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
if (ntohl(dbuf.version) != DCONS_VERSION) {
|
||||||
|
snprintf(ebuf, sizeof(ebuf),
|
||||||
|
#if __FreeBSD_version < 500000
|
||||||
|
"wrong version %ld,%d",
|
||||||
|
#else
|
||||||
|
"wrong version %d,%d",
|
||||||
|
#endif
|
||||||
|
ntohl(dbuf.version), DCONS_VERSION);
|
||||||
|
/* XXX exit? */
|
||||||
|
dconschat_ready(dc, 0, ebuf);
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (j = 0; j < DCONS_NPORT; j++) {
|
||||||
|
struct dcons_ch *o, *i;
|
||||||
|
off_t newbuf;
|
||||||
|
int new = 0;
|
||||||
|
|
||||||
|
o = &dc->port[j].o;
|
||||||
|
newbuf = dc->paddr + ntohl(dbuf.ooffset[j]);
|
||||||
|
o->size = ntohl(dbuf.osize[j]);
|
||||||
|
|
||||||
|
if (newbuf != o->buf) {
|
||||||
|
/* buffer address has changes */
|
||||||
|
new = 1;
|
||||||
|
o->gen = ntohl(dbuf.optr[j]) >> DCONS_GEN_SHIFT;
|
||||||
|
o->pos = ntohl(dbuf.optr[j]) & DCONS_POS_MASK;
|
||||||
|
o->buf = newbuf;
|
||||||
|
}
|
||||||
|
|
||||||
|
i = &dc->port[j].i;
|
||||||
|
i->size = ntohl(dbuf.isize[j]);
|
||||||
|
i->gen = ntohl(dbuf.iptr[j]) >> DCONS_GEN_SHIFT;
|
||||||
|
i->pos = ntohl(dbuf.iptr[j]) & DCONS_POS_MASK;
|
||||||
|
i->buf = dc->paddr + ntohl(dbuf.ioffset[j]);
|
||||||
|
|
||||||
|
if (verbose) {
|
||||||
|
printf("port %d size offset gen pos\n", j);
|
||||||
|
#if __FreeBSD_version < 500000
|
||||||
|
printf("output: %5d %6ld %5d %5d\n"
|
||||||
|
"input : %5d %6ld %5d %5d\n",
|
||||||
|
#else
|
||||||
|
printf("output: %5d %6d %5d %5d\n"
|
||||||
|
"input : %5d %6d %5d %5d\n",
|
||||||
|
#endif
|
||||||
|
o->size, ntohl(dbuf.ooffset[j]), o->gen, o->pos,
|
||||||
|
i->size, ntohl(dbuf.ioffset[j]), i->gen, i->pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IS_CONSOLE(&dc->port[j]) && new &&
|
||||||
|
(dc->flags & F_REPLAY) !=0) {
|
||||||
|
if (o->gen > 0)
|
||||||
|
o->gen --;
|
||||||
|
else
|
||||||
|
o->pos = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dconschat_ready(dc, 1, NULL);
|
||||||
|
return(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
dconschat_get_ptr (struct dcons_state *dc) {
|
||||||
|
int dlen, i;
|
||||||
|
u_int32_t ptr[DCONS_NPORT*2+1];
|
||||||
|
static int retry = RETRY;
|
||||||
|
|
||||||
|
again:
|
||||||
|
dlen = dread(dc, &ptr, sizeof(ptr),
|
||||||
|
dc->paddr + __offsetof(struct dcons_buf, magic));
|
||||||
|
|
||||||
|
if (dlen < 0) {
|
||||||
|
if (errno == ETIMEDOUT)
|
||||||
|
if (retry -- > 0)
|
||||||
|
goto again;
|
||||||
|
dconschat_ready(dc, 0, "get ptr failed");
|
||||||
|
return(-1);
|
||||||
|
}
|
||||||
|
if (ptr[0] != htonl(DCONS_MAGIC)) {
|
||||||
|
dconschat_ready(dc, 0, "wrong magic");
|
||||||
|
return(-1);
|
||||||
|
}
|
||||||
|
retry = RETRY;
|
||||||
|
for (i = 0; i < DCONS_NPORT; i ++) {
|
||||||
|
dc->port[i].optr = ntohl(ptr[i + 1]);
|
||||||
|
dc->port[i].iptr = ntohl(ptr[DCONS_NPORT + i + 1]);
|
||||||
|
}
|
||||||
|
return(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define MAX_XFER 2048
|
||||||
|
static int
|
||||||
|
dconschat_read_dcons(struct dcons_state *dc, int port, char *buf, int len)
|
||||||
|
{
|
||||||
|
struct dcons_ch *ch;
|
||||||
|
u_int32_t ptr, pos, gen, next_gen;
|
||||||
|
int rlen, dlen, lost;
|
||||||
|
int retry = RETRY;
|
||||||
|
|
||||||
|
ch = &dc->port[port].o;
|
||||||
|
ptr = dc->port[port].optr;
|
||||||
|
gen = ptr >> DCONS_GEN_SHIFT;
|
||||||
|
pos = ptr & DCONS_POS_MASK;
|
||||||
|
if (gen == ch->gen && pos == ch->pos)
|
||||||
|
return (-1);
|
||||||
|
|
||||||
|
next_gen = DCONS_NEXT_GEN(ch->gen);
|
||||||
|
/* XXX sanity check */
|
||||||
|
if (gen == ch->gen) {
|
||||||
|
if (pos > ch->pos)
|
||||||
|
goto ok;
|
||||||
|
lost = ch->size * DCONS_GEN_MASK - ch->pos;
|
||||||
|
ch->pos = 0;
|
||||||
|
} else if (gen == next_gen) {
|
||||||
|
if (pos <= ch->pos)
|
||||||
|
goto ok;
|
||||||
|
lost = pos - ch->pos;
|
||||||
|
ch->pos = pos;
|
||||||
|
} else {
|
||||||
|
lost = gen - ch->gen;
|
||||||
|
if (lost < 0)
|
||||||
|
lost += DCONS_GEN_MASK;
|
||||||
|
if (verbose)
|
||||||
|
printf("[genskip %d]", lost);
|
||||||
|
lost = lost * ch->size - ch->pos;
|
||||||
|
ch->pos = 0;
|
||||||
|
ch->gen = gen;
|
||||||
|
}
|
||||||
|
/* generation skipped !! */
|
||||||
|
/* XXX discard */
|
||||||
|
if (verbose)
|
||||||
|
printf("[lost %d]", lost);
|
||||||
|
ok:
|
||||||
|
if (gen == ch->gen)
|
||||||
|
rlen = pos - ch->pos;
|
||||||
|
else
|
||||||
|
rlen = ch->size - ch->pos;
|
||||||
|
|
||||||
|
if (rlen > MAX_XFER)
|
||||||
|
rlen = MAX_XFER;
|
||||||
|
if (rlen > len)
|
||||||
|
rlen = len;
|
||||||
|
|
||||||
|
#if 1
|
||||||
|
if (verbose)
|
||||||
|
printf("[%d]", rlen); fflush(stdout);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
again:
|
||||||
|
dlen = dread(dc, buf, rlen, ch->buf + ch->pos);
|
||||||
|
if (dlen < 0) {
|
||||||
|
if (errno == ETIMEDOUT)
|
||||||
|
if (retry -- > 0)
|
||||||
|
goto again;
|
||||||
|
dconschat_ready(dc, 0, "read buffer failed");
|
||||||
|
return(-1);
|
||||||
|
}
|
||||||
|
if (dlen != rlen)
|
||||||
|
warnx("dlen(%d) != rlen(%d)\n", dlen, rlen);
|
||||||
|
ch->pos += dlen;
|
||||||
|
if (ch->pos >= ch->size) {
|
||||||
|
ch->gen = next_gen;
|
||||||
|
ch->pos = 0;
|
||||||
|
if (verbose)
|
||||||
|
printf("read_dcons: gen=%d", ch->gen);
|
||||||
|
}
|
||||||
|
return (dlen);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
dconschat_write_dcons(struct dcons_state *dc, int port, char *buf, int blen)
|
||||||
|
{
|
||||||
|
struct dcons_ch *ch;
|
||||||
|
u_int32_t ptr;
|
||||||
|
int len, wlen;
|
||||||
|
int retry = RETRY;
|
||||||
|
|
||||||
|
ch = &dc->port[port].i;
|
||||||
|
ptr = dc->port[port].iptr;
|
||||||
|
|
||||||
|
/* the others may advance the pointer sync with it */
|
||||||
|
ch->gen = ptr >> DCONS_GEN_SHIFT;
|
||||||
|
ch->pos = ptr & DCONS_POS_MASK;
|
||||||
|
|
||||||
|
while(blen > 0) {
|
||||||
|
wlen = MIN(blen, ch->size - ch->pos);
|
||||||
|
wlen = MIN(wlen, MAX_XFER);
|
||||||
|
len = dwrite(dc, buf, wlen, ch->buf + ch->pos);
|
||||||
|
if (len < 0) {
|
||||||
|
if (errno == ETIMEDOUT)
|
||||||
|
if (retry -- > 0)
|
||||||
|
continue; /* try again */
|
||||||
|
dconschat_ready(dc, 0, "write buffer failed");
|
||||||
|
return(-1);
|
||||||
|
}
|
||||||
|
ch->pos += len;
|
||||||
|
buf += len;
|
||||||
|
blen -= len;
|
||||||
|
if (ch->pos >= ch->size) {
|
||||||
|
ch->gen = DCONS_NEXT_GEN(ch->gen);
|
||||||
|
ch->pos = 0;
|
||||||
|
if (verbose)
|
||||||
|
printf("write_dcons: gen=%d", ch->gen);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ptr = DCONS_MAKE_PTR(ch);
|
||||||
|
dc->port[port].iptr = ptr;
|
||||||
|
|
||||||
|
if (verbose > 2)
|
||||||
|
printf("(iptr: 0x%x)", ptr);
|
||||||
|
again:
|
||||||
|
len = dwrite(dc, &ptr, sizeof(u_int32_t),
|
||||||
|
dc->paddr + __offsetof(struct dcons_buf, iptr[port]));
|
||||||
|
if (len < 0) {
|
||||||
|
if (errno == ETIMEDOUT)
|
||||||
|
if (retry -- > 0)
|
||||||
|
goto again;
|
||||||
|
dconschat_ready(dc, 0, "write ptr failed");
|
||||||
|
return(-1);
|
||||||
|
}
|
||||||
|
return(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
dconschat_write_socket(int fd, char *buf, int len)
|
||||||
|
{
|
||||||
|
write(fd, buf, len);
|
||||||
|
if (verbose > 1) {
|
||||||
|
buf[len] = 0;
|
||||||
|
printf("[%s]", buf);
|
||||||
|
}
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
dconschat_init_socket(struct dcons_state *dc, int port, char *host, int sport)
|
||||||
|
{
|
||||||
|
struct addrinfo hints, *res;
|
||||||
|
int on = 1, error;
|
||||||
|
char service[10];
|
||||||
|
struct kevent kev;
|
||||||
|
struct dcons_port *p;
|
||||||
|
|
||||||
|
p = &dc->port[port];
|
||||||
|
p->port = port;
|
||||||
|
p->infd = p->outfd = -1;
|
||||||
|
|
||||||
|
if (sport < 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (sport == 0) {
|
||||||
|
|
||||||
|
/* Use stdin and stdout */
|
||||||
|
p->infd = STDIN_FILENO;
|
||||||
|
p->outfd = STDOUT_FILENO;
|
||||||
|
p->s = -1;
|
||||||
|
if (tc_set == 0 &&
|
||||||
|
tcgetattr(STDIN_FILENO, &dc->tsave) == 0) {
|
||||||
|
struct termios traw;
|
||||||
|
|
||||||
|
traw = dc->tsave;
|
||||||
|
cfmakeraw(&traw);
|
||||||
|
tcsetattr(STDIN_FILENO, TCSADRAIN, &traw);
|
||||||
|
tc_set = 1;
|
||||||
|
}
|
||||||
|
EV_SET(&kev, p->infd, EVFILT_READ, EV_ADD, NOTE_LOWAT, 1,
|
||||||
|
(void *)p);
|
||||||
|
kevent(dc->kq, &kev, 1, NULL, 0, &dc->zero);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(&hints, 0, sizeof(hints));
|
||||||
|
hints.ai_flags = AI_PASSIVE;
|
||||||
|
#if 1 /* gdb can talk v4 only */
|
||||||
|
hints.ai_family = PF_INET;
|
||||||
|
#else
|
||||||
|
hints.ai_family = PF_UNSPEC;
|
||||||
|
#endif
|
||||||
|
hints.ai_socktype = SOCK_STREAM;
|
||||||
|
hints.ai_protocol = 0;
|
||||||
|
|
||||||
|
if (verbose)
|
||||||
|
printf("%s:%d for port %d\n",
|
||||||
|
host == NULL ? "*" : host, sport, port);
|
||||||
|
snprintf(service, sizeof(service), "%d", sport);
|
||||||
|
error = getaddrinfo(host, service, &hints, &res);
|
||||||
|
if (error)
|
||||||
|
errx(1, "tcp/%s: %s\n", service, gai_strerror(error));
|
||||||
|
p->res = res;
|
||||||
|
p->s = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
|
||||||
|
if (p->s < 0)
|
||||||
|
err(1, "socket");
|
||||||
|
setsockopt(p->s, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
|
||||||
|
|
||||||
|
if (bind(p->s, p->res->ai_addr, p->res->ai_addrlen) < 0) {
|
||||||
|
err(1, "bind");
|
||||||
|
}
|
||||||
|
if (listen(p->s, 1) < 0)
|
||||||
|
err(1, "listen");
|
||||||
|
EV_SET(&kev, p->s, EVFILT_READ, EV_ADD | EV_ONESHOT, 0, 0, (void *)p);
|
||||||
|
error = kevent(dc->kq, &kev, 1, NULL, 0, &dc->to);
|
||||||
|
if (error < 0)
|
||||||
|
err(1, "kevent");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
dconschat_accept_socket(struct dcons_state *dc, struct dcons_port *p)
|
||||||
|
{
|
||||||
|
int foo, ns, flags;
|
||||||
|
struct kevent kev;
|
||||||
|
|
||||||
|
/* accept connection */
|
||||||
|
foo = p->res->ai_addrlen;
|
||||||
|
ns = accept(p->s, p->res->ai_addr, &foo);
|
||||||
|
if (ns < 0)
|
||||||
|
err(1, "accept");
|
||||||
|
if (verbose)
|
||||||
|
printf("port%d accepted\n", p->port);
|
||||||
|
|
||||||
|
flags = fcntl(ns, F_GETFL, 0);
|
||||||
|
flags |= O_NDELAY;
|
||||||
|
fcntl(ns, F_SETFL, flags);
|
||||||
|
#if 1
|
||||||
|
if (IS_CONSOLE(p) && (dc->flags & F_TELNET) != 0) {
|
||||||
|
char sga[] = {IAC, WILL, TELOPT_SGA};
|
||||||
|
char linemode[] = {IAC, DONT, TELOPT_LINEMODE};
|
||||||
|
char echo[] = {IAC, WILL, TELOPT_ECHO};
|
||||||
|
char bin[] = {IAC, DO, TELOPT_BINARY};
|
||||||
|
|
||||||
|
write(ns, sga, sizeof(sga));
|
||||||
|
write(ns, linemode, sizeof(linemode));
|
||||||
|
write(ns, echo, sizeof(echo));
|
||||||
|
write(ns, bin, sizeof(bin));
|
||||||
|
p->skip_read = 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
p->infd = p->outfd = ns;
|
||||||
|
EV_SET(&kev, ns, EVFILT_READ, EV_ADD, NOTE_LOWAT, 1, (void *)p);
|
||||||
|
kevent(dc->kq, &kev, 1, NULL, 0, &dc->zero);
|
||||||
|
return(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
dconschat_read_filter(struct dcons_state *dc, struct dcons_port *p,
|
||||||
|
u_char *sp, int slen, u_char *dp, int *dlen)
|
||||||
|
{
|
||||||
|
static u_char abreak[3] = {13 /* CR */, 126 /* ~ */, 2 /* ^B */};
|
||||||
|
|
||||||
|
while (slen > 0) {
|
||||||
|
if (IS_CONSOLE(p)) {
|
||||||
|
if ((dc->flags & F_TELNET) != 0) {
|
||||||
|
/* XXX Telent workarounds */
|
||||||
|
if (p->skip_read -- > 0) {
|
||||||
|
sp ++;
|
||||||
|
slen --;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (*sp == IAC) {
|
||||||
|
if (verbose)
|
||||||
|
printf("(IAC)");
|
||||||
|
p->skip_read = 2;
|
||||||
|
sp ++;
|
||||||
|
slen --;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (*sp == 0) {
|
||||||
|
if (verbose)
|
||||||
|
printf("(0 stripped)");
|
||||||
|
sp ++;
|
||||||
|
slen --;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
switch (dc->escape_state) {
|
||||||
|
case STATE1:
|
||||||
|
if (*sp == KEY_TILDE)
|
||||||
|
dc->escape_state = STATE2;
|
||||||
|
else
|
||||||
|
dc->escape_state = STATE0;
|
||||||
|
break;
|
||||||
|
case STATE2:
|
||||||
|
dc->escape_state = STATE0;
|
||||||
|
if (*sp == '.')
|
||||||
|
dconschat_cleanup(0);
|
||||||
|
}
|
||||||
|
if (*sp == KEY_CR)
|
||||||
|
dc->escape_state = STATE1;
|
||||||
|
} else if (IS_GDB(p)) {
|
||||||
|
/* GDB: ^C -> CR+~+^B */
|
||||||
|
if (*sp == 0x3 && (dc->flags & F_ALT_BREAK) != 0) {
|
||||||
|
bcopy(abreak, dp, 3);
|
||||||
|
dp += 3;
|
||||||
|
sp ++;
|
||||||
|
*dlen += 3;
|
||||||
|
/* discard rest of the packet */
|
||||||
|
slen = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*dp++ = *sp++;
|
||||||
|
(*dlen) ++;
|
||||||
|
slen --;
|
||||||
|
}
|
||||||
|
return (*dlen);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
dconschat_read_socket(struct dcons_state *dc, struct dcons_port *p)
|
||||||
|
{
|
||||||
|
struct kevent kev;
|
||||||
|
int len, wlen;
|
||||||
|
char rbuf[MAX_XFER], wbuf[MAX_XFER+2];
|
||||||
|
|
||||||
|
if ((len = read(p->infd, rbuf, sizeof(rbuf))) > 0) {
|
||||||
|
wlen = 0;
|
||||||
|
dconschat_read_filter(dc, p, rbuf, len, wbuf, &wlen);
|
||||||
|
/* XXX discard if not ready*/
|
||||||
|
if (wlen > 0 && (dc->flags & F_READY) != 0) {
|
||||||
|
dconschat_write_dcons(dc, p->port, wbuf, wlen);
|
||||||
|
if (verbose > 1) {
|
||||||
|
wbuf[wlen] = 0;
|
||||||
|
printf("(%s)\n", wbuf);
|
||||||
|
}
|
||||||
|
if (verbose) {
|
||||||
|
printf("(%d)", wlen);
|
||||||
|
fflush(stdout);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (verbose) {
|
||||||
|
if (len == 0)
|
||||||
|
warnx("port%d: closed", p->port);
|
||||||
|
else
|
||||||
|
warn("port%d: read", p->port);
|
||||||
|
}
|
||||||
|
EV_SET(&kev, p->infd, EVFILT_READ,
|
||||||
|
EV_DELETE, 0, 0, NULL);
|
||||||
|
kevent(dc->kq, &kev, 1, NULL, 0, &dc->zero);
|
||||||
|
close(p->infd);
|
||||||
|
close(p->outfd);
|
||||||
|
/* XXX exit for pipe case XXX */
|
||||||
|
EV_SET(&kev, p->s, EVFILT_READ,
|
||||||
|
EV_ADD | EV_ONESHOT, 0, 0, (void *) p);
|
||||||
|
kevent(dc->kq, &kev, 1, NULL, 0, &dc->zero);
|
||||||
|
p->infd = p->outfd = -1;
|
||||||
|
}
|
||||||
|
return(0);
|
||||||
|
}
|
||||||
|
#define NEVENT 5
|
||||||
|
static int
|
||||||
|
dconschat_proc_socket(struct dcons_state *dc)
|
||||||
|
{
|
||||||
|
struct kevent elist[NEVENT], *e;
|
||||||
|
int i, n;
|
||||||
|
struct dcons_port *p;
|
||||||
|
|
||||||
|
n = kevent(dc->kq, NULL, 0, elist, NEVENT, &dc->to);
|
||||||
|
for (i = 0; i < n; i ++) {
|
||||||
|
e = &elist[i];
|
||||||
|
p = (struct dcons_port *)e->udata;
|
||||||
|
if (e->ident == p->s) {
|
||||||
|
dconschat_accept_socket(dc, p);
|
||||||
|
} else {
|
||||||
|
dconschat_read_socket(dc, p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
dconschat_proc_dcons(struct dcons_state *dc)
|
||||||
|
{
|
||||||
|
int port, len, err;
|
||||||
|
char buf[MAX_XFER];
|
||||||
|
struct dcons_port *p;
|
||||||
|
|
||||||
|
err = dconschat_get_ptr(dc);
|
||||||
|
if (err) {
|
||||||
|
/* XXX we should stop write operation too. */
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
for (port = 0; port < DCONS_NPORT; port ++) {
|
||||||
|
p = &dc->port[port];
|
||||||
|
if (p->infd < 0)
|
||||||
|
continue;
|
||||||
|
while ((len = dconschat_read_dcons(dc, port, buf,
|
||||||
|
sizeof(buf))) > 0) {
|
||||||
|
dconschat_write_socket(p->outfd, buf, len);
|
||||||
|
dconschat_get_ptr(dc);
|
||||||
|
}
|
||||||
|
if ((dc->flags & F_ONE_SHOT) != 0 && len <= 0)
|
||||||
|
dconschat_cleanup(0);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
dconschat_start_session(struct dcons_state *dc)
|
||||||
|
{
|
||||||
|
int counter = 0;
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
if ((dc->flags & F_READY) == 0 && (++counter % 200) == 0)
|
||||||
|
dconschat_fetch_header(dc);
|
||||||
|
if ((dc->flags & F_READY) != 0)
|
||||||
|
dconschat_proc_dcons(dc);
|
||||||
|
dconschat_proc_socket(dc);
|
||||||
|
}
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
usage(void)
|
||||||
|
{
|
||||||
|
fprintf(stderr,
|
||||||
|
"usage: dconschat [-brvwRT1] [-h hz] [-C port] [-G port]\n"
|
||||||
|
"\t\t\t[-M core] [-N system]\n"
|
||||||
|
"\t\t\t[-u unit] [-a address] [-t target_eui64]\n"
|
||||||
|
"\t-b translate ctrl-C to CR+~+ctrl-B on gdb port\n"
|
||||||
|
"\t-v verbose\n"
|
||||||
|
"\t-w listen on wildcard address rather than localhost\n"
|
||||||
|
"\t-r replay old buffer on connection\n"
|
||||||
|
"\t-R read-only\n"
|
||||||
|
"\t-T enable Telnet protocol workaround on console port\n"
|
||||||
|
"\t-1 one shot: read buffer and exit\n"
|
||||||
|
"\t-h polling rate\n"
|
||||||
|
"\t-C port number for console port\n"
|
||||||
|
"\t-G port number for gdb port\n"
|
||||||
|
"\t(for KVM)\n"
|
||||||
|
"\t-M core file\n"
|
||||||
|
"\t-N system file\n"
|
||||||
|
"\t(for FireWire)\n"
|
||||||
|
"\t-u specify unit number of the bus\n"
|
||||||
|
"\t-t EUI64 of target host (must be specified)\n"
|
||||||
|
"\t-a physical address of dcons buffer on target host\n"
|
||||||
|
);
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
int
|
||||||
|
main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
struct dcons_state *dc;
|
||||||
|
struct fw_eui64 eui;
|
||||||
|
char devname[256], *core = NULL, *system = NULL;
|
||||||
|
int i, ch, error;
|
||||||
|
int unit=0, wildcard=0, poll_hz = DCONS_POLL_HZ;
|
||||||
|
int port[DCONS_NPORT];
|
||||||
|
u_int64_t target = 0;
|
||||||
|
|
||||||
|
bzero(&sc, sizeof(sc));
|
||||||
|
dc = ≻
|
||||||
|
dc->flags |= USE_CROM ? F_USE_CROM : 0;
|
||||||
|
|
||||||
|
/* defualt ports */
|
||||||
|
port[0] = 0; /* stdin/out for console */
|
||||||
|
port[1] = -1; /* disable gdb port */
|
||||||
|
|
||||||
|
while ((ch = getopt(argc, argv, "a:bh:rt:u:vwC:G:M:N:RT1")) != -1) {
|
||||||
|
switch(ch) {
|
||||||
|
case 'a':
|
||||||
|
dc->paddr = strtoull(optarg, NULL, 0);
|
||||||
|
dc->flags &= ~F_USE_CROM;
|
||||||
|
break;
|
||||||
|
case 'b':
|
||||||
|
dc->flags |= F_ALT_BREAK;
|
||||||
|
break;
|
||||||
|
case 'h':
|
||||||
|
poll_hz = strtoul(optarg, NULL, 0);
|
||||||
|
if (poll_hz == 0)
|
||||||
|
poll_hz = DCONS_POLL_HZ;
|
||||||
|
printf("poll_hz = %d\n", poll_hz);
|
||||||
|
break;
|
||||||
|
case 'r':
|
||||||
|
dc->flags |= F_REPLAY;
|
||||||
|
break;
|
||||||
|
case 't':
|
||||||
|
target = strtoull(optarg, NULL, 0);
|
||||||
|
eui.hi = target >> 32;
|
||||||
|
eui.lo = target & (((u_int64_t)1 << 32) - 1);
|
||||||
|
dc->type = TYPE_FW;
|
||||||
|
break;
|
||||||
|
case 'u':
|
||||||
|
unit = strtol(optarg, NULL, 0);
|
||||||
|
break;
|
||||||
|
case 'v':
|
||||||
|
verbose ++;
|
||||||
|
break;
|
||||||
|
case 'w':
|
||||||
|
wildcard = 1;
|
||||||
|
break;
|
||||||
|
case 'C':
|
||||||
|
port[0] = strtol(optarg, NULL, 0);
|
||||||
|
break;
|
||||||
|
case 'G':
|
||||||
|
port[1] = strtol(optarg, NULL, 0);
|
||||||
|
break;
|
||||||
|
case 'M':
|
||||||
|
core = optarg;
|
||||||
|
break;
|
||||||
|
case 'N':
|
||||||
|
system = optarg;
|
||||||
|
break;
|
||||||
|
case 'R':
|
||||||
|
dc->flags |= F_RD_ONLY;
|
||||||
|
break;
|
||||||
|
case 'T':
|
||||||
|
dc->flags |= F_TELNET;
|
||||||
|
break;
|
||||||
|
case '1':
|
||||||
|
dc->flags |= F_ONE_SHOT | F_REPLAY;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
usage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (dc->paddr == 0 && (dc->flags & F_USE_CROM) == 0) {
|
||||||
|
warnx("no address specified");
|
||||||
|
usage();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (port[0] < 0 && port[1] < 0) {
|
||||||
|
warnx("no port specified");
|
||||||
|
usage();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* set signal handler */
|
||||||
|
signal(SIGHUP, dconschat_cleanup);
|
||||||
|
signal(SIGINT, dconschat_cleanup);
|
||||||
|
signal(SIGPIPE, dconschat_cleanup);
|
||||||
|
signal(SIGTERM, dconschat_cleanup);
|
||||||
|
|
||||||
|
/* init firewire */
|
||||||
|
switch (dc->type) {
|
||||||
|
case TYPE_FW:
|
||||||
|
#define MAXDEV 4
|
||||||
|
for (i = 0; i < MAXDEV; i ++) {
|
||||||
|
snprintf(devname, sizeof(devname),
|
||||||
|
"/dev/fwmem%d.%d", unit, i);
|
||||||
|
dc->fd = open(devname, O_RDWR);
|
||||||
|
if (dc->fd >= 0)
|
||||||
|
goto found;
|
||||||
|
}
|
||||||
|
err(1, "open");
|
||||||
|
found:
|
||||||
|
error = ioctl(dc->fd, FW_SDEUI64, &eui);
|
||||||
|
if (error)
|
||||||
|
err(1, "ioctl");
|
||||||
|
break;
|
||||||
|
case TYPE_KVM:
|
||||||
|
{
|
||||||
|
struct nlist nl[] = {{"dcons_buf"}, {""}};
|
||||||
|
void *dcons_buf;
|
||||||
|
|
||||||
|
dc->kd = kvm_open(system, core, NULL,
|
||||||
|
(dc->flags & F_RD_ONLY) ? O_RDONLY : O_RDWR, "dconschat");
|
||||||
|
if (dc->kd == NULL)
|
||||||
|
errx(1, "kvm_open");
|
||||||
|
|
||||||
|
if (kvm_nlist(dc->kd, nl) < 0)
|
||||||
|
errx(1, "kvm_nlist: %s", kvm_geterr(dc->kd));
|
||||||
|
|
||||||
|
if (kvm_read(dc->kd, nl[0].n_value, &dcons_buf,
|
||||||
|
sizeof(void *)) < 0)
|
||||||
|
errx(1, "kvm_read: %s", kvm_geterr(dc->kd));
|
||||||
|
dc->paddr = (uintptr_t)dcons_buf;
|
||||||
|
if (verbose)
|
||||||
|
printf("dcons_buf: 0x%x\n", (uint)dc->paddr);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dconschat_fetch_header(dc);
|
||||||
|
|
||||||
|
/* iniit sockets */
|
||||||
|
dc->kq = kqueue();
|
||||||
|
if (poll_hz == 1) {
|
||||||
|
dc->to.tv_sec = 1;
|
||||||
|
dc->to.tv_nsec = 0;
|
||||||
|
} else {
|
||||||
|
dc->to.tv_sec = 0;
|
||||||
|
dc->to.tv_nsec = 1000 * 1000 * 1000 / poll_hz;
|
||||||
|
}
|
||||||
|
dc->zero.tv_sec = 0;
|
||||||
|
dc->zero.tv_nsec = 0;
|
||||||
|
for (i = 0; i < DCONS_NPORT; i++)
|
||||||
|
dconschat_init_socket(dc, i,
|
||||||
|
wildcard ? NULL : "localhost", port[i]);
|
||||||
|
|
||||||
|
dconschat_start_session(dc);
|
||||||
|
|
||||||
|
for (i = 0; i < DCONS_NPORT; i++) {
|
||||||
|
freeaddrinfo(dc->port[i].res);
|
||||||
|
}
|
||||||
|
return (0);
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user