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