From 4bb348e620229225e01adb7c0e7eca61d749d2a5 Mon Sep 17 00:00:00 2001 From: "H. Peter Anvin" Date: Fri, 3 Apr 2009 15:02:37 -0700 Subject: [PATCH] com32: merge all memory map discovery to one file Merge the memory map discovery for malloc and the memory map discovery for memmap into one file that scans memory and invokes a callback. Signed-off-by: H. Peter Anvin --- com32/include/syslinux/memscan.h | 37 ++++++++++ com32/lib/Makefile | 2 + com32/lib/malloc.c | 98 +++++++++---------------- com32/lib/syslinux/memmap.c | 125 ++++---------------------------- com32/lib/syslinux/memscan.c | 153 +++++++++++++++++++++++++++++++++++++++ 5 files changed, 241 insertions(+), 174 deletions(-) create mode 100644 com32/include/syslinux/memscan.h create mode 100644 com32/lib/syslinux/memscan.c diff --git a/com32/include/syslinux/memscan.h b/com32/include/syslinux/memscan.h new file mode 100644 index 0000000..098a224 --- /dev/null +++ b/com32/include/syslinux/memscan.h @@ -0,0 +1,37 @@ +/* ----------------------------------------------------------------------- * + * + * Copyright 2007-2009 H. Peter Anvin - All Rights Reserved + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall + * be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * ----------------------------------------------------------------------- */ + +#ifndef _SYSLINUX_MEMSCAN_H +#define _SYSLINUX_MEMSCAN_H + +#include +#include /* addr_t */ + +typedef int (*scan_memory_callback)(void *, addr_t, addr_t, bool); +int syslinux_scan_memory(scan_memory_callback callback, void *data); + +#endif /* _SYSLINUX_MEMSCAN_H */ diff --git a/com32/lib/Makefile b/com32/lib/Makefile index 6c137f9..984c6df 100644 --- a/com32/lib/Makefile +++ b/com32/lib/Makefile @@ -84,6 +84,8 @@ LIBOBJS = \ syslinux/ipappend.o syslinux/dsinfo.o syslinux/version.o \ syslinux/keyboard.o \ \ + syslinux/memscan.o \ + \ syslinux/addlist.o syslinux/freelist.o syslinux/memmap.o \ syslinux/movebits.o syslinux/shuffle.o syslinux/shuffle_pm.o \ syslinux/shuffle_rm.o syslinux/zonelist.o \ diff --git a/com32/lib/malloc.c b/com32/lib/malloc.c index 6ba8067..40e88b4 100644 --- a/com32/lib/malloc.c +++ b/com32/lib/malloc.c @@ -7,6 +7,7 @@ #include #include #include +#include #include "init.h" #include "malloc.h" @@ -33,22 +34,43 @@ static inline size_t sp(void) return sp; } -struct e820_entry { - uint64_t start; - uint64_t len; - uint32_t type; - uint32_t extattr; -}; - #define E820_MEM_MAX 0xfff00000 /* 4 GB - 1 MB */ +static int consider_memory_area(void *dummy, addr_t start, + addr_t len, bool valid) +{ + struct free_arena_header *fp; + addr_t end; + + (void)dummy; + + if (valid && start < E820_MEM_MAX) { + if (len > E820_MEM_MAX - start) + len = E820_MEM_MAX - start; + + end = start + len; + + if (end > __com32.cs_memsize) { + if (start <= __com32.cs_memsize) { + start = __com32.cs_memsize; + len = end - start; + } + + if (len >= 2*sizeof(struct arena_header)) { + fp = (struct free_arena_header *)start; + fp->a.size = len; + __inject_free_block(fp); + } + } + } + + return 0; +} + static void __constructor init_memory_arena(void) { - struct free_arena_header *fp, *fx; + struct free_arena_header *fp; size_t start, total_space; - static com32sys_t ireg; - com32sys_t oreg; - struct e820_entry *e820buf; start = (size_t)ARENA_ALIGN_UP(__mem_end); total_space = sp() - start; @@ -64,61 +86,11 @@ static void __constructor init_memory_arena(void) __inject_free_block(fp); - /* Scan E820 to see if there are any other suitable blocks */ + /* Scan the memory map to look for other suitable regions */ if (!__com32.cs_memsize) return; /* Old Syslinux core, can't do this... */ - e820buf = __com32.cs_bounce; - ireg.eax.w[0] = 0xe820; - ireg.edx.l = 0x534d4150; - /* ireg.ebx.l = 0; */ - ireg.ecx.b[0] = sizeof(*e820buf); - ireg.es = SEG(e820buf); - ireg.edi.w[0] = OFFS(e820buf); - memset(e820buf, 0, sizeof *e820buf); - /* Set this in case the BIOS doesn't, but doesn't change %ecx to match. */ - e820buf->extattr = 1; - - do { - size_t start, end, len; - - __intcall(0x15, &ireg, &oreg); - - if ((oreg.eflags.l & EFLAGS_CF) || - (oreg.eax.l != 0x534d4150) || - (oreg.ecx.l < 20)) - break; - - if (oreg.ecx.l > 20 && !(e820buf->extattr & 1)) - continue; - if (e820buf->type != 1) - continue; - - /* Careful... these may be truncated values */ - start = e820buf->start; - len = e820buf->len; - - if (e820buf->start >= E820_MEM_MAX) - continue; - if (e820buf->len > E820_MEM_MAX - start) - len = E820_MEM_MAX - start; - - /* Now all the values should be within range */ - end = start + len; - - if (end <= __com32.cs_memsize) - continue; - if (start <= __com32.cs_memsize) { - start = __com32.cs_memsize; - len = end - start; - } - - if (len >= 2*sizeof(struct arena_header)) { - fp = (struct free_arena_header *)start; - fp->a.size = len; - __inject_free_block(fp); - } - } while ((ireg.ebx.l = oreg.ebx.l) != 0); + syslinux_scan_memory(consider_memory_area, NULL); } static void *__malloc_from_block(struct free_arena_header *fp, size_t size) diff --git a/com32/lib/syslinux/memmap.c b/com32/lib/syslinux/memmap.c index 4ccddd2..f253803 100644 --- a/com32/lib/syslinux/memmap.c +++ b/com32/lib/syslinux/memmap.c @@ -32,132 +32,35 @@ */ #include -#include -#include +#include #include #include -#include -#include -#include +#include #include -struct e820_entry { - uint64_t start; - uint64_t len; - uint32_t type; - uint32_t extattr; -}; +static int syslinux_memory_map_callback(void *map, addr_t start, + addr_t len, bool valid) +{ + struct syslinux_memmap **mmap = map; + return syslinux_add_memmap(mmap, start, len, + valid ? SMT_FREE : SMT_RESERVED); +} struct syslinux_memmap *syslinux_memory_map(void) { - static com32sys_t ireg, zireg; - com32sys_t oreg; - struct e820_entry *e820buf = __com32.cs_bounce; - uint64_t start, len, maxlen; - int memfound = 0; struct syslinux_memmap *mmap; enum syslinux_memmap_types type; + int rv; mmap = syslinux_init_memmap(); if (!mmap) - goto bail; + return NULL; - /* Use INT 12h to get DOS memory above 0x7c00 */ - __intcall(0x12, &zireg, &oreg); - if (oreg.eax.w[0] > 31 && oreg.eax.w[0] <= 640) { - addr_t dosmem = (oreg.eax.w[0] << 10) - 0x7c00; - if (syslinux_add_memmap(&mmap, 0x7c00, dosmem, SMT_FREE)) - goto bail; - } - - /* First try INT 15h AX=E820h */ - ireg.eax.l = 0xe820; - ireg.edx.l = 0x534d4150; - ireg.ebx.l = 0; - ireg.ecx.l = sizeof(*e820buf); - ireg.es = SEG(e820buf); - ireg.edi.w[0] = OFFS(e820buf); - memset(e820buf, 0, sizeof *e820buf); - /* Set this in case the BIOS doesn't, but doesn't change %ecx to match. */ - e820buf->extattr = 1; - - do { - __intcall(0x15, &ireg, &oreg); - - if ((oreg.eflags.l & EFLAGS_CF) || - (oreg.eax.l != 0x534d4150) || - (oreg.ecx.l < 20)) - break; - - if (oreg.ecx.l < 24) - e820buf->extattr = 1; /* Enabled, normal */ - - if (!(e820buf->extattr & 1)) - continue; - - type = e820buf->type == 1 ? SMT_FREE : SMT_RESERVED; - start = e820buf->start; - len = e820buf->len; - - if (start < 0x100000000ULL) { - /* Don't rely on E820 being valid for low memory. Doing so - could mean stuff like overwriting the PXE stack even when - using "keeppxe", etc. */ - if (start < 0x100000ULL) { - if (len > 0x100000ULL-start) - len -= 0x100000ULL-start; - else - len = 0; - start = 0x100000ULL; - } - - maxlen = 0x100000000ULL-start; - if (len > maxlen) - len = maxlen; - - if (len) { - if (syslinux_add_memmap(&mmap, (addr_t)start, (addr_t)len, type)) - goto bail; - memfound = 1; - } - } - - ireg.ebx.l = oreg.ebx.l; - } while (oreg.ebx.l); - - if (memfound) - return mmap; - - /* Next try INT 15h AX=E801h */ - ireg.eax.w[0] = 0xe801; - __intcall(0x15, &ireg, &oreg); - - if (!(oreg.eflags.l & EFLAGS_CF) && oreg.ecx.w[0]) { - if (syslinux_add_memmap(&mmap, (addr_t)1 << 20, oreg.ecx.w[0] << 10, - SMT_FREE)) - goto bail; - - if (oreg.edx.w[0]) { - if (syslinux_add_memmap(&mmap, (addr_t)16 << 20, oreg.edx.w[0] << 16, - SMT_FREE)) - goto bail; - } - - return mmap; - } - - /* Finally try INT 15h AH=88h */ - ireg.eax.w[0] = 0x8800; - if (!(oreg.eflags.l & EFLAGS_CF) && oreg.eax.w[0]) { - if (syslinux_add_memmap(&mmap, (addr_t)1 << 20, oreg.ecx.w[0] << 10, - SMT_FREE)) - goto bail; + if (syslinux_scan_memory(syslinux_memory_map_callback, &mmap)) { + syslinux_free_memmap(mmap); + return NULL; } return mmap; - - bail: - syslinux_free_memmap(mmap); - return NULL; } diff --git a/com32/lib/syslinux/memscan.c b/com32/lib/syslinux/memscan.c new file mode 100644 index 0000000..a5661e3 --- /dev/null +++ b/com32/lib/syslinux/memscan.c @@ -0,0 +1,153 @@ +/* ----------------------------------------------------------------------- * + * + * Copyright 2007-2009 H. Peter Anvin - All Rights Reserved + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall + * be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * ----------------------------------------------------------------------- */ + +/* + * memscan.c + * + * Query the system for free memory + */ + +#include +#include +#include +#include +#include +#include + +#include + +struct e820_entry { + uint64_t start; + uint64_t len; + uint32_t type; + uint32_t extattr; +}; + +int syslinux_scan_memory(scan_memory_callback callback, void *data) +{ + static com32sys_t ireg, zireg; + com32sys_t oreg; + struct e820_entry *e820buf = __com32.cs_bounce; + uint64_t start, len, maxlen; + int memfound = 0; + int rv; + + /* Use INT 12h to get DOS memory above 0x7c00 */ + __intcall(0x12, &zireg, &oreg); + if (oreg.eax.w[0] > 2 && oreg.eax.w[0] <= 640) { + addr_t dosmem = (oreg.eax.w[0] << 10) - 0x504; + rv = callback(data, 0x504, dosmem, true); + if (rv) + return rv; + } + + /* First try INT 15h AX=E820h */ + ireg.eax.l = 0xe820; + ireg.edx.l = 0x534d4150; + ireg.ebx.l = 0; + ireg.ecx.l = sizeof(*e820buf); + ireg.es = SEG(e820buf); + ireg.edi.w[0] = OFFS(e820buf); + memset(e820buf, 0, sizeof *e820buf); + /* Set this in case the BIOS doesn't, but doesn't change %ecx to match. */ + e820buf->extattr = 1; + + do { + __intcall(0x15, &ireg, &oreg); + + if ((oreg.eflags.l & EFLAGS_CF) || + (oreg.eax.l != 0x534d4150) || + (oreg.ecx.l < 20)) + break; + + if (oreg.ecx.l < 24) + e820buf->extattr = 1; /* Enabled, normal */ + + if (!(e820buf->extattr & 1)) + continue; + + start = e820buf->start; + len = e820buf->len; + + if (start < 0x100000000ULL) { + /* Don't rely on E820 being valid for low memory. Doing so + could mean stuff like overwriting the PXE stack even when + using "keeppxe", etc. */ + if (start < 0x100000ULL) { + if (len > 0x100000ULL-start) + len -= 0x100000ULL-start; + else + len = 0; + start = 0x100000ULL; + } + + maxlen = 0x100000000ULL-start; + if (len > maxlen) + len = maxlen; + + if (len) { + rv = callback(data, (addr_t)start, (addr_t)len, e820buf->type == 1); + if (rv) + return rv; + memfound = 1; + } + } + + ireg.ebx.l = oreg.ebx.l; + } while (oreg.ebx.l); + + if (memfound) + return 0; + + /* Next try INT 15h AX=E801h */ + ireg.eax.w[0] = 0xe801; + __intcall(0x15, &ireg, &oreg); + + if (!(oreg.eflags.l & EFLAGS_CF) && oreg.ecx.w[0]) { + rv = callback(data, (addr_t)1 << 20, oreg.ecx.w[0] << 10, true); + if (rv) + return rv; + + if (oreg.edx.w[0]) { + rv = callback(data, (addr_t)16 << 20, oreg.edx.w[0] << 16, true); + if (rv) + return rv; + } + + return 0; + } + + /* Finally try INT 15h AH=88h */ + ireg.eax.w[0] = 0x8800; + if (!(oreg.eflags.l & EFLAGS_CF) && oreg.eax.w[0]) { + rv = callback(data, (addr_t)1 << 20, oreg.ecx.w[0] << 10, true); + if (rv) + return rv; + } + + return 0; +} -- 2.7.4