diff options
Diffstat (limited to 'contrib/syslinux-4.02/utils/memdiskfind.c')
-rw-r--r-- | contrib/syslinux-4.02/utils/memdiskfind.c | 158 |
1 files changed, 158 insertions, 0 deletions
diff --git a/contrib/syslinux-4.02/utils/memdiskfind.c b/contrib/syslinux-4.02/utils/memdiskfind.c new file mode 100644 index 0000000..decc788 --- /dev/null +++ b/contrib/syslinux-4.02/utils/memdiskfind.c @@ -0,0 +1,158 @@ +/* ----------------------------------------------------------------------- * + * + * Copyright 2010 Intel Corporation; author: H. Peter Anvin + * + * This program 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, Inc., 51 Franklin St, Fifth Floor, + * Boston MA 02110-1301, USA; either version 2 of the License, or + * (at your option) any later version; incorporated herein by reference. + * + * ----------------------------------------------------------------------- */ + +/* + * memdiskfind.c + * + * Simple utility to search for a MEMDISK instance and output the parameters + * needed to use the "phram" driver in Linux to map it. + */ + +#include <errno.h> +#include <fcntl.h> +#include <inttypes.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <sys/mman.h> +#include <sys/stat.h> +#include "../memdisk/mstructs.h" + +#define MBFT_MIN_LENGTH (36+4+26) + +static bool valid_mbft(const struct mBFT *mbft, size_t space) +{ + uint8_t csum; + size_t i; + + if (memcmp(mbft->acpi.signature, "mBFT", 4)) + return false; + + if (mbft->acpi.length < MBFT_MIN_LENGTH) + return false; + + if (mbft->acpi.length > space) + return false; + + if ((size_t)mbft->acpi.length != (size_t)mbft->mdi.bytes + 36+4) + return false; + + csum = 0; + for (i = 0; i < mbft->acpi.length; i++) + csum += ((const uint8_t *)mbft)[i]; + + if (csum) + return false; + + return true; +} + +static void output_params(const struct mBFT *mbft) +{ + int sector_shift = mbft->mdi.sector_shift; + + if (!sector_shift) + sector_shift = 9; + + printf("%#x,%#x\n", + mbft->mdi.diskbuf, mbft->mdi.disksize << sector_shift); +} + +static size_t memlimit(void) +{ + char txtline[256], user[256]; + size_t maxram = 0; + unsigned long long start, end; + FILE *iomem; + + iomem = fopen("/proc/iomem", "r"); + if (!iomem) + return 0; + + while (fgets(txtline, sizeof txtline, iomem) != NULL) { + if (sscanf(txtline, "%llx-%llx : %[^\n]", &start, &end, user) != 3) + continue; + if (strcmp(user, "System RAM")) + continue; + if (start >= 0xa0000) + continue; + maxram = (end >= 0xa0000) ? 0xa0000 : end+1; + } + fclose(iomem); + + return maxram; +} + +int main(int argc, char *argv[]) +{ + const char *map; + int memfd; + size_t fbm; + const char *ptr, *end; + size_t page = sysconf(_SC_PAGESIZE); + size_t mapbase, maplen; + int err = 1; + + (void)argc; + + mapbase = memlimit() & ~(page - 1); + if (!mapbase) + return 2; + + memfd = open("/dev/mem", O_RDONLY); + if (memfd < 0) { + fprintf(stderr, "%s: cannot open /dev/mem: %s\n", + argv[0], strerror(errno)); + return 2; + } + + map = mmap(NULL, page, PROT_READ, MAP_SHARED, memfd, 0); + if (map == MAP_FAILED) { + fprintf(stderr, "%s: cannot map page 0: %s\n", + argv[0], strerror(errno)); + return 2; + } + + fbm = *(uint16_t *)(map + 0x413) << 10; + if (fbm < mapbase) + fbm = mapbase; + + munmap((void *)map, page); + + if (fbm < 64*1024 || fbm >= 640*1024) + return 1; + + maplen = 0xa0000 - mapbase; + map = mmap(NULL, maplen, PROT_READ, MAP_SHARED, memfd, mapbase); + if (map == MAP_FAILED) { + fprintf(stderr, "%s: cannot map base memory: %s\n", + argv[0], strerror(errno)); + return 2; + } + + ptr = map + (fbm - mapbase); + end = map + (0xa0000 - mapbase); + while (ptr < end) { + if (valid_mbft((const struct mBFT *)ptr, end-ptr)) { + output_params((const struct mBFT *)ptr); + err = 0; + break; + } + ptr += 16; + } + + munmap((void *)map, maplen); + + return err; +} |