2008-08-12 Robert Millan
* conf/i386-pc.rmk (kernel_img_SOURCES): Add `kern/i386/pc/mmap.c'.
* include/grub/i386/pc/init.h: Include `'.
(GRUB_MACHINE_MEMORY_AVAILABLE, GRUB_MACHINE_MEMORY_RESERVED): New
macros.
(grub_mmap_iterate): New function declaration.
(struct grub_machine_mmap_entry): Move from here ...
* include/grub/multiboot.h (struct grub_mmap_entry): ... to here.
Update all users.
(GRUB_MMAP_MEMORY_AVAILABLE, GRUB_MMAP_MEMORY_RESERVED): New
macros.
* kern/i386/pc/init.c (grub_machine_init): Replace hardcoded region
type check value with `GRUB_MACHINE_MEMORY_AVAILABLE'.
Move e820 parsing from here ...
* kern/i386/pc/mmap.c: New file.
(grub_mmap_iterate): ... to here.
* include/grub/i386/coreboot/memory.h: Remove `'.
(GRUB_LINUXBIOS_MEMORY_AVAILABLE): Rename (for consistency) to ...
(GRUB_MACHINE_MEMORY_AVAILABLE): ... this. Update all users.
(grub_available_iterate): Redeclare to return `void', and redeclare
its hook to use grub_uint64_t as addr and size parameters, and rename
to ...
(grub_mmap_iterate): ... this. Update all users.
* kern/i386/coreboot/mmap.c (grub_mmap_iterate): Simplify parser loop
to make it more readable.
* loader/i386/pc/multiboot.c (mmap_addr, mmap_length): New variables.
(grub_get_multiboot_mmap_len, grub_fill_multiboot_mmap): New functions.
(grub_multiboot): Allocate an extra region after the payload, and fill
it with a Multiboot memory map. Adjust a.out loader to calculate size
with the extra space.
(grub_multiboot_load_elf32): Adjust elf32 loader to calculate size
with the extra space.
Index: conf/i386-pc.rmk
===================================================================
--- conf/i386-pc.rmk (revision 1802)
+++ conf/i386-pc.rmk (working copy)
@@ -43,7 +43,8 @@
kern/disk.c kern/dl.c kern/file.c kern/fs.c kern/err.c \
kern/misc.c kern/mm.c kern/loader.c kern/rescue.c kern/term.c \
kern/time.c \
- kern/i386/dl.c kern/i386/pc/init.c kern/parser.c kern/partition.c \
+ kern/i386/dl.c kern/i386/pc/init.c kern/i386/pc/mmap.c \
+ kern/parser.c kern/partition.c \
kern/i386/tsc.c kern/i386/pit.c \
kern/generic/rtc_get_time_ms.c \
kern/generic/millisleep.c \
Index: kern/i386/pc/init.c
===================================================================
--- kern/i386/pc/init.c (revision 1802)
+++ kern/i386/pc/init.c (working copy)
@@ -132,9 +132,6 @@
void
grub_machine_init (void)
{
- grub_uint32_t cont;
- struct grub_machine_mmap_entry *entry
- = (struct grub_machine_mmap_entry *) GRUB_MEMORY_MACHINE_SCRATCH_ADDR;
int i;
/* Initialize the console as early as possible. */
@@ -156,55 +153,35 @@
add_mem_region (GRUB_MEMORY_MACHINE_RESERVED_END,
grub_lower_mem - GRUB_MEMORY_MACHINE_RESERVED_END);
- /* Check if grub_get_mmap_entry works. */
- cont = grub_get_mmap_entry (entry, 0);
-
- if (entry->size)
- do
- {
- /* Avoid the lower memory. */
- if (entry->addr < 0x100000)
- {
- if (entry->len <= 0x100000 - entry->addr)
- goto next;
-
- entry->len -= 0x100000 - entry->addr;
- entry->addr = 0x100000;
- }
-
- /* Ignore >4GB. */
- if (entry->addr <= 0xFFFFFFFF && entry->type == 1)
- {
- grub_addr_t addr;
- grub_size_t len;
-
- addr = (grub_addr_t) entry->addr;
- len = ((addr + entry->len > 0xFFFFFFFF)
- ? 0xFFFFFFFF - addr
- : (grub_size_t) entry->len);
- add_mem_region (addr, len);
- }
-
- next:
- if (! cont)
- break;
-
- cont = grub_get_mmap_entry (entry, cont);
- }
- while (entry->size);
- else
+ auto int hook (grub_uint64_t, grub_uint64_t, grub_uint32_t);
+ int hook (grub_uint64_t addr, grub_uint64_t size, grub_uint32_t type)
{
- grub_uint32_t eisa_mmap = grub_get_eisa_mmap ();
-
- if (eisa_mmap)
+ /* Avoid the lower memory. */
+ if (addr < 0x100000)
{
- add_mem_region (0x100000, (eisa_mmap & 0xFFFF) << 10);
- add_mem_region (0x1000000, eisa_mmap & ~0xFFFF);
+ if (size <= 0x100000 - addr)
+ return 0;
+
+ size -= 0x100000 - addr;
+ addr = 0x100000;
}
- else
- add_mem_region (0x100000, grub_get_memsize (1) << 10);
+
+ /* Ignore >4GB. */
+ if (addr <= 0xFFFFFFFF && type == GRUB_MMAP_MEMORY_AVAILABLE)
+ {
+ grub_size_t len;
+
+ len = (grub_size_t) ((addr + size > 0xFFFFFFFF)
+ ? 0xFFFFFFFF - addr
+ : size);
+ add_mem_region (addr, len);
+ }
+
+ return 0;
}
+ grub_mmap_iterate (hook);
+
compact_mem_regions ();
/* Add the memory regions to free memory, except for the region starting
Index: kern/i386/pc/mmap.c
===================================================================
--- kern/i386/pc/mmap.c (revision 0)
+++ kern/i386/pc/mmap.c (revision 0)
@@ -0,0 +1,60 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2002,2003,2004,2005,2006,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 .
+ */
+
+#include
+#include
+#include
+
+void
+grub_mmap_iterate (int (*hook) (grub_uint64_t, grub_uint64_t, grub_uint32_t))
+{
+ grub_uint32_t cont;
+ struct grub_mmap_entry *entry
+ = (struct grub_mmap_entry *) GRUB_MEMORY_MACHINE_SCRATCH_ADDR;
+
+ /* Check if grub_get_mmap_entry works. */
+ cont = grub_get_mmap_entry (entry, 0);
+
+ if (entry->size)
+ do
+ {
+ if (hook (entry->addr, entry->len,
+ /* Multiboot mmaps have been defined to match with the E820 definition.
+ Therefore, we can just pass type through. */
+ entry->type))
+ break;
+
+ if (! cont)
+ break;
+
+ cont = grub_get_mmap_entry (entry, cont);
+ }
+ while (entry->size);
+ else
+ {
+ grub_uint32_t eisa_mmap = grub_get_eisa_mmap ();
+
+ if (eisa_mmap)
+ {
+ if (hook (0x100000, (eisa_mmap & 0xFFFF) << 10, GRUB_MMAP_MEMORY_AVAILABLE) == 0)
+ hook (0x1000000, eisa_mmap & ~0xFFFF, GRUB_MMAP_MEMORY_AVAILABLE);
+ }
+ else
+ hook (0x100000, grub_get_memsize (1) << 10, GRUB_MMAP_MEMORY_AVAILABLE);
+ }
+}
Index: kern/i386/coreboot/init.c
===================================================================
--- kern/i386/coreboot/init.c (revision 1802)
+++ kern/i386/coreboot/init.c (working copy)
@@ -82,12 +82,9 @@
grub_lower_mem = GRUB_MEMORY_MACHINE_LOWER_USABLE;
grub_upper_mem = 0;
- auto int heap_init (mem_region_t);
- int heap_init (mem_region_t mem_region)
+ auto int heap_init (grub_uint64_t, grub_uint64_t, grub_uint32_t);
+ int heap_init (grub_uint64_t addr, grub_uint64_t size, grub_uint32_t type)
{
- grub_uint64_t addr = mem_region->addr;
- grub_uint64_t size = mem_region->size;
-
#if GRUB_CPU_SIZEOF_VOID_P == 4
/* Restrict ourselves to 32-bit memory space. */
if (addr > ULONG_MAX)
@@ -101,7 +98,7 @@
grub_upper_mem = grub_max (grub_upper_mem, addr + size);
- if (mem_region->type != GRUB_LINUXBIOS_MEMORY_AVAILABLE)
+ if (type != GRUB_MACHINE_MEMORY_AVAILABLE)
return 0;
/* Avoid the lower memory. */
@@ -134,7 +131,7 @@
return 0;
}
- grub_available_iterate (heap_init);
+ grub_mmap_iterate (heap_init);
/* This variable indicates size, not offset. */
grub_upper_mem -= GRUB_MEMORY_MACHINE_UPPER_START;
Index: kern/i386/coreboot/mmap.c
===================================================================
--- kern/i386/coreboot/mmap.c (revision 1802)
+++ kern/i386/coreboot/mmap.c (working copy)
@@ -63,8 +63,8 @@
return 0;
}
-grub_err_t
-grub_available_iterate (int (*hook) (mem_region_t))
+void
+grub_mmap_iterate (int (*hook) (grub_uint64_t, grub_uint64_t, grub_uint32_t))
{
mem_region_t mem_region;
@@ -77,11 +77,17 @@
mem_region =
(mem_region_t) ((long) table_item +
sizeof (struct grub_linuxbios_table_item));
- for (; (long) mem_region < (long) table_item + (long) table_item->size;
- mem_region++)
- if (hook (mem_region))
- return 1;
+ while ((long) mem_region < (long) table_item + (long) table_item->size)
+ {
+ if (hook (mem_region->addr, mem_region->size,
+ /* Multiboot mmaps match with the coreboot mmap definition.
+ Therefore, we can just pass type through. */
+ mem_region->type))
+ return 1;
+ mem_region++;
+ }
+
return 0;
}
Index: include/grub/i386/pc/init.h
===================================================================
--- include/grub/i386/pc/init.h (revision 1802)
+++ include/grub/i386/pc/init.h (working copy)
@@ -1,6 +1,6 @@
/*
* GRUB -- GRand Unified Bootloader
- * Copyright (C) 2002,2004,2005,2007 Free Software Foundation, Inc.
+ * Copyright (C) 2002,2004,2005,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
@@ -21,6 +21,8 @@
#include
#include
+#include /* For struct grub_mmap_entry, which is also
+ needed by Multiboot. */
/* Get the memory size in KB. If EXTENDED is zero, return conventional
memory, otherwise return extended memory. */
@@ -30,19 +32,18 @@
in 1KB parts, and upper 16 bits are above 16MB in 64KB parts. */
grub_uint32_t grub_get_eisa_mmap (void);
-struct grub_machine_mmap_entry
-{
- grub_uint32_t size;
- grub_uint64_t addr;
- grub_uint64_t len;
- grub_uint32_t type;
-} __attribute__((packed));
+/* Multiboot mmaps have been defined to match with the E820 definition. */
+#define GRUB_MACHINE_MEMORY_AVAILABLE GRUB_MMAP_MEMORY_AVAILABLE
+#define GRUB_MACHINE_MEMORY_RESERVED GRUB_MMAP_MEMORY_RESERVED
/* Get a memory map entry. Return next continuation value. Zero means
the end. */
-grub_uint32_t EXPORT_FUNC(grub_get_mmap_entry) (struct grub_machine_mmap_entry *entry,
+grub_uint32_t EXPORT_FUNC(grub_get_mmap_entry) (struct grub_mmap_entry *entry,
grub_uint32_t cont);
+void EXPORT_FUNC(grub_mmap_iterate)
+ (int (*hook) (grub_uint64_t, grub_uint64_t, grub_uint32_t));
+
/* Turn on/off Gate A20. */
void grub_gate_a20 (int on);
Index: include/grub/i386/coreboot/memory.h
===================================================================
--- include/grub/i386/coreboot/memory.h (revision 1802)
+++ include/grub/i386/coreboot/memory.h (working copy)
@@ -25,7 +25,6 @@
#ifndef ASM_FILE
#include
-#include
#endif
#define GRUB_MEMORY_MACHINE_LOWER_USABLE 0x9fc00 /* 640 kiB - 1 kiB */
@@ -55,13 +54,13 @@
{
grub_uint64_t addr;
grub_uint64_t size;
-#define GRUB_LINUXBIOS_MEMORY_AVAILABLE 1
+#define GRUB_MACHINE_MEMORY_AVAILABLE 1
grub_uint32_t type;
};
typedef struct grub_linuxbios_mem_region *mem_region_t;
-grub_err_t EXPORT_FUNC(grub_available_iterate)
- (int (*hook) (mem_region_t));
+void EXPORT_FUNC(grub_mmap_iterate)
+ (int (*hook) (grub_uint64_t, grub_uint64_t, grub_uint32_t));
#endif
Index: include/grub/multiboot.h
===================================================================
--- include/grub/multiboot.h (revision 1802)
+++ include/grub/multiboot.h (working copy)
@@ -1,7 +1,7 @@
/* multiboot.h - multiboot header file with grub definitions. */
/*
* GRUB -- GRand Unified Bootloader
- * Copyright (C) 2003,2007 Free Software Foundation, Inc.
+ * Copyright (C) 2003,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
@@ -101,6 +101,16 @@
grub_uint16_t vbe_interface_len;
};
+struct grub_mmap_entry
+{
+ grub_uint32_t size;
+ grub_uint64_t addr;
+ grub_uint64_t len;
+#define GRUB_MMAP_MEMORY_AVAILABLE 1
+#define GRUB_MMAP_MEMORY_RESERVED 2
+ grub_uint32_t type;
+} __attribute__((packed));
+
struct grub_mod_list
{
/* the memory used goes from bytes 'mod_start' to 'mod_end-1' inclusive */
Index: loader/i386/pc/multiboot.c
===================================================================
--- loader/i386/pc/multiboot.c (revision 1802)
+++ loader/i386/pc/multiboot.c (working copy)
@@ -78,14 +78,60 @@
grub_free ((void *) mbi->cmdline);
grub_free (mbi);
}
-
-
+
mbi = 0;
grub_dl_unref (my_mod);
return GRUB_ERR_NONE;
}
+/* FIXME: grub_uint32_t will break for addresses above 4 GiB, but is mandated
+ by the spec. Is there something we can do about it? */
+static grub_uint32_t mmap_addr = 0;
+static grub_uint32_t mmap_length;
+
+/* Return the length of the Multiboot mmap that will be needed to allocate
+ our platform's map. */
+static grub_uint32_t
+grub_get_multiboot_mmap_len ()
+{
+ grub_size_t count = 0;
+
+ auto int hook (grub_uint64_t, grub_uint64_t, grub_uint32_t);
+ int hook (grub_uint64_t addr __attribute__ ((unused)),
+ grub_uint64_t size __attribute__ ((unused)),
+ grub_uint32_t type __attribute__ ((unused)))
+ {
+ count++;
+ return 0;
+ }
+
+ grub_mmap_iterate (hook);
+
+ return count * sizeof (struct grub_mmap_entry);
+}
+
+/* Fill previously allocated Multiboot mmap. */
+static void
+grub_fill_multiboot_mmap (struct grub_mmap_entry *first_entry)
+{
+ struct grub_mmap_entry *mmap_entry = (struct grub_mmap_entry *) first_entry;
+
+ auto int hook (grub_uint64_t, grub_uint64_t, grub_uint32_t);
+ int hook (grub_uint64_t addr, grub_uint64_t size, grub_uint32_t type)
+ {
+ mmap_entry->addr = addr;
+ mmap_entry->len = size;
+ mmap_entry->type = type;
+ mmap_entry->size = sizeof (struct grub_mmap_entry) - sizeof (mmap_entry->size);
+ mmap_entry++;
+
+ return 0;
+ }
+
+ grub_mmap_iterate (hook);
+}
+
/* Check if BUFFER contains ELF32. */
static int
grub_multiboot_is_elf32 (void *buffer)
@@ -127,7 +173,7 @@
if (phdr(i)->p_paddr > phdr(highest_segment)->p_paddr)
highest_segment = i;
}
- grub_multiboot_payload_size = (phdr(highest_segment)->p_paddr + phdr(highest_segment)->p_memsz) - phdr(lowest_segment)->p_paddr;
+ grub_multiboot_payload_size += (phdr(highest_segment)->p_paddr + phdr(highest_segment)->p_memsz) - phdr(lowest_segment)->p_paddr;
grub_multiboot_payload_dest = phdr(lowest_segment)->p_paddr;
playground = grub_malloc (RELOCATOR_SIZEOF(forward) + grub_multiboot_payload_size + RELOCATOR_SIZEOF(backward));
@@ -379,6 +425,9 @@
playground = NULL;
}
+ mmap_length = grub_get_multiboot_mmap_len ();
+ grub_multiboot_payload_size = mmap_length;
+
if (header->flags & MULTIBOOT_AOUT_KLUDGE)
{
int offset = ((char *) header - buffer -
@@ -387,9 +436,9 @@
header->load_end_addr - header->load_addr);
if (header->bss_end_addr)
- grub_multiboot_payload_size = (header->bss_end_addr - header->load_addr);
+ grub_multiboot_payload_size += (header->bss_end_addr - header->load_addr);
else
- grub_multiboot_payload_size = load_size;
+ grub_multiboot_payload_size += load_size;
grub_multiboot_payload_dest = header->load_addr;
playground = grub_malloc (RELOCATOR_SIZEOF(forward) + grub_multiboot_payload_size + RELOCATOR_SIZEOF(backward));
@@ -416,6 +465,12 @@
goto fail;
+ grub_fill_multiboot_mmap ((struct grub_mmap_entry *) (grub_multiboot_payload_orig
+ + grub_multiboot_payload_size
+ - mmap_length));
+
+ mmap_addr = grub_multiboot_payload_dest + grub_multiboot_payload_size - mmap_length;
+
if (grub_multiboot_payload_dest >= grub_multiboot_payload_orig)
{
grub_memmove (playground, &grub_multiboot_forward_relocator, RELOCATOR_SIZEOF(forward));
@@ -439,12 +494,15 @@
grub_memset (mbi, 0, sizeof (struct grub_multiboot_info));
- mbi->flags = MULTIBOOT_INFO_MEMORY;
-
/* Convert from bytes to kilobytes. */
mbi->mem_lower = grub_lower_mem / 1024;
mbi->mem_upper = grub_upper_mem / 1024;
+ mbi->flags |= MULTIBOOT_INFO_MEMORY;
+ mbi->mmap_addr = mmap_addr;
+ mbi->mmap_length = mmap_length;
+ mbi->flags |= MULTIBOOT_INFO_MEM_MAP;
+
for (i = 0, len = 0; i < argc; i++)
len += grub_strlen (argv[i]) + 1;
Index: loader/i386/bsd.c
===================================================================
--- loader/i386/bsd.c (revision 1802)
+++ loader/i386/bsd.c (working copy)
@@ -313,7 +313,7 @@
grub_openbsd_boot (void)
{
char *buf = (char *) GRUB_BSD_TEMP_BUFFER;
- struct grub_machine_mmap_entry mmap;
+ struct grub_mmap_entry mmap;
struct grub_openbsd_bios_mmap *pm;
struct grub_openbsd_bootargs *pa;
grub_uint32_t bootdev, biosdev, unit, slice, part, cont;