diff --git a/conf/i386.rmk b/conf/i386.rmk index 93f84ce..5338457 100644 --- a/conf/i386.rmk +++ b/conf/i386.rmk @@ -14,3 +14,8 @@ pkglib_MODULES += vga_text.mod vga_text_mod_SOURCES = term/i386/pc/vga_text.c term/i386/vga_common.c vga_text_mod_CFLAGS = $(COMMON_CFLAGS) vga_text_mod_LDFLAGS = $(COMMON_LDFLAGS) + +pkglib_MODULES += uppermem.mod +uppermem_mod_SOURCES = lib/i386/uppermem.c +uppermem_mod_CFLAGS = $(COMMON_CFLAGS) +uppermem_mod_LDFLAGS = $(COMMON_LDFLAGS) diff --git a/lib/i386/uppermem.c b/lib/i386/uppermem.c new file mode 100644 index 0000000..623535f --- /dev/null +++ b/lib/i386/uppermem.c @@ -0,0 +1,127 @@ +/* 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 . + */ + +#ifndef EFIEMU +#include +#include +#endif + +#include +#include + +struct region +{ + grub_uint64_t start; + grub_uint64_t end; +}; + +#ifdef EFIEMU +grub_err_t +grub_efiemu_get_lower_upper_memory (grub_uint64_t *lower, grub_uint64_t *upper) +#else +grub_err_t +grub_get_lower_upper_memory (grub_uint64_t *lower, grub_uint64_t *upper) +#endif +{ + grub_size_t count = 0; + struct region *regions = 0; + int done = 1; + unsigned i; + struct region t; + grub_uint64_t last_addr; + + 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) + { +#ifdef EFIEMU + if (type != GRUB_EFIEMU_MEMORY_AVAILABLE) +#else + if (type != GRUB_MACHINE_MEMORY_AVAILABLE) +#endif + return 0; + regions = (struct region *) + grub_realloc (regions, (count + 1) * sizeof (struct region)); + regions[count].start = addr; + regions[count].end = addr + size; + count++; + return 0; + } + +#ifdef EFIEMU + grub_efiemu_mmap_iterate (hook); +#else + grub_machine_mmap_iterate (hook); +#endif + + /* Bubble-sort the memory map */ + while (done) + { + done = 0; + for (i = 0; i < count - 1; i++) + if (regions[i].start > regions[i + 1].start) + { + done = 1; + t = regions[i]; + regions[i] = regions[i + 1]; + regions[i + 1] = t; + } + } + + /* Set mem_upper and mem_lower */ + last_addr = 0; + for (i = 0; i < count; i++) + { + grub_uint64_t end = regions[i].end; + /* Don't use memory after 0xa0000*/ + if (end > 0xa0000) + end = 0xa0000; + + /* low memory is finished */ + if (regions[i].start > end) + break; + + /* A hole */ + if (regions[i].start > last_addr) + break; + + last_addr = end; + } + + *lower = last_addr; + + /* Skip low memory */ + for (i = 0; i < count && regions[i].end <= 0x100000; + i++); + + last_addr = 0x100000; + for (; i < count; i++) + { + /* A hole */ + if (regions[i].start > last_addr) + break; + + last_addr = regions[i].end; + } + + *upper = (last_addr - 0x100000); + grub_free (regions); + + return GRUB_ERR_NONE; +}