All of lore.kernel.org
 help / color / mirror / Atom feed
From: Keith Mannthey <kmannth@us.ibm.com>
To: Linus Torvalds <torvalds@transmeta.com>
Cc: linux-kernel <linux-kernel@vger.kernel.org>
Subject: [PATCH] Early printk/console for 2.5.12
Date: Thu, 02 May 2002 17:58:01 -0700	[thread overview]
Message-ID: <184120000.1020387481@flay> (raw)

Hello Linus,
  The following patch provides the ability to add early
consoles (to use with printk calls before console_init)
and then have them automatically removed right before
the real consoles are added.  This is useful if a kernel
doesn't boot past console init.

   Included in the patch are 3 drivers for i386. Primarily 
there is a VGA driver and a serial console driver that both 
work well with i386. This has been tested on a desktop
PC, an SMP machine, and a 16 processor NUMA-Q.

  An earlier variation was submitted by Bill Irwin in
November.  This is a cleaned up version a few more
features.

  I would like this to be added to the kernel to make
early debugging (before console_init) easier and a
provide a standard early console.

  Thanks for your time,
        Keith Mannthey

PS. The patch was generated against 2.5.11, but applies
cleanly against 2.5.12


diff -urN linux-2.5.11/arch/i386/Config.help linux-2.5.11.early/arch/i386/Config.help
--- linux-2.5.11/arch/i386/Config.help	Sun Apr 28 20:11:34 2002
+++ linux-2.5.11.early/arch/i386/Config.help	Tue Apr 30 13:41:41 2002
@@ -940,3 +940,23 @@
 CONFIG_DEBUG_OBSOLETE
   Say Y here if you want to reduce the chances of the tree compiling,
   and are prepared to dig into driver internals to fix compile errors.
+
+Early printk support
+NO_CONFIG_EARLY_CONSOLE
+  If you are not doing early kernel devolopment NONE is what you want.
+  The other will add a early console for you (in i386)
+  This will allow you see printk output before console_init is called.
+  This is handy if you need to debug the kernel before this point.
+ 
+ VGA will give you a VGA console, your screen.
+ SERIAL will give you out put on your serial line.
+
+Location of serial port
+CONFIG_EARLY_CONSOLE_SERIAL_PORT
+  0x3F8 == COMM 1
+  0x3E8 == COMM 2
+
+Baud rate
+CONFIG_EARLY_CONSOLE_SERIAL_BAUD
+  Set the the Baud of your serial console.
+
diff -urN linux-2.5.11/arch/i386/config.in linux-2.5.11.early/arch/i386/config.in
--- linux-2.5.11/arch/i386/config.in	Sun Apr 28 20:12:15 2002
+++ linux-2.5.11.early/arch/i386/config.in	Tue Apr 30 13:38:10 2002
@@ -408,6 +408,16 @@
    if [ "$CONFIG_HIGHMEM" = "y" ]; then
       bool '  Highmem debugging' CONFIG_DEBUG_HIGHMEM
    fi
+   choice 'Early printk support'  \
+               "NONE               NO_CONFIG_EARLY_CONSOLE \
+                VGA                CONFIG_EARLY_CONSOLE_VGA \
+                Serial_PORT       CONFIG_EARLY_CONSOLE_SERIAL\
+                Bochs_0xE9_hack    CONFIG_EARLY_CONSOLE_BOCHS_E9_HACK " NONE
+   if [ "$CONFIG_EARLY_CONSOLE_SERIAL" = "y" ]; then
+      hex "Location of serial port " CONFIG_EARLY_CONSOLE_SERIAL_PORT 0x3F8
+      int "Baud rate " CONFIG_EARLY_CONSOLE_SERIAL_BAUD  38400
+   fi
+
 fi
 
 endmenu
diff -urN linux-2.5.11/arch/i386/kernel/Makefile linux-2.5.11.early/arch/i386/kernel/Makefile
--- linux-2.5.11/arch/i386/kernel/Makefile	Sun Apr 28 20:11:44 2002
+++ linux-2.5.11.early/arch/i386/kernel/Makefile	Tue Apr 30 13:45:10 2002
@@ -19,7 +19,7 @@
 obj-y	:= process.o semaphore.o signal.o entry.o traps.o irq.o vm86.o \
 		ptrace.o i8259.o ioport.o ldt.o setup.o time.o sys_i386.o \
 		pci-dma.o i386_ksyms.o i387.o bluesmoke.o dmi_scan.o \
-		bootflag.o
+		bootflag.o early_consoles.o
 
 
 ifdef CONFIG_PCI
diff -urN linux-2.5.11/arch/i386/kernel/early_consoles.c linux-2.5.11.early/arch/i386/kernel/early_consoles.c
--- linux-2.5.11/arch/i386/kernel/early_consoles.c	Wed Dec 31 16:00:00 1969
+++ linux-2.5.11.early/arch/i386/kernel/early_consoles.c	Tue Apr 30 13:35:53 2002
@@ -0,0 +1,417 @@
+/*
+ * 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 <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.
+ *
+ * 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.
+ */
+
+#ifdef CONFIG_EARLY_CONSOLE_SERIAL
+#define MAX_BAUD 115200
+#define BAUD_MSB (CONFIG_EARLY_CONSOLE_SERIAL_BAUD/MAX_BAUD)/0xFF
+#define BAUD_LSB (CONFIG_EARLY_CONSOLE_SERIAL_BAUD/MAX_BAUD)%0xFF
+
+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 int serial_init = 0; 
+
+static void init_serial_io_port(unsigned port)
+{
+	serial_init = 1;
+
+	wait_for_readiness(port);
+
+        /*
+         * Disable interrupts.
+         */
+        outb(0x0, MK_PORT(port + 1));
+
+        /*
+         * Set the baud rate divisor's LSB.
+         */
+        outb(BAUD_MSB, MK_PORT(port + 3));
+
+        /*
+         * Set the baud rate divisor's MSB.
+         */
+        outb(BAUD_LSB, MK_PORT(port));
+
+        /*
+         * Set no parity, 8 bits, 1 stop bit, and select
+         * interrupt enable register.
+         */
+        outb(0x3, MK_PORT(port + 3));
+}
+
+
+static void __init write_serial_io_port(unsigned port,
+					const char *s,
+					unsigned n)
+{
+	unsigned k;
+	
+	if (serial_init==0)
+	{
+		init_serial_io_port(port);
+	}
+
+	/*
+	 * 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));
+		}
+	}
+}
+
+
+
+/*
+ * On Intel-derived architectures it is customary for onboard serial
+ * ports to have I/O ports at these two port addresses.
+ */
+
+static void __init write_serial(struct console *c, const char *s, unsigned n)
+{
+	write_serial_io_port(CONFIG_EARLY_CONSOLE_SERIAL_PORT, s, n);
+}
+
+static struct console __initdata early_console_serial =
+{
+	write: write_serial
+};
+#endif
+
+
+#ifdef CONFIG_EARLY_CONSOLE_VGA
+
+/*
+ * 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.
+ */
+
+#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 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;
+	
+
+/*from martin bligh's early_printk */
+static inline void __init update_cursor(void)
+{
+        int pos = (col + VGA_MAXCOL*row) *2;
+   
+       	outb_p(14, VGA_REG_PORT);
+        outb_p(0xff & (pos >> 9), VGA_VAL_PORT);
+        outb_p(15, VGA_REG_PORT);
+        outb_p(0xff & (pos >> 1), VGA_VAL_PORT);
+}
+
+
+void __init clear_vga_mem(void)
+{
+        int x, y;
+
+        for (x = 0; x < 80; x++) {
+                for (y = 0; y < 25; y++) {
+                        VGA_CHAR(y,x) = ' ';
+                }
+        }
+	row =0;
+	col =0;
+	update_cursor();
+}
+
+
+	
+
+/*
+ * 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 = ' ';
+}
+
+
+/*
+ * 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]);
+		update_cursor();
+	}
+}
+
+static struct console __initdata early_console_vga =
+{
+	write: write_vga
+};
+
+#endif /*END 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_SERIAL
+		&early_console_serial,
+#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 add_early_consoles(void)
+{
+	
+	struct console **c = early_console_table;
+	while(*c)
+	{
+		register_early_console(*c++);
+		printk ("consoled added!\n\n");
+	}
+#ifdef CONFIG_EARLY_CONSOLE_VGA
+	clear_vga_mem();
+#endif 
+
+}
+
diff -urN linux-2.5.11/arch/i386/kernel/setup.c linux-2.5.11.early/arch/i386/kernel/setup.c
--- linux-2.5.11/arch/i386/kernel/setup.c	Sun Apr 28 20:12:46 2002
+++ linux-2.5.11.early/arch/i386/kernel/setup.c	Tue Apr 30 13:35:53 2002
@@ -672,7 +672,9 @@
 	unsigned long bootmap_size, low_mem_size;
 	unsigned long start_pfn, max_low_pfn;
 	int i;
-
+	
+	add_early_consoles();
+	
 #ifdef CONFIG_VISWS
 	visws_get_board_type_and_rev();
 #endif
diff -urN linux-2.5.11/drivers/char/console.c linux-2.5.11.early/drivers/char/console.c
--- linux-2.5.11/drivers/char/console.c	Sun Apr 28 20:12:11 2002
+++ linux-2.5.11.early/drivers/char/console.c	Tue Apr 30 13:35:53 2002
@@ -2437,7 +2437,8 @@
 {
 	const char *display_desc = NULL;
 	unsigned int currcons = 0;
-
+	int removed =0;
+	
 	if (conswitchp)
 		display_desc = conswitchp->con_startup();
 	if (!display_desc) {
@@ -2513,10 +2514,14 @@
 		display_desc, video_num_columns, video_num_lines);
 	printable = 1;
 	printk("\n");
-
+	
+	/*clear any early consoles*/
+	removed = clear_early_consoles();
+	
 #ifdef CONFIG_VT_CONSOLE
 	register_console(&vt_console_driver);
 #endif
+	printk ("removed %d early consoles \n",removed);
 }
 
 #ifndef VT_SINGLE_DRIVER
diff -urN linux-2.5.11/include/linux/console.h linux-2.5.11.early/include/linux/console.h
--- linux-2.5.11/include/linux/console.h	Sun Apr 28 20:12:35 2002
+++ linux-2.5.11.early/include/linux/console.h	Tue Apr 30 13:54:23 2002
@@ -90,7 +90,7 @@
 #define CON_PRINTBUFFER	(1)
 #define CON_CONSDEV	(2) /* Last on the command line */
 #define CON_ENABLED	(4)
-
+#define EARLY_CONSOLE   (8) /* Early flag. Remove in con_init  */
 struct console
 {
 	char	name[8];
@@ -105,6 +105,7 @@
 	struct	 console *next;
 };
 
+
 extern void register_console(struct console *);
 extern int unregister_console(struct console *);
 extern struct console *console_drivers;
@@ -112,6 +113,9 @@
 extern void release_console_sem(void);
 extern void console_conditional_schedule(void);
 extern void console_unblank(void);
+extern int clear_early_consoles(void);
+extern void register_early_console(struct console *);
+
 
 /* VESA Blanking Levels */
 #define VESA_NO_BLANKING        0
diff -urN linux-2.5.11/kernel/printk.c linux-2.5.11.early/kernel/printk.c
--- linux-2.5.11/kernel/printk.c	Sun Apr 28 20:12:49 2002
+++ linux-2.5.11.early/kernel/printk.c	Tue Apr 30 13:35:53 2002
@@ -669,6 +669,50 @@
 }
 EXPORT_SYMBOL(unregister_console);
 	
+/* This will clear any and all console_drivers that 
+   use only in con_init to remove any consoles that setup_arch
+   may have added for early console support  
+ */
+int clear_early_consoles(void)
+{
+        struct console *a, *b;
+        int removed = 0;
+	
+	if(console_drivers)
+	{
+	acquire_console_sem();
+	
+	
+	for (a=console_drivers->next, b=console_drivers; a; b=a,a=b->next)
+	{
+		if (a->flags & EARLY_CONSOLE)
+                {
+		        b->next = a->next;        	
+		        removed++;
+		}
+	}
+
+	if (console_drivers->flags & EARLY_CONSOLE)
+	{
+		console_drivers=console_drivers->next;
+		removed++;
+	
+	}
+
+	if (console_drivers == NULL)
+		preferred_console = -1;
+
+	release_console_sem();
+	}
+	return removed;
+}
+
+void register_early_console(struct console *early_con)
+{
+        early_con->flags |= EARLY_CONSOLE;
+	register_console(early_con);
+}
+
 /**
  * tty_write_message - write a message to a certain tty, not just the console.
  *


                 reply	other threads:[~2002-05-03  0:00 UTC|newest]

Thread overview: [no followups] expand[flat|nested]  mbox.gz  Atom feed

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=184120000.1020387481@flay \
    --to=kmannth@us.ibm.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=torvalds@transmeta.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.