xref: /freebsd/usr.sbin/dconschat/dconschat.c (revision 75d11bfbc6d4289e4b3d91414e46a3af51f4402a)
1df57947fSPedro F. Giffuni /*-
2df57947fSPedro F. Giffuni  * SPDX-License-Identifier: BSD-4-Clause
3df57947fSPedro F. Giffuni  *
4869093b1SHidetoshi Shimokawa  * Copyright (C) 2003
5869093b1SHidetoshi Shimokawa  * 	Hidetoshi Shimokawa. All rights reserved.
6869093b1SHidetoshi Shimokawa  *
7869093b1SHidetoshi Shimokawa  * Redistribution and use in source and binary forms, with or without
8869093b1SHidetoshi Shimokawa  * modification, are permitted provided that the following conditions
9869093b1SHidetoshi Shimokawa  * are met:
10869093b1SHidetoshi Shimokawa  * 1. Redistributions of source code must retain the above copyright
11869093b1SHidetoshi Shimokawa  *    notice, this list of conditions and the following disclaimer.
12869093b1SHidetoshi Shimokawa  * 2. Redistributions in binary form must reproduce the above copyright
13869093b1SHidetoshi Shimokawa  *    notice, this list of conditions and the following disclaimer in the
14869093b1SHidetoshi Shimokawa  *    documentation and/or other materials provided with the distribution.
15869093b1SHidetoshi Shimokawa  * 3. All advertising materials mentioning features or use of this software
16869093b1SHidetoshi Shimokawa  *    must display the following acknowledgement:
17869093b1SHidetoshi Shimokawa  *
18869093b1SHidetoshi Shimokawa  *	This product includes software developed by Hidetoshi Shimokawa.
19869093b1SHidetoshi Shimokawa  *
20869093b1SHidetoshi Shimokawa  * 4. Neither the name of the author nor the names of its contributors
21869093b1SHidetoshi Shimokawa  *    may be used to endorse or promote products derived from this software
22869093b1SHidetoshi Shimokawa  *    without specific prior written permission.
23869093b1SHidetoshi Shimokawa  *
24869093b1SHidetoshi Shimokawa  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25869093b1SHidetoshi Shimokawa  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26869093b1SHidetoshi Shimokawa  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27869093b1SHidetoshi Shimokawa  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28869093b1SHidetoshi Shimokawa  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29869093b1SHidetoshi Shimokawa  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30869093b1SHidetoshi Shimokawa  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31869093b1SHidetoshi Shimokawa  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32869093b1SHidetoshi Shimokawa  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33869093b1SHidetoshi Shimokawa  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34869093b1SHidetoshi Shimokawa  * SUCH DAMAGE.
35869093b1SHidetoshi Shimokawa  *
36869093b1SHidetoshi Shimokawa  * $Id: dconschat.c,v 1.76 2003/10/23 06:21:13 simokawa Exp $
37869093b1SHidetoshi Shimokawa  */
38869093b1SHidetoshi Shimokawa 
39869093b1SHidetoshi Shimokawa #include <sys/param.h>
40869093b1SHidetoshi Shimokawa #include <sys/types.h>
41869093b1SHidetoshi Shimokawa #include <sys/uio.h>
4232cf31faSEd Schouten #include <sys/wait.h>
43869093b1SHidetoshi Shimokawa #include <unistd.h>
44869093b1SHidetoshi Shimokawa #include <fcntl.h>
4532cf31faSEd Schouten #include <signal.h>
460aa9d419SDimitry Andric #include <stdint.h>
47869093b1SHidetoshi Shimokawa #include <stdio.h>
48869093b1SHidetoshi Shimokawa #include <stdlib.h>
49869093b1SHidetoshi Shimokawa #include <termios.h>
50869093b1SHidetoshi Shimokawa #include <dev/dcons/dcons.h>
51869093b1SHidetoshi Shimokawa 
52869093b1SHidetoshi Shimokawa #include <sys/socket.h>
53869093b1SHidetoshi Shimokawa #include <netinet/in.h>
54869093b1SHidetoshi Shimokawa #include <netdb.h>
55869093b1SHidetoshi Shimokawa #include <err.h>
56869093b1SHidetoshi Shimokawa #include <string.h>
57cb5df0b2SBrooks Davis #include <sys/eui64.h>
58869093b1SHidetoshi Shimokawa #include <sys/event.h>
59869093b1SHidetoshi Shimokawa #include <sys/time.h>
60869093b1SHidetoshi Shimokawa #include <arpa/telnet.h>
61869093b1SHidetoshi Shimokawa 
62869093b1SHidetoshi Shimokawa #include <sys/ioccom.h>
63869093b1SHidetoshi Shimokawa #include <dev/firewire/firewire.h>
64869093b1SHidetoshi Shimokawa #include <dev/firewire/iec13213.h>
65869093b1SHidetoshi Shimokawa 
66869093b1SHidetoshi Shimokawa #include <kvm.h>
67869093b1SHidetoshi Shimokawa #include <nlist.h>
68869093b1SHidetoshi Shimokawa 
69869093b1SHidetoshi Shimokawa #include <sys/errno.h>
70869093b1SHidetoshi Shimokawa 
71869093b1SHidetoshi Shimokawa #define	DCONS_POLL_HZ		100
727d72cc56SHidetoshi Shimokawa #define	DCONS_POLL_OFFLINE	2	/* sec */
73869093b1SHidetoshi Shimokawa 
74869093b1SHidetoshi Shimokawa #define RETRY 3
75869093b1SHidetoshi Shimokawa 
76869093b1SHidetoshi Shimokawa #ifdef CSRVAL_VENDOR_PRIVATE
77869093b1SHidetoshi Shimokawa #define	USE_CROM 1
78869093b1SHidetoshi Shimokawa #else
79869093b1SHidetoshi Shimokawa #define	USE_CROM 0
80869093b1SHidetoshi Shimokawa #endif
81869093b1SHidetoshi Shimokawa 
82869093b1SHidetoshi Shimokawa int verbose = 0;
83869093b1SHidetoshi Shimokawa int tc_set = 0;
847d72cc56SHidetoshi Shimokawa int poll_hz = DCONS_POLL_HZ;
858bd69949SHidetoshi Shimokawa static u_char abreak[3] = {13 /* CR */, 126 /* ~ */, 2 /* ^B */};
86869093b1SHidetoshi Shimokawa 
878bd69949SHidetoshi Shimokawa #define IS_CONSOLE(p)	((p)->port == DCONS_CON)
888bd69949SHidetoshi Shimokawa #define IS_GDB(p)	((p)->port == DCONS_GDB)
89869093b1SHidetoshi Shimokawa 
90869093b1SHidetoshi Shimokawa static struct dcons_state {
91869093b1SHidetoshi Shimokawa 	int fd;
92869093b1SHidetoshi Shimokawa 	kvm_t *kd;
93869093b1SHidetoshi Shimokawa 	int kq;
94869093b1SHidetoshi Shimokawa 	off_t paddr;
950311fbe1SHidetoshi Shimokawa 	off_t reset;
96869093b1SHidetoshi Shimokawa #define F_READY		(1 << 1)
97869093b1SHidetoshi Shimokawa #define F_RD_ONLY	(1 << 2)
98869093b1SHidetoshi Shimokawa #define F_ALT_BREAK	(1 << 3)
99869093b1SHidetoshi Shimokawa #define F_TELNET	(1 << 4)
100869093b1SHidetoshi Shimokawa #define F_USE_CROM	(1 << 5)
101869093b1SHidetoshi Shimokawa #define F_ONE_SHOT	(1 << 6)
102869093b1SHidetoshi Shimokawa #define F_REPLAY	(1 << 7)
103869093b1SHidetoshi Shimokawa 	int flags;
104869093b1SHidetoshi Shimokawa 	enum {
105869093b1SHidetoshi Shimokawa 		TYPE_KVM,
106869093b1SHidetoshi Shimokawa 		TYPE_FW
107869093b1SHidetoshi Shimokawa 	} type;
108869093b1SHidetoshi Shimokawa 	int escape_state;
109869093b1SHidetoshi Shimokawa 	struct dcons_port {
110869093b1SHidetoshi Shimokawa 		int port;
1118bd69949SHidetoshi Shimokawa 		int sport;
112869093b1SHidetoshi Shimokawa 		struct dcons_ch o;
113869093b1SHidetoshi Shimokawa 		struct dcons_ch i;
114869093b1SHidetoshi Shimokawa 		u_int32_t optr;
115869093b1SHidetoshi Shimokawa 		u_int32_t iptr;
116869093b1SHidetoshi Shimokawa 		int s;
117869093b1SHidetoshi Shimokawa 		int infd;
118869093b1SHidetoshi Shimokawa 		int outfd;
119869093b1SHidetoshi Shimokawa 		struct addrinfo *res;
120869093b1SHidetoshi Shimokawa 		int skip_read;
121869093b1SHidetoshi Shimokawa 	} port[DCONS_NPORT];
122869093b1SHidetoshi Shimokawa 	struct timespec to;
123869093b1SHidetoshi Shimokawa 	struct timespec zero;
124869093b1SHidetoshi Shimokawa 	struct termios tsave;
1250311fbe1SHidetoshi Shimokawa 	struct termios traw;
1268bd69949SHidetoshi Shimokawa 	char escape;
127869093b1SHidetoshi Shimokawa } sc;
128869093b1SHidetoshi Shimokawa 
1298bd69949SHidetoshi Shimokawa static int dconschat_write_dcons(struct dcons_state *, int, char *, int);
1308bd69949SHidetoshi Shimokawa 
131869093b1SHidetoshi Shimokawa static int
dread(struct dcons_state * dc,void * buf,size_t n,off_t offset)132869093b1SHidetoshi Shimokawa dread(struct dcons_state *dc, void *buf, size_t n, off_t offset)
133869093b1SHidetoshi Shimokawa {
134869093b1SHidetoshi Shimokawa 	switch (dc->type) {
135869093b1SHidetoshi Shimokawa 	case TYPE_FW:
136869093b1SHidetoshi Shimokawa 		return (pread(dc->fd, buf, n, offset));
137869093b1SHidetoshi Shimokawa 	case TYPE_KVM:
138869093b1SHidetoshi Shimokawa 		return (kvm_read(dc->kd, offset, buf, n));
139869093b1SHidetoshi Shimokawa 	}
140869093b1SHidetoshi Shimokawa 	return (-1);
141869093b1SHidetoshi Shimokawa }
142869093b1SHidetoshi Shimokawa 
143869093b1SHidetoshi Shimokawa static int
dwrite(struct dcons_state * dc,void * buf,size_t n,off_t offset)144869093b1SHidetoshi Shimokawa dwrite(struct dcons_state *dc, void *buf, size_t n, off_t offset)
145869093b1SHidetoshi Shimokawa {
146869093b1SHidetoshi Shimokawa 	if ((dc->flags & F_RD_ONLY) != 0)
147869093b1SHidetoshi Shimokawa 		return (n);
148869093b1SHidetoshi Shimokawa 
149869093b1SHidetoshi Shimokawa 	switch (dc->type) {
150869093b1SHidetoshi Shimokawa 	case TYPE_FW:
151869093b1SHidetoshi Shimokawa 		return (pwrite(dc->fd, buf, n, offset));
152869093b1SHidetoshi Shimokawa 	case TYPE_KVM:
153869093b1SHidetoshi Shimokawa 		return (kvm_write(dc->kd, offset, buf, n));
154869093b1SHidetoshi Shimokawa 	}
155869093b1SHidetoshi Shimokawa 	return (-1);
156869093b1SHidetoshi Shimokawa }
157869093b1SHidetoshi Shimokawa 
158869093b1SHidetoshi Shimokawa static void
dconschat_reset_target(struct dcons_state * dc,struct dcons_port * p)1598bd69949SHidetoshi Shimokawa dconschat_reset_target(struct dcons_state *dc, struct dcons_port *p)
1600311fbe1SHidetoshi Shimokawa {
1618bd69949SHidetoshi Shimokawa 	char buf[PAGE_SIZE];
1620311fbe1SHidetoshi Shimokawa 	if (dc->reset == 0)
1630311fbe1SHidetoshi Shimokawa 		return;
1640311fbe1SHidetoshi Shimokawa 
1650aa9d419SDimitry Andric 	snprintf(buf, PAGE_SIZE,
1660aa9d419SDimitry Andric 	    "\r\n[dconschat reset target(addr=0x%jx)...]\r\n",
1670aa9d419SDimitry Andric 	    (intmax_t)dc->reset);
1688bd69949SHidetoshi Shimokawa 	write(p->outfd, buf, strlen(buf));
1698bd69949SHidetoshi Shimokawa 	bzero(&buf[0], PAGE_SIZE);
1708bd69949SHidetoshi Shimokawa 	dwrite(dc, (void *)buf, PAGE_SIZE, dc->reset);
1710311fbe1SHidetoshi Shimokawa }
1720311fbe1SHidetoshi Shimokawa 
1730311fbe1SHidetoshi Shimokawa 
1740311fbe1SHidetoshi Shimokawa static void
dconschat_suspend(struct dcons_state * dc,struct dcons_port * p)1758bd69949SHidetoshi Shimokawa dconschat_suspend(struct dcons_state *dc, struct dcons_port *p)
1760311fbe1SHidetoshi Shimokawa {
1778bd69949SHidetoshi Shimokawa 	if (p->sport != 0)
1788bd69949SHidetoshi Shimokawa 		return;
1798bd69949SHidetoshi Shimokawa 
1800311fbe1SHidetoshi Shimokawa 	if (tc_set)
1810311fbe1SHidetoshi Shimokawa 		tcsetattr(STDIN_FILENO, TCSADRAIN, &dc->tsave);
1820311fbe1SHidetoshi Shimokawa 
1830311fbe1SHidetoshi Shimokawa 	printf("\n[dconschat suspend]\n");
1840311fbe1SHidetoshi Shimokawa 	kill(getpid(), SIGTSTP);
1850311fbe1SHidetoshi Shimokawa 
1860311fbe1SHidetoshi Shimokawa 	if (tc_set)
1870311fbe1SHidetoshi Shimokawa 		tcsetattr(STDIN_FILENO, TCSADRAIN, &dc->traw);
1880311fbe1SHidetoshi Shimokawa }
1890311fbe1SHidetoshi Shimokawa 
1900311fbe1SHidetoshi Shimokawa static void
dconschat_sigchld(int s)1918bd69949SHidetoshi Shimokawa dconschat_sigchld(int s)
1928bd69949SHidetoshi Shimokawa {
1938bd69949SHidetoshi Shimokawa 	struct kevent kev;
1948bd69949SHidetoshi Shimokawa 	struct dcons_port *p;
1958bd69949SHidetoshi Shimokawa 	char buf[256];
1968bd69949SHidetoshi Shimokawa 
1978bd69949SHidetoshi Shimokawa 	p = &sc.port[DCONS_CON];
1988bd69949SHidetoshi Shimokawa 
1998bd69949SHidetoshi Shimokawa 	snprintf(buf, 256, "\r\n[child exit]\r\n");
2008bd69949SHidetoshi Shimokawa 	write(p->outfd, buf, strlen(buf));
2018bd69949SHidetoshi Shimokawa 
2028bd69949SHidetoshi Shimokawa 	if (tc_set)
2038bd69949SHidetoshi Shimokawa 		tcsetattr(STDIN_FILENO, TCSADRAIN, &sc.traw);
2048bd69949SHidetoshi Shimokawa 
2058bd69949SHidetoshi Shimokawa 	EV_SET(&kev, p->infd, EVFILT_READ, EV_ADD, NOTE_LOWAT, 1, (void *)p);
2068bd69949SHidetoshi Shimokawa 	kevent(sc.kq, &kev, 1, NULL, 0, &sc.zero);
2078bd69949SHidetoshi Shimokawa }
2088bd69949SHidetoshi Shimokawa 
2098bd69949SHidetoshi Shimokawa static void
dconschat_fork_gdb(struct dcons_state * dc,struct dcons_port * p)2108bd69949SHidetoshi Shimokawa dconschat_fork_gdb(struct dcons_state *dc, struct dcons_port *p)
2118bd69949SHidetoshi Shimokawa {
2128bd69949SHidetoshi Shimokawa 	pid_t pid;
2138bd69949SHidetoshi Shimokawa 	char buf[256], com[256];
2148bd69949SHidetoshi Shimokawa 	struct kevent kev;
2158bd69949SHidetoshi Shimokawa 
2168bd69949SHidetoshi Shimokawa 	pid = fork();
2178bd69949SHidetoshi Shimokawa 	if (pid < 0) {
2188bd69949SHidetoshi Shimokawa 		snprintf(buf, 256, "\r\n[%s: fork failed]\r\n", __FUNCTION__);
2198bd69949SHidetoshi Shimokawa 		write(p->outfd, buf, strlen(buf));
2208bd69949SHidetoshi Shimokawa 	}
2218bd69949SHidetoshi Shimokawa 
2228bd69949SHidetoshi Shimokawa 
2238bd69949SHidetoshi Shimokawa 	if (pid == 0) {
2248bd69949SHidetoshi Shimokawa 		/* child */
2258bd69949SHidetoshi Shimokawa 		if (tc_set)
2268bd69949SHidetoshi Shimokawa 			tcsetattr(STDIN_FILENO, TCSADRAIN, &dc->tsave);
2278bd69949SHidetoshi Shimokawa 
2288bd69949SHidetoshi Shimokawa 		snprintf(com, sizeof(buf), "kgdb -r :%d kernel",
2298bd69949SHidetoshi Shimokawa 			dc->port[DCONS_GDB].sport);
2308bd69949SHidetoshi Shimokawa 		snprintf(buf, 256, "\n[fork %s]\n", com);
2318bd69949SHidetoshi Shimokawa 		write(p->outfd, buf, strlen(buf));
2328bd69949SHidetoshi Shimokawa 
23332376289SPedro F. Giffuni 		execl("/bin/sh", "/bin/sh", "-c", com, NULL);
2348bd69949SHidetoshi Shimokawa 
2358bd69949SHidetoshi Shimokawa 		snprintf(buf, 256, "\n[fork failed]\n");
2368bd69949SHidetoshi Shimokawa 		write(p->outfd, buf, strlen(buf));
2378bd69949SHidetoshi Shimokawa 
2388bd69949SHidetoshi Shimokawa 		if (tc_set)
2398bd69949SHidetoshi Shimokawa 			tcsetattr(STDIN_FILENO, TCSADRAIN, &dc->traw);
2408bd69949SHidetoshi Shimokawa 
2418bd69949SHidetoshi Shimokawa 		exit(0);
2428bd69949SHidetoshi Shimokawa 	} else {
2438bd69949SHidetoshi Shimokawa 		signal(SIGCHLD, dconschat_sigchld);
2448bd69949SHidetoshi Shimokawa 		EV_SET(&kev, p->infd, EVFILT_READ, EV_DELETE, 0, 0, NULL);
2458bd69949SHidetoshi Shimokawa 		kevent(sc.kq, &kev, 1, NULL, 0, &sc.zero);
2468bd69949SHidetoshi Shimokawa 	}
2478bd69949SHidetoshi Shimokawa }
2488bd69949SHidetoshi Shimokawa 
2498bd69949SHidetoshi Shimokawa 
2508bd69949SHidetoshi Shimokawa static void
dconschat_cleanup(int sig)251869093b1SHidetoshi Shimokawa dconschat_cleanup(int sig)
252869093b1SHidetoshi Shimokawa {
253869093b1SHidetoshi Shimokawa 	struct dcons_state *dc;
2548bd69949SHidetoshi Shimokawa 	int status;
255869093b1SHidetoshi Shimokawa 
256869093b1SHidetoshi Shimokawa 	dc = &sc;
257869093b1SHidetoshi Shimokawa 	if (tc_set != 0)
258869093b1SHidetoshi Shimokawa 		tcsetattr(STDIN_FILENO, TCSADRAIN, &dc->tsave);
259869093b1SHidetoshi Shimokawa 
260869093b1SHidetoshi Shimokawa 	if (sig > 0)
2613a97f68fSHidetoshi Shimokawa 		printf("\n[dconschat exiting with signal %d ...]\n", sig);
262869093b1SHidetoshi Shimokawa 	else
2633a97f68fSHidetoshi Shimokawa 		printf("\n[dconschat exiting...]\n");
2648bd69949SHidetoshi Shimokawa 	wait(&status);
265869093b1SHidetoshi Shimokawa 	exit(0);
266869093b1SHidetoshi Shimokawa }
267869093b1SHidetoshi Shimokawa 
268869093b1SHidetoshi Shimokawa #if USE_CROM
269869093b1SHidetoshi Shimokawa static int
dconschat_get_crom(struct dcons_state * dc)270869093b1SHidetoshi Shimokawa dconschat_get_crom(struct dcons_state *dc)
271869093b1SHidetoshi Shimokawa {
272869093b1SHidetoshi Shimokawa 	off_t addr;
273869093b1SHidetoshi Shimokawa 	int i, state = 0;
2740311fbe1SHidetoshi Shimokawa 	u_int32_t buf, hi = 0, lo = 0, reset_hi = 0, reset_lo = 0;
275869093b1SHidetoshi Shimokawa 	struct csrreg *reg;
276869093b1SHidetoshi Shimokawa 
277869093b1SHidetoshi Shimokawa 	reg = (struct csrreg *)&buf;
278869093b1SHidetoshi Shimokawa 	addr = 0xffff;
279869093b1SHidetoshi Shimokawa 	addr = (addr << 32) | 0xf0000400;
280869093b1SHidetoshi Shimokawa 	for (i = 20; i < 0x400; i += 4) {
281869093b1SHidetoshi Shimokawa 		if (dread(dc, &buf, 4, addr + i) < 0) {
282869093b1SHidetoshi Shimokawa 			if (verbose)
2837bef61eeSGordon Bergling 				warn("crom read failed");
2842ac79858SHidetoshi Shimokawa 			goto out;
285869093b1SHidetoshi Shimokawa 		}
286869093b1SHidetoshi Shimokawa 		buf = ntohl(buf);
287869093b1SHidetoshi Shimokawa 		if (verbose)
288869093b1SHidetoshi Shimokawa 			printf("%d %02x %06x\n", state, reg->key, reg->val);
289869093b1SHidetoshi Shimokawa 		switch (state) {
290869093b1SHidetoshi Shimokawa 		case 0:
291869093b1SHidetoshi Shimokawa 			if (reg->key == CSRKEY_SPEC &&
292869093b1SHidetoshi Shimokawa 					reg->val == CSRVAL_VENDOR_PRIVATE)
293869093b1SHidetoshi Shimokawa 				state = 1;
294869093b1SHidetoshi Shimokawa 			break;
295869093b1SHidetoshi Shimokawa 		case 1:
296869093b1SHidetoshi Shimokawa 			if (reg->key == CSRKEY_VER &&
297869093b1SHidetoshi Shimokawa 					reg->val == DCONS_CSR_VAL_VER)
298869093b1SHidetoshi Shimokawa 				state = 2;
299869093b1SHidetoshi Shimokawa 			break;
300869093b1SHidetoshi Shimokawa 		case 2:
3010311fbe1SHidetoshi Shimokawa 			switch (reg->key) {
3020311fbe1SHidetoshi Shimokawa 			case DCONS_CSR_KEY_HI:
303869093b1SHidetoshi Shimokawa 				hi = reg->val;
3040311fbe1SHidetoshi Shimokawa 				break;
3050311fbe1SHidetoshi Shimokawa 			case DCONS_CSR_KEY_LO:
306869093b1SHidetoshi Shimokawa 				lo = reg->val;
3070311fbe1SHidetoshi Shimokawa 				break;
3080311fbe1SHidetoshi Shimokawa 			case DCONS_CSR_KEY_RESET_HI:
3090311fbe1SHidetoshi Shimokawa 				reset_hi = reg->val;
3100311fbe1SHidetoshi Shimokawa 				break;
3110311fbe1SHidetoshi Shimokawa 			case DCONS_CSR_KEY_RESET_LO:
3120311fbe1SHidetoshi Shimokawa 				reset_lo = reg->val;
313869093b1SHidetoshi Shimokawa 				goto out;
3140311fbe1SHidetoshi Shimokawa 				break;
3150311fbe1SHidetoshi Shimokawa 			case 0x81:
3160311fbe1SHidetoshi Shimokawa 				break;
3170311fbe1SHidetoshi Shimokawa 			default:
3180311fbe1SHidetoshi Shimokawa 				state = 0;
319869093b1SHidetoshi Shimokawa 			}
320869093b1SHidetoshi Shimokawa 			break;
321869093b1SHidetoshi Shimokawa 		}
322869093b1SHidetoshi Shimokawa 	}
323869093b1SHidetoshi Shimokawa out:
324869093b1SHidetoshi Shimokawa 	if (verbose)
325869093b1SHidetoshi Shimokawa 		printf("addr: %06x %06x\n", hi, lo);
326869093b1SHidetoshi Shimokawa 	dc->paddr = ((off_t)hi << 24) | lo;
3270311fbe1SHidetoshi Shimokawa 	dc->reset = ((off_t)reset_hi << 24) | reset_lo;
3280311fbe1SHidetoshi Shimokawa 	if (dc->paddr == 0)
3290311fbe1SHidetoshi Shimokawa 		return (-1);
330869093b1SHidetoshi Shimokawa 	return (0);
331869093b1SHidetoshi Shimokawa }
332869093b1SHidetoshi Shimokawa #endif
333869093b1SHidetoshi Shimokawa 
334869093b1SHidetoshi Shimokawa static void
dconschat_ready(struct dcons_state * dc,int ready,char * reason)335869093b1SHidetoshi Shimokawa dconschat_ready(struct dcons_state *dc, int ready, char *reason)
336869093b1SHidetoshi Shimokawa {
337869093b1SHidetoshi Shimokawa 	static char oldreason[64] = "";
338869093b1SHidetoshi Shimokawa 	int old;
339869093b1SHidetoshi Shimokawa 
340869093b1SHidetoshi Shimokawa 	old = (dc->flags & F_READY) ? 1 : 0;
341869093b1SHidetoshi Shimokawa 
342869093b1SHidetoshi Shimokawa 	if (ready) {
343869093b1SHidetoshi Shimokawa 		dc->flags |= F_READY;
344869093b1SHidetoshi Shimokawa 		if (ready != old)
345869093b1SHidetoshi Shimokawa 			printf("[dcons connected]\r\n");
346869093b1SHidetoshi Shimokawa 		oldreason[0] = 0;
347869093b1SHidetoshi Shimokawa 	} else {
348869093b1SHidetoshi Shimokawa 		dc->flags &= ~F_READY;
349869093b1SHidetoshi Shimokawa 		if (strncmp(oldreason, reason, sizeof(oldreason)) != 0) {
350869093b1SHidetoshi Shimokawa 			printf("[dcons disconnected (%s)]\r\n", reason);
351869093b1SHidetoshi Shimokawa 			strlcpy(oldreason, reason, sizeof(oldreason));
352869093b1SHidetoshi Shimokawa 		}
353869093b1SHidetoshi Shimokawa 	}
354869093b1SHidetoshi Shimokawa }
355869093b1SHidetoshi Shimokawa 
356869093b1SHidetoshi Shimokawa static int
dconschat_fetch_header(struct dcons_state * dc)357869093b1SHidetoshi Shimokawa dconschat_fetch_header(struct dcons_state *dc)
358869093b1SHidetoshi Shimokawa {
359869093b1SHidetoshi Shimokawa 	char ebuf[64];
360869093b1SHidetoshi Shimokawa 	struct dcons_buf dbuf;
361869093b1SHidetoshi Shimokawa 	int j;
362869093b1SHidetoshi Shimokawa 
363869093b1SHidetoshi Shimokawa #if USE_CROM
364869093b1SHidetoshi Shimokawa 	if (dc->paddr == 0 && (dc->flags & F_USE_CROM) != 0) {
365869093b1SHidetoshi Shimokawa 		if (dconschat_get_crom(dc)) {
366869093b1SHidetoshi Shimokawa 			dconschat_ready(dc, 0, "get crom failed");
367869093b1SHidetoshi Shimokawa 			return (-1);
368869093b1SHidetoshi Shimokawa 		}
369869093b1SHidetoshi Shimokawa 	}
370869093b1SHidetoshi Shimokawa #endif
371869093b1SHidetoshi Shimokawa 
372869093b1SHidetoshi Shimokawa 	if (dread(dc, &dbuf, DCONS_HEADER_SIZE, dc->paddr) < 0) {
373869093b1SHidetoshi Shimokawa 		dconschat_ready(dc, 0, "read header failed");
374869093b1SHidetoshi Shimokawa 		return (-1);
375869093b1SHidetoshi Shimokawa 	}
376869093b1SHidetoshi Shimokawa 	if (dbuf.magic != htonl(DCONS_MAGIC)) {
377869093b1SHidetoshi Shimokawa 		if ((dc->flags & F_USE_CROM) !=0)
378869093b1SHidetoshi Shimokawa 			dc->paddr = 0;
379869093b1SHidetoshi Shimokawa 		snprintf(ebuf, sizeof(ebuf), "wrong magic 0x%08x", dbuf.magic);
380869093b1SHidetoshi Shimokawa 		dconschat_ready(dc, 0, ebuf);
381869093b1SHidetoshi Shimokawa 		return (-1);
382869093b1SHidetoshi Shimokawa 	}
383869093b1SHidetoshi Shimokawa 	if (ntohl(dbuf.version) != DCONS_VERSION) {
384869093b1SHidetoshi Shimokawa 		snprintf(ebuf, sizeof(ebuf),
385869093b1SHidetoshi Shimokawa 		    "wrong version %d,%d",
386869093b1SHidetoshi Shimokawa 		    ntohl(dbuf.version), DCONS_VERSION);
387869093b1SHidetoshi Shimokawa 		/* XXX exit? */
388869093b1SHidetoshi Shimokawa 		dconschat_ready(dc, 0, ebuf);
389869093b1SHidetoshi Shimokawa 		return (-1);
390869093b1SHidetoshi Shimokawa 	}
391869093b1SHidetoshi Shimokawa 
392869093b1SHidetoshi Shimokawa 	for (j = 0; j < DCONS_NPORT; j++) {
393869093b1SHidetoshi Shimokawa 		struct dcons_ch *o, *i;
394869093b1SHidetoshi Shimokawa 		off_t newbuf;
395869093b1SHidetoshi Shimokawa 		int new = 0;
396869093b1SHidetoshi Shimokawa 
397869093b1SHidetoshi Shimokawa 		o = &dc->port[j].o;
398869093b1SHidetoshi Shimokawa 		newbuf = dc->paddr + ntohl(dbuf.ooffset[j]);
399869093b1SHidetoshi Shimokawa 		o->size = ntohl(dbuf.osize[j]);
400869093b1SHidetoshi Shimokawa 
401869093b1SHidetoshi Shimokawa 		if (newbuf != o->buf) {
402869093b1SHidetoshi Shimokawa 			/* buffer address has changes */
403869093b1SHidetoshi Shimokawa 			new = 1;
404869093b1SHidetoshi Shimokawa 			o->gen = ntohl(dbuf.optr[j]) >> DCONS_GEN_SHIFT;
405869093b1SHidetoshi Shimokawa 			o->pos = ntohl(dbuf.optr[j]) & DCONS_POS_MASK;
406869093b1SHidetoshi Shimokawa 			o->buf = newbuf;
407869093b1SHidetoshi Shimokawa 		}
408869093b1SHidetoshi Shimokawa 
409869093b1SHidetoshi Shimokawa 		i = &dc->port[j].i;
410869093b1SHidetoshi Shimokawa 		i->size = ntohl(dbuf.isize[j]);
411869093b1SHidetoshi Shimokawa 		i->gen = ntohl(dbuf.iptr[j]) >> DCONS_GEN_SHIFT;
412869093b1SHidetoshi Shimokawa 		i->pos = ntohl(dbuf.iptr[j]) & DCONS_POS_MASK;
413869093b1SHidetoshi Shimokawa 		i->buf = dc->paddr + ntohl(dbuf.ioffset[j]);
414869093b1SHidetoshi Shimokawa 
415869093b1SHidetoshi Shimokawa 		if (verbose) {
416869093b1SHidetoshi Shimokawa 			printf("port %d   size offset   gen   pos\n", j);
417869093b1SHidetoshi Shimokawa 			printf("output: %5d %6d %5d %5d\n"
418869093b1SHidetoshi Shimokawa 				"input : %5d %6d %5d %5d\n",
419869093b1SHidetoshi Shimokawa 			o->size, ntohl(dbuf.ooffset[j]), o->gen, o->pos,
420869093b1SHidetoshi Shimokawa 			i->size, ntohl(dbuf.ioffset[j]), i->gen, i->pos);
421869093b1SHidetoshi Shimokawa 		}
422869093b1SHidetoshi Shimokawa 
423869093b1SHidetoshi Shimokawa 		if (IS_CONSOLE(&dc->port[j]) && new &&
424869093b1SHidetoshi Shimokawa 		    (dc->flags & F_REPLAY) !=0) {
425869093b1SHidetoshi Shimokawa 			if (o->gen > 0)
426869093b1SHidetoshi Shimokawa 				o->gen --;
427869093b1SHidetoshi Shimokawa 			else
428869093b1SHidetoshi Shimokawa 				o->pos = 0;
429869093b1SHidetoshi Shimokawa 		}
430869093b1SHidetoshi Shimokawa 	}
431869093b1SHidetoshi Shimokawa 	dconschat_ready(dc, 1, NULL);
432869093b1SHidetoshi Shimokawa 	return(0);
433869093b1SHidetoshi Shimokawa }
434869093b1SHidetoshi Shimokawa 
435869093b1SHidetoshi Shimokawa static int
dconschat_get_ptr(struct dcons_state * dc)436869093b1SHidetoshi Shimokawa dconschat_get_ptr (struct dcons_state *dc) {
437869093b1SHidetoshi Shimokawa 	int dlen, i;
438869093b1SHidetoshi Shimokawa 	u_int32_t ptr[DCONS_NPORT*2+1];
439869093b1SHidetoshi Shimokawa 	static int retry = RETRY;
44000fab05dSHidetoshi Shimokawa 	char ebuf[64];
441869093b1SHidetoshi Shimokawa 
442869093b1SHidetoshi Shimokawa again:
443869093b1SHidetoshi Shimokawa 	dlen = dread(dc, &ptr, sizeof(ptr),
444869093b1SHidetoshi Shimokawa 		dc->paddr + __offsetof(struct dcons_buf, magic));
445869093b1SHidetoshi Shimokawa 
446869093b1SHidetoshi Shimokawa 	if (dlen < 0) {
447869093b1SHidetoshi Shimokawa 		if (errno == ETIMEDOUT)
448869093b1SHidetoshi Shimokawa 			if (retry -- > 0)
449869093b1SHidetoshi Shimokawa 				goto again;
450869093b1SHidetoshi Shimokawa 		dconschat_ready(dc, 0, "get ptr failed");
451869093b1SHidetoshi Shimokawa 		return(-1);
452869093b1SHidetoshi Shimokawa 	}
453869093b1SHidetoshi Shimokawa 	if (ptr[0] != htonl(DCONS_MAGIC)) {
45400fab05dSHidetoshi Shimokawa 		if ((dc->flags & F_USE_CROM) !=0)
45500fab05dSHidetoshi Shimokawa 			dc->paddr = 0;
45600fab05dSHidetoshi Shimokawa 		snprintf(ebuf, sizeof(ebuf), "wrong magic 0x%08x", ptr[0]);
45700fab05dSHidetoshi Shimokawa 		dconschat_ready(dc, 0, ebuf);
458869093b1SHidetoshi Shimokawa 		return(-1);
459869093b1SHidetoshi Shimokawa 	}
460869093b1SHidetoshi Shimokawa 	retry = RETRY;
461869093b1SHidetoshi Shimokawa 	for (i = 0; i < DCONS_NPORT; i ++) {
462869093b1SHidetoshi Shimokawa 		dc->port[i].optr = ntohl(ptr[i + 1]);
463869093b1SHidetoshi Shimokawa 		dc->port[i].iptr = ntohl(ptr[DCONS_NPORT + i + 1]);
464869093b1SHidetoshi Shimokawa 	}
465869093b1SHidetoshi Shimokawa 	return(0);
466869093b1SHidetoshi Shimokawa }
467869093b1SHidetoshi Shimokawa 
468869093b1SHidetoshi Shimokawa #define MAX_XFER 2048
469869093b1SHidetoshi Shimokawa static int
dconschat_read_dcons(struct dcons_state * dc,int port,char * buf,int len)470869093b1SHidetoshi Shimokawa dconschat_read_dcons(struct dcons_state *dc, int port, char *buf, int len)
471869093b1SHidetoshi Shimokawa {
472869093b1SHidetoshi Shimokawa 	struct dcons_ch *ch;
473869093b1SHidetoshi Shimokawa 	u_int32_t ptr, pos, gen, next_gen;
474869093b1SHidetoshi Shimokawa 	int rlen, dlen, lost;
475869093b1SHidetoshi Shimokawa 	int retry = RETRY;
476869093b1SHidetoshi Shimokawa 
477869093b1SHidetoshi Shimokawa 	ch = &dc->port[port].o;
478869093b1SHidetoshi Shimokawa 	ptr = dc->port[port].optr;
479869093b1SHidetoshi Shimokawa 	gen = ptr >> DCONS_GEN_SHIFT;
480869093b1SHidetoshi Shimokawa 	pos = ptr & DCONS_POS_MASK;
481869093b1SHidetoshi Shimokawa 	if (gen == ch->gen && pos == ch->pos)
482869093b1SHidetoshi Shimokawa 		return (-1);
483869093b1SHidetoshi Shimokawa 
484869093b1SHidetoshi Shimokawa 	next_gen = DCONS_NEXT_GEN(ch->gen);
485869093b1SHidetoshi Shimokawa 	/* XXX sanity check */
486869093b1SHidetoshi Shimokawa 	if (gen == ch->gen) {
487869093b1SHidetoshi Shimokawa 		if (pos > ch->pos)
488869093b1SHidetoshi Shimokawa 			goto ok;
489869093b1SHidetoshi Shimokawa 		lost = ch->size * DCONS_GEN_MASK - ch->pos;
490869093b1SHidetoshi Shimokawa 		ch->pos = 0;
491869093b1SHidetoshi Shimokawa 	} else if (gen == next_gen) {
492869093b1SHidetoshi Shimokawa 		if (pos <= ch->pos)
493869093b1SHidetoshi Shimokawa 			goto ok;
494869093b1SHidetoshi Shimokawa 		lost = pos - ch->pos;
495869093b1SHidetoshi Shimokawa 		ch->pos = pos;
496869093b1SHidetoshi Shimokawa 	} else {
497869093b1SHidetoshi Shimokawa 		lost = gen - ch->gen;
498869093b1SHidetoshi Shimokawa 		if (lost < 0)
499869093b1SHidetoshi Shimokawa 			lost += DCONS_GEN_MASK;
500869093b1SHidetoshi Shimokawa 		if (verbose)
501869093b1SHidetoshi Shimokawa 			printf("[genskip %d]", lost);
502869093b1SHidetoshi Shimokawa 		lost = lost * ch->size - ch->pos;
503869093b1SHidetoshi Shimokawa 		ch->pos = 0;
504869093b1SHidetoshi Shimokawa 		ch->gen = gen;
505869093b1SHidetoshi Shimokawa 	}
506869093b1SHidetoshi Shimokawa 	/* generation skipped !! */
507869093b1SHidetoshi Shimokawa 	/* XXX discard */
508869093b1SHidetoshi Shimokawa 	if (verbose)
509869093b1SHidetoshi Shimokawa 		printf("[lost %d]", lost);
510869093b1SHidetoshi Shimokawa ok:
511869093b1SHidetoshi Shimokawa 	if (gen == ch->gen)
512869093b1SHidetoshi Shimokawa 		rlen = pos - ch->pos;
513869093b1SHidetoshi Shimokawa 	else
514869093b1SHidetoshi Shimokawa 		rlen = ch->size - ch->pos;
515869093b1SHidetoshi Shimokawa 
516869093b1SHidetoshi Shimokawa 	if (rlen > MAX_XFER)
517869093b1SHidetoshi Shimokawa 		rlen = MAX_XFER;
518869093b1SHidetoshi Shimokawa 	if (rlen > len)
519869093b1SHidetoshi Shimokawa 		rlen = len;
520869093b1SHidetoshi Shimokawa 
521869093b1SHidetoshi Shimokawa #if 1
522*75d11bfbSEd Maste 	if (verbose == 1) {
523*75d11bfbSEd Maste 		printf("[%d]", rlen);
524*75d11bfbSEd Maste 		fflush(stdout);
525*75d11bfbSEd Maste 	}
526869093b1SHidetoshi Shimokawa #endif
527869093b1SHidetoshi Shimokawa 
528869093b1SHidetoshi Shimokawa again:
529869093b1SHidetoshi Shimokawa 	dlen = dread(dc, buf, rlen, ch->buf + ch->pos);
530869093b1SHidetoshi Shimokawa 	if (dlen < 0) {
531869093b1SHidetoshi Shimokawa 		if (errno == ETIMEDOUT)
532869093b1SHidetoshi Shimokawa 			if (retry -- > 0)
533869093b1SHidetoshi Shimokawa 				goto again;
534869093b1SHidetoshi Shimokawa 		dconschat_ready(dc, 0, "read buffer failed");
535869093b1SHidetoshi Shimokawa 		return(-1);
536869093b1SHidetoshi Shimokawa 	}
537869093b1SHidetoshi Shimokawa 	if (dlen != rlen)
538869093b1SHidetoshi Shimokawa 		warnx("dlen(%d) != rlen(%d)\n", dlen, rlen);
539869093b1SHidetoshi Shimokawa 	ch->pos += dlen;
540869093b1SHidetoshi Shimokawa 	if (ch->pos >= ch->size) {
541869093b1SHidetoshi Shimokawa 		ch->gen = next_gen;
542869093b1SHidetoshi Shimokawa 		ch->pos = 0;
543869093b1SHidetoshi Shimokawa 		if (verbose)
544869093b1SHidetoshi Shimokawa 			printf("read_dcons: gen=%d", ch->gen);
545869093b1SHidetoshi Shimokawa 	}
546869093b1SHidetoshi Shimokawa 	return (dlen);
547869093b1SHidetoshi Shimokawa }
548869093b1SHidetoshi Shimokawa 
549869093b1SHidetoshi Shimokawa static int
dconschat_write_dcons(struct dcons_state * dc,int port,char * buf,int blen)550869093b1SHidetoshi Shimokawa dconschat_write_dcons(struct dcons_state *dc, int port, char *buf, int blen)
551869093b1SHidetoshi Shimokawa {
552869093b1SHidetoshi Shimokawa 	struct dcons_ch *ch;
553869093b1SHidetoshi Shimokawa 	u_int32_t ptr;
554869093b1SHidetoshi Shimokawa 	int len, wlen;
555869093b1SHidetoshi Shimokawa 	int retry = RETRY;
556869093b1SHidetoshi Shimokawa 
557869093b1SHidetoshi Shimokawa 	ch = &dc->port[port].i;
558869093b1SHidetoshi Shimokawa 	ptr = dc->port[port].iptr;
559869093b1SHidetoshi Shimokawa 
560869093b1SHidetoshi Shimokawa 	/* the others may advance the pointer sync with it */
561869093b1SHidetoshi Shimokawa 	ch->gen = ptr >> DCONS_GEN_SHIFT;
562869093b1SHidetoshi Shimokawa 	ch->pos = ptr & DCONS_POS_MASK;
563869093b1SHidetoshi Shimokawa 
564869093b1SHidetoshi Shimokawa 	while(blen > 0) {
565869093b1SHidetoshi Shimokawa 		wlen = MIN(blen, ch->size - ch->pos);
566869093b1SHidetoshi Shimokawa 		wlen = MIN(wlen, MAX_XFER);
567869093b1SHidetoshi Shimokawa 		len = dwrite(dc, buf, wlen, ch->buf + ch->pos);
568869093b1SHidetoshi Shimokawa 		if (len < 0) {
569869093b1SHidetoshi Shimokawa 			if (errno == ETIMEDOUT)
570869093b1SHidetoshi Shimokawa 				if (retry -- > 0)
571869093b1SHidetoshi Shimokawa 					continue; /* try again */
572869093b1SHidetoshi Shimokawa 			dconschat_ready(dc, 0, "write buffer failed");
573869093b1SHidetoshi Shimokawa 			return(-1);
574869093b1SHidetoshi Shimokawa 		}
575869093b1SHidetoshi Shimokawa 		ch->pos += len;
576869093b1SHidetoshi Shimokawa 		buf += len;
577869093b1SHidetoshi Shimokawa 		blen -= len;
578869093b1SHidetoshi Shimokawa 		if (ch->pos >= ch->size) {
579869093b1SHidetoshi Shimokawa 			ch->gen = DCONS_NEXT_GEN(ch->gen);
580869093b1SHidetoshi Shimokawa 			ch->pos = 0;
581869093b1SHidetoshi Shimokawa 			if (verbose)
582869093b1SHidetoshi Shimokawa 				printf("write_dcons: gen=%d", ch->gen);
583869093b1SHidetoshi Shimokawa 
584869093b1SHidetoshi Shimokawa 		}
585869093b1SHidetoshi Shimokawa 	}
586869093b1SHidetoshi Shimokawa 
587869093b1SHidetoshi Shimokawa 	ptr = DCONS_MAKE_PTR(ch);
588869093b1SHidetoshi Shimokawa 	dc->port[port].iptr = ptr;
589869093b1SHidetoshi Shimokawa 
590869093b1SHidetoshi Shimokawa 	if (verbose > 2)
591869093b1SHidetoshi Shimokawa 		printf("(iptr: 0x%x)", ptr);
592869093b1SHidetoshi Shimokawa again:
593869093b1SHidetoshi Shimokawa 	len = dwrite(dc, &ptr, sizeof(u_int32_t),
594869093b1SHidetoshi Shimokawa 		dc->paddr + __offsetof(struct dcons_buf, iptr[port]));
595869093b1SHidetoshi Shimokawa 	if (len < 0) {
596869093b1SHidetoshi Shimokawa 		if (errno == ETIMEDOUT)
597869093b1SHidetoshi Shimokawa 			if (retry -- > 0)
598869093b1SHidetoshi Shimokawa 				goto again;
599869093b1SHidetoshi Shimokawa 		dconschat_ready(dc, 0, "write ptr failed");
600869093b1SHidetoshi Shimokawa 		return(-1);
601869093b1SHidetoshi Shimokawa 	}
602869093b1SHidetoshi Shimokawa 	return(0);
603869093b1SHidetoshi Shimokawa }
604869093b1SHidetoshi Shimokawa 
6058bd69949SHidetoshi Shimokawa 
606869093b1SHidetoshi Shimokawa static int
dconschat_write_socket(int fd,char * buf,int len)607869093b1SHidetoshi Shimokawa dconschat_write_socket(int fd, char *buf, int len)
608869093b1SHidetoshi Shimokawa {
609869093b1SHidetoshi Shimokawa 	write(fd, buf, len);
610869093b1SHidetoshi Shimokawa 	if (verbose > 1) {
611869093b1SHidetoshi Shimokawa 		buf[len] = 0;
6128bd69949SHidetoshi Shimokawa 		printf("<- %s\n", buf);
613869093b1SHidetoshi Shimokawa 	}
614869093b1SHidetoshi Shimokawa 	return (0);
615869093b1SHidetoshi Shimokawa }
616869093b1SHidetoshi Shimokawa 
617869093b1SHidetoshi Shimokawa static void
dconschat_init_socket(struct dcons_state * dc,int port,char * host,int sport)618869093b1SHidetoshi Shimokawa dconschat_init_socket(struct dcons_state *dc, int port, char *host, int sport)
619869093b1SHidetoshi Shimokawa {
620869093b1SHidetoshi Shimokawa 	struct addrinfo hints, *res;
621869093b1SHidetoshi Shimokawa 	int on = 1, error;
622869093b1SHidetoshi Shimokawa 	char service[10];
623869093b1SHidetoshi Shimokawa 	struct kevent kev;
624869093b1SHidetoshi Shimokawa 	struct dcons_port *p;
625869093b1SHidetoshi Shimokawa 
626869093b1SHidetoshi Shimokawa 	p = &dc->port[port];
627869093b1SHidetoshi Shimokawa 	p->port = port;
6288bd69949SHidetoshi Shimokawa 	p->sport = sport;
629869093b1SHidetoshi Shimokawa 	p->infd = p->outfd = -1;
630869093b1SHidetoshi Shimokawa 
631869093b1SHidetoshi Shimokawa 	if (sport < 0)
632869093b1SHidetoshi Shimokawa 		return;
633869093b1SHidetoshi Shimokawa 
634869093b1SHidetoshi Shimokawa 	if (sport == 0) {
635869093b1SHidetoshi Shimokawa 
636869093b1SHidetoshi Shimokawa 		/* Use stdin and stdout */
637869093b1SHidetoshi Shimokawa 		p->infd = STDIN_FILENO;
638869093b1SHidetoshi Shimokawa 		p->outfd = STDOUT_FILENO;
639869093b1SHidetoshi Shimokawa 		p->s = -1;
640869093b1SHidetoshi Shimokawa 		if (tc_set == 0 &&
641869093b1SHidetoshi Shimokawa 		    tcgetattr(STDIN_FILENO, &dc->tsave) == 0) {
6420311fbe1SHidetoshi Shimokawa 			dc->traw = dc->tsave;
6430311fbe1SHidetoshi Shimokawa 			cfmakeraw(&dc->traw);
6440311fbe1SHidetoshi Shimokawa 			tcsetattr(STDIN_FILENO, TCSADRAIN, &dc->traw);
645869093b1SHidetoshi Shimokawa 			tc_set = 1;
646869093b1SHidetoshi Shimokawa 		}
647869093b1SHidetoshi Shimokawa 		EV_SET(&kev, p->infd, EVFILT_READ, EV_ADD, NOTE_LOWAT, 1,
648869093b1SHidetoshi Shimokawa 		    (void *)p);
649869093b1SHidetoshi Shimokawa 		kevent(dc->kq, &kev, 1, NULL, 0, &dc->zero);
650869093b1SHidetoshi Shimokawa 		return;
651869093b1SHidetoshi Shimokawa 	}
652869093b1SHidetoshi Shimokawa 
653869093b1SHidetoshi Shimokawa 	memset(&hints, 0, sizeof(hints));
654869093b1SHidetoshi Shimokawa 	hints.ai_flags = AI_PASSIVE;
655869093b1SHidetoshi Shimokawa #if 1	/* gdb can talk v4 only */
656869093b1SHidetoshi Shimokawa 	hints.ai_family = PF_INET;
657869093b1SHidetoshi Shimokawa #else
658869093b1SHidetoshi Shimokawa 	hints.ai_family = PF_UNSPEC;
659869093b1SHidetoshi Shimokawa #endif
660869093b1SHidetoshi Shimokawa 	hints.ai_socktype = SOCK_STREAM;
661869093b1SHidetoshi Shimokawa 	hints.ai_protocol = 0;
662869093b1SHidetoshi Shimokawa 
663869093b1SHidetoshi Shimokawa 	if (verbose)
664869093b1SHidetoshi Shimokawa 		printf("%s:%d for port %d\n",
665869093b1SHidetoshi Shimokawa 			host == NULL ? "*" : host, sport, port);
666869093b1SHidetoshi Shimokawa 	snprintf(service, sizeof(service), "%d", sport);
667869093b1SHidetoshi Shimokawa 	error = getaddrinfo(host, service,  &hints, &res);
668869093b1SHidetoshi Shimokawa 	if (error)
669869093b1SHidetoshi Shimokawa 		errx(1, "tcp/%s: %s\n", service, gai_strerror(error));
670869093b1SHidetoshi Shimokawa 	p->res = res;
671869093b1SHidetoshi Shimokawa 	p->s = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
672869093b1SHidetoshi Shimokawa 	if (p->s < 0)
673869093b1SHidetoshi Shimokawa 		err(1, "socket");
674869093b1SHidetoshi Shimokawa 	setsockopt(p->s, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
675869093b1SHidetoshi Shimokawa 
676869093b1SHidetoshi Shimokawa 	if (bind(p->s, p->res->ai_addr, p->res->ai_addrlen) < 0) {
677869093b1SHidetoshi Shimokawa 		err(1, "bind");
678869093b1SHidetoshi Shimokawa 	}
679869093b1SHidetoshi Shimokawa 	if (listen(p->s, 1) < 0)
680869093b1SHidetoshi Shimokawa 		err(1, "listen");
681869093b1SHidetoshi Shimokawa 	EV_SET(&kev, p->s, EVFILT_READ, EV_ADD | EV_ONESHOT, 0, 0, (void *)p);
682869093b1SHidetoshi Shimokawa 	error = kevent(dc->kq, &kev, 1, NULL, 0, &dc->to);
683869093b1SHidetoshi Shimokawa 	if (error < 0)
684869093b1SHidetoshi Shimokawa 		err(1, "kevent");
685869093b1SHidetoshi Shimokawa }
686869093b1SHidetoshi Shimokawa 
687869093b1SHidetoshi Shimokawa static int
dconschat_accept_socket(struct dcons_state * dc,struct dcons_port * p)688869093b1SHidetoshi Shimokawa dconschat_accept_socket(struct dcons_state *dc, struct dcons_port *p)
689869093b1SHidetoshi Shimokawa {
690595e5323SStefan Farfeleder 	socklen_t addrlen;
691595e5323SStefan Farfeleder 	int ns, flags;
692869093b1SHidetoshi Shimokawa 	struct kevent kev;
693869093b1SHidetoshi Shimokawa 
694869093b1SHidetoshi Shimokawa 	/* accept connection */
695595e5323SStefan Farfeleder 	addrlen = p->res->ai_addrlen;
696595e5323SStefan Farfeleder 	ns = accept(p->s, p->res->ai_addr, &addrlen);
697869093b1SHidetoshi Shimokawa 	if (ns < 0)
698869093b1SHidetoshi Shimokawa 		err(1, "accept");
699869093b1SHidetoshi Shimokawa 	if (verbose)
700869093b1SHidetoshi Shimokawa 		printf("port%d accepted\n", p->port);
701869093b1SHidetoshi Shimokawa 
702869093b1SHidetoshi Shimokawa 	flags = fcntl(ns, F_GETFL, 0);
703869093b1SHidetoshi Shimokawa 	flags |= O_NDELAY;
704869093b1SHidetoshi Shimokawa 	fcntl(ns, F_SETFL, flags);
705869093b1SHidetoshi Shimokawa #if 1
706869093b1SHidetoshi Shimokawa 	if (IS_CONSOLE(p) && (dc->flags & F_TELNET) != 0) {
707869093b1SHidetoshi Shimokawa 		char sga[] = {IAC, WILL, TELOPT_SGA};
708869093b1SHidetoshi Shimokawa 		char linemode[] = {IAC, DONT, TELOPT_LINEMODE};
709869093b1SHidetoshi Shimokawa 		char echo[] = {IAC, WILL, TELOPT_ECHO};
710869093b1SHidetoshi Shimokawa 		char bin[] = {IAC, DO, TELOPT_BINARY};
711869093b1SHidetoshi Shimokawa 
712869093b1SHidetoshi Shimokawa 		write(ns, sga, sizeof(sga));
713869093b1SHidetoshi Shimokawa 		write(ns, linemode, sizeof(linemode));
714869093b1SHidetoshi Shimokawa 		write(ns, echo, sizeof(echo));
715869093b1SHidetoshi Shimokawa 		write(ns, bin, sizeof(bin));
716869093b1SHidetoshi Shimokawa 		p->skip_read = 0;
717869093b1SHidetoshi Shimokawa 	}
718869093b1SHidetoshi Shimokawa #endif
719820f6fa9SHidetoshi Shimokawa 	/* discard backlog on GDB port */
720820f6fa9SHidetoshi Shimokawa 	if (IS_GDB(p)) {
721820f6fa9SHidetoshi Shimokawa 		char buf[2048];
722820f6fa9SHidetoshi Shimokawa 		int len;
723820f6fa9SHidetoshi Shimokawa 
724820f6fa9SHidetoshi Shimokawa 		while ((len = dconschat_read_dcons(dc, DCONS_GDB, &buf[0],
725820f6fa9SHidetoshi Shimokawa 				 2048)) > 0)
726820f6fa9SHidetoshi Shimokawa 			if (verbose)
727820f6fa9SHidetoshi Shimokawa 				printf("discard %d chars on GDB port\n", len);
728820f6fa9SHidetoshi Shimokawa 	}
729869093b1SHidetoshi Shimokawa 
730869093b1SHidetoshi Shimokawa 	p->infd = p->outfd = ns;
731869093b1SHidetoshi Shimokawa 	EV_SET(&kev, ns, EVFILT_READ, EV_ADD, NOTE_LOWAT, 1, (void *)p);
732869093b1SHidetoshi Shimokawa 	kevent(dc->kq, &kev, 1, NULL, 0, &dc->zero);
733869093b1SHidetoshi Shimokawa 	return(0);
734869093b1SHidetoshi Shimokawa }
735869093b1SHidetoshi Shimokawa 
736869093b1SHidetoshi Shimokawa static int
dconschat_read_filter(struct dcons_state * dc,struct dcons_port * p,u_char * sp,int slen,u_char * dp,int * dlen)737869093b1SHidetoshi Shimokawa dconschat_read_filter(struct dcons_state *dc, struct dcons_port *p,
738869093b1SHidetoshi Shimokawa     u_char *sp, int slen, u_char *dp, int *dlen)
739869093b1SHidetoshi Shimokawa {
7400311fbe1SHidetoshi Shimokawa 	int skip;
7418bd69949SHidetoshi Shimokawa 	char *buf;
742869093b1SHidetoshi Shimokawa 
743869093b1SHidetoshi Shimokawa 	while (slen > 0) {
7440311fbe1SHidetoshi Shimokawa 		skip = 0;
745869093b1SHidetoshi Shimokawa 		if (IS_CONSOLE(p)) {
746869093b1SHidetoshi Shimokawa 			if ((dc->flags & F_TELNET) != 0) {
747c9a4ff25SStefan Farfeleder 				/* XXX Telnet workarounds */
748869093b1SHidetoshi Shimokawa 				if (p->skip_read -- > 0) {
749869093b1SHidetoshi Shimokawa 					sp ++;
750869093b1SHidetoshi Shimokawa 					slen --;
751869093b1SHidetoshi Shimokawa 					continue;
752869093b1SHidetoshi Shimokawa 				}
753869093b1SHidetoshi Shimokawa 				if (*sp == IAC) {
754869093b1SHidetoshi Shimokawa 					if (verbose)
755869093b1SHidetoshi Shimokawa 						printf("(IAC)");
756869093b1SHidetoshi Shimokawa 					p->skip_read = 2;
757869093b1SHidetoshi Shimokawa 					sp ++;
758869093b1SHidetoshi Shimokawa 					slen --;
759869093b1SHidetoshi Shimokawa 					continue;
760869093b1SHidetoshi Shimokawa 				}
761869093b1SHidetoshi Shimokawa 				if (*sp == 0) {
762869093b1SHidetoshi Shimokawa 					if (verbose)
763869093b1SHidetoshi Shimokawa 						printf("(0 stripped)");
764869093b1SHidetoshi Shimokawa 					sp ++;
765869093b1SHidetoshi Shimokawa 					slen --;
766869093b1SHidetoshi Shimokawa 					continue;
767869093b1SHidetoshi Shimokawa 				}
768869093b1SHidetoshi Shimokawa 			}
769869093b1SHidetoshi Shimokawa 			switch (dc->escape_state) {
770869093b1SHidetoshi Shimokawa 			case STATE1:
7718bd69949SHidetoshi Shimokawa 				if (*sp == dc->escape) {
7720311fbe1SHidetoshi Shimokawa 					skip = 1;
773869093b1SHidetoshi Shimokawa 					dc->escape_state = STATE2;
7740311fbe1SHidetoshi Shimokawa 				} else
775869093b1SHidetoshi Shimokawa 					dc->escape_state = STATE0;
776869093b1SHidetoshi Shimokawa 				break;
777869093b1SHidetoshi Shimokawa 			case STATE2:
778869093b1SHidetoshi Shimokawa 				dc->escape_state = STATE0;
7798bd69949SHidetoshi Shimokawa 				skip = 1;
780869093b1SHidetoshi Shimokawa 				if (*sp == '.')
781869093b1SHidetoshi Shimokawa 					dconschat_cleanup(0);
7828bd69949SHidetoshi Shimokawa 				else if (*sp == CTRL('B')) {
7838bd69949SHidetoshi Shimokawa 					bcopy(abreak, dp, 3);
7848bd69949SHidetoshi Shimokawa 					dp += 3;
7858bd69949SHidetoshi Shimokawa 					*dlen += 3;
7868bd69949SHidetoshi Shimokawa 				}
7878bd69949SHidetoshi Shimokawa 				else if (*sp == CTRL('G'))
7888bd69949SHidetoshi Shimokawa 					dconschat_fork_gdb(dc, p);
7898bd69949SHidetoshi Shimokawa 				else if ((*sp == CTRL('R'))
7900311fbe1SHidetoshi Shimokawa 						&& (dc->reset != 0)) {
7910311fbe1SHidetoshi Shimokawa 					dc->escape_state = STATE3;
7928bd69949SHidetoshi Shimokawa 					buf = "\r\n[Are you sure to reset target? (y/N)]";
7938bd69949SHidetoshi Shimokawa 					write(p->outfd, buf, strlen(buf));
7948bd69949SHidetoshi Shimokawa 				} else if (*sp == CTRL('Z'))
7958bd69949SHidetoshi Shimokawa 					dconschat_suspend(dc, p);
7968bd69949SHidetoshi Shimokawa 				else {
7978bd69949SHidetoshi Shimokawa 					skip = 0;
7988bd69949SHidetoshi Shimokawa 					*dp++ = dc->escape;
7990311fbe1SHidetoshi Shimokawa 					(*dlen) ++;
8000311fbe1SHidetoshi Shimokawa 				}
8010311fbe1SHidetoshi Shimokawa 				break;
8020311fbe1SHidetoshi Shimokawa 			case STATE3:
8030311fbe1SHidetoshi Shimokawa 				dc->escape_state = STATE0;
8040311fbe1SHidetoshi Shimokawa 				skip = 1;
8050311fbe1SHidetoshi Shimokawa 				if (*sp == 'y')
8068bd69949SHidetoshi Shimokawa 					dconschat_reset_target(dc, p);
8078bd69949SHidetoshi Shimokawa 				else {
8088bd69949SHidetoshi Shimokawa 					write(p->outfd, sp, 1);
8098bd69949SHidetoshi Shimokawa 					write(p->outfd, "\r\n", 2);
8108bd69949SHidetoshi Shimokawa 				}
8110311fbe1SHidetoshi Shimokawa 				break;
812869093b1SHidetoshi Shimokawa 			}
813869093b1SHidetoshi Shimokawa 			if (*sp == KEY_CR)
814869093b1SHidetoshi Shimokawa 				dc->escape_state = STATE1;
815869093b1SHidetoshi Shimokawa 		} else if (IS_GDB(p)) {
816869093b1SHidetoshi Shimokawa 			/* GDB: ^C -> CR+~+^B */
8178bd69949SHidetoshi Shimokawa 			if (*sp == CTRL('C') && (dc->flags & F_ALT_BREAK) != 0) {
818869093b1SHidetoshi Shimokawa 				bcopy(abreak, dp, 3);
819869093b1SHidetoshi Shimokawa 				dp += 3;
820869093b1SHidetoshi Shimokawa 				sp ++;
821869093b1SHidetoshi Shimokawa 				*dlen += 3;
822869093b1SHidetoshi Shimokawa 				/* discard rest of the packet */
823869093b1SHidetoshi Shimokawa 				slen = 0;
824869093b1SHidetoshi Shimokawa 				break;
825869093b1SHidetoshi Shimokawa 			}
826869093b1SHidetoshi Shimokawa 		}
8270311fbe1SHidetoshi Shimokawa 		if (!skip) {
8280311fbe1SHidetoshi Shimokawa 			*dp++ = *sp;
829869093b1SHidetoshi Shimokawa 			(*dlen) ++;
8300311fbe1SHidetoshi Shimokawa 		}
8310311fbe1SHidetoshi Shimokawa 		sp ++;
832869093b1SHidetoshi Shimokawa 		slen --;
833869093b1SHidetoshi Shimokawa 	}
834869093b1SHidetoshi Shimokawa 	return (*dlen);
835869093b1SHidetoshi Shimokawa 
836869093b1SHidetoshi Shimokawa }
837869093b1SHidetoshi Shimokawa 
838869093b1SHidetoshi Shimokawa static int
dconschat_read_socket(struct dcons_state * dc,struct dcons_port * p)839869093b1SHidetoshi Shimokawa dconschat_read_socket(struct dcons_state *dc, struct dcons_port *p)
840869093b1SHidetoshi Shimokawa {
841869093b1SHidetoshi Shimokawa 	struct kevent kev;
842869093b1SHidetoshi Shimokawa 	int len, wlen;
843869093b1SHidetoshi Shimokawa 	char rbuf[MAX_XFER], wbuf[MAX_XFER+2];
844869093b1SHidetoshi Shimokawa 
845869093b1SHidetoshi Shimokawa 	if ((len = read(p->infd, rbuf, sizeof(rbuf))) > 0) {
846869093b1SHidetoshi Shimokawa 		wlen = 0;
847869093b1SHidetoshi Shimokawa 		dconschat_read_filter(dc, p, rbuf, len, wbuf, &wlen);
848869093b1SHidetoshi Shimokawa 		/* XXX discard if not ready*/
849869093b1SHidetoshi Shimokawa 		if (wlen > 0 && (dc->flags & F_READY) != 0) {
850869093b1SHidetoshi Shimokawa 			dconschat_write_dcons(dc, p->port, wbuf, wlen);
851869093b1SHidetoshi Shimokawa 			if (verbose > 1) {
852869093b1SHidetoshi Shimokawa 				wbuf[wlen] = 0;
8538bd69949SHidetoshi Shimokawa 				printf("-> %s\n", wbuf);
8548bd69949SHidetoshi Shimokawa 			} else if (verbose == 1) {
855869093b1SHidetoshi Shimokawa 				printf("(%d)", wlen);
856869093b1SHidetoshi Shimokawa 				fflush(stdout);
857869093b1SHidetoshi Shimokawa 			}
858869093b1SHidetoshi Shimokawa 		}
859869093b1SHidetoshi Shimokawa 	} else {
860869093b1SHidetoshi Shimokawa 		if (verbose) {
861869093b1SHidetoshi Shimokawa 			if (len == 0)
862869093b1SHidetoshi Shimokawa 				warnx("port%d: closed", p->port);
863869093b1SHidetoshi Shimokawa 			else
864869093b1SHidetoshi Shimokawa 				warn("port%d: read", p->port);
865869093b1SHidetoshi Shimokawa 		}
866869093b1SHidetoshi Shimokawa 		EV_SET(&kev, p->infd, EVFILT_READ,
867869093b1SHidetoshi Shimokawa 			EV_DELETE, 0, 0, NULL);
868869093b1SHidetoshi Shimokawa 		kevent(dc->kq, &kev, 1, NULL, 0, &dc->zero);
869869093b1SHidetoshi Shimokawa 		close(p->infd);
870869093b1SHidetoshi Shimokawa 		close(p->outfd);
871869093b1SHidetoshi Shimokawa 		/* XXX exit for pipe case XXX */
872869093b1SHidetoshi Shimokawa 		EV_SET(&kev, p->s, EVFILT_READ,
873869093b1SHidetoshi Shimokawa 				EV_ADD | EV_ONESHOT, 0, 0, (void *) p);
874869093b1SHidetoshi Shimokawa 		kevent(dc->kq, &kev, 1, NULL, 0, &dc->zero);
875869093b1SHidetoshi Shimokawa 		p->infd = p->outfd = -1;
876869093b1SHidetoshi Shimokawa 	}
877869093b1SHidetoshi Shimokawa 	return(0);
878869093b1SHidetoshi Shimokawa }
879869093b1SHidetoshi Shimokawa #define NEVENT 5
880869093b1SHidetoshi Shimokawa static int
dconschat_proc_socket(struct dcons_state * dc)881869093b1SHidetoshi Shimokawa dconschat_proc_socket(struct dcons_state *dc)
882869093b1SHidetoshi Shimokawa {
883869093b1SHidetoshi Shimokawa 	struct kevent elist[NEVENT], *e;
884869093b1SHidetoshi Shimokawa 	int i, n;
885869093b1SHidetoshi Shimokawa 	struct dcons_port *p;
886869093b1SHidetoshi Shimokawa 
887869093b1SHidetoshi Shimokawa 	n = kevent(dc->kq, NULL, 0, elist, NEVENT, &dc->to);
888869093b1SHidetoshi Shimokawa 	for (i = 0; i < n; i ++) {
889869093b1SHidetoshi Shimokawa 		e = &elist[i];
890869093b1SHidetoshi Shimokawa 		p = (struct dcons_port *)e->udata;
891869093b1SHidetoshi Shimokawa 		if (e->ident == p->s) {
892869093b1SHidetoshi Shimokawa 			dconschat_accept_socket(dc, p);
893869093b1SHidetoshi Shimokawa 		} else {
894869093b1SHidetoshi Shimokawa 			dconschat_read_socket(dc, p);
895869093b1SHidetoshi Shimokawa 		}
896869093b1SHidetoshi Shimokawa 	}
897869093b1SHidetoshi Shimokawa 	return(0);
898869093b1SHidetoshi Shimokawa }
899869093b1SHidetoshi Shimokawa 
900869093b1SHidetoshi Shimokawa static int
dconschat_proc_dcons(struct dcons_state * dc)901869093b1SHidetoshi Shimokawa dconschat_proc_dcons(struct dcons_state *dc)
902869093b1SHidetoshi Shimokawa {
903869093b1SHidetoshi Shimokawa 	int port, len, err;
904869093b1SHidetoshi Shimokawa 	char buf[MAX_XFER];
905869093b1SHidetoshi Shimokawa 	struct dcons_port *p;
906869093b1SHidetoshi Shimokawa 
907869093b1SHidetoshi Shimokawa 	err = dconschat_get_ptr(dc);
908869093b1SHidetoshi Shimokawa 	if (err) {
909869093b1SHidetoshi Shimokawa 		/* XXX we should stop write operation too. */
910869093b1SHidetoshi Shimokawa 		return err;
911869093b1SHidetoshi Shimokawa 	}
912869093b1SHidetoshi Shimokawa 	for (port = 0; port < DCONS_NPORT; port ++) {
913869093b1SHidetoshi Shimokawa 		p = &dc->port[port];
914869093b1SHidetoshi Shimokawa 		if (p->infd < 0)
915869093b1SHidetoshi Shimokawa 			continue;
916869093b1SHidetoshi Shimokawa 		while ((len = dconschat_read_dcons(dc, port, buf,
917869093b1SHidetoshi Shimokawa 		    sizeof(buf))) > 0) {
918869093b1SHidetoshi Shimokawa 			dconschat_write_socket(p->outfd, buf, len);
919f6416cb4SHidetoshi Shimokawa 			if ((err = dconschat_get_ptr(dc)))
920f6416cb4SHidetoshi Shimokawa 				return (err);
921869093b1SHidetoshi Shimokawa 		}
922869093b1SHidetoshi Shimokawa 		if ((dc->flags & F_ONE_SHOT) != 0 && len <= 0)
923869093b1SHidetoshi Shimokawa 			dconschat_cleanup(0);
924869093b1SHidetoshi Shimokawa 	}
925869093b1SHidetoshi Shimokawa 	return 0;
926869093b1SHidetoshi Shimokawa }
927869093b1SHidetoshi Shimokawa 
928869093b1SHidetoshi Shimokawa static int
dconschat_start_session(struct dcons_state * dc)929869093b1SHidetoshi Shimokawa dconschat_start_session(struct dcons_state *dc)
930869093b1SHidetoshi Shimokawa {
931869093b1SHidetoshi Shimokawa 	int counter = 0;
932f6416cb4SHidetoshi Shimokawa 	int retry = 0;
933f6416cb4SHidetoshi Shimokawa 	int retry_unit_init = MAX(1, poll_hz / 10);
934f6416cb4SHidetoshi Shimokawa 	int retry_unit_offline = poll_hz * DCONS_POLL_OFFLINE;
935f6416cb4SHidetoshi Shimokawa 	int retry_unit = retry_unit_init;
936f6416cb4SHidetoshi Shimokawa 	int retry_max = retry_unit_offline / retry_unit;
937869093b1SHidetoshi Shimokawa 
938869093b1SHidetoshi Shimokawa 	while (1) {
939f6416cb4SHidetoshi Shimokawa 		if (((dc->flags & F_READY) == 0) && ++counter > retry_unit) {
940f6416cb4SHidetoshi Shimokawa 			counter = 0;
941f6416cb4SHidetoshi Shimokawa 			retry ++;
942f6416cb4SHidetoshi Shimokawa 			if (retry > retry_max)
943f6416cb4SHidetoshi Shimokawa 				retry_unit = retry_unit_offline;
944f6416cb4SHidetoshi Shimokawa 			if (verbose) {
945f6416cb4SHidetoshi Shimokawa 				printf("%d/%d ", retry, retry_max);
946f6416cb4SHidetoshi Shimokawa 				fflush(stdout);
947f6416cb4SHidetoshi Shimokawa 			}
948869093b1SHidetoshi Shimokawa 			dconschat_fetch_header(dc);
949f6416cb4SHidetoshi Shimokawa 		}
950f6416cb4SHidetoshi Shimokawa 		if ((dc->flags & F_READY) != 0) {
951f6416cb4SHidetoshi Shimokawa 			counter = 0;
952f6416cb4SHidetoshi Shimokawa 			retry = 0;
953f6416cb4SHidetoshi Shimokawa 			retry_unit = retry_unit_init;
954869093b1SHidetoshi Shimokawa 			dconschat_proc_dcons(dc);
955f6416cb4SHidetoshi Shimokawa 		}
956869093b1SHidetoshi Shimokawa 		dconschat_proc_socket(dc);
957869093b1SHidetoshi Shimokawa 	}
958869093b1SHidetoshi Shimokawa 	return (0);
959869093b1SHidetoshi Shimokawa }
960869093b1SHidetoshi Shimokawa 
961869093b1SHidetoshi Shimokawa static void
usage(void)962869093b1SHidetoshi Shimokawa usage(void)
963869093b1SHidetoshi Shimokawa {
964869093b1SHidetoshi Shimokawa 	fprintf(stderr,
965869093b1SHidetoshi Shimokawa  	    "usage: dconschat [-brvwRT1] [-h hz] [-C port] [-G port]\n"
966869093b1SHidetoshi Shimokawa 	    "\t\t\t[-M core] [-N system]\n"
967869093b1SHidetoshi Shimokawa 	    "\t\t\t[-u unit] [-a address] [-t target_eui64]\n"
968869093b1SHidetoshi Shimokawa 	    "\t-b	translate ctrl-C to CR+~+ctrl-B on gdb port\n"
969869093b1SHidetoshi Shimokawa 	    "\t-v	verbose\n"
970869093b1SHidetoshi Shimokawa 	    "\t-w	listen on wildcard address rather than localhost\n"
971869093b1SHidetoshi Shimokawa 	    "\t-r	replay old buffer on connection\n"
972869093b1SHidetoshi Shimokawa 	    "\t-R	read-only\n"
973869093b1SHidetoshi Shimokawa 	    "\t-T	enable Telnet protocol workaround on console port\n"
974869093b1SHidetoshi Shimokawa 	    "\t-1	one shot: read buffer and exit\n"
975869093b1SHidetoshi Shimokawa 	    "\t-h	polling rate\n"
976869093b1SHidetoshi Shimokawa 	    "\t-C	port number for console port\n"
977869093b1SHidetoshi Shimokawa 	    "\t-G	port number for gdb port\n"
978869093b1SHidetoshi Shimokawa 	    "\t(for KVM)\n"
979869093b1SHidetoshi Shimokawa 	    "\t-M	core file\n"
980869093b1SHidetoshi Shimokawa 	    "\t-N	system file\n"
981869093b1SHidetoshi Shimokawa 	    "\t(for FireWire)\n"
982869093b1SHidetoshi Shimokawa 	    "\t-u	specify unit number of the bus\n"
983869093b1SHidetoshi Shimokawa 	    "\t-t	EUI64 of target host (must be specified)\n"
984869093b1SHidetoshi Shimokawa 	    "\t-a	physical address of dcons buffer on target host\n"
985869093b1SHidetoshi Shimokawa 	);
986869093b1SHidetoshi Shimokawa 	exit(0);
987869093b1SHidetoshi Shimokawa }
988869093b1SHidetoshi Shimokawa int
main(int argc,char ** argv)989869093b1SHidetoshi Shimokawa main(int argc, char **argv)
990869093b1SHidetoshi Shimokawa {
991869093b1SHidetoshi Shimokawa 	struct dcons_state *dc;
992869093b1SHidetoshi Shimokawa 	struct fw_eui64 eui;
993cb5df0b2SBrooks Davis 	struct eui64 target;
994869093b1SHidetoshi Shimokawa 	char devname[256], *core = NULL, *system = NULL;
995869093b1SHidetoshi Shimokawa 	int i, ch, error;
9967d72cc56SHidetoshi Shimokawa 	int unit=0, wildcard=0;
997869093b1SHidetoshi Shimokawa 	int port[DCONS_NPORT];
998869093b1SHidetoshi Shimokawa 
999869093b1SHidetoshi Shimokawa 	bzero(&sc, sizeof(sc));
1000869093b1SHidetoshi Shimokawa 	dc = &sc;
1001869093b1SHidetoshi Shimokawa 	dc->flags |= USE_CROM ? F_USE_CROM : 0;
1002869093b1SHidetoshi Shimokawa 
1003c9a4ff25SStefan Farfeleder 	/* default ports */
1004869093b1SHidetoshi Shimokawa 	port[0] = 0;	/* stdin/out for console */
1005869093b1SHidetoshi Shimokawa 	port[1] = -1;	/* disable gdb port */
1006869093b1SHidetoshi Shimokawa 
10073992d42cSHidetoshi Shimokawa 	/* default escape char */
10083992d42cSHidetoshi Shimokawa 	dc->escape = KEY_TILDE;
10093992d42cSHidetoshi Shimokawa 
10108bd69949SHidetoshi Shimokawa 	while ((ch = getopt(argc, argv, "a:be:h:rt:u:vwC:G:M:N:RT1")) != -1) {
1011869093b1SHidetoshi Shimokawa 		switch(ch) {
1012869093b1SHidetoshi Shimokawa 		case 'a':
1013869093b1SHidetoshi Shimokawa 			dc->paddr = strtoull(optarg, NULL, 0);
1014869093b1SHidetoshi Shimokawa 			dc->flags &= ~F_USE_CROM;
1015869093b1SHidetoshi Shimokawa 			break;
1016869093b1SHidetoshi Shimokawa 		case 'b':
1017869093b1SHidetoshi Shimokawa 			dc->flags |= F_ALT_BREAK;
1018869093b1SHidetoshi Shimokawa 			break;
10198bd69949SHidetoshi Shimokawa 		case 'e':
10203992d42cSHidetoshi Shimokawa 			dc->escape = optarg[0];
10218bd69949SHidetoshi Shimokawa 			break;
1022869093b1SHidetoshi Shimokawa 		case 'h':
1023869093b1SHidetoshi Shimokawa 			poll_hz = strtoul(optarg, NULL, 0);
1024869093b1SHidetoshi Shimokawa 			if (poll_hz == 0)
1025869093b1SHidetoshi Shimokawa 				poll_hz = DCONS_POLL_HZ;
1026869093b1SHidetoshi Shimokawa 			break;
1027869093b1SHidetoshi Shimokawa 		case 'r':
1028869093b1SHidetoshi Shimokawa 			dc->flags |= F_REPLAY;
1029869093b1SHidetoshi Shimokawa 			break;
1030869093b1SHidetoshi Shimokawa 		case 't':
1031cb5df0b2SBrooks Davis 			if (eui64_hostton(optarg, &target) != 0 &&
1032cb5df0b2SBrooks Davis 			    eui64_aton(optarg, &target) != 0)
1033cb5df0b2SBrooks Davis 				errx(1, "invalid target: %s", optarg);
1034cb5df0b2SBrooks Davis 			eui.hi = ntohl(*(u_int32_t*)&(target.octet[0]));
1035cb5df0b2SBrooks Davis 			eui.lo = ntohl(*(u_int32_t*)&(target.octet[4]));
1036869093b1SHidetoshi Shimokawa 			dc->type = TYPE_FW;
1037869093b1SHidetoshi Shimokawa 			break;
1038869093b1SHidetoshi Shimokawa 		case 'u':
1039869093b1SHidetoshi Shimokawa 			unit = strtol(optarg, NULL, 0);
1040869093b1SHidetoshi Shimokawa 			break;
1041869093b1SHidetoshi Shimokawa 		case 'v':
1042869093b1SHidetoshi Shimokawa 			verbose ++;
1043869093b1SHidetoshi Shimokawa 			break;
1044869093b1SHidetoshi Shimokawa 		case 'w':
1045869093b1SHidetoshi Shimokawa 			wildcard = 1;
1046869093b1SHidetoshi Shimokawa 			break;
1047869093b1SHidetoshi Shimokawa 		case 'C':
1048869093b1SHidetoshi Shimokawa 			port[0] = strtol(optarg, NULL, 0);
1049869093b1SHidetoshi Shimokawa 			break;
1050869093b1SHidetoshi Shimokawa 		case 'G':
1051869093b1SHidetoshi Shimokawa 			port[1] = strtol(optarg, NULL, 0);
1052869093b1SHidetoshi Shimokawa 			break;
1053869093b1SHidetoshi Shimokawa 		case 'M':
1054869093b1SHidetoshi Shimokawa 			core = optarg;
1055869093b1SHidetoshi Shimokawa 			break;
1056869093b1SHidetoshi Shimokawa 		case 'N':
1057869093b1SHidetoshi Shimokawa 			system = optarg;
1058869093b1SHidetoshi Shimokawa 			break;
1059869093b1SHidetoshi Shimokawa 		case 'R':
1060869093b1SHidetoshi Shimokawa 			dc->flags |= F_RD_ONLY;
1061869093b1SHidetoshi Shimokawa 			break;
1062869093b1SHidetoshi Shimokawa 		case 'T':
1063869093b1SHidetoshi Shimokawa 			dc->flags |= F_TELNET;
1064869093b1SHidetoshi Shimokawa 			break;
1065869093b1SHidetoshi Shimokawa 		case '1':
1066869093b1SHidetoshi Shimokawa 			dc->flags |= F_ONE_SHOT | F_REPLAY;
1067869093b1SHidetoshi Shimokawa 			break;
1068869093b1SHidetoshi Shimokawa 		default:
1069869093b1SHidetoshi Shimokawa 			usage();
1070869093b1SHidetoshi Shimokawa 		}
1071869093b1SHidetoshi Shimokawa 	}
1072869093b1SHidetoshi Shimokawa 	if (dc->paddr == 0 && (dc->flags & F_USE_CROM) == 0) {
1073869093b1SHidetoshi Shimokawa 		warnx("no address specified");
1074869093b1SHidetoshi Shimokawa 		usage();
1075869093b1SHidetoshi Shimokawa 	}
1076869093b1SHidetoshi Shimokawa 
1077869093b1SHidetoshi Shimokawa 	if (port[0] < 0 && port[1] < 0) {
1078869093b1SHidetoshi Shimokawa 		warnx("no port specified");
1079869093b1SHidetoshi Shimokawa 		usage();
1080869093b1SHidetoshi Shimokawa 	}
1081869093b1SHidetoshi Shimokawa 
1082869093b1SHidetoshi Shimokawa 	/* set signal handler */
1083869093b1SHidetoshi Shimokawa 	signal(SIGHUP, dconschat_cleanup);
1084869093b1SHidetoshi Shimokawa 	signal(SIGINT, dconschat_cleanup);
1085869093b1SHidetoshi Shimokawa 	signal(SIGPIPE, dconschat_cleanup);
1086869093b1SHidetoshi Shimokawa 	signal(SIGTERM, dconschat_cleanup);
1087869093b1SHidetoshi Shimokawa 
1088869093b1SHidetoshi Shimokawa 	/* init firewire */
1089869093b1SHidetoshi Shimokawa 	switch (dc->type) {
1090869093b1SHidetoshi Shimokawa 	case TYPE_FW:
10910e49db83SHidetoshi Shimokawa #define MAXDEV 10
1092869093b1SHidetoshi Shimokawa 		for (i = 0; i < MAXDEV; i ++) {
1093869093b1SHidetoshi Shimokawa 			snprintf(devname, sizeof(devname),
1094869093b1SHidetoshi Shimokawa 			    "/dev/fwmem%d.%d", unit, i);
1095869093b1SHidetoshi Shimokawa 			dc->fd = open(devname, O_RDWR);
1096869093b1SHidetoshi Shimokawa 			if (dc->fd >= 0)
1097869093b1SHidetoshi Shimokawa 				goto found;
1098869093b1SHidetoshi Shimokawa 		}
1099869093b1SHidetoshi Shimokawa 		err(1, "open");
1100869093b1SHidetoshi Shimokawa found:
1101869093b1SHidetoshi Shimokawa 		error = ioctl(dc->fd, FW_SDEUI64, &eui);
1102869093b1SHidetoshi Shimokawa 		if (error)
1103869093b1SHidetoshi Shimokawa 			err(1, "ioctl");
1104869093b1SHidetoshi Shimokawa 		break;
1105869093b1SHidetoshi Shimokawa 	case TYPE_KVM:
1106869093b1SHidetoshi Shimokawa 	{
1107869093b1SHidetoshi Shimokawa 		struct nlist nl[] = {{"dcons_buf"}, {""}};
1108869093b1SHidetoshi Shimokawa 		void *dcons_buf;
1109869093b1SHidetoshi Shimokawa 
1110869093b1SHidetoshi Shimokawa 		dc->kd = kvm_open(system, core, NULL,
1111869093b1SHidetoshi Shimokawa 		    (dc->flags & F_RD_ONLY) ? O_RDONLY : O_RDWR, "dconschat");
1112869093b1SHidetoshi Shimokawa 		if (dc->kd == NULL)
1113869093b1SHidetoshi Shimokawa 			errx(1, "kvm_open");
1114869093b1SHidetoshi Shimokawa 
1115869093b1SHidetoshi Shimokawa 		if (kvm_nlist(dc->kd, nl) < 0)
1116869093b1SHidetoshi Shimokawa 			errx(1, "kvm_nlist: %s", kvm_geterr(dc->kd));
1117869093b1SHidetoshi Shimokawa 
1118869093b1SHidetoshi Shimokawa 		if (kvm_read(dc->kd, nl[0].n_value, &dcons_buf,
1119869093b1SHidetoshi Shimokawa 		    sizeof(void *)) < 0)
1120869093b1SHidetoshi Shimokawa 			errx(1, "kvm_read: %s", kvm_geterr(dc->kd));
1121869093b1SHidetoshi Shimokawa 		dc->paddr = (uintptr_t)dcons_buf;
1122869093b1SHidetoshi Shimokawa 		if (verbose)
1123869093b1SHidetoshi Shimokawa 			printf("dcons_buf: 0x%x\n", (uint)dc->paddr);
1124869093b1SHidetoshi Shimokawa 		break;
1125869093b1SHidetoshi Shimokawa 	}
1126869093b1SHidetoshi Shimokawa 	}
1127869093b1SHidetoshi Shimokawa 	dconschat_fetch_header(dc);
1128869093b1SHidetoshi Shimokawa 
1129c9a4ff25SStefan Farfeleder 	/* init sockets */
1130869093b1SHidetoshi Shimokawa 	dc->kq = kqueue();
1131869093b1SHidetoshi Shimokawa 	if (poll_hz == 1) {
1132869093b1SHidetoshi Shimokawa 		dc->to.tv_sec = 1;
1133869093b1SHidetoshi Shimokawa 		dc->to.tv_nsec = 0;
1134869093b1SHidetoshi Shimokawa 	} else {
1135869093b1SHidetoshi Shimokawa 		dc->to.tv_sec = 0;
1136869093b1SHidetoshi Shimokawa 		dc->to.tv_nsec = 1000 * 1000 * 1000 / poll_hz;
1137869093b1SHidetoshi Shimokawa 	}
1138869093b1SHidetoshi Shimokawa 	dc->zero.tv_sec = 0;
1139869093b1SHidetoshi Shimokawa 	dc->zero.tv_nsec = 0;
1140869093b1SHidetoshi Shimokawa 	for (i = 0; i < DCONS_NPORT; i++)
1141869093b1SHidetoshi Shimokawa 		dconschat_init_socket(dc, i,
1142869093b1SHidetoshi Shimokawa 		    wildcard ? NULL : "localhost", port[i]);
1143869093b1SHidetoshi Shimokawa 
1144869093b1SHidetoshi Shimokawa 	dconschat_start_session(dc);
1145869093b1SHidetoshi Shimokawa 
1146869093b1SHidetoshi Shimokawa 	for (i = 0; i < DCONS_NPORT; i++) {
1147869093b1SHidetoshi Shimokawa 		freeaddrinfo(dc->port[i].res);
1148869093b1SHidetoshi Shimokawa 	}
1149869093b1SHidetoshi Shimokawa 	return (0);
1150869093b1SHidetoshi Shimokawa }
1151