1121468Ssimokawa/* 2121468Ssimokawa * Copyright (C) 2003 3121468Ssimokawa * Hidetoshi Shimokawa. All rights reserved. 4121468Ssimokawa * 5121468Ssimokawa * Redistribution and use in source and binary forms, with or without 6121468Ssimokawa * modification, are permitted provided that the following conditions 7121468Ssimokawa * are met: 8121468Ssimokawa * 1. Redistributions of source code must retain the above copyright 9121468Ssimokawa * notice, this list of conditions and the following disclaimer. 10121468Ssimokawa * 2. Redistributions in binary form must reproduce the above copyright 11121468Ssimokawa * notice, this list of conditions and the following disclaimer in the 12121468Ssimokawa * documentation and/or other materials provided with the distribution. 13121468Ssimokawa * 3. All advertising materials mentioning features or use of this software 14121468Ssimokawa * must display the following acknowledgement: 15121468Ssimokawa * 16121468Ssimokawa * This product includes software developed by Hidetoshi Shimokawa. 17121468Ssimokawa * 18121468Ssimokawa * 4. Neither the name of the author nor the names of its contributors 19121468Ssimokawa * may be used to endorse or promote products derived from this software 20121468Ssimokawa * without specific prior written permission. 21121468Ssimokawa * 22121468Ssimokawa * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23121468Ssimokawa * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24121468Ssimokawa * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25121468Ssimokawa * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26121468Ssimokawa * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27121468Ssimokawa * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28121468Ssimokawa * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29121468Ssimokawa * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30121468Ssimokawa * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31121468Ssimokawa * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32121468Ssimokawa * SUCH DAMAGE. 33121468Ssimokawa * 34121468Ssimokawa * $Id: dconschat.c,v 1.76 2003/10/23 06:21:13 simokawa Exp $ 35121468Ssimokawa * $FreeBSD: releng/10.3/usr.sbin/dconschat/dconschat.c 285007 2015-07-01 15:03:49Z pfg $ 36121468Ssimokawa */ 37121468Ssimokawa 38121468Ssimokawa#include <sys/param.h> 39121468Ssimokawa#include <sys/types.h> 40121468Ssimokawa#include <sys/uio.h> 41194187Sed#include <sys/wait.h> 42121468Ssimokawa#include <unistd.h> 43121468Ssimokawa#include <fcntl.h> 44194187Sed#include <signal.h> 45233195Sdim#include <stdint.h> 46121468Ssimokawa#include <stdio.h> 47121468Ssimokawa#include <stdlib.h> 48121468Ssimokawa#include <termios.h> 49121468Ssimokawa#include <dev/dcons/dcons.h> 50121468Ssimokawa 51121468Ssimokawa#include <sys/socket.h> 52121468Ssimokawa#include <netinet/in.h> 53121468Ssimokawa#include <netdb.h> 54121468Ssimokawa#include <err.h> 55121468Ssimokawa#include <string.h> 56129760Sbrooks#include <sys/eui64.h> 57121468Ssimokawa#include <sys/event.h> 58121468Ssimokawa#include <sys/time.h> 59121468Ssimokawa#include <arpa/telnet.h> 60121468Ssimokawa 61121468Ssimokawa#include <sys/ioccom.h> 62121468Ssimokawa#include <dev/firewire/firewire.h> 63121468Ssimokawa#include <dev/firewire/iec13213.h> 64121468Ssimokawa 65121468Ssimokawa#include <kvm.h> 66121468Ssimokawa#include <nlist.h> 67121468Ssimokawa 68121468Ssimokawa#include <sys/errno.h> 69121468Ssimokawa 70126038Ssimokawa#define DCONS_POLL_HZ 100 71126038Ssimokawa#define DCONS_POLL_OFFLINE 2 /* sec */ 72121468Ssimokawa 73121468Ssimokawa#define RETRY 3 74121468Ssimokawa 75121468Ssimokawa#ifdef CSRVAL_VENDOR_PRIVATE 76121468Ssimokawa#define USE_CROM 1 77121468Ssimokawa#else 78121468Ssimokawa#define USE_CROM 0 79121468Ssimokawa#endif 80121468Ssimokawa 81121468Ssimokawaint verbose = 0; 82121468Ssimokawaint tc_set = 0; 83126038Ssimokawaint poll_hz = DCONS_POLL_HZ; 84170775Ssimokawastatic u_char abreak[3] = {13 /* CR */, 126 /* ~ */, 2 /* ^B */}; 85121468Ssimokawa 86170775Ssimokawa#define IS_CONSOLE(p) ((p)->port == DCONS_CON) 87170775Ssimokawa#define IS_GDB(p) ((p)->port == DCONS_GDB) 88121468Ssimokawa 89121468Ssimokawastatic struct dcons_state { 90121468Ssimokawa int fd; 91121468Ssimokawa kvm_t *kd; 92121468Ssimokawa int kq; 93121468Ssimokawa off_t paddr; 94170422Ssimokawa off_t reset; 95121468Ssimokawa#define F_READY (1 << 1) 96121468Ssimokawa#define F_RD_ONLY (1 << 2) 97121468Ssimokawa#define F_ALT_BREAK (1 << 3) 98121468Ssimokawa#define F_TELNET (1 << 4) 99121468Ssimokawa#define F_USE_CROM (1 << 5) 100121468Ssimokawa#define F_ONE_SHOT (1 << 6) 101121468Ssimokawa#define F_REPLAY (1 << 7) 102121468Ssimokawa int flags; 103121468Ssimokawa enum { 104121468Ssimokawa TYPE_KVM, 105121468Ssimokawa TYPE_FW 106121468Ssimokawa } type; 107121468Ssimokawa int escape_state; 108121468Ssimokawa struct dcons_port { 109121468Ssimokawa int port; 110170775Ssimokawa int sport; 111121468Ssimokawa struct dcons_ch o; 112121468Ssimokawa struct dcons_ch i; 113121468Ssimokawa u_int32_t optr; 114121468Ssimokawa u_int32_t iptr; 115121468Ssimokawa int s; 116121468Ssimokawa int infd; 117121468Ssimokawa int outfd; 118121468Ssimokawa struct addrinfo *res; 119121468Ssimokawa int skip_read; 120121468Ssimokawa } port[DCONS_NPORT]; 121121468Ssimokawa struct timespec to; 122121468Ssimokawa struct timespec zero; 123121468Ssimokawa struct termios tsave; 124170422Ssimokawa struct termios traw; 125170775Ssimokawa char escape; 126121468Ssimokawa} sc; 127121468Ssimokawa 128170775Ssimokawastatic int dconschat_write_dcons(struct dcons_state *, int, char *, int); 129170775Ssimokawa 130121468Ssimokawastatic int 131121468Ssimokawadread(struct dcons_state *dc, void *buf, size_t n, off_t offset) 132121468Ssimokawa{ 133121468Ssimokawa switch (dc->type) { 134121468Ssimokawa case TYPE_FW: 135121468Ssimokawa return (pread(dc->fd, buf, n, offset)); 136121468Ssimokawa case TYPE_KVM: 137121468Ssimokawa return (kvm_read(dc->kd, offset, buf, n)); 138121468Ssimokawa } 139121468Ssimokawa return (-1); 140121468Ssimokawa} 141121468Ssimokawa 142121468Ssimokawastatic int 143121468Ssimokawadwrite(struct dcons_state *dc, void *buf, size_t n, off_t offset) 144121468Ssimokawa{ 145121468Ssimokawa if ((dc->flags & F_RD_ONLY) != 0) 146121468Ssimokawa return (n); 147121468Ssimokawa 148121468Ssimokawa switch (dc->type) { 149121468Ssimokawa case TYPE_FW: 150121468Ssimokawa return (pwrite(dc->fd, buf, n, offset)); 151121468Ssimokawa case TYPE_KVM: 152121468Ssimokawa return (kvm_write(dc->kd, offset, buf, n)); 153121468Ssimokawa } 154121468Ssimokawa return (-1); 155121468Ssimokawa} 156121468Ssimokawa 157121468Ssimokawastatic void 158170775Ssimokawadconschat_reset_target(struct dcons_state *dc, struct dcons_port *p) 159170422Ssimokawa{ 160170775Ssimokawa char buf[PAGE_SIZE]; 161170422Ssimokawa if (dc->reset == 0) 162170422Ssimokawa return; 163170422Ssimokawa 164233195Sdim snprintf(buf, PAGE_SIZE, 165233195Sdim "\r\n[dconschat reset target(addr=0x%jx)...]\r\n", 166233195Sdim (intmax_t)dc->reset); 167170775Ssimokawa write(p->outfd, buf, strlen(buf)); 168170775Ssimokawa bzero(&buf[0], PAGE_SIZE); 169170775Ssimokawa dwrite(dc, (void *)buf, PAGE_SIZE, dc->reset); 170170422Ssimokawa} 171170422Ssimokawa 172170422Ssimokawa 173170422Ssimokawastatic void 174170775Ssimokawadconschat_suspend(struct dcons_state *dc, struct dcons_port *p) 175170422Ssimokawa{ 176170775Ssimokawa if (p->sport != 0) 177170775Ssimokawa return; 178170775Ssimokawa 179170422Ssimokawa if (tc_set) 180170422Ssimokawa tcsetattr(STDIN_FILENO, TCSADRAIN, &dc->tsave); 181170422Ssimokawa 182170422Ssimokawa printf("\n[dconschat suspend]\n"); 183170422Ssimokawa kill(getpid(), SIGTSTP); 184170422Ssimokawa 185170422Ssimokawa if (tc_set) 186170422Ssimokawa tcsetattr(STDIN_FILENO, TCSADRAIN, &dc->traw); 187170422Ssimokawa} 188170422Ssimokawa 189170422Ssimokawastatic void 190170775Ssimokawadconschat_sigchld(int s) 191170775Ssimokawa{ 192170775Ssimokawa struct kevent kev; 193170775Ssimokawa struct dcons_port *p; 194170775Ssimokawa char buf[256]; 195170775Ssimokawa 196170775Ssimokawa p = &sc.port[DCONS_CON]; 197170775Ssimokawa 198170775Ssimokawa snprintf(buf, 256, "\r\n[child exit]\r\n"); 199170775Ssimokawa write(p->outfd, buf, strlen(buf)); 200170775Ssimokawa 201170775Ssimokawa if (tc_set) 202170775Ssimokawa tcsetattr(STDIN_FILENO, TCSADRAIN, &sc.traw); 203170775Ssimokawa 204170775Ssimokawa EV_SET(&kev, p->infd, EVFILT_READ, EV_ADD, NOTE_LOWAT, 1, (void *)p); 205170775Ssimokawa kevent(sc.kq, &kev, 1, NULL, 0, &sc.zero); 206170775Ssimokawa} 207170775Ssimokawa 208170775Ssimokawastatic void 209170775Ssimokawadconschat_fork_gdb(struct dcons_state *dc, struct dcons_port *p) 210170775Ssimokawa{ 211170775Ssimokawa pid_t pid; 212170775Ssimokawa char buf[256], com[256]; 213170775Ssimokawa struct kevent kev; 214170775Ssimokawa 215170775Ssimokawa pid = fork(); 216170775Ssimokawa if (pid < 0) { 217170775Ssimokawa snprintf(buf, 256, "\r\n[%s: fork failed]\r\n", __FUNCTION__); 218170775Ssimokawa write(p->outfd, buf, strlen(buf)); 219170775Ssimokawa } 220170775Ssimokawa 221170775Ssimokawa 222170775Ssimokawa if (pid == 0) { 223170775Ssimokawa /* child */ 224170775Ssimokawa if (tc_set) 225170775Ssimokawa tcsetattr(STDIN_FILENO, TCSADRAIN, &dc->tsave); 226170775Ssimokawa 227170775Ssimokawa snprintf(com, sizeof(buf), "kgdb -r :%d kernel", 228170775Ssimokawa dc->port[DCONS_GDB].sport); 229170775Ssimokawa snprintf(buf, 256, "\n[fork %s]\n", com); 230170775Ssimokawa write(p->outfd, buf, strlen(buf)); 231170775Ssimokawa 232285007Spfg execl("/bin/sh", "/bin/sh", "-c", com, NULL); 233170775Ssimokawa 234170775Ssimokawa snprintf(buf, 256, "\n[fork failed]\n"); 235170775Ssimokawa write(p->outfd, buf, strlen(buf)); 236170775Ssimokawa 237170775Ssimokawa if (tc_set) 238170775Ssimokawa tcsetattr(STDIN_FILENO, TCSADRAIN, &dc->traw); 239170775Ssimokawa 240170775Ssimokawa exit(0); 241170775Ssimokawa } else { 242170775Ssimokawa signal(SIGCHLD, dconschat_sigchld); 243170775Ssimokawa EV_SET(&kev, p->infd, EVFILT_READ, EV_DELETE, 0, 0, NULL); 244170775Ssimokawa kevent(sc.kq, &kev, 1, NULL, 0, &sc.zero); 245170775Ssimokawa } 246170775Ssimokawa} 247170775Ssimokawa 248170775Ssimokawa 249170775Ssimokawastatic void 250121468Ssimokawadconschat_cleanup(int sig) 251121468Ssimokawa{ 252121468Ssimokawa struct dcons_state *dc; 253170775Ssimokawa int status; 254121468Ssimokawa 255121468Ssimokawa dc = ≻ 256121468Ssimokawa if (tc_set != 0) 257121468Ssimokawa tcsetattr(STDIN_FILENO, TCSADRAIN, &dc->tsave); 258121468Ssimokawa 259121468Ssimokawa if (sig > 0) 260122224Ssimokawa printf("\n[dconschat exiting with signal %d ...]\n", sig); 261121468Ssimokawa else 262122224Ssimokawa printf("\n[dconschat exiting...]\n"); 263170775Ssimokawa wait(&status); 264121468Ssimokawa exit(0); 265121468Ssimokawa} 266121468Ssimokawa 267121468Ssimokawa#if USE_CROM 268121468Ssimokawastatic int 269121468Ssimokawadconschat_get_crom(struct dcons_state *dc) 270121468Ssimokawa{ 271121468Ssimokawa off_t addr; 272121468Ssimokawa int i, state = 0; 273170422Ssimokawa u_int32_t buf, hi = 0, lo = 0, reset_hi = 0, reset_lo = 0; 274121468Ssimokawa struct csrreg *reg; 275121468Ssimokawa 276121468Ssimokawa reg = (struct csrreg *)&buf; 277121468Ssimokawa addr = 0xffff; 278121468Ssimokawa addr = (addr << 32) | 0xf0000400; 279121468Ssimokawa for (i = 20; i < 0x400; i += 4) { 280121468Ssimokawa if (dread(dc, &buf, 4, addr + i) < 0) { 281121468Ssimokawa if (verbose) 282121468Ssimokawa warn("crom read faild"); 283170433Ssimokawa goto out; 284121468Ssimokawa } 285121468Ssimokawa buf = ntohl(buf); 286121468Ssimokawa if (verbose) 287121468Ssimokawa printf("%d %02x %06x\n", state, reg->key, reg->val); 288121468Ssimokawa switch (state) { 289121468Ssimokawa case 0: 290121468Ssimokawa if (reg->key == CSRKEY_SPEC && 291121468Ssimokawa reg->val == CSRVAL_VENDOR_PRIVATE) 292121468Ssimokawa state = 1; 293121468Ssimokawa break; 294121468Ssimokawa case 1: 295121468Ssimokawa if (reg->key == CSRKEY_VER && 296121468Ssimokawa reg->val == DCONS_CSR_VAL_VER) 297121468Ssimokawa state = 2; 298121468Ssimokawa break; 299121468Ssimokawa case 2: 300170422Ssimokawa switch (reg->key) { 301170422Ssimokawa case DCONS_CSR_KEY_HI: 302121468Ssimokawa hi = reg->val; 303170422Ssimokawa break; 304170422Ssimokawa case DCONS_CSR_KEY_LO: 305121468Ssimokawa lo = reg->val; 306170422Ssimokawa break; 307170422Ssimokawa case DCONS_CSR_KEY_RESET_HI: 308170422Ssimokawa reset_hi = reg->val; 309170422Ssimokawa break; 310170422Ssimokawa case DCONS_CSR_KEY_RESET_LO: 311170422Ssimokawa reset_lo = reg->val; 312121468Ssimokawa goto out; 313170422Ssimokawa break; 314170422Ssimokawa case 0x81: 315170422Ssimokawa break; 316170422Ssimokawa default: 317170422Ssimokawa state = 0; 318121468Ssimokawa } 319121468Ssimokawa break; 320121468Ssimokawa } 321121468Ssimokawa } 322121468Ssimokawaout: 323121468Ssimokawa if (verbose) 324121468Ssimokawa printf("addr: %06x %06x\n", hi, lo); 325121468Ssimokawa dc->paddr = ((off_t)hi << 24) | lo; 326170422Ssimokawa dc->reset = ((off_t)reset_hi << 24) | reset_lo; 327170422Ssimokawa if (dc->paddr == 0) 328170422Ssimokawa return (-1); 329121468Ssimokawa return (0); 330121468Ssimokawa} 331121468Ssimokawa#endif 332121468Ssimokawa 333121468Ssimokawastatic void 334121468Ssimokawadconschat_ready(struct dcons_state *dc, int ready, char *reason) 335121468Ssimokawa{ 336121468Ssimokawa static char oldreason[64] = ""; 337121468Ssimokawa int old; 338121468Ssimokawa 339121468Ssimokawa old = (dc->flags & F_READY) ? 1 : 0; 340121468Ssimokawa 341121468Ssimokawa if (ready) { 342121468Ssimokawa dc->flags |= F_READY; 343121468Ssimokawa if (ready != old) 344121468Ssimokawa printf("[dcons connected]\r\n"); 345121468Ssimokawa oldreason[0] = 0; 346121468Ssimokawa } else { 347121468Ssimokawa dc->flags &= ~F_READY; 348121468Ssimokawa if (strncmp(oldreason, reason, sizeof(oldreason)) != 0) { 349121468Ssimokawa printf("[dcons disconnected (%s)]\r\n", reason); 350121468Ssimokawa strlcpy(oldreason, reason, sizeof(oldreason)); 351121468Ssimokawa } 352121468Ssimokawa } 353121468Ssimokawa} 354121468Ssimokawa 355121468Ssimokawastatic int 356121468Ssimokawadconschat_fetch_header(struct dcons_state *dc) 357121468Ssimokawa{ 358121468Ssimokawa char ebuf[64]; 359121468Ssimokawa struct dcons_buf dbuf; 360121468Ssimokawa int j; 361121468Ssimokawa 362121468Ssimokawa#if USE_CROM 363121468Ssimokawa if (dc->paddr == 0 && (dc->flags & F_USE_CROM) != 0) { 364121468Ssimokawa if (dconschat_get_crom(dc)) { 365121468Ssimokawa dconschat_ready(dc, 0, "get crom failed"); 366121468Ssimokawa return (-1); 367121468Ssimokawa } 368121468Ssimokawa } 369121468Ssimokawa#endif 370121468Ssimokawa 371121468Ssimokawa if (dread(dc, &dbuf, DCONS_HEADER_SIZE, dc->paddr) < 0) { 372121468Ssimokawa dconschat_ready(dc, 0, "read header failed"); 373121468Ssimokawa return (-1); 374121468Ssimokawa } 375121468Ssimokawa if (dbuf.magic != htonl(DCONS_MAGIC)) { 376121468Ssimokawa if ((dc->flags & F_USE_CROM) !=0) 377121468Ssimokawa dc->paddr = 0; 378121468Ssimokawa snprintf(ebuf, sizeof(ebuf), "wrong magic 0x%08x", dbuf.magic); 379121468Ssimokawa dconschat_ready(dc, 0, ebuf); 380121468Ssimokawa return (-1); 381121468Ssimokawa } 382121468Ssimokawa if (ntohl(dbuf.version) != DCONS_VERSION) { 383121468Ssimokawa snprintf(ebuf, sizeof(ebuf), 384121468Ssimokawa#if __FreeBSD_version < 500000 385121468Ssimokawa "wrong version %ld,%d", 386121468Ssimokawa#else 387121468Ssimokawa "wrong version %d,%d", 388121468Ssimokawa#endif 389121468Ssimokawa ntohl(dbuf.version), DCONS_VERSION); 390121468Ssimokawa /* XXX exit? */ 391121468Ssimokawa dconschat_ready(dc, 0, ebuf); 392121468Ssimokawa return (-1); 393121468Ssimokawa } 394121468Ssimokawa 395121468Ssimokawa for (j = 0; j < DCONS_NPORT; j++) { 396121468Ssimokawa struct dcons_ch *o, *i; 397121468Ssimokawa off_t newbuf; 398121468Ssimokawa int new = 0; 399121468Ssimokawa 400121468Ssimokawa o = &dc->port[j].o; 401121468Ssimokawa newbuf = dc->paddr + ntohl(dbuf.ooffset[j]); 402121468Ssimokawa o->size = ntohl(dbuf.osize[j]); 403121468Ssimokawa 404121468Ssimokawa if (newbuf != o->buf) { 405121468Ssimokawa /* buffer address has changes */ 406121468Ssimokawa new = 1; 407121468Ssimokawa o->gen = ntohl(dbuf.optr[j]) >> DCONS_GEN_SHIFT; 408121468Ssimokawa o->pos = ntohl(dbuf.optr[j]) & DCONS_POS_MASK; 409121468Ssimokawa o->buf = newbuf; 410121468Ssimokawa } 411121468Ssimokawa 412121468Ssimokawa i = &dc->port[j].i; 413121468Ssimokawa i->size = ntohl(dbuf.isize[j]); 414121468Ssimokawa i->gen = ntohl(dbuf.iptr[j]) >> DCONS_GEN_SHIFT; 415121468Ssimokawa i->pos = ntohl(dbuf.iptr[j]) & DCONS_POS_MASK; 416121468Ssimokawa i->buf = dc->paddr + ntohl(dbuf.ioffset[j]); 417121468Ssimokawa 418121468Ssimokawa if (verbose) { 419121468Ssimokawa printf("port %d size offset gen pos\n", j); 420121468Ssimokawa#if __FreeBSD_version < 500000 421121468Ssimokawa printf("output: %5d %6ld %5d %5d\n" 422121468Ssimokawa "input : %5d %6ld %5d %5d\n", 423121468Ssimokawa#else 424121468Ssimokawa printf("output: %5d %6d %5d %5d\n" 425121468Ssimokawa "input : %5d %6d %5d %5d\n", 426121468Ssimokawa#endif 427121468Ssimokawa o->size, ntohl(dbuf.ooffset[j]), o->gen, o->pos, 428121468Ssimokawa i->size, ntohl(dbuf.ioffset[j]), i->gen, i->pos); 429121468Ssimokawa } 430121468Ssimokawa 431121468Ssimokawa if (IS_CONSOLE(&dc->port[j]) && new && 432121468Ssimokawa (dc->flags & F_REPLAY) !=0) { 433121468Ssimokawa if (o->gen > 0) 434121468Ssimokawa o->gen --; 435121468Ssimokawa else 436121468Ssimokawa o->pos = 0; 437121468Ssimokawa } 438121468Ssimokawa } 439121468Ssimokawa dconschat_ready(dc, 1, NULL); 440121468Ssimokawa return(0); 441121468Ssimokawa} 442121468Ssimokawa 443121468Ssimokawastatic int 444121468Ssimokawadconschat_get_ptr (struct dcons_state *dc) { 445121468Ssimokawa int dlen, i; 446121468Ssimokawa u_int32_t ptr[DCONS_NPORT*2+1]; 447121468Ssimokawa static int retry = RETRY; 448135821Ssimokawa char ebuf[64]; 449121468Ssimokawa 450121468Ssimokawaagain: 451121468Ssimokawa dlen = dread(dc, &ptr, sizeof(ptr), 452121468Ssimokawa dc->paddr + __offsetof(struct dcons_buf, magic)); 453121468Ssimokawa 454121468Ssimokawa if (dlen < 0) { 455121468Ssimokawa if (errno == ETIMEDOUT) 456121468Ssimokawa if (retry -- > 0) 457121468Ssimokawa goto again; 458121468Ssimokawa dconschat_ready(dc, 0, "get ptr failed"); 459121468Ssimokawa return(-1); 460121468Ssimokawa } 461121468Ssimokawa if (ptr[0] != htonl(DCONS_MAGIC)) { 462135821Ssimokawa if ((dc->flags & F_USE_CROM) !=0) 463135821Ssimokawa dc->paddr = 0; 464135821Ssimokawa snprintf(ebuf, sizeof(ebuf), "wrong magic 0x%08x", ptr[0]); 465135821Ssimokawa dconschat_ready(dc, 0, ebuf); 466121468Ssimokawa return(-1); 467121468Ssimokawa } 468121468Ssimokawa retry = RETRY; 469121468Ssimokawa for (i = 0; i < DCONS_NPORT; i ++) { 470121468Ssimokawa dc->port[i].optr = ntohl(ptr[i + 1]); 471121468Ssimokawa dc->port[i].iptr = ntohl(ptr[DCONS_NPORT + i + 1]); 472121468Ssimokawa } 473121468Ssimokawa return(0); 474121468Ssimokawa} 475121468Ssimokawa 476121468Ssimokawa#define MAX_XFER 2048 477121468Ssimokawastatic int 478121468Ssimokawadconschat_read_dcons(struct dcons_state *dc, int port, char *buf, int len) 479121468Ssimokawa{ 480121468Ssimokawa struct dcons_ch *ch; 481121468Ssimokawa u_int32_t ptr, pos, gen, next_gen; 482121468Ssimokawa int rlen, dlen, lost; 483121468Ssimokawa int retry = RETRY; 484121468Ssimokawa 485121468Ssimokawa ch = &dc->port[port].o; 486121468Ssimokawa ptr = dc->port[port].optr; 487121468Ssimokawa gen = ptr >> DCONS_GEN_SHIFT; 488121468Ssimokawa pos = ptr & DCONS_POS_MASK; 489121468Ssimokawa if (gen == ch->gen && pos == ch->pos) 490121468Ssimokawa return (-1); 491121468Ssimokawa 492121468Ssimokawa next_gen = DCONS_NEXT_GEN(ch->gen); 493121468Ssimokawa /* XXX sanity check */ 494121468Ssimokawa if (gen == ch->gen) { 495121468Ssimokawa if (pos > ch->pos) 496121468Ssimokawa goto ok; 497121468Ssimokawa lost = ch->size * DCONS_GEN_MASK - ch->pos; 498121468Ssimokawa ch->pos = 0; 499121468Ssimokawa } else if (gen == next_gen) { 500121468Ssimokawa if (pos <= ch->pos) 501121468Ssimokawa goto ok; 502121468Ssimokawa lost = pos - ch->pos; 503121468Ssimokawa ch->pos = pos; 504121468Ssimokawa } else { 505121468Ssimokawa lost = gen - ch->gen; 506121468Ssimokawa if (lost < 0) 507121468Ssimokawa lost += DCONS_GEN_MASK; 508121468Ssimokawa if (verbose) 509121468Ssimokawa printf("[genskip %d]", lost); 510121468Ssimokawa lost = lost * ch->size - ch->pos; 511121468Ssimokawa ch->pos = 0; 512121468Ssimokawa ch->gen = gen; 513121468Ssimokawa } 514121468Ssimokawa /* generation skipped !! */ 515121468Ssimokawa /* XXX discard */ 516121468Ssimokawa if (verbose) 517121468Ssimokawa printf("[lost %d]", lost); 518121468Ssimokawaok: 519121468Ssimokawa if (gen == ch->gen) 520121468Ssimokawa rlen = pos - ch->pos; 521121468Ssimokawa else 522121468Ssimokawa rlen = ch->size - ch->pos; 523121468Ssimokawa 524121468Ssimokawa if (rlen > MAX_XFER) 525121468Ssimokawa rlen = MAX_XFER; 526121468Ssimokawa if (rlen > len) 527121468Ssimokawa rlen = len; 528121468Ssimokawa 529121468Ssimokawa#if 1 530170775Ssimokawa if (verbose == 1) 531121468Ssimokawa printf("[%d]", rlen); fflush(stdout); 532121468Ssimokawa#endif 533121468Ssimokawa 534121468Ssimokawaagain: 535121468Ssimokawa dlen = dread(dc, buf, rlen, ch->buf + ch->pos); 536121468Ssimokawa if (dlen < 0) { 537121468Ssimokawa if (errno == ETIMEDOUT) 538121468Ssimokawa if (retry -- > 0) 539121468Ssimokawa goto again; 540121468Ssimokawa dconschat_ready(dc, 0, "read buffer failed"); 541121468Ssimokawa return(-1); 542121468Ssimokawa } 543121468Ssimokawa if (dlen != rlen) 544121468Ssimokawa warnx("dlen(%d) != rlen(%d)\n", dlen, rlen); 545121468Ssimokawa ch->pos += dlen; 546121468Ssimokawa if (ch->pos >= ch->size) { 547121468Ssimokawa ch->gen = next_gen; 548121468Ssimokawa ch->pos = 0; 549121468Ssimokawa if (verbose) 550121468Ssimokawa printf("read_dcons: gen=%d", ch->gen); 551121468Ssimokawa } 552121468Ssimokawa return (dlen); 553121468Ssimokawa} 554121468Ssimokawa 555121468Ssimokawastatic int 556121468Ssimokawadconschat_write_dcons(struct dcons_state *dc, int port, char *buf, int blen) 557121468Ssimokawa{ 558121468Ssimokawa struct dcons_ch *ch; 559121468Ssimokawa u_int32_t ptr; 560121468Ssimokawa int len, wlen; 561121468Ssimokawa int retry = RETRY; 562121468Ssimokawa 563121468Ssimokawa ch = &dc->port[port].i; 564121468Ssimokawa ptr = dc->port[port].iptr; 565121468Ssimokawa 566121468Ssimokawa /* the others may advance the pointer sync with it */ 567121468Ssimokawa ch->gen = ptr >> DCONS_GEN_SHIFT; 568121468Ssimokawa ch->pos = ptr & DCONS_POS_MASK; 569121468Ssimokawa 570121468Ssimokawa while(blen > 0) { 571121468Ssimokawa wlen = MIN(blen, ch->size - ch->pos); 572121468Ssimokawa wlen = MIN(wlen, MAX_XFER); 573121468Ssimokawa len = dwrite(dc, buf, wlen, ch->buf + ch->pos); 574121468Ssimokawa if (len < 0) { 575121468Ssimokawa if (errno == ETIMEDOUT) 576121468Ssimokawa if (retry -- > 0) 577121468Ssimokawa continue; /* try again */ 578121468Ssimokawa dconschat_ready(dc, 0, "write buffer failed"); 579121468Ssimokawa return(-1); 580121468Ssimokawa } 581121468Ssimokawa ch->pos += len; 582121468Ssimokawa buf += len; 583121468Ssimokawa blen -= len; 584121468Ssimokawa if (ch->pos >= ch->size) { 585121468Ssimokawa ch->gen = DCONS_NEXT_GEN(ch->gen); 586121468Ssimokawa ch->pos = 0; 587121468Ssimokawa if (verbose) 588121468Ssimokawa printf("write_dcons: gen=%d", ch->gen); 589121468Ssimokawa 590121468Ssimokawa } 591121468Ssimokawa } 592121468Ssimokawa 593121468Ssimokawa ptr = DCONS_MAKE_PTR(ch); 594121468Ssimokawa dc->port[port].iptr = ptr; 595121468Ssimokawa 596121468Ssimokawa if (verbose > 2) 597121468Ssimokawa printf("(iptr: 0x%x)", ptr); 598121468Ssimokawaagain: 599121468Ssimokawa len = dwrite(dc, &ptr, sizeof(u_int32_t), 600121468Ssimokawa dc->paddr + __offsetof(struct dcons_buf, iptr[port])); 601121468Ssimokawa if (len < 0) { 602121468Ssimokawa if (errno == ETIMEDOUT) 603121468Ssimokawa if (retry -- > 0) 604121468Ssimokawa goto again; 605121468Ssimokawa dconschat_ready(dc, 0, "write ptr failed"); 606121468Ssimokawa return(-1); 607121468Ssimokawa } 608121468Ssimokawa return(0); 609121468Ssimokawa} 610121468Ssimokawa 611170775Ssimokawa 612121468Ssimokawastatic int 613121468Ssimokawadconschat_write_socket(int fd, char *buf, int len) 614121468Ssimokawa{ 615121468Ssimokawa write(fd, buf, len); 616121468Ssimokawa if (verbose > 1) { 617121468Ssimokawa buf[len] = 0; 618170775Ssimokawa printf("<- %s\n", buf); 619121468Ssimokawa } 620121468Ssimokawa return (0); 621121468Ssimokawa} 622121468Ssimokawa 623121468Ssimokawastatic void 624121468Ssimokawadconschat_init_socket(struct dcons_state *dc, int port, char *host, int sport) 625121468Ssimokawa{ 626121468Ssimokawa struct addrinfo hints, *res; 627121468Ssimokawa int on = 1, error; 628121468Ssimokawa char service[10]; 629121468Ssimokawa struct kevent kev; 630121468Ssimokawa struct dcons_port *p; 631121468Ssimokawa 632121468Ssimokawa p = &dc->port[port]; 633121468Ssimokawa p->port = port; 634170775Ssimokawa p->sport = sport; 635121468Ssimokawa p->infd = p->outfd = -1; 636121468Ssimokawa 637121468Ssimokawa if (sport < 0) 638121468Ssimokawa return; 639121468Ssimokawa 640121468Ssimokawa if (sport == 0) { 641121468Ssimokawa 642121468Ssimokawa /* Use stdin and stdout */ 643121468Ssimokawa p->infd = STDIN_FILENO; 644121468Ssimokawa p->outfd = STDOUT_FILENO; 645121468Ssimokawa p->s = -1; 646121468Ssimokawa if (tc_set == 0 && 647121468Ssimokawa tcgetattr(STDIN_FILENO, &dc->tsave) == 0) { 648170422Ssimokawa dc->traw = dc->tsave; 649170422Ssimokawa cfmakeraw(&dc->traw); 650170422Ssimokawa tcsetattr(STDIN_FILENO, TCSADRAIN, &dc->traw); 651121468Ssimokawa tc_set = 1; 652121468Ssimokawa } 653121468Ssimokawa EV_SET(&kev, p->infd, EVFILT_READ, EV_ADD, NOTE_LOWAT, 1, 654121468Ssimokawa (void *)p); 655121468Ssimokawa kevent(dc->kq, &kev, 1, NULL, 0, &dc->zero); 656121468Ssimokawa return; 657121468Ssimokawa } 658121468Ssimokawa 659121468Ssimokawa memset(&hints, 0, sizeof(hints)); 660121468Ssimokawa hints.ai_flags = AI_PASSIVE; 661121468Ssimokawa#if 1 /* gdb can talk v4 only */ 662121468Ssimokawa hints.ai_family = PF_INET; 663121468Ssimokawa#else 664121468Ssimokawa hints.ai_family = PF_UNSPEC; 665121468Ssimokawa#endif 666121468Ssimokawa hints.ai_socktype = SOCK_STREAM; 667121468Ssimokawa hints.ai_protocol = 0; 668121468Ssimokawa 669121468Ssimokawa if (verbose) 670121468Ssimokawa printf("%s:%d for port %d\n", 671121468Ssimokawa host == NULL ? "*" : host, sport, port); 672121468Ssimokawa snprintf(service, sizeof(service), "%d", sport); 673121468Ssimokawa error = getaddrinfo(host, service, &hints, &res); 674121468Ssimokawa if (error) 675121468Ssimokawa errx(1, "tcp/%s: %s\n", service, gai_strerror(error)); 676121468Ssimokawa p->res = res; 677121468Ssimokawa p->s = socket(res->ai_family, res->ai_socktype, res->ai_protocol); 678121468Ssimokawa if (p->s < 0) 679121468Ssimokawa err(1, "socket"); 680121468Ssimokawa setsockopt(p->s, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); 681121468Ssimokawa 682121468Ssimokawa if (bind(p->s, p->res->ai_addr, p->res->ai_addrlen) < 0) { 683121468Ssimokawa err(1, "bind"); 684121468Ssimokawa } 685121468Ssimokawa if (listen(p->s, 1) < 0) 686121468Ssimokawa err(1, "listen"); 687121468Ssimokawa EV_SET(&kev, p->s, EVFILT_READ, EV_ADD | EV_ONESHOT, 0, 0, (void *)p); 688121468Ssimokawa error = kevent(dc->kq, &kev, 1, NULL, 0, &dc->to); 689121468Ssimokawa if (error < 0) 690121468Ssimokawa err(1, "kevent"); 691121468Ssimokawa return; 692121468Ssimokawa} 693121468Ssimokawa 694121468Ssimokawastatic int 695121468Ssimokawadconschat_accept_socket(struct dcons_state *dc, struct dcons_port *p) 696121468Ssimokawa{ 697143415Sstefanf socklen_t addrlen; 698143415Sstefanf int ns, flags; 699121468Ssimokawa struct kevent kev; 700121468Ssimokawa 701121468Ssimokawa /* accept connection */ 702143415Sstefanf addrlen = p->res->ai_addrlen; 703143415Sstefanf ns = accept(p->s, p->res->ai_addr, &addrlen); 704121468Ssimokawa if (ns < 0) 705121468Ssimokawa err(1, "accept"); 706121468Ssimokawa if (verbose) 707121468Ssimokawa printf("port%d accepted\n", p->port); 708121468Ssimokawa 709121468Ssimokawa flags = fcntl(ns, F_GETFL, 0); 710121468Ssimokawa flags |= O_NDELAY; 711121468Ssimokawa fcntl(ns, F_SETFL, flags); 712121468Ssimokawa#if 1 713121468Ssimokawa if (IS_CONSOLE(p) && (dc->flags & F_TELNET) != 0) { 714121468Ssimokawa char sga[] = {IAC, WILL, TELOPT_SGA}; 715121468Ssimokawa char linemode[] = {IAC, DONT, TELOPT_LINEMODE}; 716121468Ssimokawa char echo[] = {IAC, WILL, TELOPT_ECHO}; 717121468Ssimokawa char bin[] = {IAC, DO, TELOPT_BINARY}; 718121468Ssimokawa 719121468Ssimokawa write(ns, sga, sizeof(sga)); 720121468Ssimokawa write(ns, linemode, sizeof(linemode)); 721121468Ssimokawa write(ns, echo, sizeof(echo)); 722121468Ssimokawa write(ns, bin, sizeof(bin)); 723121468Ssimokawa p->skip_read = 0; 724121468Ssimokawa } 725121468Ssimokawa#endif 726170146Ssimokawa /* discard backlog on GDB port */ 727170146Ssimokawa if (IS_GDB(p)) { 728170146Ssimokawa char buf[2048]; 729170146Ssimokawa int len; 730121468Ssimokawa 731170146Ssimokawa while ((len = dconschat_read_dcons(dc, DCONS_GDB, &buf[0], 732170146Ssimokawa 2048)) > 0) 733170146Ssimokawa if (verbose) 734170146Ssimokawa printf("discard %d chars on GDB port\n", len); 735170146Ssimokawa } 736170146Ssimokawa 737121468Ssimokawa p->infd = p->outfd = ns; 738121468Ssimokawa EV_SET(&kev, ns, EVFILT_READ, EV_ADD, NOTE_LOWAT, 1, (void *)p); 739121468Ssimokawa kevent(dc->kq, &kev, 1, NULL, 0, &dc->zero); 740121468Ssimokawa return(0); 741121468Ssimokawa} 742121468Ssimokawa 743121468Ssimokawastatic int 744121468Ssimokawadconschat_read_filter(struct dcons_state *dc, struct dcons_port *p, 745121468Ssimokawa u_char *sp, int slen, u_char *dp, int *dlen) 746121468Ssimokawa{ 747170422Ssimokawa int skip; 748170775Ssimokawa char *buf; 749121468Ssimokawa 750121468Ssimokawa while (slen > 0) { 751170422Ssimokawa skip = 0; 752121468Ssimokawa if (IS_CONSOLE(p)) { 753121468Ssimokawa if ((dc->flags & F_TELNET) != 0) { 754143416Sstefanf /* XXX Telnet workarounds */ 755121468Ssimokawa if (p->skip_read -- > 0) { 756121468Ssimokawa sp ++; 757121468Ssimokawa slen --; 758121468Ssimokawa continue; 759121468Ssimokawa } 760121468Ssimokawa if (*sp == IAC) { 761121468Ssimokawa if (verbose) 762121468Ssimokawa printf("(IAC)"); 763121468Ssimokawa p->skip_read = 2; 764121468Ssimokawa sp ++; 765121468Ssimokawa slen --; 766121468Ssimokawa continue; 767121468Ssimokawa } 768121468Ssimokawa if (*sp == 0) { 769121468Ssimokawa if (verbose) 770121468Ssimokawa printf("(0 stripped)"); 771121468Ssimokawa sp ++; 772121468Ssimokawa slen --; 773121468Ssimokawa continue; 774121468Ssimokawa } 775121468Ssimokawa } 776121468Ssimokawa switch (dc->escape_state) { 777121468Ssimokawa case STATE1: 778170775Ssimokawa if (*sp == dc->escape) { 779170422Ssimokawa skip = 1; 780121468Ssimokawa dc->escape_state = STATE2; 781170422Ssimokawa } else 782121468Ssimokawa dc->escape_state = STATE0; 783121468Ssimokawa break; 784121468Ssimokawa case STATE2: 785121468Ssimokawa dc->escape_state = STATE0; 786170775Ssimokawa skip = 1; 787121468Ssimokawa if (*sp == '.') 788121468Ssimokawa dconschat_cleanup(0); 789170775Ssimokawa else if (*sp == CTRL('B')) { 790170775Ssimokawa bcopy(abreak, dp, 3); 791170775Ssimokawa dp += 3; 792170775Ssimokawa *dlen += 3; 793170775Ssimokawa } 794170775Ssimokawa else if (*sp == CTRL('G')) 795170775Ssimokawa dconschat_fork_gdb(dc, p); 796170775Ssimokawa else if ((*sp == CTRL('R')) 797170422Ssimokawa && (dc->reset != 0)) { 798170422Ssimokawa dc->escape_state = STATE3; 799170775Ssimokawa buf = "\r\n[Are you sure to reset target? (y/N)]"; 800170775Ssimokawa write(p->outfd, buf, strlen(buf)); 801170775Ssimokawa } else if (*sp == CTRL('Z')) 802170775Ssimokawa dconschat_suspend(dc, p); 803170775Ssimokawa else { 804170775Ssimokawa skip = 0; 805170775Ssimokawa *dp++ = dc->escape; 806170422Ssimokawa (*dlen) ++; 807170422Ssimokawa } 808170422Ssimokawa break; 809170422Ssimokawa case STATE3: 810170422Ssimokawa dc->escape_state = STATE0; 811170422Ssimokawa skip = 1; 812170422Ssimokawa if (*sp == 'y') 813170775Ssimokawa dconschat_reset_target(dc, p); 814170775Ssimokawa else { 815170775Ssimokawa write(p->outfd, sp, 1); 816170775Ssimokawa write(p->outfd, "\r\n", 2); 817170775Ssimokawa } 818170422Ssimokawa break; 819121468Ssimokawa } 820121468Ssimokawa if (*sp == KEY_CR) 821121468Ssimokawa dc->escape_state = STATE1; 822121468Ssimokawa } else if (IS_GDB(p)) { 823121468Ssimokawa /* GDB: ^C -> CR+~+^B */ 824170775Ssimokawa if (*sp == CTRL('C') && (dc->flags & F_ALT_BREAK) != 0) { 825121468Ssimokawa bcopy(abreak, dp, 3); 826121468Ssimokawa dp += 3; 827121468Ssimokawa sp ++; 828121468Ssimokawa *dlen += 3; 829121468Ssimokawa /* discard rest of the packet */ 830121468Ssimokawa slen = 0; 831121468Ssimokawa break; 832121468Ssimokawa } 833121468Ssimokawa } 834170422Ssimokawa if (!skip) { 835170422Ssimokawa *dp++ = *sp; 836170422Ssimokawa (*dlen) ++; 837170422Ssimokawa } 838170422Ssimokawa sp ++; 839121468Ssimokawa slen --; 840121468Ssimokawa } 841121468Ssimokawa return (*dlen); 842121468Ssimokawa 843121468Ssimokawa} 844121468Ssimokawa 845121468Ssimokawastatic int 846121468Ssimokawadconschat_read_socket(struct dcons_state *dc, struct dcons_port *p) 847121468Ssimokawa{ 848121468Ssimokawa struct kevent kev; 849121468Ssimokawa int len, wlen; 850121468Ssimokawa char rbuf[MAX_XFER], wbuf[MAX_XFER+2]; 851121468Ssimokawa 852121468Ssimokawa if ((len = read(p->infd, rbuf, sizeof(rbuf))) > 0) { 853121468Ssimokawa wlen = 0; 854121468Ssimokawa dconschat_read_filter(dc, p, rbuf, len, wbuf, &wlen); 855121468Ssimokawa /* XXX discard if not ready*/ 856121468Ssimokawa if (wlen > 0 && (dc->flags & F_READY) != 0) { 857121468Ssimokawa dconschat_write_dcons(dc, p->port, wbuf, wlen); 858121468Ssimokawa if (verbose > 1) { 859121468Ssimokawa wbuf[wlen] = 0; 860170775Ssimokawa printf("-> %s\n", wbuf); 861170775Ssimokawa } else if (verbose == 1) { 862121468Ssimokawa printf("(%d)", wlen); 863121468Ssimokawa fflush(stdout); 864121468Ssimokawa } 865121468Ssimokawa } 866121468Ssimokawa } else { 867121468Ssimokawa if (verbose) { 868121468Ssimokawa if (len == 0) 869121468Ssimokawa warnx("port%d: closed", p->port); 870121468Ssimokawa else 871121468Ssimokawa warn("port%d: read", p->port); 872121468Ssimokawa } 873121468Ssimokawa EV_SET(&kev, p->infd, EVFILT_READ, 874121468Ssimokawa EV_DELETE, 0, 0, NULL); 875121468Ssimokawa kevent(dc->kq, &kev, 1, NULL, 0, &dc->zero); 876121468Ssimokawa close(p->infd); 877121468Ssimokawa close(p->outfd); 878121468Ssimokawa /* XXX exit for pipe case XXX */ 879121468Ssimokawa EV_SET(&kev, p->s, EVFILT_READ, 880121468Ssimokawa EV_ADD | EV_ONESHOT, 0, 0, (void *) p); 881121468Ssimokawa kevent(dc->kq, &kev, 1, NULL, 0, &dc->zero); 882121468Ssimokawa p->infd = p->outfd = -1; 883121468Ssimokawa } 884121468Ssimokawa return(0); 885121468Ssimokawa} 886121468Ssimokawa#define NEVENT 5 887121468Ssimokawastatic int 888121468Ssimokawadconschat_proc_socket(struct dcons_state *dc) 889121468Ssimokawa{ 890121468Ssimokawa struct kevent elist[NEVENT], *e; 891121468Ssimokawa int i, n; 892121468Ssimokawa struct dcons_port *p; 893121468Ssimokawa 894121468Ssimokawa n = kevent(dc->kq, NULL, 0, elist, NEVENT, &dc->to); 895121468Ssimokawa for (i = 0; i < n; i ++) { 896121468Ssimokawa e = &elist[i]; 897121468Ssimokawa p = (struct dcons_port *)e->udata; 898121468Ssimokawa if (e->ident == p->s) { 899121468Ssimokawa dconschat_accept_socket(dc, p); 900121468Ssimokawa } else { 901121468Ssimokawa dconschat_read_socket(dc, p); 902121468Ssimokawa } 903121468Ssimokawa } 904121468Ssimokawa return(0); 905121468Ssimokawa} 906121468Ssimokawa 907121468Ssimokawastatic int 908121468Ssimokawadconschat_proc_dcons(struct dcons_state *dc) 909121468Ssimokawa{ 910121468Ssimokawa int port, len, err; 911121468Ssimokawa char buf[MAX_XFER]; 912121468Ssimokawa struct dcons_port *p; 913121468Ssimokawa 914121468Ssimokawa err = dconschat_get_ptr(dc); 915121468Ssimokawa if (err) { 916121468Ssimokawa /* XXX we should stop write operation too. */ 917121468Ssimokawa return err; 918121468Ssimokawa } 919121468Ssimokawa for (port = 0; port < DCONS_NPORT; port ++) { 920121468Ssimokawa p = &dc->port[port]; 921121468Ssimokawa if (p->infd < 0) 922121468Ssimokawa continue; 923121468Ssimokawa while ((len = dconschat_read_dcons(dc, port, buf, 924121468Ssimokawa sizeof(buf))) > 0) { 925121468Ssimokawa dconschat_write_socket(p->outfd, buf, len); 926170399Ssimokawa if ((err = dconschat_get_ptr(dc))) 927170399Ssimokawa return (err); 928121468Ssimokawa } 929121468Ssimokawa if ((dc->flags & F_ONE_SHOT) != 0 && len <= 0) 930121468Ssimokawa dconschat_cleanup(0); 931121468Ssimokawa } 932121468Ssimokawa return 0; 933121468Ssimokawa} 934121468Ssimokawa 935121468Ssimokawastatic int 936121468Ssimokawadconschat_start_session(struct dcons_state *dc) 937121468Ssimokawa{ 938121468Ssimokawa int counter = 0; 939170399Ssimokawa int retry = 0; 940170399Ssimokawa int retry_unit_init = MAX(1, poll_hz / 10); 941170399Ssimokawa int retry_unit_offline = poll_hz * DCONS_POLL_OFFLINE; 942170399Ssimokawa int retry_unit = retry_unit_init; 943170399Ssimokawa int retry_max = retry_unit_offline / retry_unit; 944121468Ssimokawa 945121468Ssimokawa while (1) { 946170399Ssimokawa if (((dc->flags & F_READY) == 0) && ++counter > retry_unit) { 947170399Ssimokawa counter = 0; 948170399Ssimokawa retry ++; 949170399Ssimokawa if (retry > retry_max) 950170399Ssimokawa retry_unit = retry_unit_offline; 951170399Ssimokawa if (verbose) { 952170399Ssimokawa printf("%d/%d ", retry, retry_max); 953170399Ssimokawa fflush(stdout); 954170399Ssimokawa } 955121468Ssimokawa dconschat_fetch_header(dc); 956170399Ssimokawa } 957170399Ssimokawa if ((dc->flags & F_READY) != 0) { 958170399Ssimokawa counter = 0; 959170399Ssimokawa retry = 0; 960170399Ssimokawa retry_unit = retry_unit_init; 961126038Ssimokawa dconschat_proc_dcons(dc); 962170399Ssimokawa } 963121468Ssimokawa dconschat_proc_socket(dc); 964121468Ssimokawa } 965121468Ssimokawa return (0); 966121468Ssimokawa} 967121468Ssimokawa 968121468Ssimokawastatic void 969121468Ssimokawausage(void) 970121468Ssimokawa{ 971121468Ssimokawa fprintf(stderr, 972121468Ssimokawa "usage: dconschat [-brvwRT1] [-h hz] [-C port] [-G port]\n" 973121468Ssimokawa "\t\t\t[-M core] [-N system]\n" 974121468Ssimokawa "\t\t\t[-u unit] [-a address] [-t target_eui64]\n" 975121468Ssimokawa "\t-b translate ctrl-C to CR+~+ctrl-B on gdb port\n" 976121468Ssimokawa "\t-v verbose\n" 977121468Ssimokawa "\t-w listen on wildcard address rather than localhost\n" 978121468Ssimokawa "\t-r replay old buffer on connection\n" 979121468Ssimokawa "\t-R read-only\n" 980121468Ssimokawa "\t-T enable Telnet protocol workaround on console port\n" 981121468Ssimokawa "\t-1 one shot: read buffer and exit\n" 982121468Ssimokawa "\t-h polling rate\n" 983121468Ssimokawa "\t-C port number for console port\n" 984121468Ssimokawa "\t-G port number for gdb port\n" 985121468Ssimokawa "\t(for KVM)\n" 986121468Ssimokawa "\t-M core file\n" 987121468Ssimokawa "\t-N system file\n" 988121468Ssimokawa "\t(for FireWire)\n" 989121468Ssimokawa "\t-u specify unit number of the bus\n" 990121468Ssimokawa "\t-t EUI64 of target host (must be specified)\n" 991121468Ssimokawa "\t-a physical address of dcons buffer on target host\n" 992121468Ssimokawa ); 993121468Ssimokawa exit(0); 994121468Ssimokawa} 995121468Ssimokawaint 996121468Ssimokawamain(int argc, char **argv) 997121468Ssimokawa{ 998121468Ssimokawa struct dcons_state *dc; 999121468Ssimokawa struct fw_eui64 eui; 1000129760Sbrooks struct eui64 target; 1001121468Ssimokawa char devname[256], *core = NULL, *system = NULL; 1002121468Ssimokawa int i, ch, error; 1003126038Ssimokawa int unit=0, wildcard=0; 1004121468Ssimokawa int port[DCONS_NPORT]; 1005121468Ssimokawa 1006121468Ssimokawa bzero(&sc, sizeof(sc)); 1007121468Ssimokawa dc = ≻ 1008121468Ssimokawa dc->flags |= USE_CROM ? F_USE_CROM : 0; 1009121468Ssimokawa 1010143416Sstefanf /* default ports */ 1011121468Ssimokawa port[0] = 0; /* stdin/out for console */ 1012121468Ssimokawa port[1] = -1; /* disable gdb port */ 1013121468Ssimokawa 1014171397Ssimokawa /* default escape char */ 1015171397Ssimokawa dc->escape = KEY_TILDE; 1016171397Ssimokawa 1017170775Ssimokawa while ((ch = getopt(argc, argv, "a:be:h:rt:u:vwC:G:M:N:RT1")) != -1) { 1018121468Ssimokawa switch(ch) { 1019121468Ssimokawa case 'a': 1020121468Ssimokawa dc->paddr = strtoull(optarg, NULL, 0); 1021121468Ssimokawa dc->flags &= ~F_USE_CROM; 1022121468Ssimokawa break; 1023121468Ssimokawa case 'b': 1024121468Ssimokawa dc->flags |= F_ALT_BREAK; 1025121468Ssimokawa break; 1026170775Ssimokawa case 'e': 1027171397Ssimokawa dc->escape = optarg[0]; 1028170775Ssimokawa break; 1029121468Ssimokawa case 'h': 1030121468Ssimokawa poll_hz = strtoul(optarg, NULL, 0); 1031121468Ssimokawa if (poll_hz == 0) 1032121468Ssimokawa poll_hz = DCONS_POLL_HZ; 1033121468Ssimokawa break; 1034121468Ssimokawa case 'r': 1035121468Ssimokawa dc->flags |= F_REPLAY; 1036121468Ssimokawa break; 1037121468Ssimokawa case 't': 1038129760Sbrooks if (eui64_hostton(optarg, &target) != 0 && 1039129760Sbrooks eui64_aton(optarg, &target) != 0) 1040129760Sbrooks errx(1, "invalid target: %s", optarg); 1041129760Sbrooks eui.hi = ntohl(*(u_int32_t*)&(target.octet[0])); 1042129760Sbrooks eui.lo = ntohl(*(u_int32_t*)&(target.octet[4])); 1043121468Ssimokawa dc->type = TYPE_FW; 1044121468Ssimokawa break; 1045121468Ssimokawa case 'u': 1046121468Ssimokawa unit = strtol(optarg, NULL, 0); 1047121468Ssimokawa break; 1048121468Ssimokawa case 'v': 1049121468Ssimokawa verbose ++; 1050121468Ssimokawa break; 1051121468Ssimokawa case 'w': 1052121468Ssimokawa wildcard = 1; 1053121468Ssimokawa break; 1054121468Ssimokawa case 'C': 1055121468Ssimokawa port[0] = strtol(optarg, NULL, 0); 1056121468Ssimokawa break; 1057121468Ssimokawa case 'G': 1058121468Ssimokawa port[1] = strtol(optarg, NULL, 0); 1059121468Ssimokawa break; 1060121468Ssimokawa case 'M': 1061121468Ssimokawa core = optarg; 1062121468Ssimokawa break; 1063121468Ssimokawa case 'N': 1064121468Ssimokawa system = optarg; 1065121468Ssimokawa break; 1066121468Ssimokawa case 'R': 1067121468Ssimokawa dc->flags |= F_RD_ONLY; 1068121468Ssimokawa break; 1069121468Ssimokawa case 'T': 1070121468Ssimokawa dc->flags |= F_TELNET; 1071121468Ssimokawa break; 1072121468Ssimokawa case '1': 1073121468Ssimokawa dc->flags |= F_ONE_SHOT | F_REPLAY; 1074121468Ssimokawa break; 1075121468Ssimokawa default: 1076121468Ssimokawa usage(); 1077121468Ssimokawa } 1078121468Ssimokawa } 1079121468Ssimokawa if (dc->paddr == 0 && (dc->flags & F_USE_CROM) == 0) { 1080121468Ssimokawa warnx("no address specified"); 1081121468Ssimokawa usage(); 1082121468Ssimokawa } 1083121468Ssimokawa 1084121468Ssimokawa if (port[0] < 0 && port[1] < 0) { 1085121468Ssimokawa warnx("no port specified"); 1086121468Ssimokawa usage(); 1087121468Ssimokawa } 1088121468Ssimokawa 1089121468Ssimokawa /* set signal handler */ 1090121468Ssimokawa signal(SIGHUP, dconschat_cleanup); 1091121468Ssimokawa signal(SIGINT, dconschat_cleanup); 1092121468Ssimokawa signal(SIGPIPE, dconschat_cleanup); 1093121468Ssimokawa signal(SIGTERM, dconschat_cleanup); 1094121468Ssimokawa 1095121468Ssimokawa /* init firewire */ 1096121468Ssimokawa switch (dc->type) { 1097121468Ssimokawa case TYPE_FW: 1098122356Ssimokawa#define MAXDEV 10 1099121468Ssimokawa for (i = 0; i < MAXDEV; i ++) { 1100121468Ssimokawa snprintf(devname, sizeof(devname), 1101121468Ssimokawa "/dev/fwmem%d.%d", unit, i); 1102121468Ssimokawa dc->fd = open(devname, O_RDWR); 1103121468Ssimokawa if (dc->fd >= 0) 1104121468Ssimokawa goto found; 1105121468Ssimokawa } 1106121468Ssimokawa err(1, "open"); 1107121468Ssimokawafound: 1108121468Ssimokawa error = ioctl(dc->fd, FW_SDEUI64, &eui); 1109121468Ssimokawa if (error) 1110121468Ssimokawa err(1, "ioctl"); 1111121468Ssimokawa break; 1112121468Ssimokawa case TYPE_KVM: 1113121468Ssimokawa { 1114121468Ssimokawa struct nlist nl[] = {{"dcons_buf"}, {""}}; 1115121468Ssimokawa void *dcons_buf; 1116121468Ssimokawa 1117121468Ssimokawa dc->kd = kvm_open(system, core, NULL, 1118121468Ssimokawa (dc->flags & F_RD_ONLY) ? O_RDONLY : O_RDWR, "dconschat"); 1119121468Ssimokawa if (dc->kd == NULL) 1120121468Ssimokawa errx(1, "kvm_open"); 1121121468Ssimokawa 1122121468Ssimokawa if (kvm_nlist(dc->kd, nl) < 0) 1123121468Ssimokawa errx(1, "kvm_nlist: %s", kvm_geterr(dc->kd)); 1124121468Ssimokawa 1125121468Ssimokawa if (kvm_read(dc->kd, nl[0].n_value, &dcons_buf, 1126121468Ssimokawa sizeof(void *)) < 0) 1127121468Ssimokawa errx(1, "kvm_read: %s", kvm_geterr(dc->kd)); 1128121468Ssimokawa dc->paddr = (uintptr_t)dcons_buf; 1129121468Ssimokawa if (verbose) 1130121468Ssimokawa printf("dcons_buf: 0x%x\n", (uint)dc->paddr); 1131121468Ssimokawa break; 1132121468Ssimokawa } 1133121468Ssimokawa } 1134121468Ssimokawa dconschat_fetch_header(dc); 1135121468Ssimokawa 1136143416Sstefanf /* init sockets */ 1137121468Ssimokawa dc->kq = kqueue(); 1138121468Ssimokawa if (poll_hz == 1) { 1139121468Ssimokawa dc->to.tv_sec = 1; 1140121468Ssimokawa dc->to.tv_nsec = 0; 1141121468Ssimokawa } else { 1142121468Ssimokawa dc->to.tv_sec = 0; 1143121468Ssimokawa dc->to.tv_nsec = 1000 * 1000 * 1000 / poll_hz; 1144121468Ssimokawa } 1145121468Ssimokawa dc->zero.tv_sec = 0; 1146121468Ssimokawa dc->zero.tv_nsec = 0; 1147121468Ssimokawa for (i = 0; i < DCONS_NPORT; i++) 1148121468Ssimokawa dconschat_init_socket(dc, i, 1149121468Ssimokawa wildcard ? NULL : "localhost", port[i]); 1150121468Ssimokawa 1151121468Ssimokawa dconschat_start_session(dc); 1152121468Ssimokawa 1153121468Ssimokawa for (i = 0; i < DCONS_NPORT; i++) { 1154121468Ssimokawa freeaddrinfo(dc->port[i].res); 1155121468Ssimokawa } 1156121468Ssimokawa return (0); 1157121468Ssimokawa} 1158