earlier printk

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



So I've taken a stab at getting some console output a bit earlier in
boot, and reorganized my various hacks to make them slightly more
suitable for public consumption. Please do advise on ways to improve
my handling of the situation.


Thanks,
Bill

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	Tue Nov 20 04:51:52 2001
@@ -0,0 +1,267 @@
+/*
+ * 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(),
+ * but that printk() uses the ->write callback and that callback
+ * only during its operation.
+ */
+#include <linux/kernel.h>
+#include <linux/console.h>
+#include <linux/serial_reg.h>
+#include <asm/io.h>
+
+/*
+ * 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.
+ */
+#define MK_PORT(port) (port)
+
+#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE)
+
+
+#if defined(CONFIG_EARLY_CONSOLE_3F8) || defined(CONFIG_EARLY_CONSOLE_3E8)
+
+static inline void wait_for_readiness(unsigned port)
+{
+	unsigned retries;
+	unsigned char status;
+	/*
+	 * Wait for transmitter holding and shift registers to empty.
+	 * If the retries are exceeded, give up.
+	 */
+	for(retries = 0; retries < 65536; ++retries) {
+		status = inb(MK_PORT(port + 5));
+		if((status & BOTH_EMPTY) == BOTH_EMPTY)
+			break;
+	}
+}
+
+static void 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 */
+
+#ifdef CONFIG_EARLY_CONSOLE_3F8
+static void write_3F8(struct console *c, const char *s, unsigned n)
+{
+	write_serial_io_port(0x3F8, s, n);
+}
+
+static struct console early_console_3F8 =
+{
+	write: write_3F8
+};
+#endif
+
+#ifdef CONFIG_EARLY_CONSOLE_3E8
+static void write_3E8(struct console *c, const char *s, unsigned n)
+{
+	write_serial_io_port(0x3E8, s, n);
+}
+
+static struct console early_console_3E8 =
+{
+	write: write_3E8
+};
+#endif
+
+#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 *vga_mem = 
+	(struct vga_char_desc *)(VGA_TEXT_BUFFER + PAGE_OFFSET);
+
+static inline void 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 = ' ';
+}
+
+static unsigned short row = 0;
+static unsigned short col = 0;
+
+static inline void vga_line_advance(void)
+{
+	++row;
+
+	if(row >= VGA_MAXROW) {
+		row = VGA_MAXROW - 1;
+		vga_scroll_up();
+	}
+}
+
+static inline void vga_char_advance(void)
+{
+	++col;
+
+	if(col >= VGA_MAXCOL) {
+		col = 0;
+		vga_line_advance();
+	}
+}
+
+static void 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;
+	}
+}
+
+static void 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 early_console_vga =
+{
+	write: write_vga
+};
+
+#endif /* CONFIG_EARLY_CONSOLE_VGA */
+
+#ifdef CONFIG_EARLY_CONSOLE_BOCHS_E9_HACK
+static void 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 early_console_bochs =
+{
+	write: write_bochs
+};
+#endif /* CONFIG_EARLY_CONSOLE_BOCHS_E9_HACK */
+
+void register_early_consoles(void)
+{
+#ifdef CONFIG_EARLY_CONSOLE_3F8
+	register_console(&early_console_3F8);
+#endif
+
+#ifdef CONFIG_EARLY_CONSOLE_3E8
+	register_console(&early_console_3E8);
+#endif
+
+#ifdef CONFIG_EARLY_CONSOLE_VGA
+	register_console(&early_console_vga);
+#endif
+
+#ifdef CONFIG_EARLY_CONSOLE_BOCHS_E9_HACK
+	register_console(&early_console_bochs);
+#endif
+}
+
+void unregister_early_consoles(void)
+{
+#ifdef CONFIG_EARLY_CONSOLE_3F8
+	unregister_console(&early_console_3F8);
+#endif
+
+#ifdef CONFIG_EARLY_CONSOLE_3E8
+	unregister_console(&early_console_3E8);
+#endif
+
+#ifdef CONFIG_EARLY_CONSOLE_VGA
+	unregister_console(&early_console_vga);
+#endif
+
+#ifdef CONFIG_EARLY_CONSOLE_BOCHS_E9_HACK
+	unregister_console(&early_console_bochs);
+#endif
+}
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	Mon Nov 19 20:43:12 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();
--
Kernelnewbies: Help each other learn about the Linux kernel.
Archive:       http://mail.nl.linux.org/kernelnewbies/
IRC Channel:   irc.openprojects.net / #kernelnewbies
Web Page:      http://www.kernelnewbies.org/



[Index of Archives]     [Newbies FAQ]     [Linux Kernel Mentors]     [Linux Kernel Development]     [IETF Annouce]     [Git]     [Networking]     [Security]     [Bugtraq]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux RAID]     [Linux SCSI]     [Linux ACPI]
  Powered by Linux