Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 113350
b: refs/heads/master
c: 9f07787
h: refs/heads/master
v: v3
  • Loading branch information
Jeremy Fitzhardinge authored and Ingo Molnar committed Sep 7, 2008
1 parent 3dce2be commit fca8780
Show file tree
Hide file tree
Showing 4 changed files with 107 additions and 29 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: bb577f980ef35e2b0d00aeed566724e5032aa5eb
refs/heads/master: 9f077871ce7237e2387fc76542b3b4033cb05e49
28 changes: 23 additions & 5 deletions trunk/Documentation/kernel-parameters.txt
Original file line number Diff line number Diff line change
Expand Up @@ -360,11 +360,6 @@ and is between 256 and 4096 characters. It is defined in the file
Format: <io>,<irq>,<mode>
See header of drivers/net/hamradio/baycom_ser_hdx.c.

bios_corruption_check=0/1 [X86]
Some BIOSes seem to corrupt the first 64k of memory
when doing things like suspend/resume. Setting this
option will scan the memory looking for corruption.

boot_delay= Milliseconds to delay each printk during boot.
Values larger than 10 seconds (10000) are changed to
no delay (0).
Expand Down Expand Up @@ -1233,6 +1228,29 @@ and is between 256 and 4096 characters. It is defined in the file
or
memmap=0x10000$0x18690000

memory_corruption_check=0/1 [X86]
Some BIOSes seem to corrupt the first 64k of
memory when doing things like suspend/resume.
Setting this option will scan the memory
looking for corruption. Enabling this will
both detect corruption and prevent the kernel
from using the memory being corrupted.
However, its intended as a diagnostic tool; if
repeatable BIOS-originated corruption always
affects the same memory, you can use memmap=
to prevent the kernel from using that memory.

memory_corruption_check_size=size [X86]
By default it checks for corruption in the low
64k, making this memory unavailable for normal
use. Use this parameter to scan for
corruption in more or less memory.

memory_corruption_check_period=seconds [X86]
By default it checks for corruption every 60
seconds. Use this parameter to check at some
other rate. 0 disables periodic checking.

memtest= [KNL,X86] Enable memtest
Format: <integer>
range: 0,4 : pattern number
Expand Down
26 changes: 23 additions & 3 deletions trunk/arch/x86/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -201,9 +201,6 @@ config X86_TRAMPOLINE
depends on X86_SMP || (X86_VOYAGER && SMP) || (64BIT && ACPI_SLEEP)
default y

config X86_CHECK_BIOS_CORRUPTION
def_bool y

config KTIME_SCALAR
def_bool X86_32
source "init/Kconfig"
Expand Down Expand Up @@ -1062,6 +1059,29 @@ config HIGHPTE
low memory. Setting this option will put user-space page table
entries in high memory.

config X86_CHECK_BIOS_CORRUPTION
bool "Check for low memory corruption"
default y
help
Periodically check for memory corruption in low memory, which
is suspected to be caused by BIOS. Even when enabled in the
configuration, it is disabled at runtime. Enable it by
setting "memory_corruption_check=1" on the kernel command
line. By default it scans the low 64k of memory every 60
seconds; see the memory_corruption_check_size and
memory_corruption_check_period parameters in
Documentation/kernel-parameters.txt to adjust this.

When enabled with the default parameters, this option has
almost no overhead, as it reserves a relatively small amount
of memory and scans it infrequently. It both detects corruption
and prevents it from affecting the running system.

It is, however, intended as a diagnostic tool; if repeatable
BIOS-originated corruption always affects the same memory,
you can use memmap= to prevent the kernel from using that
memory.

config MATH_EMULATION
bool
prompt "Math emulation" if X86_32
Expand Down
80 changes: 60 additions & 20 deletions trunk/arch/x86/kernel/setup.c
Original file line number Diff line number Diff line change
Expand Up @@ -586,22 +586,71 @@ struct x86_quirks *x86_quirks __initdata = &default_x86_quirks;
*/
#ifdef CONFIG_X86_CHECK_BIOS_CORRUPTION
#define MAX_SCAN_AREAS 8

static int __read_mostly memory_corruption_check = 0;
static unsigned __read_mostly corruption_check_size = 64*1024;
static unsigned __read_mostly corruption_check_period = 60; /* seconds */

static struct e820entry scan_areas[MAX_SCAN_AREAS];
static int num_scan_areas;


static int set_corruption_check(char *arg)
{
char *end;

memory_corruption_check = simple_strtol(arg, &end, 10);

return (*end == 0) ? 0 : -EINVAL;
}
early_param("memory_corruption_check", set_corruption_check);

static int set_corruption_check_period(char *arg)
{
char *end;

corruption_check_period = simple_strtoul(arg, &end, 10);

return (*end == 0) ? 0 : -EINVAL;
}
early_param("memory_corruption_check_period", set_corruption_check_period);

static int set_corruption_check_size(char *arg)
{
char *end;
unsigned size;

size = memparse(arg, &end);

if (*end == '\0')
corruption_check_size = size;

return (size == corruption_check_size) ? 0 : -EINVAL;
}
early_param("memory_corruption_check_size", set_corruption_check_size);


static void __init setup_bios_corruption_check(void)
{
u64 addr = PAGE_SIZE; /* assume first page is reserved anyway */

while(addr < 0x10000 && num_scan_areas < MAX_SCAN_AREAS) {
if (corruption_check_size == 0)
memory_corruption_check = 0;

if (!memory_corruption_check)
return;

corruption_check_size = round_up(corruption_check_size, PAGE_SIZE);

while(addr < corruption_check_size && num_scan_areas < MAX_SCAN_AREAS) {
u64 size;
addr = find_e820_area_size(addr, &size, PAGE_SIZE);

if (addr == 0)
break;

if ((addr + size) > 0x10000)
size = 0x10000 - addr;
if ((addr + size) > corruption_check_size)
size = corruption_check_size - addr;

if (size == 0)
break;
Expand All @@ -617,20 +666,19 @@ static void __init setup_bios_corruption_check(void)
addr += size;
}

printk(KERN_INFO "scanning %d areas for BIOS corruption\n",
printk(KERN_INFO "Scanning %d areas for low memory corruption\n",
num_scan_areas);
update_e820();
}

static int __read_mostly bios_corruption_check = 1;
static struct timer_list periodic_check_timer;

void check_for_bios_corruption(void)
{
int i;
int corruption = 0;

if (!bios_corruption_check)
if (!memory_corruption_check)
return;

for(i = 0; i < num_scan_areas; i++) {
Expand All @@ -647,35 +695,27 @@ void check_for_bios_corruption(void)
}
}

if (corruption)
dump_stack();
WARN(corruption, KERN_ERR "Memory corruption detected in low memory\n");
}

static void periodic_check_for_corruption(unsigned long data)
{
check_for_bios_corruption();
mod_timer(&periodic_check_timer, jiffies + 60*HZ);
mod_timer(&periodic_check_timer, jiffies + corruption_check_period*HZ);
}

void start_periodic_check_for_corruption(void)
{
if (!bios_corruption_check)
if (!memory_corruption_check || corruption_check_period == 0)
return;

printk(KERN_INFO "Scanning for low memory corruption every %d seconds\n",
corruption_check_period);

init_timer(&periodic_check_timer);
periodic_check_timer.function = &periodic_check_for_corruption;
periodic_check_for_corruption(0);
}

static int set_bios_corruption_check(char *arg)
{
char *end;

bios_corruption_check = simple_strtol(arg, &end, 10);

return (*end == 0) ? 0 : -EINVAL;
}
early_param("bios_corruption_check", set_bios_corruption_check);
#endif

/*
Expand Down

0 comments on commit fca8780

Please sign in to comment.