Merge "tpm: export vlan and ethertype." into prism_dev
diff --git a/arch/arm/configs/gflt200_defconfig b/arch/arm/configs/gflt200_defconfig
index d36faff..2457f5b 100644
--- a/arch/arm/configs/gflt200_defconfig
+++ b/arch/arm/configs/gflt200_defconfig
@@ -78,6 +78,8 @@
# CONFIG_KALLSYMS_EXTRA_PASS is not set
CONFIG_HOTPLUG=y
CONFIG_PRINTK=y
+CONFIG_PRINTK_PERSIST=y
+CONFIG_PRINTK_TIME=y
CONFIG_BUG=y
CONFIG_ELF_CORE=y
CONFIG_BASE_FULL=y
@@ -566,7 +568,7 @@
#
CONFIG_ZBOOT_ROM_TEXT=0x0
CONFIG_ZBOOT_ROM_BSS=0x0
-CONFIG_CMDLINE="console=ttyS0,115200"
+CONFIG_CMDLINE="console=ttyS0,115200 log_buf_len=1048576"
# CONFIG_XIP_KERNEL is not set
# CONFIG_KEXEC is not set
diff --git a/init/Kconfig b/init/Kconfig
index eb4b337..072d249 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -818,6 +818,18 @@
very difficult to diagnose system problems, saying N here is
strongly discouraged.
+config PRINTK_PERSIST
+ default n
+ bool "printk log persists across reboots" if PRINTK
+ help
+ This option tries to keep the printk memory buffer in a well-known
+ location in physical memory. It isn't cleared on reboot (unless RAM
+ is wiped by your boot loader or BIOS) so if your system crashes
+ or panics, you might get to examine all the log messages next time you
+ boot. The persisted log messages show up in your 'dmesg' output.
+ Note: you must supply the log_buf_len= kernel parameter to
+ activate this feature.
+
config BUG
bool "BUG() support" if EMBEDDED
default y
diff --git a/kernel/printk.c b/kernel/printk.c
index d2cde12..ad1a79b 100755
--- a/kernel/printk.c
+++ b/kernel/printk.c
@@ -71,8 +71,6 @@
DEFAULT_CONSOLE_LOGLEVEL, /* default_console_loglevel */
};
-static int saved_console_loglevel = -1;
-
/*
* Low level drivers may need that to know if they can schedule in
* their unblank() callback or not. So let's export it.
@@ -115,7 +113,12 @@
*/
static unsigned log_start; /* Index into log_buf: next char to be read by syslog() */
static unsigned con_start; /* Index into log_buf: next char to be sent to consoles */
+
+#ifdef CONFIG_PRINTK_PERSIST
+#define log_end logbits->_log_end
+#else
static unsigned log_end; /* Index into log_buf: most-recently-written-char + 1 */
+#endif
/*
* Array of consoles built from command line options (console=)
@@ -143,11 +146,6 @@
#ifdef CONFIG_PRINTK
-static char __log_buf[__LOG_BUF_LEN];
-static char *log_buf = __log_buf;
-static int log_buf_len = __LOG_BUF_LEN;
-static unsigned logged_chars; /* Number of chars produced since last read+clear operation */
-
#ifdef CONFIG_KEXEC
/*
* This appends the listed symbols to /proc/vmcoreinfo
@@ -166,6 +164,97 @@
}
#endif
+static int saved_console_loglevel = -1;
+static char __log_buf[__LOG_BUF_LEN];
+static char *log_buf = __log_buf;
+
+#ifndef CONFIG_PRINTK_PERSIST
+
+static int log_buf_len = __LOG_BUF_LEN;
+static unsigned logged_chars; /* Number of chars produced since last read+clear operation */
+
+static __init char *log_buf_alloc(unsigned long size, unsigned *dest_offset)
+{
+ return alloc_bootmem(size);
+}
+
+#else /* CONFIG_PRINTK_PERSIST */
+
+struct logbits {
+ int magic; /* needed to verify the memory across reboots */
+ int _log_buf_len; /* leading _ so they aren't replaced by #define */
+ unsigned _logged_chars;
+ unsigned _log_end;
+};
+static struct logbits __logbits = {
+ ._log_buf_len = __LOG_BUF_LEN,
+};
+static struct logbits *logbits = &__logbits;
+#define log_buf_len logbits->_log_buf_len
+#define logged_chars logbits->_logged_chars
+
+#define PERSIST_SEARCH_START 0
+#define PERSIST_SEARCH_END 0xfe000000
+#define PERSIST_SEARCH_JUMP (16*1024*1024)
+#define PERSIST_MAGIC 0xbabb1e
+
+/*
+ * size is a power of 2 so that the printk offset mask will work. We'll add
+ * a bit more space to the end of the buffer for our extra data, but that
+ * won't change the offset of the buffers.
+ */
+static __init char *log_buf_alloc(unsigned long size, unsigned *dest_offset)
+{
+ unsigned long where;
+ char *buf;
+ unsigned long full_size = size + sizeof(struct logbits);
+ struct logbits *new_logbits;
+
+ for (where = PERSIST_SEARCH_END - size;
+ where >= PERSIST_SEARCH_START;
+ where -= PERSIST_SEARCH_JUMP) {
+ if (reserve_bootmem(where, full_size, BOOTMEM_EXCLUSIVE))
+ continue;
+
+ buf = phys_to_virt(where);
+ new_logbits = phys_to_virt(where + size);
+ printk(KERN_INFO "printk_persist: memory reserved @ 0x%08lx\n",
+ where);
+ if (new_logbits->magic != PERSIST_MAGIC ||
+ new_logbits->_log_buf_len != size ||
+ new_logbits->_logged_chars > size) {
+ printk(KERN_INFO "printk_persist: header invalid, "
+ "cleared.\n");
+ memset(buf, 0, full_size);
+ new_logbits->magic = PERSIST_MAGIC;
+ new_logbits->_log_buf_len = size;
+ new_logbits->_logged_chars = 0;
+ new_logbits->_log_end = 0;
+ } else {
+ printk(KERN_INFO "printk_persist: header valid; "
+ "logged=%d next=%d\n",
+ new_logbits->_logged_chars,
+ new_logbits->_log_end);
+ }
+ *dest_offset = new_logbits->_log_end;
+ new_logbits->_log_end = log_end;
+ if (new_logbits->_logged_chars + logged_chars <= size)
+ new_logbits->_logged_chars += logged_chars;
+ else
+ new_logbits->_logged_chars = size;
+ logbits = new_logbits;
+ return buf;
+ }
+ goto error;
+
+error:
+ /* replace the buffer, but don't bother to swap struct logbits */
+ printk(KERN_ERR "printk_persist: failed to reserve bootmem "
+ "area. disabled.\n");
+ return alloc_bootmem(full_size);
+}
+#endif /* CONFIG_PRINTK_PERSIST */
+
static int __init log_buf_len_setup(char *str)
{
unsigned size = memparse(str, &str);
@@ -174,10 +263,10 @@
if (size)
size = roundup_pow_of_two(size);
if (size > log_buf_len) {
- unsigned start, dest_idx, offset;
+ unsigned start, dest_offset = 0, dest_idx, offset;
char *new_log_buf;
- new_log_buf = alloc_bootmem(size);
+ new_log_buf = log_buf_alloc(size, &dest_offset);
if (!new_log_buf) {
printk(KERN_WARNING "log_buf_len: allocation failed\n");
goto out;
@@ -188,15 +277,16 @@
log_buf = new_log_buf;
offset = start = min(con_start, log_start);
- dest_idx = 0;
+ dest_idx = dest_offset;
while (start != log_end) {
- log_buf[dest_idx] = __log_buf[start & (__LOG_BUF_LEN - 1)];
+ log_buf[dest_idx & (size - 1)] =
+ __log_buf[start & (__LOG_BUF_LEN - 1)];
start++;
dest_idx++;
}
- log_start -= offset;
- con_start -= offset;
- log_end -= offset;
+ log_start += dest_offset - offset;
+ con_start += dest_offset - offset;
+ log_end += dest_offset - offset;
spin_unlock_irqrestore(&logbuf_lock, flags);
printk(KERN_NOTICE "log_buf_len: %d\n", log_buf_len);
@@ -260,6 +350,7 @@
}
#endif
+#define COPY_SIZE 4096
/*
* Commands to do_syslog:
*
@@ -277,6 +368,7 @@
*/
int do_syslog(int type, char __user *buf, int len)
{
+ char *copybuf;
unsigned i, j, limit, count;
int do_clear = 0;
char c;
@@ -336,6 +428,11 @@
error = -EFAULT;
goto out;
}
+ copybuf = kmalloc(COPY_SIZE, GFP_KERNEL);
+ if (!copybuf) {
+ error = -ENOMEM;
+ goto out;
+ }
count = len;
if (count > log_buf_len)
count = log_buf_len;
@@ -346,7 +443,7 @@
logged_chars = 0;
limit = log_end;
/*
- * __put_user() could sleep, and while we sleep
+ * copy_to_user() could sleep, and while we sleep
* printk() could overwrite the messages
* we try to copy to user space. Therefore
* the messages are copied in reverse. <manfreds>
@@ -356,14 +453,26 @@
if (j + log_buf_len < log_end)
break;
c = LOG_BUF(j);
- spin_unlock_irq(&logbuf_lock);
- error = __put_user(c,&buf[count-1-i]);
- cond_resched();
- spin_lock_irq(&logbuf_lock);
+ copybuf[COPY_SIZE-1-(i % COPY_SIZE)] = c;
+ if ((i+1) % COPY_SIZE == 0) {
+ spin_unlock_irq(&logbuf_lock);
+ error = copy_to_user(&buf[count-1-i],
+ copybuf, COPY_SIZE);
+ cond_resched();
+ spin_lock_irq(&logbuf_lock);
+ }
}
spin_unlock_irq(&logbuf_lock);
- if (error)
- break;
+ if (!error) {
+ /* in case copybuf was only partially filled */
+ error = copy_to_user(&buf[count-i],
+ copybuf + COPY_SIZE - (i % COPY_SIZE),
+ i % COPY_SIZE);
+ }
+ if (error) {
+ error = -EFAULT;
+ goto copy_done;
+ }
error = i;
if (i != count) {
int offset = count-error;
@@ -377,6 +486,8 @@
cond_resched();
}
}
+copy_done:
+ kfree(copybuf);
break;
case 5: /* Clear ring buffer */
logged_chars = 0;
@@ -757,7 +868,6 @@
emit_log_char('<');
emit_log_char(current_log_level + '0');
emit_log_char('>');
- printed_len += 3;
new_text_line = 0;
if (printk_time) {
@@ -775,7 +885,6 @@
for (tp = tbuf; tp < tbuf + tlen; tp++)
emit_log_char(*tp);
- printed_len += tlen;
}
if (!*p)