169 lines
3.7 KiB
C
169 lines
3.7 KiB
C
/* ----------------------------------------------------------------------- *
|
|
*
|
|
* 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;
|
|
}
|
|
|
|
static inline size_t get_page_size(void)
|
|
{
|
|
#ifdef _SC_PAGESIZE
|
|
return sysconf(_SC_PAGESIZE);
|
|
#else
|
|
/* klibc, for one, doesn't have sysconf() due to excessive multiplex */
|
|
return getpagesize();
|
|
#endif
|
|
}
|
|
|
|
int main(int argc, char *argv[])
|
|
{
|
|
const char *map;
|
|
int memfd;
|
|
size_t fbm;
|
|
const char *ptr, *end;
|
|
size_t page = get_page_size();
|
|
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;
|
|
}
|