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. */