In message <200508140243.aa50444_at_nowhere.iedowse.com>, Ian Dowse writes: > >Currently the baud rate used by the i386/amd64 loader for a serial >console is hard-coded as 9600 baud and you need to recompile the >loader to change it. Below is a patch that adds a "comconsole_speed" >loader environment variable so that the speed can be changed from >loader.conf or manually from the loader prompt. It doesn't quite >do what you want though, since the loader has already printed a >number of things by the time it reads loader.conf. Any comments? Following a few suggestions, here's a more extensive change that allows you to just write "-h -S19200" for example to /boot.config, and the setting will propagate to boot2, loader and the kernel. The rate can be overridden from the 'boot:' prompt and also via the loader "comconsole_speed" variable This adds about 50 bytes to the size of boot2, and it required a few other boot2 changes to limit the size impact. The loader stage now assumes that the baud rate has already been set if the previous stage boot loader requested a serial console (RB_SERIAL or RB_MULTIPLE). I'm not sure if this is a reasonable assumption in all cases? Ian Index: i386/boot2/boot2.c =================================================================== RCS file: /dump/FreeBSD-CVS/src/sys/boot/i386/boot2/boot2.c,v retrieving revision 1.71 diff -u -r1.71 boot2.c --- i386/boot2/boot2.c 18 Sep 2004 02:07:00 -0000 1.71 +++ i386/boot2/boot2.c 14 Aug 2005 16:16:33 -0000 _at__at_ -63,7 +63,6 _at__at_ #define RBX_NOINTR 0x1c /* -n */ /* 0x1d is reserved for log2(RB_MULTIPLE) and is just misnamed here. */ #define RBX_DUAL 0x1d /* -D */ -#define RBX_PROBEKBD 0x1e /* -P */ /* 0x1f is reserved for log2(RB_BOOTINFO). */ /* pass: -a, -s, -r, -d, -c, -v, -h, -C, -g, -m, -p, -D */ _at__at_ -91,7 +90,7 _at__at_ extern uint32_t _end; -static const char optstr[NOPT] = "DhaCgmnPprsv"; +static const char optstr[NOPT] = "DhaCgmnprsv"; /* Also 'P', 'S' */ static const unsigned char flags[NOPT] = { RBX_DUAL, RBX_SERIAL, _at__at_ -100,7 +99,6 _at__at_ RBX_GDB, RBX_MUTE, RBX_NOINTR, - RBX_PROBEKBD, RBX_PAUSE, RBX_DFLTROOT, RBX_SINGLE, _at__at_ -122,6 +120,7 _at__at_ static char cmd[512]; static char kname[1024]; static uint32_t opts; +static int comspeed = SIOSPD; static struct bootinfo bootinfo; static uint8_t ioctrl = IO_KEYBOARD; _at__at_ -390,34 +389,47 _at__at_ parse() { char *arg = cmd; - char *p, *q; + char *ep, *p, *q; unsigned int drv; - int c, i; + int c, i, j; while ((c = *arg++)) { if (c == ' ' || c == '\t' || c == '\n') continue; for (p = arg; *p && *p != '\n' && *p != ' ' && *p != '\t'; p++); + ep = p; if (*p) *p++ = 0; if (c == '-') { while ((c = *arg++)) { + if (c == 'P') { + if (*(uint8_t *)PTOV(0x496) & 0x10) { + q = "yes"; + } else { + opts |= 1 << RBX_DUAL | 1 << RBX_SERIAL; + q = "no"; + } + printf("Keyboard: %s\n", q); + continue; + } else if (c == 'S') { + j = 0; + while ((unsigned int)(i = *arg++ - '0') <= 9) + j = j * 10 + i; + if (j > 0 && i == -'0') { + comspeed = j; + break; + } + /* Fall through to error below ('S' not in optstr[]). */ + } for (i = 0; c != optstr[i]; i++) if (i == NOPT - 1) return -1; opts ^= 1 << flags[i]; } - if (opts & 1 << RBX_PROBEKBD) { - i = *(uint8_t *)PTOV(0x496) & 0x10; - printf("Keyboard: %s\n", i ? "yes" : "no"); - if (!i) - opts |= 1 << RBX_DUAL | 1 << RBX_SERIAL; - opts &= ~(1 << RBX_PROBEKBD); - } ioctrl = opts & 1 << RBX_DUAL ? (IO_SERIAL|IO_KEYBOARD) : opts & 1 << RBX_SERIAL ? IO_SERIAL : IO_KEYBOARD; if (ioctrl & IO_SERIAL) - sio_init(); + sio_init(115200 / comspeed); } else { for (q = arg--; *q && *q != '('; q++); if (*q) { _at__at_ -459,7 +471,7 _at__at_ ? DRV_HARD : 0) + drv; dsk_meta = 0; } - if ((i = p - arg - !*(p - 1))) { + if ((i = ep - arg)) { if ((size_t)i >= sizeof(kname)) return -1; memcpy(kname, arg, i + 1); Index: i386/boot2/lib.h =================================================================== RCS file: /dump/FreeBSD-CVS/src/sys/boot/i386/boot2/lib.h,v retrieving revision 1.2 diff -u -r1.2 lib.h --- i386/boot2/lib.h 28 Aug 1999 00:40:02 -0000 1.2 +++ i386/boot2/lib.h 14 Aug 2005 16:02:57 -0000 _at__at_ -17,7 +17,7 _at__at_ * $FreeBSD: src/sys/boot/i386/boot2/lib.h,v 1.2 1999/08/28 00:40:02 peter Exp $ */ -void sio_init(void); +void sio_init(int); void sio_flush(void); void sio_putc(int); int sio_getc(void); Index: i386/boot2/sio.S =================================================================== RCS file: /dump/FreeBSD-CVS/src/sys/boot/i386/boot2/sio.S,v retrieving revision 1.9 diff -u -r1.9 sio.S --- i386/boot2/sio.S 14 May 2004 20:29:29 -0000 1.9 +++ i386/boot2/sio.S 14 Aug 2005 16:02:57 -0000 _at__at_ -17,7 +17,6 _at__at_ .set SIO_PRT,SIOPRT # Base port .set SIO_FMT,SIOFMT # 8N1 - .set SIO_DIV,(115200/SIOSPD) # 115200 / SPD .globl sio_init .globl sio_flush _at__at_ -25,14 +24,14 _at__at_ .globl sio_getc .globl sio_ischar -/* void sio_init(void) */ +/* void sio_init(int div) */ sio_init: movw $SIO_PRT+0x3,%dx # Data format reg movb $SIO_FMT|0x80,%al # Set format outb %al,(%dx) # and DLAB pushl %edx # Save subb $0x3,%dl # Divisor latch reg - movw $SIO_DIV,%ax # Set + movl 0x8(%esp),%eax # Set outw %ax,(%dx) # BPS popl %edx # Restore movb $SIO_FMT,%al # Clear _at__at_ -41,6 +40,8 _at__at_ movb $0x3,%al # Set RTS, outb %al,(%dx) # DTR incl %edx # Line status reg + call sio_flush + ret $0x4 /* void sio_flush(void) */ Index: i386/libi386/comconsole.c =================================================================== RCS file: /dump/FreeBSD-CVS/src/sys/boot/i386/libi386/comconsole.c,v retrieving revision 1.10 diff -u -r1.10 comconsole.c --- i386/libi386/comconsole.c 16 Sep 2003 11:24:23 -0000 1.10 +++ i386/libi386/comconsole.c 14 Aug 2005 15:59:37 -0000 _at__at_ -35,6 +35,7 _at__at_ #define COMC_FMT 0x3 /* 8N1 */ #define COMC_TXWAIT 0x40000 /* transmit timeout */ #define COMC_BPS(x) (115200 / (x)) /* speed to DLAB divisor */ +#define COMC_DIV2BPS(x) (115200 / (x)) /* DLAB divisor to speed */ #ifndef COMPORT #define COMPORT 0x3f8 _at__at_ -47,9 +48,15 _at__at_ static int comc_init(int arg); static void comc_putchar(int c); static int comc_getchar(void); +static int comc_getspeed(void); static int comc_ischar(void); +static int comc_parsespeed(const char *string); +static void comc_setup(int speed); +static int comc_speed_set(struct env_var *ev, int flags, + const void *value); static int comc_started; +static int comc_curspeed; struct console comconsole = { "comconsole", _at__at_ -65,26 +72,50 _at__at_ static void comc_probe(struct console *cp) { + char speedbuf[16]; + char *cons, *speedenv; + int speed; + /* XXX check the BIOS equipment list? */ cp->c_flags |= (C_PRESENTIN | C_PRESENTOUT); + + if (comc_curspeed == 0) { + comc_curspeed = COMSPEED; + /* + * Assume that the speed was set by an earlier boot loader if + * comconsole is already the preferred console. + */ + cons = getenv("console"); + if ((cons != NULL && strcmp(cons, comconsole.c_name) == 0) || + getenv("boot_multicons") != NULL) { + comc_curspeed = comc_getspeed(); + } + speedenv = getenv("comconsole_speed"); + if (speedenv != NULL) { + speed = comc_parsespeed(speedenv); + if (speed > 0) + comc_curspeed = speed; + } + + sprintf(speedbuf, "%d", comc_curspeed); + unsetenv("comconsole_speed"); + env_setenv("comconsole_speed", EV_VOLATILE, speedbuf, comc_speed_set, + env_nounset); + } } static int comc_init(int arg) { + char speedbuf[16]; + char *cons, *speedenv; + int speed; + if (comc_started && arg == 0) return 0; comc_started = 1; - outb(COMPORT + com_cfcr, CFCR_DLAB | COMC_FMT); - outb(COMPORT + com_dlbl, COMC_BPS(COMSPEED) & 0xff); - outb(COMPORT + com_dlbh, COMC_BPS(COMSPEED) >> 8); - outb(COMPORT + com_cfcr, COMC_FMT); - outb(COMPORT + com_mcr, MCR_RTS | MCR_DTR); - - do - inb(COMPORT + com_data); - while (inb(COMPORT + com_lsr) & LSR_RXRDY); + comc_setup(comc_curspeed); return(0); } _at__at_ -112,3 +143,76 _at__at_ { return(inb(COMPORT + com_lsr) & LSR_RXRDY); } + +static int +comc_speed_set(struct env_var *ev, int flags, const void *value) +{ + int speed; + + if (value == NULL || (speed = comc_parsespeed(value)) <= 0) { + printf("Invalid speed\n"); + return (CMD_ERROR); + } + + if (comc_started && comc_curspeed != speed) + comc_setup(speed); + + env_setenv(ev->ev_name, flags | EV_NOHOOK, value, NULL, NULL); + + return (CMD_OK); +} + +static void +comc_setup(int speed) +{ + + comc_curspeed = speed; + + outb(COMPORT + com_cfcr, CFCR_DLAB | COMC_FMT); + outb(COMPORT + com_dlbl, COMC_BPS(speed) & 0xff); + outb(COMPORT + com_dlbh, COMC_BPS(speed) >> 8); + outb(COMPORT + com_cfcr, COMC_FMT); + outb(COMPORT + com_mcr, MCR_RTS | MCR_DTR); + + do + inb(COMPORT + com_data); + while (inb(COMPORT + com_lsr) & LSR_RXRDY); +} + +static int +comc_parsespeed(const char *speedstr) +{ + char *p; + int speed; + + speed = strtol(speedstr, &p, 0); + if (p == speedstr || *p != '\0' || speed <= 0) + return (-1); + + return (speed); +} + +static int +comc_getspeed(void) +{ + u_int divisor; + u_char dlbh; + u_char dlbl; + u_char cfcr; + + cfcr = inb(COMPORT + com_cfcr); + outb(COMPORT + com_cfcr, CFCR_DLAB | cfcr); + + dlbl = inb(COMPORT + com_dlbl); + dlbh = inb(COMPORT + com_dlbh); + + outb(COMPORT + com_cfcr, cfcr); + + divisor = dlbh << 8 | dlbl; + + /* XXX there should be more sanity checking. */ + if (divisor == 0) + return (COMSPEED); + return (COMC_DIV2BPS(divisor)); +} +Received on Sun Aug 14 2005 - 14:35:38 UTC
This archive was generated by hypermail 2.4.0 : Wed May 19 2021 - 11:38:41 UTC