From 041d1ea37802bf7178a31a53f96c26efa6b8fb7b Mon Sep 17 00:00:00 2001 From: James Date: Fri, 16 Nov 2012 10:41:01 +0000 Subject: fish --- grub-core/mmap/i386/mmap.c | 99 ++++++++++++++++ grub-core/mmap/i386/pc/mmap.c | 216 +++++++++++++++++++++++++++++++++++ grub-core/mmap/i386/pc/mmap_helper.S | 133 +++++++++++++++++++++ grub-core/mmap/i386/uppermem.c | 89 +++++++++++++++ 4 files changed, 537 insertions(+) create mode 100644 grub-core/mmap/i386/mmap.c create mode 100644 grub-core/mmap/i386/pc/mmap.c create mode 100644 grub-core/mmap/i386/pc/mmap_helper.S create mode 100644 grub-core/mmap/i386/uppermem.c (limited to 'grub-core/mmap/i386') diff --git a/grub-core/mmap/i386/mmap.c b/grub-core/mmap/i386/mmap.c new file mode 100644 index 0000000..e9c030b --- /dev/null +++ b/grub-core/mmap/i386/mmap.c @@ -0,0 +1,99 @@ +/* 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 . + */ + +#include +#include +#include +#include +#include +#include + + +#ifndef GRUB_MMAP_REGISTER_BY_FIRMWARE + +void * +grub_mmap_malign_and_register (grub_uint64_t align, grub_uint64_t size, + int *handle, int type, int flags) +{ + grub_uint64_t highestlow = 0; + + auto int NESTED_FUNC_ATTR find_hook (grub_uint64_t, grub_uint64_t, + grub_memory_type_t); + int NESTED_FUNC_ATTR find_hook (grub_uint64_t start, grub_uint64_t rangesize, + grub_memory_type_t memtype) + { + grub_uint64_t end = start + rangesize; + if (memtype != GRUB_MEMORY_AVAILABLE) + return 0; + if (end > 0x100000) + end = 0x100000; + if (end > start + size + && highestlow < ((end - size) - ((end - size) & (align - 1)))) + highestlow = (end - size) - ((end - size) & (align - 1)); + return 0; + } + + void *ret; + if (flags & GRUB_MMAP_MALLOC_LOW) + { + /* FIXME: use low-memory mm allocation once it's available. */ + grub_mmap_iterate (find_hook); + ret = UINT_TO_PTR (highestlow); + } + else + ret = grub_memalign (align, size); + + if (! ret) + { + *handle = 0; + return 0; + } + + *handle = grub_mmap_register (PTR_TO_UINT64 (ret), size, type); + if (! *handle) + { + grub_free (ret); + return 0; + } + + return ret; +} + +void +grub_mmap_free_and_unregister (int handle) +{ + struct grub_mmap_region *cur; + grub_uint64_t addr; + + for (cur = grub_mmap_overlays; cur; cur = cur->next) + if (cur->handle == handle) + break; + + if (! cur) + return; + + addr = cur->start; + + grub_mmap_unregister (handle); + + if (addr >= 0x100000) + grub_free (UINT_TO_PTR (addr)); +} + +#endif diff --git a/grub-core/mmap/i386/pc/mmap.c b/grub-core/mmap/i386/pc/mmap.c new file mode 100644 index 0000000..8dec083 --- /dev/null +++ b/grub-core/mmap/i386/pc/mmap.c @@ -0,0 +1,216 @@ +/* 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 . + */ + +#include +#include +#include +#include +#include + +#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_memory_type_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; + 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_memory_type_t type __attribute__ ((unused))) + { + regcount++; + 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_free_and_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); + + reentry = 1; + hooktarget + = grub_mmap_malign_and_register (16, hooksize, &mmapregion, + GRUB_MEMORY_RESERVED, + GRUB_MMAP_MALLOC_LOW); + reentry = 0; + + if (! hooktarget) + { + slots_available = 0; + return grub_error (GRUB_ERR_OUT_OF_MEMORY, "no space for mmap hook"); + } + 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; + + err = malloc_hook (); + if (err) + return err; + + if (! preb_handle) + { + grub_dprintf ("mmap", "adding preboot\n"); + preb_handle + = grub_loader_register_preboot_hook (preboot, preboot_rest, + GRUB_LOADER_PREBOOT_HOOK_PRIO_MEMORY); + 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/grub-core/mmap/i386/pc/mmap_helper.S b/grub-core/mmap/i386/pc/mmap_helper.S new file mode 100644 index 0000000..3302a9a --- /dev/null +++ b/grub-core/mmap/i386/pc/mmap_helper.S @@ -0,0 +1,133 @@ +/* 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 . + */ + +#include + +#define DS(x) ((x) - LOCAL (segstart)) + +LOCAL (segstart): +VARIABLE(grub_machine_mmaphook_start) + .code16 +VARIABLE(grub_machine_mmaphook_int12) + push %ds + push %cs + pop %ds + movw DS (LOCAL (kblow)), %ax + pop %ds + iret + +VARIABLE(grub_machine_mmaphook_int15) + pushf + cmpw $0xe801, %ax + jz LOCAL (e801) + cmpw $0xe820, %ax + jz LOCAL (e820) + cmpb $0x88, %ah + jz LOCAL (h88) + popf + /* ljmp */ + .byte 0xea +VARIABLE (grub_machine_mmaphook_int15offset) + .word 0 +VARIABLE (grub_machine_mmaphook_int15segment) + .word 0 + +LOCAL (e801): + popf + push %ds + push %cs + pop %ds + movw DS (LOCAL (kbin16mb)), %ax + movw DS (LOCAL (m64kbin4gb)), %bx + movw %ax, %cx + movw %bx, %dx + pop %ds + clc + jmp LOCAL (iret_cf) + +LOCAL (h88): + popf + push %ds + push %cs + pop %ds + movw DS (LOCAL (kbin16mb)), %ax + pop %ds + clc + jmp LOCAL (iret_cf) + +LOCAL (e820): + popf + push %ds + push %cs + pop %ds + cmpw $20, %cx + jb LOCAL (errexit) + cmpw DS (LOCAL (mmap_num)), %bx + jae LOCAL (errexit) + cmp $0x534d4150, %edx + jne LOCAL (errexit) + push %si + push %di + movw $20, %cx + movw $(DS(LOCAL (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(LOCAL (mmap_num)), %bx + jb LOCAL (noclean) + xor %bx, %bx +LOCAL (noclean): + mov $0x534d4150, %eax + pop %ds + clc + jmp LOCAL (iret_cf) +LOCAL (errexit): + mov $0x534d4150, %eax + pop %ds + xor %bx, %bx + stc + +LOCAL (iret_cf): + push %bp + mov %sp, %bp + setc 6(%bp) + pop %bp + iret + +VARIABLE(grub_machine_mmaphook_mmap_num) +LOCAL (mmap_num): + .word 0 +VARIABLE(grub_machine_mmaphook_kblow) +LOCAL (kblow): + .word 0 +VARIABLE (grub_machine_mmaphook_kbin16mb) +LOCAL (kbin16mb): + .word 0 +VARIABLE (grub_machine_mmaphook_64kbin4gb) +LOCAL (m64kbin4gb): + .word 0 +LOCAL (mmaphook_mmap): + /* Memory map is placed just after the interrupt handlers. */ +VARIABLE(grub_machine_mmaphook_end) + .byte 0 diff --git a/grub-core/mmap/i386/uppermem.c b/grub-core/mmap/i386/uppermem.c new file mode 100644 index 0000000..2aa4301 --- /dev/null +++ b/grub-core/mmap/i386/uppermem.c @@ -0,0 +1,89 @@ +/* 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 . + */ + +#include +#include +#include +#include + +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_memory_type_t); + int NESTED_FUNC_ATTR hook (grub_uint64_t addr, grub_uint64_t size, + grub_memory_type_t type) + { + if (type != GRUB_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_memory_type_t); + int NESTED_FUNC_ATTR hook (grub_uint64_t addr, grub_uint64_t size, + grub_memory_type_t type) + { + if (type != GRUB_MEMORY_AVAILABLE) + return 0; + if (addr <= 0x100000 && addr + size > 0x100000) + upper = addr + size - 0x100000; + return 0; + } + + grub_mmap_iterate (hook); + return upper; +} + +/* Count the continuous 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_memory_type_t); + int NESTED_FUNC_ATTR hook (grub_uint64_t addr, grub_uint64_t size, + grub_memory_type_t type) + { + if (type != GRUB_MEMORY_AVAILABLE) + return 0; + if (addr <= 0x4000000 && addr + size > 0x4000000) + post64 = addr + size - 0x4000000; + return 0; + } + + grub_mmap_iterate (hook); + return post64; +} -- cgit v1.2.3