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 = ≻
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 = ≻
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