summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--memdisk/Makefile37
-rw-r--r--memdisk/e820.h30
-rw-r--r--memdisk/e820data13
-rw-r--r--memdisk/e820func.c96
-rw-r--r--memdisk/e820test.c74
-rw-r--r--memdisk/msetup.c183
-rw-r--r--memdisk/testdata113
-rw-r--r--memdisk/testdata210
8 files changed, 456 insertions, 0 deletions
diff --git a/memdisk/Makefile b/memdisk/Makefile
new file mode 100644
index 00000000..9eb73cf7
--- /dev/null
+++ b/memdisk/Makefile
@@ -0,0 +1,37 @@
+#ident "$Id$"
+## -----------------------------------------------------------------------
+##
+## Copyright 2001 H. Peter Anvin - All Rights Reserved
+##
+## 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., 53 Temple Place Ste 330,
+## Bostom MA 02111-1307, USA; either version 2 of the License, or
+## (at your option) any later version; incorporated herein by reference.
+##
+## -----------------------------------------------------------------------
+
+CC = gcc
+CFLAGS = -g -O2 -fomit-frame-pointer -march=i386 -malign-functions=0 -malign-jumps=0 -malign-loops=0
+LDFLAGS =
+
+all: e820func.o16 msetup.o16 e820test
+
+clean:
+ rm -f *.o *.s *.o16 *.s16 e820test
+
+%.o16: %.s16
+ as -o $@ $<
+
+%.s16: %.s
+ echo '.code16' | cat - $< > $@
+
+%.s: %.c
+ $(CC) $(CFLAGS) -S -o $@ $<
+
+%.o: %.c
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+e820test: e820func.o msetup.o e820test.o
+ $(CC) $(LDFLAGS) -o $@ $^
+
diff --git a/memdisk/e820.h b/memdisk/e820.h
new file mode 100644
index 00000000..ec261d7f
--- /dev/null
+++ b/memdisk/e820.h
@@ -0,0 +1,30 @@
+#ident "$Id$"
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2001 H. Peter Anvin - All Rights Reserved
+ *
+ * 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., 53 Temple Place Ste 330,
+ * Bostom MA 02111-1307, USA; either version 2 of the License, or
+ * (at your option) any later version; incorporated herein by reference.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * e820.h
+ *
+ * Common routines for e820 memory map management
+ */
+
+#include <stdint.h>
+
+struct e820range {
+ uint64_t start;
+ uint32_t type;
+} __attribute__((packed));
+
+extern struct e820range ranges[];
+extern int nranges;
+
+extern void insertrange(uint64_t, uint64_t, uint32_t);
diff --git a/memdisk/e820data b/memdisk/e820data
new file mode 100644
index 00000000..34ab566d
--- /dev/null
+++ b/memdisk/e820data
@@ -0,0 +1,13 @@
+0000000000000000 000000000009bc00 1
+000000000009bc00 0000000000004400 2
+00000000000e9800 0000000000016800 2
+0000000000100000 0000000006ee0000 1
+0000000006fe0000 000000000000fc00 3
+0000000006fefc00 0000000000000400 4
+0000000006ff0000 0000000000002000 2
+0000000006ff2000 000000000000e000 1
+0000000007000000 0000000000100000 2
+00000000fff00000 0000000000100000 2
+
+0000000000586000 0000000000168000 2
+000000000009ba00 0000000000000200 2
diff --git a/memdisk/e820func.c b/memdisk/e820func.c
new file mode 100644
index 00000000..72e1bf80
--- /dev/null
+++ b/memdisk/e820func.c
@@ -0,0 +1,96 @@
+#ident "$Id$"
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2001 H. Peter Anvin - All Rights Reserved
+ *
+ * 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., 53 Temple Place Ste 330,
+ * Bostom MA 02111-1307, USA; either version 2 of the License, or
+ * (at your option) any later version; incorporated herein by reference.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * e820func.c
+ *
+ * E820 range database manager
+ */
+
+#include <stdint.h>
+#include "e820.h"
+
+#define MAXRANGES 64
+/* All of memory starts out as one range of "indeterminate" type */
+struct e820range ranges[MAXRANGES] = { { 0ULL, 0 }, { 0ULL, (uint32_t)-1 } };
+int nranges = 1;
+
+static void insertrange_at(int where, uint64_t start, uint32_t type)
+{
+ int i;
+
+ for ( i = nranges ; i > where ; i-- )
+ ranges[i] = ranges[i-1];
+
+ ranges[where].start = start;
+ ranges[where].type = type;
+
+ nranges++;
+ ranges[nranges].start = 0ULL;
+ ranges[nranges].type = (uint32_t)-1;
+}
+
+void insertrange(uint64_t start, uint64_t len, uint32_t type)
+{
+ uint64_t newstart, last;
+ uint32_t oldtype;
+ int i, j;
+
+ /* Remove this to make len == 0 mean all of memory */
+ if ( len == 0 )
+ return; /* Nothing to insert */
+
+ last = start+len-1; /* May roll over */
+
+ i = 0;
+ oldtype = -2;
+ while ( start > ranges[i].start && ranges[i].type != -1 ) {
+ oldtype = ranges[i].type;
+ i++;
+ }
+
+ /* Consider the replacement policy. This current one is "overwrite." */
+
+ if ( start < ranges[i].start || ranges[i].type == -1 )
+ insertrange_at(i++, start, type);
+
+ while ( i == 0 || last > ranges[i].start-1 ) {
+ oldtype = ranges[i].type;
+ ranges[i].type = type;
+ i++;
+ }
+
+ if ( last < ranges[i].start-1 )
+ insertrange_at(i, last+1, oldtype);
+
+ /* Now the map is correct, but quite possibly not optimal. Scan the
+ map for ranges which are redundant and remove them. */
+ i = j = 1;
+ oldtype = ranges[0].type;
+ while ( i < nranges ) {
+ if ( ranges[i].type == oldtype ) {
+ i++;
+ } else {
+ oldtype = ranges[i].type;
+ if ( i != j )
+ ranges[j] = ranges[i];
+ i++; j++;
+ }
+ }
+
+ if ( i != j ) {
+ ranges[j] = ranges[i]; /* Termination sentinel copy */
+ nranges -= (i-j);
+ }
+}
+
diff --git a/memdisk/e820test.c b/memdisk/e820test.c
new file mode 100644
index 00000000..2717fdcd
--- /dev/null
+++ b/memdisk/e820test.c
@@ -0,0 +1,74 @@
+#ident "$Id$"
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2001 H. Peter Anvin - All Rights Reserved
+ *
+ * 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., 53 Temple Place Ste 330,
+ * Bostom MA 02111-1307, USA; either version 2 of the License, or
+ * (at your option) any later version; incorporated herein by reference.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * e820hack.c
+ *
+ * Test of INT 15:E820 canonicalization/manipulation routine
+ */
+
+#include <stdio.h>
+#include <inttypes.h>
+#include "e820.h"
+
+extern void parse_mem(void);
+extern uint32_t dos_mem, low_mem, high_mem;
+
+void printranges(void) {
+ int i;
+
+ for ( i = 0 ; i < nranges ; i++ ) {
+ printf("%016Lx %016Lx %d\n",
+ ranges[i].start,
+ ranges[i+1].start - ranges[i].start,
+ ranges[i].type);
+ }
+}
+
+int main(int argc, char *argv[])
+{
+ uint64_t start, len;
+ uint32_t type;
+
+ printranges();
+
+ while ( scanf("%Lx %Lx %d", &start, &len, &type) == 3 ) {
+ putchar('\n');
+ printf("%016Lx %016Lx %d <-\n", start, len, type);
+ putchar('\n');
+ insertrange(start, len, type);
+ printranges();
+ }
+
+ parse_mem();
+
+ putchar('\n');
+ printf("DOS mem = %#10x (%u K)\n", dos_mem, dos_mem >> 10);
+ printf("Low mem = %#10x (%u K)\n", low_mem, low_mem >> 10);
+ printf("High mem = %#10x (%u K)\n", high_mem, high_mem >> 10);
+ putchar('\n');
+
+ /* Now, steal a chunk (2K) of DOS memory and make sure it registered OK */
+ insertrange(dos_mem-2048, 2048, 2); /* Type 2 = reserved */
+
+ printranges();
+ parse_mem();
+
+ putchar('\n');
+ printf("DOS mem = %#10x (%u K)\n", dos_mem, dos_mem >> 10);
+ printf("Low mem = %#10x (%u K)\n", low_mem, low_mem >> 10);
+ printf("High mem = %#10x (%u K)\n", high_mem, high_mem >> 10);
+ putchar('\n');
+
+ return 0;
+}
diff --git a/memdisk/msetup.c b/memdisk/msetup.c
new file mode 100644
index 00000000..c37169be
--- /dev/null
+++ b/memdisk/msetup.c
@@ -0,0 +1,183 @@
+#ident "$Id$"
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2001 H. Peter Anvin - All Rights Reserved
+ *
+ * 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., 53 Temple Place Ste 330,
+ * Bostom MA 02111-1307, USA; either version 2 of the License, or
+ * (at your option) any later version; incorporated herein by reference.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * msetup.c
+ *
+ * Initialization code for memory-based disk
+ */
+
+#include <stdint.h>
+#include "e820.h"
+
+static inline int get_e820(void)
+{
+ struct e820_info {
+ uint64_t base;
+ uint64_t len;
+ uint32_t type;
+ } __attribute__((packed));
+ struct e820_info buf;
+ uint32_t lastptr = 0;
+ int copied;
+ int range_count;
+
+ do {
+ asm volatile("int $0x15 ; "
+ "jc 1f ; "
+ "cmpl $0x534d4150, %%eax ; "
+ "je 2f\n"
+ "1:\n\t"
+ "xorl %%ecx, %%ecx\n"
+ "2:"
+ : "=c" (copied), "=&b" (lastptr)
+ : "a" (0x0000e820), "d" (0x534d4150),
+ "c" (20), "D" (&buf)
+ : "esi", "ebp");
+
+ if ( copied < 20 )
+ break;
+
+ insertrange(buf.base, buf.len, buf.type);
+ range_count++;
+
+ } while ( lastptr );
+
+ return !range_count;
+}
+
+static inline void get_dos_mem(void)
+{
+ uint16_t dos_kb;
+
+ asm volatile("int $0x12" : "=a" (dos_kb)
+ :: "ebx", "ecx", "edx", "esi", "edi", "ebp");
+
+ insertrange(0, (uint64_t)((uint32_t)dos_kb << 10), 1);
+}
+
+static inline int get_e881(void)
+{
+ uint32_t low_mem;
+ uint32_t high_mem;
+ uint8_t err;
+
+ asm volatile("movw $0xe881, %%ax ; "
+ "int $0x15 ; "
+ "setc %2"
+ : "=a" (low_mem), "=b" (high_mem), "=d" (err)
+ :: "ecx", "esi", "edi", "ebp");
+
+ if ( !err ) {
+ if ( low_mem ) {
+ insertrange(0x100000, (uint64_t)low_mem << 10, 1);
+ }
+ if ( high_mem ) {
+ insertrange(0x1000000, (uint64_t)high_mem << 16, 1);
+ }
+ }
+
+ return err;
+}
+
+static inline int get_e801(void)
+{
+ uint16_t low_mem;
+ uint16_t high_mem;
+ uint8_t err;
+
+ asm volatile("movw $0xe801, %%ax ; "
+ "int $0x15 ; "
+ "setc %2"
+ : "=a" (low_mem), "=b" (high_mem), "=d" (err)
+ :: "ecx", "esi", "edi", "ebp");
+
+ if ( !err ) {
+ if ( low_mem ) {
+ insertrange(0x100000, (uint64_t)((uint32_t)low_mem << 10), 1);
+ }
+ if ( high_mem ) {
+ insertrange(0x1000000, (uint64_t)((uint32_t)high_mem << 16), 1);
+ }
+ }
+
+ return err;
+}
+
+static inline int get_88(void)
+{
+ uint16_t low_mem;
+ uint8_t err;
+
+ asm volatile("movb $0x88,%%ah ; "
+ "int $0x15 ; "
+ "setc %1"
+ : "=a" (low_mem), "=d" (err)
+ :: "ebx", "ecx", "esi", "edi", "ebp");
+
+ if ( !err ) {
+ if ( low_mem ) {
+ insertrange(0x100000, (uint64_t)((uint32_t)low_mem << 10), 1);
+ }
+ }
+
+ return err;
+}
+
+uint32_t dos_mem = 0; /* 0-1MB */
+uint32_t low_mem = 0; /* 1-16MB */
+uint32_t high_mem = 0; /* 16+ MB */
+
+void get_mem(void)
+{
+ if ( get_e820() ) {
+ get_dos_mem();
+ if ( get_e881() ) {
+ if ( get_e801() ) {
+ if ( get_88() ) {
+ /* Running out of ideas here... */
+ }
+ }
+ }
+ }
+}
+
+void parse_mem(void)
+{
+ struct e820range *ep;
+
+ /* Derive "dos mem", "high mem", and "low mem" from the range array */
+ for ( ep = ranges ; ep->type != -1 ; ep++ ) {
+ if ( ep->type == 1 ) {
+ /* Only look at memory ranges */
+ if ( ep->start == 0 ) {
+ if ( ep[1].start > 0x100000 )
+ dos_mem = 0x100000;
+ else
+ dos_mem = ep[1].start;
+ }
+ if ( ep->start <= 0x100000 && ep[1].start > 0x100000 ) {
+ if ( ep[1].start > 0x1000000 )
+ low_mem = 0x1000000 - ep->start;
+ else
+ low_mem = ep[1].start - ep->start;
+ }
+ if ( ep->start <= 0x1000000 && ep[1].start > 0x1000000 ) {
+ if ( ep[1].start > 0x100000000 )
+ high_mem = 0x100000000 - ep->start;
+ else
+ high_mem = ep[1].start - ep->start;
+ }
+ }
+ }
+}
diff --git a/memdisk/testdata1 b/memdisk/testdata1
new file mode 100644
index 00000000..34ab566d
--- /dev/null
+++ b/memdisk/testdata1
@@ -0,0 +1,13 @@
+0000000000000000 000000000009bc00 1
+000000000009bc00 0000000000004400 2
+00000000000e9800 0000000000016800 2
+0000000000100000 0000000006ee0000 1
+0000000006fe0000 000000000000fc00 3
+0000000006fefc00 0000000000000400 4
+0000000006ff0000 0000000000002000 2
+0000000006ff2000 000000000000e000 1
+0000000007000000 0000000000100000 2
+00000000fff00000 0000000000100000 2
+
+0000000000586000 0000000000168000 2
+000000000009ba00 0000000000000200 2
diff --git a/memdisk/testdata2 b/memdisk/testdata2
new file mode 100644
index 00000000..8bec5bfc
--- /dev/null
+++ b/memdisk/testdata2
@@ -0,0 +1,10 @@
+0000000000000000 000000000009bc00 1
+000000000009bc00 0000000000004400 2
+00000000000e9800 0000000000016800 2
+0000000000100000 0000000006ee0000 1
+0000000006fe0000 000000000000fc00 3
+0000000006fefc00 0000000000000400 4
+0000000006ff0000 0000000000002000 2
+0000000006ff2000 000000000000e000 1
+0000000007000000 0000000000100000 2
+00000000fff00000 0000000000100000 2