diff options
| author | H. Peter Anvin <hpa@linux.intel.com> | 2009-04-03 15:02:37 -0700 |
|---|---|---|
| committer | H. Peter Anvin <hpa@linux.intel.com> | 2009-04-03 15:02:37 -0700 |
| commit | 4bb348e620229225e01adb7c0e7eca61d749d2a5 (patch) | |
| tree | 6593150387e72dc6ee65bc16dd783731590cca99 /com32/lib/syslinux/memscan.c | |
| parent | 4cfcede66002a1c0caf1fdc2d4123a3096f6233f (diff) | |
| download | syslinux-4bb348e620229225e01adb7c0e7eca61d749d2a5.tar.gz | |
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 <hpa@linux.intel.com>
Diffstat (limited to 'com32/lib/syslinux/memscan.c')
| -rw-r--r-- | com32/lib/syslinux/memscan.c | 153 |
1 files changed, 153 insertions, 0 deletions
diff --git a/com32/lib/syslinux/memscan.c b/com32/lib/syslinux/memscan.c new file mode 100644 index 00000000..a5661e31 --- /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 <assert.h> +#include <stdbool.h> +#include <stdlib.h> +#include <string.h> +#include <inttypes.h> +#include <com32.h> + +#include <syslinux/memscan.h> + +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; +} |
