Make the serial console port and its baudrate configurable on the bootloader (e.g GRUB) command line. The parameter format is similar to Linux's. Examples: console=ttyS0 # to enable serial console on the first serial port console=ttyS1 # second serial port console=ttyS0,38400 # with the given baudrate Selectable parity, bits, flow control not implemented yet. Index: memtest86+-1.70/config.h =================================================================== --- memtest86+-1.70.orig/config.h +++ memtest86+-1.70/config.h @@ -15,6 +15,9 @@ /* to enable. */ #define SERIAL_CONSOLE_DEFAULT 0 +/* SERIAL_TTY - The default serial port to use. 0=ttyS0, 1=ttyS1 */ +#define SERIAL_TTY 0 + /* SERIAL_BAUD_RATE - Baud rate for the serial console */ #define SERIAL_BAUD_RATE 9600 Index: memtest86+-1.70/lib.c =================================================================== --- memtest86+-1.70.orig/lib.c +++ memtest86+-1.70/lib.c @@ -11,6 +11,18 @@ int slock = 0, lsr = 0; short serial_cons = SERIAL_CONSOLE_DEFAULT; + +#if SERIAL_TTY != 0 && SERIAL_TTY != 1 +#error Bad SERIAL_TTY. Only ttyS0 and ttyS1 are supported. +#endif +short serial_tty = SERIAL_TTY; +const short serial_base_ports[] = {0x3f8, 0x2f8}; + +#if ((115200%SERIAL_BAUD_RATE) != 0) +#error Bad default baud rate +#endif +int serial_baud_rate = SERIAL_BAUD_RATE; + char buf[18]; struct ascii_map_str { @@ -721,19 +733,9 @@ void ttyprint(int y, int x, const char * serial_echo_print(p); } -#if defined(SERIAL_BAUD_RATE) - -#if ((115200%SERIAL_BAUD_RATE) != 0) -#error Bad ttys0 baud rate -#endif - -#define SERIAL_DIV (115200/SERIAL_BAUD_RATE) - -#endif /* SERIAL_BAUD_RATE */ - void serial_echo_init(void) { - int comstat, hi, lo; + int comstat, hi, lo, serial_div; /* read the Divisor Latch */ comstat = serial_echo_inb(UART_LCR); @@ -744,12 +746,11 @@ void serial_echo_init(void) /* now do hardwired init */ serial_echo_outb(0x03, UART_LCR); /* No parity, 8 data bits, 1 stop */ -#if defined(SERIAL_BAUD_RATE) + serial_div = 115200 / serial_baud_rate; serial_echo_outb(0x83, UART_LCR); /* Access divisor latch */ - serial_echo_outb(SERIAL_DIV & 0xff, UART_DLL); /* baud rate divisor */ - serial_echo_outb((SERIAL_DIV>> 8) & 0xff, UART_DLM); + serial_echo_outb(serial_div & 0xff, UART_DLL); /* baud rate divisor */ + serial_echo_outb((serial_div >> 8) & 0xff, UART_DLM); serial_echo_outb(0x03, UART_LCR); /* Done with divisor */ -#endif /* Prior to disabling interrupts, read the LSR and RBR * registers */ @@ -974,6 +975,59 @@ void wait_keyup( void ) { } } } + +/* + * Handles "console=" command line option + * + * Examples of accepted params: + * ttyS0 + * ttyS1 + * ttyS0,115200 + */ +void serial_console_setup(char *param) +{ + char *option, *end; + unsigned long tty; + unsigned long baud_rate; + + if (strncmp(param, "ttyS", 4)) + return; /* not a serial port */ + + param += 4; + + tty = simple_strtoul(param, &option, 10); + + if (option == param) + return; /* there were no digits */ + + if (tty > 1) + return; /* only ttyS0 and ttyS1 supported */ + + if (*option == '\0') + goto save_tty; /* no options given, just ttyS? */ + + if (*option != ',') + return; /* missing the comma separator */ + + /* baud rate must follow */ + option++; + baud_rate = simple_strtoul(option, &end, 10); + + if (end == option) + return; /* no baudrate after comma */ + + if (baud_rate == 0 || (115200 % baud_rate) != 0) + return; /* wrong baud rate */ + + if (*end != '\0') + return; /* garbage at the end */ + + serial_baud_rate = (int) baud_rate; +save_tty: + serial_tty = (short) tty; + serial_cons = 1; +} + #ifdef LP #define DATA 0x00 #define STATUS 0x01 Index: memtest86+-1.70/main.c =================================================================== --- memtest86+-1.70.orig/main.c +++ memtest86+-1.70/main.c @@ -31,6 +31,7 @@ const struct tseq tseq[] = { }; char firsttime = 0; +char cmdline_parsed = 0; struct vars variables = {}; struct vars * const v = &variables; @@ -135,12 +136,53 @@ static void run_at(unsigned long addr) __run_at(run_at_addr); } +/* command line passing using the 'old' boot protocol */ +#define MK_PTR(seg,off) ((void*)(((unsigned long)(seg) << 4) + (off))) +#define OLD_CL_MAGIC_ADDR ((unsigned short*) MK_PTR(INITSEG,0x20)) +#define OLD_CL_MAGIC 0xA33F +#define OLD_CL_OFFSET_ADDR ((unsigned short*) MK_PTR(INITSEG,0x22)) + +static void parse_command_line(void) +{ + char *cmdline; + + if (cmdline_parsed) + return; + + if (*OLD_CL_MAGIC_ADDR != OLD_CL_MAGIC) + return; + + unsigned short offset = *OLD_CL_OFFSET_ADDR; + cmdline = MK_PTR(INITSEG, offset); + + /* skip leading spaces */ + while (*cmdline == ' ') + cmdline++; + + while (*cmdline) { + if (!strncmp(cmdline, "console=", 8)) { + cmdline += 8; + serial_console_setup(cmdline); + } + + /* go to the next parameter */ + while (*cmdline && *cmdline != ' ') + cmdline++; + while (*cmdline == ' ') + cmdline++; + } + + cmdline_parsed = 1; +} + void do_test(void) { int i = 0; unsigned long chunks; unsigned long lo, hi; + parse_command_line(); + /* If we have a partial relocation finish it */ if (run_at_addr == (unsigned long)&_start) { run_at_addr = 0xffffffff; Index: memtest86+-1.70/serial.h =================================================================== --- memtest86+-1.70.orig/serial.h +++ memtest86+-1.70/serial.h @@ -136,8 +136,8 @@ */ #include "io.h" -#define serial_echo_outb(v,a) outb((v),(a)+0x3f8) -#define serial_echo_inb(a) inb((a)+0x3f8) +#define serial_echo_outb(v,a) outb((v),(a)+serial_base_ports[serial_tty]) +#define serial_echo_inb(a) inb((a)+serial_base_ports[serial_tty]) #define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE) /* Wait for transmitter & holding register to empty */ #define WAIT_FOR_XMITR \ Index: memtest86+-1.70/test.h =================================================================== --- memtest86+-1.70.orig/test.h +++ memtest86+-1.70/test.h @@ -103,6 +103,7 @@ void printpatn(void); void printpatn(void); void itoa(char s[], int n); void reverse(char *p); +void serial_console_setup(char *param); void serial_echo_init(void); void serial_echo_print(const char *s); void ttyprint(int y, int x, const char *s); --