diff options
-rw-r--r-- | memdisk/Makefile | 37 | ||||
-rw-r--r-- | memdisk/e820.h | 30 | ||||
-rw-r--r-- | memdisk/e820data | 13 | ||||
-rw-r--r-- | memdisk/e820func.c | 96 | ||||
-rw-r--r-- | memdisk/e820test.c | 74 | ||||
-rw-r--r-- | memdisk/msetup.c | 183 | ||||
-rw-r--r-- | memdisk/testdata1 | 13 | ||||
-rw-r--r-- | memdisk/testdata2 | 10 |
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 |