2009-02-27 Robert Millan
* conf/i386-pc.rmk (pkglib_MODULES): Add `badram.mod'.
(badram_mod_SOURCES, badram_mod_CFLAGS)
(badram_mod_LDFLAGS): New variables.
* conf/i386-coreboot.rmk: Likewise.
* conf/powerpc-ieee1275.rmk: Likewise.
* conf/i386-ieee1275.rmk: Likewise.
* lib/badram.c: New file.
* include/grub/badram.h: New file.
* commands/lsmmap.c (grub_cmd_lsmmap): Replace
grub_machine_mmap_iterate() with grub_badram_mmap_iterate ().
* loader/i386/linux.c (find_mmap_size, allocate_pages)
(grub_linux32_boot): Likewise.
* loader/i386/pc/multiboot.c (grub_get_multiboot_mmap_len)
(grub_fill_multiboot_mmap): Likewise.
Index: conf/i386-pc.rmk
===================================================================
--- conf/i386-pc.rmk (revision 2001)
+++ conf/i386-pc.rmk (working copy)
@@ -370,6 +370,11 @@ lsmmap_mod_SOURCES = commands/lsmmap.c
lsmmap_mod_CFLAGS = $(COMMON_CFLAGS)
lsmmap_mod_LDFLAGS = $(COMMON_LDFLAGS)
+pkglib_MODULES += badram.mod
+badram_mod_SOURCES = lib/badram.c
+badram_mod_CFLAGS = $(COMMON_CFLAGS)
+badram_mod_LDFLAGS = $(COMMON_LDFLAGS)
+
# For ata_pthru.mod.
ata_pthru_mod_SOURCES = disk/ata_pthru.c
ata_pthru_mod_CFLAGS = $(COMMON_CFLAGS)
Index: conf/i386-coreboot.rmk
===================================================================
--- conf/i386-coreboot.rmk (revision 2001)
+++ conf/i386-coreboot.rmk (working copy)
@@ -211,5 +211,10 @@ lsmmap_mod_SOURCES = commands/lsmmap.c
lsmmap_mod_CFLAGS = $(COMMON_CFLAGS)
lsmmap_mod_LDFLAGS = $(COMMON_LDFLAGS)
+pkglib_MODULES += badram.mod
+badram_mod_SOURCES = lib/badram.c
+badram_mod_CFLAGS = $(COMMON_CFLAGS)
+badram_mod_LDFLAGS = $(COMMON_LDFLAGS)
+
include $(srcdir)/conf/i386.mk
include $(srcdir)/conf/common.mk
Index: conf/powerpc-ieee1275.rmk
===================================================================
--- conf/powerpc-ieee1275.rmk (revision 2001)
+++ conf/powerpc-ieee1275.rmk (working copy)
@@ -181,5 +181,10 @@ lsmmap_mod_SOURCES = commands/lsmmap.c
lsmmap_mod_CFLAGS = $(COMMON_CFLAGS)
lsmmap_mod_LDFLAGS = $(COMMON_LDFLAGS)
+pkglib_MODULES += badram.mod
+badram_mod_SOURCES = lib/badram.c
+badram_mod_CFLAGS = $(COMMON_CFLAGS)
+badram_mod_LDFLAGS = $(COMMON_LDFLAGS)
+
include $(srcdir)/conf/common.mk
Index: conf/i386-ieee1275.rmk
===================================================================
--- conf/i386-ieee1275.rmk (revision 2001)
+++ conf/i386-ieee1275.rmk (working copy)
@@ -210,5 +210,10 @@ lsmmap_mod_SOURCES = commands/lsmmap.c
lsmmap_mod_CFLAGS = $(COMMON_CFLAGS)
lsmmap_mod_LDFLAGS = $(COMMON_LDFLAGS)
+pkglib_MODULES += badram.mod
+badram_mod_SOURCES = lib/badram.c
+badram_mod_CFLAGS = $(COMMON_CFLAGS)
+badram_mod_LDFLAGS = $(COMMON_LDFLAGS)
+
include $(srcdir)/conf/i386.mk
include $(srcdir)/conf/common.mk
Index: lib/badram.c
===================================================================
--- lib/badram.c (revision 0)
+++ lib/badram.c (revision 0)
@@ -0,0 +1,127 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2009 Free Software Foundation, Inc.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see .
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#define CHUNK_SIZE 0x400
+
+struct badness
+{
+ grub_uint64_t addr;
+ grub_uint64_t mask;
+ struct badness *next;
+};
+
+static struct badness *badness;
+
+#define xor(a,b) (((a) & ~(b)) | (~(a) & (b)))
+
+static int
+is_bad (grub_uint64_t page)
+{
+ struct badness *pat;
+ for (pat = badness; pat != NULL; pat = pat->next)
+ if ((xor (page, pat->addr) & pat->mask) == 0)
+ return 1;
+ return 0;
+}
+
+grub_err_t
+grub_badram_mmap_iterate (int NESTED_FUNC_ATTR (*hook) (grub_uint64_t, grub_uint64_t, grub_uint32_t))
+{
+ char *str;
+ grub_err_t ret;
+
+ str = grub_env_get ("badram");
+ if (! str)
+ return grub_machine_mmap_iterate (hook);
+
+ while (1)
+ {
+ struct badness *new;
+ grub_uint64_t addr, mask;
+
+ /* Parse address and mask. */
+ addr = grub_strtoull (str, &str, 16);
+ if (*str == ',')
+ str++;
+ mask = grub_strtoull (str, &str, 16);
+ if (*str == ',')
+ str++;
+
+ if (grub_errno == GRUB_ERR_BAD_NUMBER)
+ {
+ grub_errno = 0;
+ break;
+ }
+
+ /* When part of a page is tainted, we discard the whole of it. There's
+ no point in providing sub-page chunks. */
+ mask &= ~(CHUNK_SIZE - 1);
+
+ new = grub_malloc (sizeof (struct badness));
+ new->addr = addr;
+ new->mask = mask;
+
+ /* Insert. */
+ new->next = badness;
+ badness = new;
+ }
+
+ auto int NESTED_FUNC_ATTR badram_hook (grub_uint64_t, grub_uint64_t, grub_uint32_t);
+ int NESTED_FUNC_ATTR badram_hook (grub_uint64_t addr, grub_uint64_t size, grub_uint32_t type)
+ {
+ /* These define the start and end of each chunk of good pages. */
+ grub_uint64_t start, end;
+
+ for (start = addr; 1; start = end)
+ {
+ /* Find a good page. */
+ for (; is_bad (start); start += CHUNK_SIZE);
+
+ /* Nothing left to use. */
+ if (start >= addr + size)
+ return 0;
+
+ /* Find the last good page in this chunk. */
+ for (end = start + CHUNK_SIZE; end < addr + size && ! is_bad (end); end += CHUNK_SIZE);
+
+ /* Process what we found. */
+ if (hook (start, end - start, type))
+ return 1;
+ }
+ }
+
+ ret = grub_machine_mmap_iterate (badram_hook);
+
+ while (badness)
+ {
+ struct badness *p;
+ p = badness->next;
+ grub_free (badness);
+ badness = p;
+ }
+
+ return ret;
+}
Index: include/grub/badram.h
===================================================================
--- include/grub/badram.h (revision 0)
+++ include/grub/badram.h (revision 0)
@@ -0,0 +1,29 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2009 Free Software Foundation, Inc.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see .
+ */
+
+#ifndef GRUB_BADRAM_HEADER
+#define GRUB_BADRAM_HEADER 1
+
+#include
+#include
+#include
+
+grub_err_t EXPORT_FUNC(grub_badram_mmap_iterate)
+ (int NESTED_FUNC_ATTR (*hook) (grub_uint64_t, grub_uint64_t, grub_uint32_t));
+
+#endif
Index: commands/lsmmap.c
===================================================================
--- commands/lsmmap.c (revision 2001)
+++ commands/lsmmap.c (working copy)
@@ -1,6 +1,6 @@
/*
* GRUB -- GRand Unified Bootloader
- * Copyright (C) 2008 Free Software Foundation, Inc.
+ * Copyright (C) 2008,2009 Free Software Foundation, Inc.
*
* GRUB is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -16,7 +16,7 @@
* along with GRUB. If not, see .
*/
-#include
+#include
#include
#include
#include
@@ -34,7 +34,7 @@ grub_cmd_lsmmap (struct grub_arg_list *s
addr, size, type);
return 0;
}
- grub_machine_mmap_iterate (hook);
+ grub_badram_mmap_iterate (hook);
return 0;
}
Index: loader/i386/linux.c
===================================================================
--- loader/i386/linux.c (revision 2001)
+++ loader/i386/linux.c (working copy)
@@ -1,6 +1,6 @@
/*
* GRUB -- GRand Unified Bootloader
- * Copyright (C) 2006,2007,2008 Free Software Foundation, Inc.
+ * Copyright (C) 2006,2007,2008,2009 Free Software Foundation, Inc.
*
* GRUB is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -20,6 +20,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -102,7 +103,7 @@ find_mmap_size (void)
return 0;
}
- grub_machine_mmap_iterate (hook);
+ grub_badram_mmap_iterate (hook);
mmap_size = count * sizeof (struct grub_e820_mmap);
@@ -173,7 +174,7 @@ allocate_pages (grub_size_t prot_size)
return 0;
}
- grub_machine_mmap_iterate (hook);
+ grub_badram_mmap_iterate (hook);
if (! real_mode_mem)
{
grub_error (GRUB_ERR_OUT_OF_MEMORY, "cannot allocate real mode pages");
@@ -258,7 +259,7 @@ grub_linux32_boot (void)
}
e820_num = 0;
- grub_machine_mmap_iterate (hook);
+ grub_badram_mmap_iterate (hook);
params->mmap_size = e820_num;
/* Hardware interrupts are not safe any longer. */
Index: loader/i386/pc/multiboot.c
===================================================================
--- loader/i386/pc/multiboot.c (revision 2001)
+++ loader/i386/pc/multiboot.c (working copy)
@@ -32,6 +32,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -98,7 +99,7 @@ grub_get_multiboot_mmap_len (void)
return 0;
}
- grub_machine_mmap_iterate (hook);
+ grub_badram_mmap_iterate (hook);
return count * sizeof (struct grub_multiboot_mmap_entry);
}
@@ -121,7 +122,7 @@ grub_fill_multiboot_mmap (struct grub_mu
return 0;
}
- grub_machine_mmap_iterate (hook);
+ grub_badram_mmap_iterate (hook);
}
/* Check if BUFFER contains ELF32. */