From: phcoder <phcoder@gmail.com>
To: The development of GRUB 2 <grub-devel@gnu.org>
Subject: mmap services
Date: Sat, 11 Apr 2009 23:01:19 +0200 [thread overview]
Message-ID: <49E1051F.6090704@gmail.com> (raw)
[-- Attachment #1: Type: text/plain, Size: 268 bytes --]
Hello. Here is the patch to allow different mmap filtering. It naturally
incorporates badram and also intercepts int12/15 so it works also with
OS recieving mmap from BIOS. It's useful for intercepting any bios
interrupts
--
Regards
Vladimir 'phcoder' Serbinenko
[-- Attachment #2: mmap.diff --]
[-- Type: text/x-diff, Size: 39093 bytes --]
diff --git a/ChangeLog b/ChangeLog
index a6dd8f7..ce0eb8d 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,52 @@
+2009-04-11 Vladimir Serbinenko <phcoder@gmail.com>
+
+ Mmap services
+
+ * commands/lsmmap.c (grub_cmd_lsmmap): use grub_mmap_iterate
+ * loader/i386/linux.c (find_mmap_size): likewise
+ (allocate_pages): likewise
+ * loader/i386/multiboot.c (grub_get_multiboot_mmap_len): likewise
+ (grub_fill_multiboot_mmap): likewise
+ (grub_multiboot): use grub_mmap_get_lower and grub_mmap_get_upper
+ * loader/i386/pc/linux.c (grub_cmd_linux): use grub_mmap_get_lower
+ * include/grub/i386/bsd.h (OPENBSD_MMAP_AVAILABLE): new definition
+ (OPENBSD_MMAP_RESERVED): likewise
+ * include/grub/i386/pc/memory.h: include grub/memory.h
+ (grub_lower_mem): removed
+ (grub_upper_mem): likewise
+ (GRUB_MACHINE_MEMORY_ACPI): new definition
+ (GRUB_MACHINE_MEMORY_NVS): likewise
+ (GRUB_MACHINE_MEMORY_MAX_TYPE): likewise
+ (GRUB_MACHINE_MEMORY_HOLE): likewise
+ (grub_machine_mmap_register): likewise
+ (grub_machine_mmap_unregister): likewise
+ (grub_machine_get_upper): likewise
+ (grub_machine_get_lower): likewise
+ (grub_machine_get_post64): likewise
+ * conf/i386-pc.rmk (pkglib_MODULES): added mmap.mod
+ (mmap_mod_SOURCES): new variable
+ (mmap_mod_LDFLAGS): likewise
+ (mmap_mod_ASFLAGS): likewise
+ * conf/i386-coreboot.rmk: likewise
+ * conf/i386-ieee1275.rmk: likewise
+ * include/grub/types.h (UINT_TO_PTR): new macro
+ (PTR_TO_UINT32): likewise
+ (PTR_TO_UINT64): likewise
+ * include/grub/memory.h: new file
+ * mmap/i386/pc/mmap.c: likewise
+ * mmap/i386/pc/mmap_helper.S: likewise
+ * mmap/i386/uppermem.c: likewise
+ * mmap/mmap.c: likewise
+ * kern/i386/coreboot/init.c (grub_machine_init): don't use
+ grub_upper_mem
+ * kern/i386/pc/init.c (grub_lower_mem): removed variable
+ (grub_upper_mem): likewise
+ (grub_machine_init): don't use grub_upper_mem,
+ make grub_lower_mem local
+ * loader/i386/bsd.c (grub_openbsd_boot): use grub_mmap_get_lower,
+ grub_mmap_iterate and grub_mmap_get_upper
+ (grub_netbsd_boot): use grub_mmap_get_lower and grub_mmap_get_upper
+
2009-04-06 Vladimir Serbinenko <phcoder@gmail.com>
Preboot hooks support
diff --git a/conf/i386-coreboot.rmk b/conf/i386-coreboot.rmk
index bc500d9..554463f 100644
--- a/conf/i386-coreboot.rmk
+++ b/conf/i386-coreboot.rmk
@@ -102,7 +102,13 @@ pkglib_MODULES = linux.mod normal.mod multiboot.mod \
aout.mod play.mod serial.mod ata.mod \
memdisk.mod pci.mod lspci.mod reboot.mod \
halt.mod datetime.mod date.mod datehook.mod \
- lsmmap.mod
+ lsmmap.mod mmap.mod
+
+# For mmap.mod.
+mmap_mod_SOURCES = mmap/mmap.c mmap/i386/uppermem.c
+mmap_mod_CFLAGS = $(COMMON_CFLAGS)
+mmap_mod_LDFLAGS = $(COMMON_LDFLAGS)
+mmap_mod_ASFLAGS = $(COMMON_ASFLAGS)
# For linux.mod.
linux_mod_SOURCES = loader/i386/linux.c
diff --git a/conf/i386-ieee1275.rmk b/conf/i386-ieee1275.rmk
index bbd6c09..9c0e4bc 100644
--- a/conf/i386-ieee1275.rmk
+++ b/conf/i386-ieee1275.rmk
@@ -103,7 +103,13 @@ grub_install_SOURCES = util/ieee1275/grub-install.in
pkglib_MODULES = normal.mod halt.mod reboot.mod suspend.mod \
multiboot.mod aout.mod serial.mod linux.mod \
nand.mod memdisk.mod pci.mod lspci.mod datetime.mod \
- date.mod datehook.mod lsmmap.mod
+ date.mod datehook.mod lsmmap.mod mmap.mod
+
+# For mmap.mod.
+mmap_mod_SOURCES = mmap/mmap.c mmap/i386/uppermem.c
+mmap_mod_CFLAGS = $(COMMON_CFLAGS)
+mmap_mod_LDFLAGS = $(COMMON_LDFLAGS)
+mmap_mod_ASFLAGS = $(COMMON_ASFLAGS)
#
# Only arch dependant part of normal.mod will be here. Common part for
diff --git a/conf/i386-pc.rmk b/conf/i386-pc.rmk
index fdb43df..178974c 100644
--- a/conf/i386-pc.rmk
+++ b/conf/i386-pc.rmk
@@ -175,7 +175,15 @@ pkglib_MODULES = biosdisk.mod chain.mod normal.mod \
ata.mod vga.mod memdisk.mod pci.mod lspci.mod \
aout.mod bsd.mod pxe.mod pxecmd.mod datetime.mod date.mod \
datehook.mod lsmmap.mod ata_pthru.mod hdparm.mod \
- usb.mod uhci.mod ohci.mod usbtest.mod usbms.mod usb_keyboard.mod
+ usb.mod uhci.mod ohci.mod usbtest.mod usbms.mod usb_keyboard.mod \
+ mmap.mod
+
+# For mmap.mod.
+mmap_mod_SOURCES = mmap/mmap.c mmap/i386/uppermem.c mmap/i386/pc/mmap.c \
+ mmap/i386/pc/mmap_helper.S
+mmap_mod_CFLAGS = $(COMMON_CFLAGS)
+mmap_mod_LDFLAGS = $(COMMON_LDFLAGS)
+mmap_mod_ASFLAGS = $(COMMON_ASFLAGS)
# For biosdisk.mod.
biosdisk_mod_SOURCES = disk/i386/pc/biosdisk.c
diff --git a/include/grub/i386/bsd.h b/include/grub/i386/bsd.h
index f50f18e..78fae79 100644
--- a/include/grub/i386/bsd.h
+++ b/include/grub/i386/bsd.h
@@ -148,6 +148,8 @@ struct grub_openbsd_bios_mmap
{
grub_uint64_t addr;
grub_uint64_t len;
+#define OPENBSD_MMAP_AVAILABLE 1
+#define OPENBSD_MMAP_RESERVED 2
grub_uint32_t type;
};
diff --git a/include/grub/i386/pc/memory.h b/include/grub/i386/pc/memory.h
index 08e92a9..610c65a 100644
--- a/include/grub/i386/pc/memory.h
+++ b/include/grub/i386/pc/memory.h
@@ -25,6 +25,7 @@
#ifndef ASM_FILE
#include <grub/types.h>
#include <grub/err.h>
+#include <grub/memory.h>
#endif
/* The scratch buffer used in real mode code. */
@@ -79,12 +80,6 @@
#ifndef ASM_FILE
-#ifndef GRUB_MACHINE_IEEE1275
-extern grub_size_t EXPORT_VAR(grub_lower_mem);
-#endif
-
-extern grub_size_t EXPORT_VAR(grub_upper_mem);
-
struct grub_machine_mmap_entry
{
grub_uint32_t size;
@@ -92,12 +87,40 @@ struct grub_machine_mmap_entry
grub_uint64_t len;
#define GRUB_MACHINE_MEMORY_AVAILABLE 1
#define GRUB_MACHINE_MEMORY_RESERVED 2
+#define GRUB_MACHINE_MEMORY_ACPI 3
+#define GRUB_MACHINE_MEMORY_NVS 4
+#define GRUB_MACHINE_MEMORY_MAX_TYPE 4
+ /* This one is special: it's used internally but is never reported
+ by firmware. */
+#define GRUB_MACHINE_MEMORY_HOLE 5
+
grub_uint32_t type;
} __attribute__((packed));
grub_err_t EXPORT_FUNC(grub_machine_mmap_iterate)
(int NESTED_FUNC_ATTR (*hook) (grub_uint64_t, grub_uint64_t, grub_uint32_t));
+grub_uint64_t grub_mmap_get_post64 (void);
+grub_uint64_t grub_mmap_get_upper (void);
+grub_uint64_t grub_mmap_get_lower (void);
+
+#ifdef GRUB_MACHINE_PCBIOS
+grub_err_t grub_machine_mmap_register (grub_uint64_t start, grub_uint64_t size,
+ int type, int handle);
+grub_err_t grub_machine_mmap_unregister (int handle);
+#else
+static inline grub_err_t grub_machine_mmap_register (grub_uint64_t start,
+ grub_uint64_t size,
+ int type, int handle)
+{
+ return GRUB_ERR_NONE;
+}
+static inline grub_err_t grub_machine_mmap_unregister (int handle)
+{
+ return GRUB_ERR_NONE;
+}
+#endif
+
#endif
#endif /* ! GRUB_MEMORY_MACHINE_HEADER */
diff --git a/include/grub/memory.h b/include/grub/memory.h
new file mode 100644
index 0000000..03a8516
--- /dev/null
+++ b/include/grub/memory.h
@@ -0,0 +1,34 @@
+/* memory.h - describe the memory map */
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2002,2007,2008 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 <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GRUB_MEMORY_HEADER
+#define GRUB_MEMORY_HEADER 1
+
+#include <grub/types.h>
+#include <grub/err.h>
+
+grub_err_t
+grub_mmap_iterate (int NESTED_FUNC_ATTR (*hook) (grub_uint64_t,
+ grub_uint64_t, grub_uint32_t));
+int
+grub_mmap_register (grub_uint64_t start, grub_uint64_t size, int type);
+grub_err_t
+grub_mmap_unregister (int handle);
+
+#endif /* ! GRUB_MEMORY_HEADER */
diff --git a/include/grub/types.h b/include/grub/types.h
index 8d51b66..faf2257 100644
--- a/include/grub/types.h
+++ b/include/grub/types.h
@@ -100,6 +100,16 @@ typedef grub_int32_t grub_ssize_t;
# define LONG_MAX 2147483647UL
#endif
+#if GRUB_CPU_SIZEOF_VOID_P == 4
+#define UINT_TO_PTR(x) ((void*)(grub_uint32_t)(x))
+#define PTR_TO_UINT64(x) ((grub_uint64_t)(grub_uint32_t)(x))
+#define PTR_TO_UINT32(x) ((grub_uint32_t)(x))
+#else
+#define UINT_TO_PTR(x) ((void*)(grub_uint64_t)(x))
+#define PTR_TO_UINT64(x) ((grub_uint64_t)(x))
+#define PTR_TO_UINT32(x) ((grub_uint32_t)(grub_uint64_t)(x))
+#endif
+
/* The type for representing a file offset. */
typedef grub_uint64_t grub_off_t;
diff --git a/kern/i386/coreboot/init.c b/kern/i386/coreboot/init.c
index 1348488..2f7e875 100644
--- a/kern/i386/coreboot/init.c
+++ b/kern/i386/coreboot/init.c
@@ -82,16 +82,11 @@ grub_machine_init (void)
#if GRUB_CPU_SIZEOF_VOID_P == 4
/* Restrict ourselves to 32-bit memory space. */
if (addr > ULONG_MAX)
- {
- grub_upper_mem = ULONG_MAX;
- return 0;
- }
+ return 0;
if (addr + size > ULONG_MAX)
size = ULONG_MAX - addr;
#endif
- grub_upper_mem = grub_max (grub_upper_mem, addr + size);
-
if (type != GRUB_MACHINE_MEMORY_AVAILABLE)
return 0;
@@ -128,9 +123,6 @@ grub_machine_init (void)
grub_machine_mmap_init ();
grub_machine_mmap_iterate (heap_init);
- /* This variable indicates size, not offset. */
- grub_upper_mem -= GRUB_MEMORY_MACHINE_UPPER_START;
-
grub_tsc_init ();
}
diff --git a/kern/i386/pc/init.c b/kern/i386/pc/init.c
index 6191412..c64497e 100644
--- a/kern/i386/pc/init.c
+++ b/kern/i386/pc/init.c
@@ -45,7 +45,6 @@ static int num_regions;
grub_addr_t grub_os_area_addr;
grub_size_t grub_os_area_size;
-grub_size_t grub_lower_mem, grub_upper_mem;
void
grub_arch_sync_caches (void *address __attribute__ ((unused)),
@@ -133,6 +132,7 @@ void
grub_machine_init (void)
{
int i;
+ int grub_lower_mem;
/* Initialize the console as early as possible. */
grub_console_init ();
@@ -197,7 +197,6 @@ grub_machine_init (void)
{
grub_size_t quarter = mem_regions[i].size >> 2;
- grub_upper_mem = mem_regions[i].size;
grub_os_area_addr = mem_regions[i].addr;
grub_os_area_size = mem_regions[i].size - quarter;
grub_mm_init_region ((void *) (grub_os_area_addr + grub_os_area_size),
diff --git a/loader/i386/bsd.c b/loader/i386/bsd.c
index 355cb3f..ea51aa2 100644
--- a/loader/i386/bsd.c
+++ b/loader/i386/bsd.c
@@ -313,30 +313,36 @@ static grub_err_t
grub_openbsd_boot (void)
{
char *buf = (char *) GRUB_BSD_TEMP_BUFFER;
- struct grub_machine_mmap_entry mmap;
struct grub_openbsd_bios_mmap *pm;
struct grub_openbsd_bootargs *pa;
- grub_uint32_t bootdev, biosdev, unit, slice, part, cont;
+ grub_uint32_t bootdev, biosdev, unit, slice, part;
+
+ auto int NESTED_FUNC_ATTR hook (grub_uint64_t, grub_uint64_t, grub_uint32_t);
+ int NESTED_FUNC_ATTR hook (grub_uint64_t addr, grub_uint64_t size, grub_uint32_t type)
+ {
+ pm->addr = addr;
+ pm->len = size;
+
+ switch (type)
+ {
+ case GRUB_MACHINE_MEMORY_AVAILABLE:
+ pm->type = OPENBSD_MMAP_AVAILABLE;
+ break;
+
+ default:
+ pm->type = OPENBSD_MMAP_RESERVED;
+ break;
+ }
+ pm++;
+
+ return 0;
+ }
pa = (struct grub_openbsd_bootargs *) buf;
pa->ba_type = OPENBSD_BOOTARG_MMAP;
pm = (struct grub_openbsd_bios_mmap *) (pa + 1);
- cont = grub_get_mmap_entry (&mmap, 0);
- if (mmap.size)
- do
- {
- pm->addr = mmap.addr;
- pm->len = mmap.len;
- pm->type = mmap.type;
- pm++;
-
- if (!cont)
- break;
-
- cont = grub_get_mmap_entry (&mmap, cont);
- }
- while (mmap.size);
+ grub_mmap_iterate (hook);
pa->ba_size = (char *) pm - (char *) pa;
pa->ba_next = (struct grub_openbsd_bootargs *) pm;
@@ -349,7 +355,8 @@ grub_openbsd_boot (void)
(part << OPENBSD_B_PARTSHIFT));
grub_unix_real_boot (entry, bootflags, bootdev, OPENBSD_BOOTARG_APIVER,
- 0, grub_upper_mem >> 10, grub_lower_mem >> 10,
+ 0, grub_mmap_get_upper () >> 10,
+ grub_mmap_get_lower () >> 10,
(char *) pa - buf, buf);
/* Not reached. */
@@ -377,7 +384,8 @@ grub_netbsd_boot (void)
bootinfo->bi_data[0] = rootdev;
grub_unix_real_boot (entry, bootflags, 0, bootinfo,
- 0, grub_upper_mem >> 10, grub_lower_mem >> 10);
+ 0, grub_mmap_get_upper () >> 10,
+ grub_mmap_get_lower () >> 10);
/* Not reached. */
return GRUB_ERR_NONE;
diff --git a/loader/i386/ieee1275/linux.c b/loader/i386/ieee1275/linux.c
index 2f52880..a563577 100644
--- a/loader/i386/ieee1275/linux.c
+++ b/loader/i386/ieee1275/linux.c
@@ -100,7 +100,7 @@ grub_linux_boot (void)
grub_memset ((char *) params, 0, GRUB_OFW_LINUX_CL_OFFSET);
- params->alt_mem = grub_upper_mem >> 10;
+ params->alt_mem = grub_mmap_get_upper () >> 10;
params->ext_mem = params->alt_mem;
lh->cmd_line_ptr = (char *)
diff --git a/loader/i386/linux.c b/loader/i386/linux.c
index 01d10d5..aac9bf3 100644
--- a/loader/i386/linux.c
+++ b/loader/i386/linux.c
@@ -168,7 +168,7 @@ find_mmap_size (void)
return 0;
}
- grub_machine_mmap_iterate (hook);
+ grub_mmap_iterate (hook);
mmap_size = count * sizeof (struct grub_e820_mmap);
@@ -237,7 +237,7 @@ allocate_pages (grub_size_t prot_size)
return 0;
}
- grub_machine_mmap_iterate (hook);
+ grub_mmap_iterate (hook);
if (! real_mode_mem)
{
grub_error (GRUB_ERR_OUT_OF_MEMORY, "cannot allocate real mode pages");
@@ -404,7 +404,7 @@ grub_linux_boot (void)
}
e820_num = 0;
- grub_machine_mmap_iterate (hook);
+ grub_mmap_iterate (hook);
params->mmap_size = e820_num;
/* Hardware interrupts are not safe any longer. */
diff --git a/loader/i386/multiboot.c b/loader/i386/multiboot.c
index 27042a5..d38590f 100644
--- a/loader/i386/multiboot.c
+++ b/loader/i386/multiboot.c
@@ -100,7 +100,7 @@ grub_get_multiboot_mmap_len (void)
return 0;
}
- grub_machine_mmap_iterate (hook);
+ grub_mmap_iterate (hook);
return count * sizeof (struct grub_multiboot_mmap_entry);
}
@@ -123,7 +123,7 @@ grub_fill_multiboot_mmap (struct grub_multiboot_mmap_entry *first_entry)
return 0;
}
- grub_machine_mmap_iterate (hook);
+ grub_mmap_iterate (hook);
}
#define MULTIBOOT_LOAD_ELF64
@@ -342,8 +342,8 @@ grub_multiboot (int argc, char *argv[])
grub_multiboot_payload_entry_offset);
/* Convert from bytes to kilobytes. */
- mbi->mem_lower = grub_lower_mem / 1024;
- mbi->mem_upper = grub_upper_mem / 1024;
+ mbi->mem_lower = grub_mmap_get_lower () / 1024;
+ mbi->mem_upper = grub_mmap_get_upper () / 1024;
mbi->flags |= MULTIBOOT_INFO_MEMORY;
cmdline = p = cmdline_addr (grub_multiboot_payload_orig);
diff --git a/loader/i386/pc/linux.c b/loader/i386/pc/linux.c
index 8ff97f4..34a4ebc 100644
--- a/loader/i386/pc/linux.c
+++ b/loader/i386/pc/linux.c
@@ -108,8 +108,9 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
lh.type_of_loader = GRUB_LINUX_BOOT_LOADER_TYPE;
/* Put the real mode part at as a high location as possible. */
- grub_linux_real_addr = (char *) (grub_lower_mem
- - GRUB_LINUX_SETUP_MOVE_SIZE);
+ grub_linux_real_addr
+ = (char *) UINT_TO_PTR (grub_mmap_get_lower ()
+ - GRUB_LINUX_SETUP_MOVE_SIZE);
/* But it must not exceed the traditional area. */
if (grub_linux_real_addr > (char *) GRUB_LINUX_OLD_REAL_MODE_ADDR)
grub_linux_real_addr = (char *) GRUB_LINUX_OLD_REAL_MODE_ADDR;
@@ -159,12 +160,12 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
}
if (grub_linux_real_addr + GRUB_LINUX_SETUP_MOVE_SIZE
- > (char *) grub_lower_mem)
+ > (char *) UINT_TO_PTR (grub_mmap_get_lower ()))
{
grub_error (GRUB_ERR_OUT_OF_RANGE,
"too small lower memory (0x%x > 0x%x)",
- grub_linux_real_addr + GRUB_LINUX_SETUP_MOVE_SIZE,
- (char *) grub_lower_mem);
+ grub_linux_real_addr + GRUB_LINUX_SETUP_MOVE_SIZE,
+ (int) grub_mmap_get_lower ());
goto fail;
}
diff --git a/mmap/i386/pc/mmap.c b/mmap/i386/pc/mmap.c
new file mode 100644
index 0000000..3b45de4
--- /dev/null
+++ b/mmap/i386/pc/mmap.c
@@ -0,0 +1,240 @@
+/* Mmap management. */
+/*
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/machine/memory.h>
+#include <grub/memory.h>
+#include <grub/loader.h>
+#include <grub/misc.h>
+#include <grub/term.h>
+
+#define min(a,b) (((a) < (b)) ? (a) : (b))
+
+static void *hooktarget = 0;
+
+extern grub_uint8_t grub_machine_mmaphook_start;
+extern grub_uint8_t grub_machine_mmaphook_end;
+extern grub_uint8_t grub_machine_mmaphook_int12;
+extern grub_uint8_t grub_machine_mmaphook_int15;
+
+static grub_uint16_t grub_machine_mmaphook_int12offset = 0;
+static grub_uint16_t grub_machine_mmaphook_int12segment = 0;
+extern grub_uint16_t grub_machine_mmaphook_int15offset;
+extern grub_uint16_t grub_machine_mmaphook_int15segment;
+
+extern grub_uint16_t grub_machine_mmaphook_mmap_num;
+extern grub_uint16_t grub_machine_mmaphook_kblow;
+extern grub_uint16_t grub_machine_mmaphook_kbin16mb;
+extern grub_uint16_t grub_machine_mmaphook_64kbin4gb;
+
+struct grub_e820_mmap_entry
+{
+ grub_uint64_t addr;
+ grub_uint64_t len;
+ grub_uint32_t type;
+} __attribute__((packed));
+
+
+static grub_err_t
+preboot (int noreturn __attribute__ ((unused)))
+{
+ struct grub_e820_mmap_entry *hookmmap, *hookmmapcur;
+ auto int NESTED_FUNC_ATTR fill_hook (grub_uint64_t, grub_uint64_t,
+ grub_uint32_t);
+ int NESTED_FUNC_ATTR fill_hook (grub_uint64_t addr, grub_uint64_t size,
+ grub_uint32_t type)
+ {
+ grub_dprintf ("mmap", "mmap chunk %llx-%llx:%x\n", addr, addr + size, type);
+ hookmmapcur->addr = addr;
+ hookmmapcur->len = size;
+ hookmmapcur->type = type;
+ hookmmapcur++;
+ return 0;
+ }
+
+ if (! hooktarget)
+ return grub_error (GRUB_ERR_OUT_OF_MEMORY,
+ "no space is allocated for memory hook");
+
+ grub_dprintf ("mmap", "installing preboot handlers\n");
+
+ hookmmapcur = hookmmap = (struct grub_e820_mmap_entry *)
+ ((grub_uint8_t *) hooktarget + (&grub_machine_mmaphook_end
+ - &grub_machine_mmaphook_start));
+
+ grub_mmap_iterate (fill_hook);
+ grub_machine_mmaphook_mmap_num = hookmmapcur - hookmmap;
+
+ grub_machine_mmaphook_kblow = grub_mmap_get_lower () >> 10;
+ grub_machine_mmaphook_kbin16mb
+ = min (grub_mmap_get_upper (),0x3f00000ULL) >> 10;
+ grub_machine_mmaphook_64kbin4gb
+ = min (grub_mmap_get_post64 (), 0xfc000000ULL) >> 16;
+
+ /* Correct BDA. */
+ *((grub_uint16_t *) 0x413) = grub_mmap_get_lower () >> 10;
+
+ /* Save old interrupt handlers. */
+ grub_machine_mmaphook_int12offset = *((grub_uint16_t *) 0x48);
+ grub_machine_mmaphook_int12segment = *((grub_uint16_t *) 0x4a);
+ grub_machine_mmaphook_int15offset = *((grub_uint16_t *) 0x54);
+ grub_machine_mmaphook_int15segment = *((grub_uint16_t *) 0x56);
+
+ grub_dprintf ("mmap", "hooktarget = %p\n", hooktarget);
+
+ /* Install the interrupt handlers. */
+ grub_memcpy (hooktarget, &grub_machine_mmaphook_start,
+ &grub_machine_mmaphook_end - &grub_machine_mmaphook_start);
+
+ *((grub_uint16_t *) 0x4a) = PTR_TO_UINT32 (hooktarget) >> 4;
+ *((grub_uint16_t *) 0x56) = PTR_TO_UINT32 (hooktarget) >> 4;
+ *((grub_uint16_t *) 0x48) = &grub_machine_mmaphook_int12
+ - &grub_machine_mmaphook_start;
+ *((grub_uint16_t *) 0x54) = &grub_machine_mmaphook_int15
+ - &grub_machine_mmaphook_start;
+
+ return GRUB_ERR_NONE;
+}
+
+static grub_err_t
+preboot_rest (void)
+{
+ /* Restore old interrupt handlers. */
+ *((grub_uint16_t *) 0x48) = grub_machine_mmaphook_int12offset;
+ *((grub_uint16_t *) 0x4a) = grub_machine_mmaphook_int12segment;
+ *((grub_uint16_t *) 0x54) = grub_machine_mmaphook_int15offset;
+ *((grub_uint16_t *) 0x56) = grub_machine_mmaphook_int15segment;
+
+ return GRUB_ERR_NONE;
+}
+
+static grub_err_t
+malloc_hook (void)
+{
+ static int reentry = 0;
+ static int mmapregion = 0;
+ static int slots_available = 0;
+ int hooksize;
+ int regcount = 0;
+ grub_uint64_t highestlow = 0;
+ auto int NESTED_FUNC_ATTR count_hook (grub_uint64_t, grub_uint64_t,
+ grub_uint32_t);
+ int NESTED_FUNC_ATTR count_hook (grub_uint64_t addr __attribute__ ((unused)),
+ grub_uint64_t size __attribute__ ((unused)),
+ grub_uint32_t type __attribute__ ((unused)))
+ {
+ regcount++;
+ return 0;
+ }
+
+ auto int NESTED_FUNC_ATTR find_hook (grub_uint64_t, grub_uint64_t,
+ grub_uint32_t);
+ int NESTED_FUNC_ATTR find_hook (grub_uint64_t start, grub_uint64_t size,
+ grub_uint32_t type)
+ {
+ grub_uint64_t end = start + size;
+ if (type != GRUB_MACHINE_MEMORY_AVAILABLE)
+ return 0;
+ if (end > 0x100000)
+ end = 0x100000;
+ if (end > start + hooksize
+ && highestlow < ((end - hooksize) & (~0xf)) )
+ highestlow = (end - hooksize) & (~0xf);
+ return 0;
+ }
+
+ if (reentry)
+ return GRUB_ERR_NONE;
+
+ grub_dprintf ("mmap", "registering\n");
+
+ grub_mmap_iterate (count_hook);
+
+ /* Mapping hook itself may introduce up to 2 additional regions. */
+ regcount += 2;
+
+ if (regcount <= slots_available)
+ return GRUB_ERR_NONE;
+
+ if (mmapregion)
+ {
+ grub_mmap_unregister (mmapregion);
+ mmapregion = 0;
+ hooktarget = 0;
+ }
+
+ hooksize = &grub_machine_mmaphook_end - &grub_machine_mmaphook_start
+ + regcount * sizeof (struct grub_e820_mmap_entry);
+ /* Allocate an integer number of KiB. */
+ hooksize = ((hooksize - 1) | 0x3ff) + 1;
+ slots_available = (hooksize - (&grub_machine_mmaphook_end
+ - &grub_machine_mmaphook_start))
+ / sizeof (struct grub_e820_mmap_entry);
+
+ /* FIXME: use low-memory mm allocation once it's available. */
+ grub_mmap_iterate (find_hook);
+ if (! highestlow)
+ {
+ slots_available = 0;
+ hooktarget = 0;
+ return grub_error (GRUB_ERR_OUT_OF_MEMORY, "No space for mmap hook");
+ }
+
+ hooktarget = UINT_TO_PTR (highestlow);
+
+ reentry = 1;
+ mmapregion = grub_mmap_register (PTR_TO_UINT64 (hooktarget), hooksize,
+ GRUB_MACHINE_MEMORY_RESERVED);
+ reentry = 0;
+ if (! mmapregion)
+ {
+ slots_available = 0;
+ hooktarget = 0;
+ return grub_errno;
+ }
+ return GRUB_ERR_NONE;
+}
+
+grub_err_t
+grub_machine_mmap_register (grub_uint64_t start __attribute__ ((unused)),
+ grub_uint64_t size __attribute__ ((unused)),
+ int type __attribute__ ((unused)),
+ int handle __attribute__ ((unused)))
+{
+ grub_err_t err;
+ static void *preb_handle = 0;
+
+ if ((err = malloc_hook ()))
+ return err;
+
+ if (! preb_handle)
+ {
+ grub_dprintf ("mmap", "adding preboot\n");
+ preb_handle = grub_loader_register_preboot_hook (preboot, preboot_rest,
+ -10);
+ if (! preb_handle)
+ return grub_errno;
+ }
+ return GRUB_ERR_NONE;
+}
+
+grub_err_t
+grub_machine_mmap_unregister (int handle __attribute__ ((unused)))
+{
+ return GRUB_ERR_NONE;
+}
diff --git a/mmap/i386/pc/mmap_helper.S b/mmap/i386/pc/mmap_helper.S
new file mode 100644
index 0000000..ab7c0d2
--- /dev/null
+++ b/mmap/i386/pc/mmap_helper.S
@@ -0,0 +1,122 @@
+/* Mmap management. */
+/*
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/symbol.h>
+
+#define DS(x) ((x) - segstart)
+
+segstart:
+VARIABLE(grub_machine_mmaphook_start)
+ .code16
+VARIABLE(grub_machine_mmaphook_int12)
+ push %ds
+ push %cs
+ pop %ds
+ movw DS (EXT_C (grub_machine_mmaphook_kblow)), %ax
+ pop %ds
+ iret
+
+VARIABLE(grub_machine_mmaphook_int15)
+ pushf
+ cmpw $0xe801, %ax
+ jz e801
+ cmpw $0xe820, %ax
+ jz e820
+ cmpb $0x88, %ah
+ jz h88
+ popf
+ /* ljmp */
+ .byte 0xea
+VARIABLE (grub_machine_mmaphook_int15offset)
+ .word 0
+VARIABLE (grub_machine_mmaphook_int15segment)
+ .word 0
+
+e801:
+ popf
+ push %ds
+ push %cs
+ pop %ds
+ movw DS (EXT_C (grub_machine_mmaphook_kbin16mb)), %ax
+ movw DS (EXT_C (grub_machine_mmaphook_64kbin4gb)), %bx
+ movw %ax, %cx
+ movw %bx, %dx
+ pop %ds
+ clc
+ iret
+
+h88:
+ popf
+ push %ds
+ push %cs
+ pop %ds
+ movw DS (EXT_C (grub_machine_mmaphook_kbin16mb)), %ax
+ pop %ds
+ clc
+ iret
+
+e820:
+ popf
+ push %ds
+ push %cs
+ pop %ds
+ cmpw $20, %cx
+ jb errexit
+ cmpw DS (EXT_C (grub_machine_mmaphook_mmap_num)), %bx
+ jae errexit
+ cmp $0x534d4150, %edx
+ jne errexit
+ push %si
+ push %di
+ movw $20, %cx
+ movw $(DS(mmaphook_mmap)), %si
+ mov %bx, %ax
+ imul $20, %ax
+ add %ax, %si
+ rep movsb
+ pop %di
+ pop %si
+ movl $20, %ecx
+ inc %bx
+ cmpw DS(EXT_C(grub_machine_mmaphook_mmap_num)), %bx
+ jb noclean
+ xor %bx, %bx
+noclean:
+ mov $0x534d4150, %eax
+ pop %ds
+ clc
+ iret
+errexit:
+ mov $0x534d4150, %eax
+ pop %ds
+ stc
+ xor %bx, %bx
+ iret
+
+VARIABLE(grub_machine_mmaphook_mmap_num)
+ .word 0
+VARIABLE(grub_machine_mmaphook_kblow)
+ .word 0
+VARIABLE (grub_machine_mmaphook_kbin16mb)
+ .word 0
+VARIABLE (grub_machine_mmaphook_64kbin4gb)
+ .word 0
+mmaphook_mmap:
+ /* Memory map is placed just after the interrupt handlers. */
+VARIABLE(grub_machine_mmaphook_end)
diff --git a/mmap/i386/uppermem.c b/mmap/i386/uppermem.c
new file mode 100644
index 0000000..1fb339d
--- /dev/null
+++ b/mmap/i386/uppermem.c
@@ -0,0 +1,85 @@
+/* Compute amount of lower and upper memory till the first hole. */
+/*
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/machine/memory.h>
+#include <grub/mm.h>
+#include <grub/misc.h>
+
+grub_uint64_t
+grub_mmap_get_lower (void)
+{
+ grub_uint64_t lower = 0;
+
+ auto int NESTED_FUNC_ATTR hook (grub_uint64_t, grub_uint64_t, grub_uint32_t);
+ int NESTED_FUNC_ATTR hook (grub_uint64_t addr, grub_uint64_t size,
+ grub_uint32_t type)
+ {
+ if (type != GRUB_MACHINE_MEMORY_AVAILABLE)
+ return 0;
+ if (addr == 0)
+ lower = size;
+ return 0;
+ }
+
+ grub_mmap_iterate (hook);
+ if (lower > 0x100000)
+ lower = 0x100000;
+ return lower;
+}
+
+grub_uint64_t
+grub_mmap_get_upper (void)
+{
+ grub_uint64_t upper = 0;
+
+ auto int NESTED_FUNC_ATTR hook (grub_uint64_t, grub_uint64_t, grub_uint32_t);
+ int NESTED_FUNC_ATTR hook (grub_uint64_t addr, grub_uint64_t size,
+ grub_uint32_t type)
+ {
+ if (type != GRUB_MACHINE_MEMORY_AVAILABLE)
+ return 0;
+ if (addr <= 0x100000 && addr + size > 0x100000)
+ upper = addr + size - 0x100000;
+ return 0;
+ }
+
+ grub_mmap_iterate (hook);
+ return upper;
+}
+
+/* Count the continous bytes after 64 MiB. */
+grub_uint64_t
+grub_mmap_get_post64 (void)
+{
+ grub_uint64_t post64 = 0;
+
+ auto int NESTED_FUNC_ATTR hook (grub_uint64_t, grub_uint64_t, grub_uint32_t);
+ int NESTED_FUNC_ATTR hook (grub_uint64_t addr, grub_uint64_t size,
+ grub_uint32_t type)
+ {
+ if (type != GRUB_MACHINE_MEMORY_AVAILABLE)
+ return 0;
+ if (addr <= 0x4000000 && addr + size > 0x4000000)
+ post64 = addr + size - 0x4000000;
+ return 0;
+ }
+
+ grub_mmap_iterate (hook);
+ return post64;
+}
diff --git a/mmap/mmap.c b/mmap/mmap.c
new file mode 100644
index 0000000..01480ff
--- /dev/null
+++ b/mmap/mmap.c
@@ -0,0 +1,364 @@
+/* Mmap management. */
+/*
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/machine/memory.h>
+#include <grub/memory.h>
+#include <grub/err.h>
+#include <grub/misc.h>
+#include <grub/mm.h>
+#include <grub/command.h>
+#include <grub/dl.h>
+
+#ifndef GRUB_MMAP_REGISTER_BY_FIRMWARE
+
+struct region
+{
+ struct region *next;
+ grub_uint64_t start;
+ grub_uint64_t end;
+ int type;
+ int handle;
+};
+
+static struct region *overlays = 0;
+static int curhandle = 1;
+
+grub_err_t
+grub_mmap_iterate (int NESTED_FUNC_ATTR (*hook) (grub_uint64_t,
+ grub_uint64_t, grub_uint32_t))
+{
+ /* This function resolves overlapping regions and sorts the memory map.
+ It uses scanline (sweeping) algorithm.
+ */
+ /* If same page is used by multiple types it's resolved
+ according to priority:
+ 1 - free memory
+ 2 - memory usable by firmware-aware code
+ 3 - unusable memory
+ 4 - a range deliberately empty
+ */
+ int priority[GRUB_MACHINE_MEMORY_MAX_TYPE + 2] =
+ {
+#ifdef GRUB_MACHINE_MEMORY_AVAILABLE
+ [GRUB_MACHINE_MEMORY_AVAILABLE] = 1,
+#endif
+#ifdef GRUB_MACHINE_MEMORY_RESERVED
+ [GRUB_MACHINE_MEMORY_RESERVED] = 3,
+#endif
+#ifdef GRUB_MACHINE_MEMORY_ACPI
+ [GRUB_MACHINE_MEMORY_ACPI] = 2,
+#endif
+#ifdef GRUB_MACHINE_MEMORY_NVS
+ [GRUB_MACHINE_MEMORY_NVS] = 3,
+#endif
+ [GRUB_MACHINE_MEMORY_HOLE] = 4,
+ };
+
+ int i, k, done;
+
+ /* Scanline events. */
+ struct grub_mmap_scan
+ {
+ /* At which memory address. */
+ grub_uint64_t pos;
+ /* 0 = region starts, 1 = region ends. */
+ int type;
+ /* Which type of memory region? */
+ int memtype;
+ };
+ struct grub_mmap_scan *scanline_events;
+ struct grub_mmap_scan t;
+
+ /* Previous scanline event. */
+ grub_uint64_t lastaddr;
+ int lasttype;
+ /* Current scanline event. */
+ int curtype;
+ /* How many regions of given type overlap at current location? */
+ int present[GRUB_MACHINE_MEMORY_MAX_TYPE + 2];
+ /* Number of mmap chunks. */
+ int mmap_num;
+
+ struct region *cur;
+
+ auto int NESTED_FUNC_ATTR count_hook (grub_uint64_t, grub_uint64_t,
+ grub_uint32_t);
+ int NESTED_FUNC_ATTR count_hook (grub_uint64_t addr __attribute__ ((unused)),
+ grub_uint64_t size __attribute__ ((unused)),
+ grub_uint32_t type __attribute__ ((unused)))
+ {
+ mmap_num++;
+ return 0;
+ }
+
+ auto int NESTED_FUNC_ATTR fill_hook (grub_uint64_t, grub_uint64_t,
+ grub_uint32_t);
+ int NESTED_FUNC_ATTR fill_hook (grub_uint64_t addr,
+ grub_uint64_t size,
+ grub_uint32_t type)
+ {
+ scanline_events[i].pos = addr;
+ scanline_events[i].type = 0;
+ if (type <= GRUB_MACHINE_MEMORY_MAX_TYPE && priority[type])
+ scanline_events[i].memtype = type;
+ else
+ {
+ grub_dprintf ("mmap", "Unknown memory type %d. Assuming unusable\n",
+ type);
+ scanline_events[i].memtype = GRUB_MACHINE_MEMORY_RESERVED;
+ }
+ i++;
+
+ scanline_events[i].pos = addr + size;
+ scanline_events[i].type = 1;
+ scanline_events[i].memtype = scanline_events[i - 1].memtype;
+ i++;
+
+ return 0;
+ }
+
+ mmap_num = 0;
+ for (cur = overlays; cur; cur = cur->next)
+ mmap_num++;
+ grub_machine_mmap_iterate (count_hook);
+
+ /* Initialize variables. */
+ grub_memset (present, 0, sizeof (present));
+ scanline_events = (struct grub_mmap_scan *)
+ grub_malloc (sizeof (struct grub_mmap_scan) * 2 * mmap_num);
+
+ if (! scanline_events)
+ {
+ return grub_error (GRUB_ERR_OUT_OF_MEMORY,
+ "couldn't allocate space for new memory map");
+ }
+
+ /* Register scanline events. */
+ for (cur = overlays, i = 0; cur; cur = cur->next)
+ {
+ scanline_events[i].pos = cur->start;
+ scanline_events[i].type = 0;
+ if (cur->type == GRUB_MACHINE_MEMORY_HOLE
+ || (cur->type >= 0 && cur->type <= GRUB_MACHINE_MEMORY_MAX_TYPE
+ && priority[cur->type]))
+ scanline_events[i].memtype = cur->type;
+ else
+ scanline_events[i].memtype = GRUB_MACHINE_MEMORY_RESERVED;
+ i++;
+
+ scanline_events[i].pos = cur->end;
+ scanline_events[i].type = 1;
+ scanline_events[i].memtype = scanline_events[i - 1].memtype;
+ i++;
+ }
+
+ grub_machine_mmap_iterate (fill_hook);
+
+ /* Primitive bubble sort. It has complexity O(n^2) but since we're
+ unlikely to have more than 100 chunks it's probably one of the
+ fastest for one purpose. */
+ done = 1;
+ while (done)
+ {
+ done = 0;
+ for (i = 0; i < 2 * mmap_num - 1; i++)
+ if (scanline_events[i + 1].pos < scanline_events[i].pos
+ || (scanline_events[i + 1].pos == scanline_events[i].pos
+ && scanline_events[i + 1].type == 0
+ && scanline_events[i].type == 1))
+ {
+ t = scanline_events[i + 1];
+ scanline_events[i + 1] = scanline_events[i];
+ scanline_events[i] = t;
+ done = 1;
+ }
+ }
+
+ lastaddr = scanline_events[0].pos;
+ lasttype = scanline_events[0].memtype;
+ for (i = 0; i < 2 * mmap_num; i++)
+ {
+ /* Process event. */
+ if (scanline_events[i].type)
+ present[scanline_events[i].memtype]--;
+ else
+ present[scanline_events[i].memtype]++;
+
+ /* Determine current region type. */
+ curtype = -1;
+ for (k = 0; k <= GRUB_MACHINE_MEMORY_MAX_TYPE + 1; k++)
+ if (present[k] && (curtype == -1 || priority[k] > priority[curtype]))
+ curtype = k;
+
+ /* Anounce region to the hook if necessary. */
+ if ((curtype == -1 || curtype != lasttype)
+ && lastaddr != scanline_events[i].pos
+ && lasttype != -1
+ && lasttype != GRUB_MACHINE_MEMORY_HOLE
+ && hook (lastaddr, scanline_events[i].pos - lastaddr, lasttype))
+ {
+ grub_free (scanline_events);
+ return GRUB_ERR_NONE;
+ }
+
+ /* Update last values if necessary. */
+ if (curtype == -1 || curtype != lasttype)
+ {
+ lasttype = curtype;
+ lastaddr = scanline_events[i].pos;
+ }
+ }
+
+ grub_free (scanline_events);
+ return GRUB_ERR_NONE;
+}
+
+int
+grub_mmap_register (grub_uint64_t start, grub_uint64_t size, int type)
+{
+ struct region *cur;
+
+ grub_dprintf ("mmap", "registering\n");
+
+ cur = (struct region *) grub_malloc (sizeof (struct region));
+ if (! cur)
+ {
+ grub_error (GRUB_ERR_OUT_OF_MEMORY,
+ "couldn't allocate memory map overlay");
+ return 0;
+ }
+
+ cur->next = overlays;
+ cur->start = start;
+ cur->end = start + size;
+ cur->type = type;
+ cur->handle = curhandle++;
+ overlays = cur;
+
+ if (grub_machine_mmap_register (start, size, type, curhandle))
+ {
+ overlays = cur->next;
+ grub_free (cur);
+ return 0;
+ }
+
+ return cur->handle;
+}
+
+grub_err_t
+grub_mmap_unregister (int handle)
+{
+ struct region *cur, *prev;
+
+ for (cur = overlays, prev = 0; cur; prev= cur, cur = cur->next)
+ if (handle == cur->handle)
+ {
+ grub_err_t err;
+ if ((err = grub_machine_mmap_unregister (handle)))
+ return err;
+
+ if (prev)
+ prev->next = cur->next;
+ else
+ overlays = cur->next;
+ grub_free (cur);
+ return GRUB_ERR_NONE;
+ }
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "mmap overlay not found");
+}
+
+#endif /* ! GRUB_MMAP_REGISTER_BY_FIRMWARE */
+
+#define CHUNK_SIZE 0x400
+
+static grub_err_t
+grub_cmd_badram (grub_command_t cmd __attribute__ ((unused)),
+ int argc, char **args)
+{
+ char * str;
+ grub_uint64_t badaddr, badmask;
+
+ auto int NESTED_FUNC_ATTR hook (grub_uint64_t, grub_uint64_t, grub_uint32_t);
+ int NESTED_FUNC_ATTR hook (grub_uint64_t addr,
+ grub_uint64_t size,
+ grub_uint32_t type __attribute__ ((unused)))
+ {
+ grub_uint64_t start;
+ grub_dprintf ("badram", "hook %llx+%llx\n", addr,size);
+
+ /* FIXME: use more efficient algorithm. */
+ for (start = (addr & ~(CHUNK_SIZE - 1)); start < addr + size;
+ start += CHUNK_SIZE)
+ if (((start ^ badaddr) & badmask) == 0)
+ {
+ grub_dprintf ("badram", "%llx is a bad boy\n", start);
+ grub_mmap_register (start, CHUNK_SIZE, GRUB_MACHINE_MEMORY_HOLE);
+ }
+ return 0;
+ }
+
+ if (argc != 1)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "badram string required");
+
+ grub_dprintf ("badram", "executing badram\n");
+
+ str = args[0];
+
+ while (1)
+ {
+ /* Parse address and mask. */
+ badaddr = grub_strtoull (str, &str, 16);
+ if (*str == ',')
+ str++;
+ badmask = grub_strtoull (str, &str, 16);
+ if (*str == ',')
+ str++;
+
+ if (grub_errno == GRUB_ERR_BAD_NUMBER)
+ {
+ grub_errno = 0;
+ return GRUB_ERR_NONE;
+ }
+
+ /* When part of a page is tainted, we discard the whole of it. There's
+ no point in providing sub-page chunks. */
+ badmask &= ~(CHUNK_SIZE - 1);
+
+ grub_dprintf ("badram", "badram %llx:%llx\n", badaddr, badmask);
+
+ grub_mmap_iterate (hook);
+ }
+}
+
+static grub_command_t cmd;
+
+\f
+GRUB_MOD_INIT(mmap)
+{
+ (void) mod; /* To stop warning. */
+ cmd = grub_register_command ("badram", grub_cmd_badram,
+ "badram ADDR1,MASK1[,ADDR2,MASK2[,...]]",
+ "declare memory regions as badram");
+}
+
+GRUB_MOD_FINI(mmap)
+{
+ grub_unregister_command (cmd);
+}
+
next reply other threads:[~2009-04-11 21:01 UTC|newest]
Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top
2009-04-11 21:01 phcoder [this message]
2009-04-26 14:42 ` mmap services Vladimir 'phcoder' Serbinenko
2009-04-30 13:36 ` Vladimir 'phcoder' Serbinenko
2009-04-30 13:46 ` David Miller
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=49E1051F.6090704@gmail.com \
--to=phcoder@gmail.com \
--cc=grub-devel@gnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.