Messages in this thread Patch in this message | | | Date | Thu, 06 May 1999 10:41:35 -0400 | From | Philip Gladstone <> | Subject | Re: Oops assist... [Solution + Patch] |
| |
On many systems, you can find memory that isn't zeroed by the BIOS on boot. I have a patch that saves the console log into such memory as it gets written -- this lets you get to the oops after the reboot.
The problem is that motherboards and BIOSes are all different. For example, on an ASUS P2B, I use the RAM between 0xb0000-0xc0000. Ahah I hear you say, this is VGA memory, this must be flushed on reboot.
It turns out that there is main memory (i.e. on the DIMM) at this location as well. This is normally disabled so that accesses go to the VGA. You can fiddle with the 82443 chip to route memory accesses into the underlying memory.
Problems:
This doesn't work in an SMP environment (I think) as there needs to be coordination between the two processors.
It is very slow as (I think) I need to flush the CPU caches to ensure that memory accesses happen in the right order.
It is very motherboard/BIOS dependant -- basically it relies on the 'bug' that the BIOS fails to clear out this hidden memory.
It doesn't work (for example) on Compaq boxes as they lock access to this area.
Anyway, I attach a patch for 2.0.36 that allows a module to get a copy of all console output (by using the register_logger function). This is the basic hook required.
Future approaches:
If *all* you want is the oops log, then it may be possible to save it in some of the CMOS ram that is available. It turns out that there is more CMOS battery backed ram than you might expect! For example, on the P2B there are *two* RTCs -- one embedded inside the southbridge and one inside the super i/o chip. With enough careful fiddling, it might be possible to write to the one that isn't being used. I'll bet that having 220 bytes of Oops is a lot better than nothing - note that you only want to save the binary data, not the text.
For all I know, you can hide data on a VGA card -- who knows if they clear out all the memory on a reset!!
Philip
Manfred Spraul wrote: > > David Weinehall wrote: > > Wouldn't it be quite reasonable to make "Reboot on Oops" an config-option > > or a sysctl? > > Obviously, yes. (I think that reboot on Oops should be the default). > But what about the oops report? I think that this report must be stored > somewhere. How do you want to find a bug without it? > (new bug report: Hey, my computer crashed yesterday at 21:15. > What's wrong?) > IMHO, the swapfile is the best & portable solution: NT uses > the swapfile, I've read the Solaris uses the swapfile, too. > > Regards, > Manfred > > - > To unsubscribe from this list: send the line "unsubscribe linux-kernel" in > the body of a message to majordomo@vger.rutgers.edu > Please read the FAQ at http://www.tux.org/lkml/
-- Philip Gladstone +1 781 530 2461 Axent Technologies, Waltham, MA--- linux/kernel/printk.c.orig Fri Jun 7 04:54:06 1996 +++ linux/kernel/printk.c Mon Sep 29 18:12:37 1997 @@ -41,6 +41,7 @@ int console_loglevel = DEFAULT_CONSOLE_LOGLEVEL; static void (*console_print_proc)(const char *) = 0; +static void (*logger_proc)(const char *, int) = 0; static char log_buf[LOG_BUF_LEN]; static unsigned long log_start = 0; static unsigned long logged_chars = 0; @@ -154,6 +155,7 @@ char *msg, *p, *buf_end; static char msg_level = -1; long flags; + char *whole_msg; save_flags(flags); cli(); @@ -162,7 +164,7 @@ buf_end = buf + 3 + i; va_end(args); for (p = buf + 3; p < buf_end; p++) { - msg = p; + whole_msg = msg = p; if (msg_level < 0) { if ( p[0] != '<' || @@ -190,6 +192,11 @@ if (*p == '\n') break; } + + if (logger_proc) + (*logger_proc)(whole_msg, + ((p < buf_end) ? (p + 1) : p) - whole_msg); + if (msg_level < console_loglevel && console_print_proc) { char tmp = p[1]; p[1] = '\0'; @@ -235,6 +242,40 @@ (*proc)(q); if (buf[j-1] == '\n') msg_level = -1; + j = 0; + } +} + +void register_logger(void (*proc)(const char *, int)) +{ + int i,j; + int p; + char buf[80]; + int nchars; + + logger_proc = proc; + + if (!logger_proc) + return; + + if (log_size == LOG_BUF_LEN) + p = (log_start + log_size) & (LOG_BUF_LEN - 1); + else + p = 0; + + if (logged_chars > LOG_BUF_LEN) + nchars = LOG_BUF_LEN; + else + nchars = logged_chars; + + for (i=0,j=0; i < nchars; i++) { + buf[j++] = log_buf[p]; + p++; p &= LOG_BUF_LEN-1; + if (buf[j-1] != '\n' && i < log_size - 1 && j < sizeof(buf)) + continue; + + (*logger_proc)(buf, j); + j = 0; } } --- linux/kernel/ksyms.c.orig Mon Sep 29 16:07:37 1997 +++ linux/kernel/ksyms.c Mon Sep 29 16:10:28 1997 @@ -83,6 +83,9 @@ extern void select_free_wait(select_table * p); extern int select_check(int flag, select_table * wait, struct file * file); +extern void register_logger(void (*) (const char *, int)); +extern void (*kd_mksound)(unsigned int, unsigned int); + struct symbol_table symbol_table = { #include <linux/symtab_begin.h> #ifdef MODVERSIONS @@ -375,6 +378,8 @@ X(disk_name), /* for md.c */ #endif + X(register_logger), + X(kd_mksound), X(watchdog_info), /* binfmt_aout */[unhandled content-type:application/x-pkcs7-signature] | |