diff -urN linux-2.4.15-pre5-virgin/arch/i386/config.in linux-2.4.15-pre5-bootmem/arch/i386/config.in --- linux-2.4.15-pre5-virgin/arch/i386/config.in Tue Nov 20 13:58:32 2001 +++ linux-2.4.15-pre5-bootmem/arch/i386/config.in Mon Nov 19 23:43:41 2001 @@ -420,6 +420,10 @@ bool ' Magic SysRq key' CONFIG_MAGIC_SYSRQ bool ' Spinlock debugging' CONFIG_DEBUG_SPINLOCK bool ' Verbose BUG() reporting (adds 70K)' CONFIG_DEBUG_BUGVERBOSE + bool ' Early printk() on serial I/O port 0x3F8' CONFIG_EARLY_CONSOLE_3F8 + bool ' Early printk() on serial I/O port 0x3E8' CONFIG_EARLY_CONSOLE_3E8 + bool ' Early printk() on VGA text console' CONFIG_EARLY_CONSOLE_VGA + bool ' Early printk() via the bochs 0xE9 hack' CONFIG_EARLY_CONSOLE_BOCHS_E9_HACK fi endmenu diff -urN linux-2.4.15-pre5-virgin/drivers/char/Makefile linux-2.4.15-pre5-bootmem/drivers/char/Makefile --- linux-2.4.15-pre5-virgin/drivers/char/Makefile Fri Nov 16 19:35:40 2001 +++ linux-2.4.15-pre5-bootmem/drivers/char/Makefile Mon Nov 19 20:54:57 2001 @@ -16,7 +16,8 @@ O_TARGET := char.o -obj-y += mem.o tty_io.o n_tty.o tty_ioctl.o raw.o pty.o misc.o random.o +obj-y += mem.o tty_io.o n_tty.o tty_ioctl.o raw.o pty.o misc.o random.o \ + early_consoles.o # All of the (potential) objects that export symbols. # This list comes from 'grep -l EXPORT_SYMBOL *.[hc]'. diff -urN linux-2.4.15-pre5-virgin/drivers/char/early_consoles.c linux-2.4.15-pre5-bootmem/drivers/char/early_consoles.c --- linux-2.4.15-pre5-virgin/drivers/char/early_consoles.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.15-pre5-bootmem/drivers/char/early_consoles.c Sun Nov 25 13:22:24 2001 @@ -0,0 +1,384 @@ +/* + * Early console drivers. + * (C) Nov 2001, William Irwin, IBM + * + * These are low-level pseudodrivers to enable early console output + * to aid in debugging during early boot. + * + * They are crude, but hopefully effective. They rely on the fact + * that consoles are largely unused prior to the true console_init(), + * and that printk() uses the ->write callback and that callback + * only during its operation. + * + * Serial port routines are derived from Linux serial.c, and + * vga_putc() is derived from vsta, (C) Andrew Valencia. + */ + +#include +#include +#include +#include + +/* + * I/O ports are not linearly mapped on all architectures. + * On IA64 in particular, port I/O is just reading/writing from + * an uncached address, but ioremap there requires ia64_io_base + * to be initialized, which does not happen until the middle of + * setup_arch(). So a port remapping macro is provided here. + * + * The IA64 case is not handled here, although the port remapping + * is demonstrated for the purposes of understanding its necessity. + * The IO_BASE is taken from Lion systems; in general, this varies. + * True handling for IA64 will be merged in given testing. + */ + +#ifdef CONFIG_IA64 + +#define IO_BASE 0xC0000FFFFC000000UL +#define MK_PORT(port) ((char *)(IO_BASE|(((port)>>2)<<12)|((port) & 0xFFF))) + +#else + +/* + * This works for i386, but not everywhere. + * Other architectures with port I/O mapping needs will need to + * add to the preprocessor case analysis above. + */ + +#define MK_PORT(port) (port) + +#endif + +#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE) + + +/* + * This serial output driver derived from the one appearing + * in serial.c + * + * It is a simple "bitbanging" style output routine, with + * initialization performed at every call. + */ + +#if defined(CONFIG_EARLY_CONSOLE_3F8) || defined(CONFIG_EARLY_CONSOLE_3E8) + +static inline __init void wait_for_readiness(unsigned port) +{ + unsigned retries; + unsigned char status; + + /* + * Wait for transmitter holding and shift registers to empty, + * which is required for output to succeed. If the retries are + * exceeded, this deliberately fails to ensure termination. + */ + for(retries = 0; retries < 65536; ++retries) { + status = inb(MK_PORT(port + 5)); + if((status & BOTH_EMPTY) == BOTH_EMPTY) + break; + } +} + +static void __init write_serial_io_port(unsigned port, + const char *s, + unsigned n) +{ + unsigned k; + + wait_for_readiness(port); + + /* + * Disable interrupts. + */ + outb(0x0, MK_PORT(port + 1)); + + /* + * Set the baud rate divisor's LSB. + */ + outb(0x83, MK_PORT(port + 3)); + + /* + * Set the baud rate divisor's MSB. + */ + outb(0xC, MK_PORT(port)); + + /* + * Set no parity, 8 bits, 1 stop bit, and select + * interrupt enable register. + */ + outb(0x3, MK_PORT(port + 3)); + + /* + * Set data terminal ready and request to send. + */ + + for(k = 0; k < n; ++k) { + wait_for_readiness(port); + outb(s[k], MK_PORT(port)); + if(s[k] == '\n') { + wait_for_readiness(port); + outb('\r', MK_PORT(port)); + } + } +} + +#endif /* CONFIG_EARLY_CONSOLE_3F8 || CONFIG_EARLY_CONSOLE_3E8 */ + + + +/* + * On Intel-derived architectures it is customary for onboard serial + * ports to have I/O ports at these two port addresses. + */ + +#ifdef CONFIG_EARLY_CONSOLE_3F8 +static void __init write_3F8(struct console *c, const char *s, unsigned n) +{ + write_serial_io_port(0x3F8, s, n); +} + +static struct console __initdata early_console_3F8 = +{ + write: write_3F8 +}; +#endif + +#ifdef CONFIG_EARLY_CONSOLE_3E8 +static void __init write_3E8(struct console *c, const char *s, unsigned n) +{ + write_serial_io_port(0x3E8, s, n); +} + +static struct console __initdata early_console_3E8 = +{ + write: write_3E8 +}; +#endif + + + + +/* + * This should work for a variety of Intel-derived architectures, + * as it is customary for VGA memory to reside in this address range. + * vga_putc() is derived from vsta sources, (C) Andrew Valencia. + * + * Several forms of functionality are intentionally omitted in the + * interest of robustness, in particular, cursor movement and cursor + * position determination. + */ + +#ifdef CONFIG_EARLY_CONSOLE_VGA + +#define VGA_MAXCOL 80 +#define VGA_MAXROW 25 +#define VGA_SCRNSZ (VGA_MAXCOL * VGA_MAXROW) +#define VGA_REG_PORT 0x3D4 +#define VGA_VAL_PORT 0x3D5 +#define VGA_TEXT_BUFFER 0xB8000 + +#define VGA_CHAR(_row_, _col_) vga_mem[(_row_)*VGA_MAXCOL + (_col_)].c + +struct vga_char_desc +{ + unsigned char c; + unsigned char color; +}; + +static struct vga_char_desc * __initdata vga_mem = + (struct vga_char_desc *)(VGA_TEXT_BUFFER + PAGE_OFFSET); + +/* + * The characters displayed at a screen position can be discerned by + * reading from the corresponding memory location. This can be used + * to simulate scrolling movement. Line blanking is simulated by + * overwriting the displayed characters with the space character. + * + * In the interest of robustness, cursor movement is also omitted. + */ +static inline void __init vga_scroll_up(void) +{ + unsigned k; + + for(k = 0; k < (VGA_SCRNSZ - VGA_MAXCOL); ++k) + vga_mem[k].c = vga_mem[k + VGA_MAXCOL].c; + + for(k = VGA_SCRNSZ - VGA_MAXCOL; k < VGA_SCRNSZ; ++k) + vga_mem[k].c = ' '; +} + +/* + * The screen position can actually be determined by port I/O, + * but in the interest of robustness, these are always initialized + * to the (0, 0) position. These position indices must always be + * strictly less than the bounds VGA_MAXROW and VGA_MAXCOL. + */ +static unsigned short __initdata row; +static unsigned short __initdata col; + + +/* + * Line advancement must preserve the invariant that the row and + * column indices are in-bounds. The semantics of this mean that + * when line advancement "beyond" the last line results in scrolling. + */ +static inline void __init vga_line_advance(void) +{ + ++row; + + if(row >= VGA_MAXROW) { + row = VGA_MAXROW - 1; + vga_scroll_up(); + } +} + + +/* + * Character advancement must once again preserve the in-bounds + * invariants, and in so doing line wrapping and advancement may occur. + */ +static inline void __init vga_char_advance(void) +{ + ++col; + + if(col >= VGA_MAXCOL) { + col = 0; + vga_line_advance(); + } +} + + +/* + * Derived from vsta sources (C) Andrew Valencia. + * Here the interpretation of several common special characters occurs, + * namely linefeeds, newlines, tabs, and backspaces. The position + * indices are updated using the vga_char_advance() and vga_line_advance() + * routines, and a vga_char_advance() is triggered on the printing of + * each ordinary character. The special characters have specialized + * position update semantics in order to be faithful to their customary + * cursor movement effects, although the cursor position is not updated. + */ +static void __init vga_putc(char c) +{ + unsigned k; + switch(c) { + case '\t': + for(k = 0; k < 8; ++k) { + VGA_CHAR(row, col) = ' '; + vga_char_advance(); + } + break; + + case '\r': + col = 0; + break; + + case '\n': + col = 0; + vga_line_advance(); + break; + + case '\b': + if(col > 0) { + --col; + VGA_CHAR(row, col) = ' '; + } + break; + + default: + VGA_CHAR(row, col) = c; + vga_char_advance(); + break; + } +} + + +/* + * write_vga(), given a NUL-terminated character array, writes + * characters to VGA space in bulk, and is the callback used for the + * driver structure. + */ +static void __init write_vga(struct console *c, const char *s, unsigned n) +{ + unsigned k; + for(k = 0; k < n; ++k) + vga_putc(s[k]); +} + +static struct console __initdata early_console_vga = +{ + write: write_vga +}; + +#endif /* CONFIG_EARLY_CONSOLE_VGA */ + + +/* + * The bochs x86 simulator has an optional feature for enabling + * debugging output through a normally unused ISA I/O port. The + * protocol for communicating with the simulated device is simply + * using port I/O writes to write a stream of characters to the + * device, and these are then relayed by the simulator to the + * controlling terminal of the simulator process. + */ +#ifdef CONFIG_EARLY_CONSOLE_BOCHS_E9_HACK +static void __init write_bochs(struct console *c, const char *s, unsigned n) +{ + unsigned k; + + for(k = 0; k < n; ++k) + outb(s[k], MK_PORT(0xE9)); +} + +static struct console __initdata early_console_bochs = +{ + write: write_bochs +}; +#endif /* CONFIG_EARLY_CONSOLE_BOCHS_E9_HACK */ + + +/* + * In order to minimize the number of #ifdefs whch must + * appear in-line, this direct-mapped, NULL-terminated table + * of console entries is used to provide a configuration-independent + * structure which may be traversed to discover all of the available + * early console devices for registration and unregistration. + * + * This is the ugliest part of the code, thanks to #ifdef + */ +static struct console * __initdata early_console_table[] = + { +#ifdef CONFIG_EARLY_CONSOLE_3F8 + &early_console_3F8, +#endif +#ifdef CONFIG_EARLY_CONSOLE_3E8 + &early_console_3E8, +#endif +#ifdef CONFIG_EARLY_CONSOLE_VGA + &early_console_vga, +#endif +#ifdef CONFIG_EARLY_CONSOLE_BOCHS_E9_HACK + &early_console_bochs, +#endif + NULL + }; + + +/* + * The above implementations are quite far from complete console + * devices, but printk() only requires the ->write callback, so this is + * somewhat deceptive, but still cleaner than editing printk.c itself. + */ +void __init register_early_consoles(void) +{ + struct console **c = early_console_table; + while(*c) + register_console(*c++); +} + +void __init unregister_early_consoles(void) +{ + struct console **c = early_console_table; + while(*c) + unregister_console(*c++); +} diff -urN linux-2.4.15-pre5-virgin/include/linux/kernel.h linux-2.4.15-pre5-bootmem/include/linux/kernel.h --- linux-2.4.15-pre5-virgin/include/linux/kernel.h Fri Nov 16 19:36:06 2001 +++ linux-2.4.15-pre5-bootmem/include/linux/kernel.h Sun Nov 25 11:58:59 2001 @@ -79,6 +79,9 @@ extern int session_of_pgrp(int pgrp); +extern void register_early_consoles(void); +extern void unregister_early_consoles(void); + asmlinkage int printk(const char * fmt, ...) __attribute__ ((format (printf, 1, 2))); diff -urN linux-2.4.15-pre5-virgin/init/main.c linux-2.4.15-pre5-bootmem/init/main.c --- linux-2.4.15-pre5-virgin/init/main.c Fri Nov 16 19:36:10 2001 +++ linux-2.4.15-pre5-bootmem/init/main.c Mon Nov 19 20:11:07 2001 @@ -549,6 +549,7 @@ * enable them */ lock_kernel(); + register_early_consoles(); printk(linux_banner); setup_arch(&command_line); printk("Kernel command line: %s\n", saved_command_line); @@ -564,6 +565,7 @@ * we've done PCI setups etc, and console_init() must be aware of * this. But we do want output early, in case something goes wrong. */ + unregister_early_consoles(); console_init(); #ifdef CONFIG_MODULES init_modules();