From 6e7a315eb67cb6c113cf37e1d66c4f11a51a2b3e Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 18:29:51 +0200 Subject: Adding upstream version 2.06. Signed-off-by: Daniel Baumann --- grub-core/kern/i386/pc/mmap.c | 193 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 193 insertions(+) create mode 100644 grub-core/kern/i386/pc/mmap.c (limited to 'grub-core/kern/i386/pc/mmap.c') diff --git a/grub-core/kern/i386/pc/mmap.c b/grub-core/kern/i386/pc/mmap.c new file mode 100644 index 0000000..c0c3c35 --- /dev/null +++ b/grub-core/kern/i386/pc/mmap.c @@ -0,0 +1,193 @@ +/* + * 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 +#include +#include + +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 +#define GRUB_MACHINE_MEMORY_ACPI 3 +#define GRUB_MACHINE_MEMORY_NVS 4 +#define GRUB_MACHINE_MEMORY_BADRAM 5 + grub_uint32_t type; +} GRUB_PACKED; + + +/* + * + * grub_get_conv_memsize(i) : return the conventional memory size in KB. + * BIOS call "INT 12H" to get conventional memory size + * The return value in AX. + */ +static inline grub_uint16_t +grub_get_conv_memsize (void) +{ + struct grub_bios_int_registers regs; + + regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT; + grub_bios_interrupt (0x12, ®s); + return regs.eax & 0xffff; +} + +/* + * grub_get_ext_memsize() : return the extended memory size in KB. + * BIOS call "INT 15H, AH=88H" to get extended memory size + * The return value in AX. + * + */ +static inline grub_uint16_t +grub_get_ext_memsize (void) +{ + struct grub_bios_int_registers regs; + + regs.eax = 0x8800; + regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT; + grub_bios_interrupt (0x15, ®s); + return regs.eax & 0xffff; +} + +/* Get a packed EISA memory map. Lower 16 bits are between 1MB and 16MB + in 1KB parts, and upper 16 bits are above 16MB in 64KB parts. If error, return zero. + BIOS call "INT 15H, AH=E801H" to get EISA memory map, + AX = memory between 1M and 16M in 1K parts. + BX = memory above 16M in 64K parts. +*/ + +static inline grub_uint32_t +grub_get_eisa_mmap (void) +{ + struct grub_bios_int_registers regs; + + regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT; + regs.eax = 0xe801; + grub_bios_interrupt (0x15, ®s); + + if ((regs.eax & 0xff00) == 0x8600) + return 0; + + return (regs.eax & 0xffff) | (regs.ebx << 16); +} + +/* + * + * grub_get_mmap_entry(addr, cont) : address and old continuation value (zero to + * start), for the Query System Address Map BIOS call. + * + * Sets the first 4-byte int value of "addr" to the size returned by + * the call. If the call fails, sets it to zero. + * + * Returns: new (non-zero) continuation value, 0 if done. + */ +/* Get a memory map entry. Return next continuation value. Zero means + the end. */ +static grub_uint32_t +grub_get_mmap_entry (struct grub_machine_mmap_entry *entry, + grub_uint32_t cont) +{ + struct grub_bios_int_registers regs; + + regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT; + + /* place address (+4) in ES:DI */ + regs.es = ((grub_addr_t) &entry->addr) >> 4; + regs.edi = ((grub_addr_t) &entry->addr) & 0xf; + + /* set continuation value */ + regs.ebx = cont; + + /* set default maximum buffer size */ + regs.ecx = sizeof (*entry) - sizeof (entry->size); + + /* set EDX to 'SMAP' */ + regs.edx = 0x534d4150; + + regs.eax = 0xe820; + grub_bios_interrupt (0x15, ®s); + + /* write length of buffer (zero if error) into ADDR */ + if ((regs.flags & GRUB_CPU_INT_FLAGS_CARRY) || regs.eax != 0x534d4150 + || regs.ecx < 0x14 || regs.ecx > 0x400) + entry->size = 0; + else + entry->size = regs.ecx; + + /* return the continuation value */ + return regs.ebx; +} + +grub_err_t +grub_machine_mmap_iterate (grub_memory_hook_t hook, void *hook_data) +{ + grub_uint32_t cont = 0; + struct grub_machine_mmap_entry *entry + = (struct grub_machine_mmap_entry *) GRUB_MEMORY_MACHINE_SCRATCH_ADDR; + int e820_works = 0; + + while (1) + { + grub_memset (entry, 0, sizeof (*entry)); + + cont = grub_get_mmap_entry (entry, cont); + + if (!entry->size) + break; + + if (entry->len) + e820_works = 1; + if (entry->len + && hook (entry->addr, entry->len, + /* GRUB mmaps have been defined to match with + the E820 definition. + Therefore, we can just pass type through. */ + entry->type, hook_data)) + break; + + if (! cont) + break; + } + + if (!e820_works) + { + grub_uint32_t eisa_mmap = grub_get_eisa_mmap (); + + if (hook (0x0, ((grub_uint32_t) grub_get_conv_memsize ()) << 10, + GRUB_MEMORY_AVAILABLE, hook_data)) + return 0; + + if (eisa_mmap) + { + if (hook (0x100000, (eisa_mmap & 0xFFFF) << 10, + GRUB_MEMORY_AVAILABLE, hook_data) == 0) + hook (0x1000000, eisa_mmap & ~0xFFFF, GRUB_MEMORY_AVAILABLE, + hook_data); + } + else + hook (0x100000, ((grub_uint32_t) grub_get_ext_memsize ()) << 10, + GRUB_MEMORY_AVAILABLE, hook_data); + } + + return 0; +} -- cgit v1.2.3