From deceb3ecd38a046c1ae641109240a35d1506d71c Mon Sep 17 00:00:00 2001 From: robertmh Date: Sun, 17 Aug 2008 16:32:18 +0000 Subject: [PATCH] 2008-08-17 Robert Millan * conf/i386-pc.rmk (kernel_img_SOURCES): Add `kern/i386/pc/mmap.c'. * include/grub/i386/pc/init.h (GRUB_MACHINE_MEMORY_AVAILABLE) (GRUB_MACHINE_MEMORY_RESERVED): New macros. (grub_machine_mmap_iterate): New function declaration. * include/grub/multiboot.h (struct grub_multiboot_mmap_entry): New structure. (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_machine_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_machine_mmap_iterate): ... this. Update all users. * kern/i386/coreboot/mmap.c (grub_mmap_iterate): Simplify parser loop to make it more readable. Rename to ... (grub_machine_mmap_iterate): ... this. * 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. --- ChangeLog | 38 +++++++++++++++ conf/i386-pc.rmk | 3 +- include/grub/i386/coreboot/memory.h | 67 +++++++++++++++++++++++++++ include/grub/i386/pc/init.h | 7 ++- include/grub/multiboot.h | 12 ++++- kern/i386/coreboot/init.c | 11 ++--- kern/i386/coreboot/mmap.c | 18 +++++--- kern/i386/pc/init.c | 71 ++++++++++------------------ kern/i386/pc/mmap.c | 60 ++++++++++++++++++++++++ loader/i386/pc/multiboot.c | 72 ++++++++++++++++++++++++++--- 10 files changed, 289 insertions(+), 70 deletions(-) create mode 100644 include/grub/i386/coreboot/memory.h create mode 100644 kern/i386/pc/mmap.c diff --git a/ChangeLog b/ChangeLog index 914e2a33a..abb359e35 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,41 @@ +2008-08-17 Robert Millan + + * conf/i386-pc.rmk (kernel_img_SOURCES): Add `kern/i386/pc/mmap.c'. + + * include/grub/i386/pc/init.h (GRUB_MACHINE_MEMORY_AVAILABLE) + (GRUB_MACHINE_MEMORY_RESERVED): New macros. + (grub_machine_mmap_iterate): New function declaration. + * include/grub/multiboot.h (struct grub_multiboot_mmap_entry): New + structure. + (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_machine_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_machine_mmap_iterate): ... this. Update all users. + + * kern/i386/coreboot/mmap.c (grub_mmap_iterate): Simplify parser loop + to make it more readable. Rename to ... + (grub_machine_mmap_iterate): ... this. + + * 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. + 2008-08-17 Carles Pina i Estany * menu/normal.c (run_menu): Add Home and End keys in grub-menu. diff --git a/conf/i386-pc.rmk b/conf/i386-pc.rmk index 1ad2e73ca..a2ab94def 100644 --- a/conf/i386-pc.rmk +++ b/conf/i386-pc.rmk @@ -43,7 +43,8 @@ kernel_img_SOURCES = kern/i386/pc/startup.S kern/main.c kern/device.c \ 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 \ diff --git a/include/grub/i386/coreboot/memory.h b/include/grub/i386/coreboot/memory.h new file mode 100644 index 000000000..687077c48 --- /dev/null +++ b/include/grub/i386/coreboot/memory.h @@ -0,0 +1,67 @@ +/* memory.h - describe the memory map */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2002,2007 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_MEMORY_MACHINE_LB_HEADER +#define _GRUB_MEMORY_MACHINE_LB_HEADER 1 + +#include +#include + +#ifndef ASM_FILE +#include +#endif + +#define GRUB_MEMORY_MACHINE_LOWER_USABLE 0x9fc00 /* 640 kiB - 1 kiB */ +#define GRUB_MEMORY_MACHINE_LOWER_SIZE 0xf0000 /* 960 kiB */ + +#define GRUB_MEMORY_MACHINE_UPPER_START 0x100000 /* 1 MiB */ + +#ifndef ASM_FILE + +struct grub_linuxbios_table_header +{ + char signature[4]; + grub_uint32_t size; +}; +typedef struct grub_linuxbios_table_header *grub_linuxbios_table_header_t; + +struct grub_linuxbios_table_item +{ +#define GRUB_LINUXBIOS_MEMBER_UNUSED 0 +#define GRUB_LINUXBIOS_MEMBER_MEMORY 1 + grub_uint32_t tag; + grub_uint32_t size; +}; +typedef struct grub_linuxbios_table_item *grub_linuxbios_table_item_t; + +struct grub_linuxbios_mem_region +{ + grub_uint64_t addr; + grub_uint64_t size; +#define GRUB_MACHINE_MEMORY_AVAILABLE 1 + grub_uint32_t type; +}; +typedef struct grub_linuxbios_mem_region *mem_region_t; + +void EXPORT_FUNC(grub_machine_mmap_iterate) + (int NESTED_FUNC_ATTR (*hook) (grub_uint64_t, grub_uint64_t, grub_uint32_t)); + +#endif + +#endif /* ! _GRUB_MEMORY_MACHINE_HEADER */ diff --git a/include/grub/i386/pc/init.h b/include/grub/i386/pc/init.h index 0c6a12934..1a031db1e 100644 --- a/include/grub/i386/pc/init.h +++ b/include/grub/i386/pc/init.h @@ -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 @@ -35,6 +35,8 @@ struct grub_machine_mmap_entry grub_uint32_t size; grub_uint64_t addr; grub_uint64_t len; +#define GRUB_MACHINE_MEMORY_AVAILABLE 1 +#define GRUB_MACHINE_MEMORY_RESERVED 2 grub_uint32_t type; } __attribute__((packed)); @@ -43,6 +45,9 @@ struct grub_machine_mmap_entry grub_uint32_t EXPORT_FUNC(grub_get_mmap_entry) (struct grub_machine_mmap_entry *entry, grub_uint32_t cont); +void EXPORT_FUNC(grub_machine_mmap_iterate) + (int NESTED_FUNC_ATTR (*hook) (grub_uint64_t, grub_uint64_t, grub_uint32_t)); + /* Turn on/off Gate A20. */ void grub_gate_a20 (int on); diff --git a/include/grub/multiboot.h b/include/grub/multiboot.h index 6a1da055b..5285ea2f5 100644 --- a/include/grub/multiboot.h +++ b/include/grub/multiboot.h @@ -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 @@ struct grub_multiboot_info grub_uint16_t vbe_interface_len; }; +struct grub_multiboot_mmap_entry +{ + grub_uint32_t size; + grub_uint64_t addr; + grub_uint64_t len; +#define GRUB_MULTIBOOT_MEMORY_AVAILABLE 1 +#define GRUB_MULTIBOOT_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 */ diff --git a/kern/i386/coreboot/init.c b/kern/i386/coreboot/init.c index f1861dda7..6890e9053 100644 --- a/kern/i386/coreboot/init.c +++ b/kern/i386/coreboot/init.c @@ -83,12 +83,9 @@ grub_machine_init (void) 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 NESTED_FUNC_ATTR heap_init (grub_uint64_t, grub_uint64_t, grub_uint32_t); + int NESTED_FUNC_ATTR 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) @@ -102,7 +99,7 @@ grub_machine_init (void) 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. */ @@ -135,7 +132,7 @@ grub_machine_init (void) return 0; } - grub_available_iterate (heap_init); + grub_machine_mmap_iterate (heap_init); /* This variable indicates size, not offset. */ grub_upper_mem -= GRUB_MEMORY_MACHINE_UPPER_START; diff --git a/kern/i386/coreboot/mmap.c b/kern/i386/coreboot/mmap.c index dac89113a..b15369ee5 100644 --- a/kern/i386/coreboot/mmap.c +++ b/kern/i386/coreboot/mmap.c @@ -63,8 +63,8 @@ signature_found: return 0; } -grub_err_t -grub_available_iterate (int (*hook) (mem_region_t)) +void +grub_machine_mmap_iterate (int NESTED_FUNC_ATTR (*hook) (grub_uint64_t, grub_uint64_t, grub_uint32_t)) { mem_region_t mem_region; @@ -77,10 +77,16 @@ grub_available_iterate (int (*hook) (mem_region_t)) 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; } diff --git a/kern/i386/pc/init.c b/kern/i386/pc/init.c index 955a52f08..c604e9352 100644 --- a/kern/i386/pc/init.c +++ b/kern/i386/pc/init.c @@ -132,9 +132,6 @@ compact_mem_regions (void) 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 @@ grub_machine_init (void) 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 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) { - 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_MACHINE_MEMORY_AVAILABLE) + { + grub_size_t len; + + len = (grub_size_t) ((addr + size > 0xFFFFFFFF) + ? 0xFFFFFFFF - addr + : size); + add_mem_region (addr, len); + } + + return 0; } + grub_machine_mmap_iterate (hook); + compact_mem_regions (); /* Add the memory regions to free memory, except for the region starting diff --git a/kern/i386/pc/mmap.c b/kern/i386/pc/mmap.c new file mode 100644 index 000000000..47aa53cff --- /dev/null +++ b/kern/i386/pc/mmap.c @@ -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_machine_mmap_iterate (int NESTED_FUNC_ATTR (*hook) (grub_uint64_t, grub_uint64_t, grub_uint32_t)) +{ + grub_uint32_t cont; + struct grub_machine_mmap_entry *entry + = (struct grub_machine_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_MACHINE_MEMORY_AVAILABLE) == 0) + hook (0x1000000, eisa_mmap & ~0xFFFF, GRUB_MACHINE_MEMORY_AVAILABLE); + } + else + hook (0x100000, grub_get_memsize (1) << 10, GRUB_MACHINE_MEMORY_AVAILABLE); + } +} diff --git a/loader/i386/pc/multiboot.c b/loader/i386/pc/multiboot.c index b9b4a9e29..fe8a1e9c1 100644 --- a/loader/i386/pc/multiboot.c +++ b/loader/i386/pc/multiboot.c @@ -78,14 +78,60 @@ grub_multiboot_unload (void) 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 NESTED_FUNC_ATTR hook (grub_uint64_t, grub_uint64_t, grub_uint32_t); + int NESTED_FUNC_ATTR hook (grub_uint64_t addr __attribute__ ((unused)), + grub_uint64_t size __attribute__ ((unused)), + grub_uint32_t type __attribute__ ((unused))) + { + count++; + return 0; + } + + grub_machine_mmap_iterate (hook); + + return count * sizeof (struct grub_multiboot_mmap_entry); +} + +/* Fill previously allocated Multiboot mmap. */ +static void +grub_fill_multiboot_mmap (struct grub_multiboot_mmap_entry *first_entry) +{ + struct grub_multiboot_mmap_entry *mmap_entry = (struct grub_multiboot_mmap_entry *) first_entry; + + 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) + { + mmap_entry->addr = addr; + mmap_entry->len = size; + mmap_entry->type = type; + mmap_entry->size = sizeof (struct grub_multiboot_mmap_entry) - sizeof (mmap_entry->size); + mmap_entry++; + + return 0; + } + + grub_machine_mmap_iterate (hook); +} + /* Check if BUFFER contains ELF32. */ static int grub_multiboot_is_elf32 (void *buffer) @@ -127,7 +173,7 @@ grub_multiboot_load_elf32 (grub_file_t file, void *buffer) 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 @@ grub_multiboot (int argc, char *argv[]) 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 @@ grub_multiboot (int argc, char *argv[]) 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 @@ grub_multiboot (int argc, char *argv[]) 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,11 +494,14 @@ grub_multiboot (int argc, char *argv[]) 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;