aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorH. Peter Anvin <hpa@zytor.com>2008-10-10 12:10:24 -0700
committerH. Peter Anvin <hpa@zytor.com>2008-10-13 12:26:58 -0700
commit652c3057145a41703e5e817d86b2584db9ab806d (patch)
tree003b164e76dad49fe944c2053dad89208e93f7e2
parentef45d17e31d591a579c1d51a5e6a026493465a64 (diff)
downloadsyslinux-elf-652c3057145a41703e5e817d86b2584db9ab806d.tar.gz
syslinux-elf-652c3057145a41703e5e817d86b2584db9ab806d.tar.xz
syslinux-elf-652c3057145a41703e5e817d86b2584db9ab806d.zip
Support "extended attributes" for INT 15h, AX=E820h
Some blithering idiot thought it was a good idea to introduce "extended attributes" for INT 15h, AX=E820h, and in doing so, breaking compatibility with ALL E820 users out there. F*cking morons. Implement handling of extended attributes in: - e820 parsing in the core - e820 parsing in libcom32 - e820 parsing *and proxying* in memdisk The latter is the really painful one. Signed-off-by: H. Peter Anvin <hpa@zytor.com>
-rw-r--r--com32/lib/syslinux/memmap.c9
-rw-r--r--core/highmem.inc14
-rw-r--r--memdisk/e820.h3
-rw-r--r--memdisk/e820data26
-rw-r--r--memdisk/e820func.c42
-rw-r--r--memdisk/e820test.c15
-rw-r--r--memdisk/memdisk.asm30
-rw-r--r--memdisk/msetup.c21
-rw-r--r--memdisk/setup.c4
9 files changed, 107 insertions, 57 deletions
diff --git a/com32/lib/syslinux/memmap.c b/com32/lib/syslinux/memmap.c
index 5a0a34f7..c5f1b251 100644
--- a/com32/lib/syslinux/memmap.c
+++ b/com32/lib/syslinux/memmap.c
@@ -46,6 +46,7 @@ struct e820_entry {
uint64_t start;
uint64_t len;
uint32_t type;
+ uint32_t extattr;
};
struct syslinux_memmap *syslinux_memory_map(void)
@@ -74,7 +75,7 @@ struct syslinux_memmap *syslinux_memory_map(void)
ireg.eax.l = 0xe820;
ireg.edx.l = 0x534d4150;
ireg.ebx.l = 0;
- ireg.ecx.l = 20;
+ ireg.ecx.l = sizeof(*e820buf);
ireg.es = SEG(e820buf);
ireg.edi.w[0] = OFFS(e820buf);
@@ -86,6 +87,12 @@ struct syslinux_memmap *syslinux_memory_map(void)
(oreg.ecx.l < 20))
break;
+ if (oreg.ecx.l >= 24)
+ e820buf->extattr = 1; /* Enabled, normal */
+
+ if (!(e820buf->extattr & 1))
+ continue;
+
type = e820buf->type == 1 ? SMT_FREE : SMT_RESERVED;
start = e820buf->start;
len = e820buf->len;
diff --git a/core/highmem.inc b/core/highmem.inc
index 1cd46dd9..7341bf27 100644
--- a/core/highmem.inc
+++ b/core/highmem.inc
@@ -47,7 +47,7 @@ get_e820:
.do_e820: mov eax,0000E820h
mov edx,534D4150h ; "SMAP" backwards
xor ecx,ecx
- mov cl,20 ; ECX <- 20
+ mov cl,24 ; ECX <- 24 (size of buffer)
mov di,E820Buf
int 15h
jnc .no_carry
@@ -58,6 +58,15 @@ get_e820:
.no_carry:
cmp eax,534D4150h
jne no_e820
+ cmp cl,24
+ jb .no_ext_attr
+ ;
+ ; Some blithering idiot added a whole new field to E820,
+ ; completely without regard for its implications...
+ ;
+ test byte [E820Buf+20],1 ; AddressRangeEnabled
+ jz .not_ram
+.no_ext_attr:
;
; Look for a memory block starting at <= 1 MB and continuing upward
;
@@ -70,6 +79,7 @@ get_e820:
; Non-memory range. Remember this as a limit; some BIOSes get the length
; of primary RAM incorrect!
;
+.not_ram:
cmp eax, (1 << 20)
jb .int_loop ; Starts in lowmem region
cmp eax,[E820Max]
@@ -142,7 +152,7 @@ got_highmem:
section .bss
alignb 4
-E820Buf resd 5 ; INT 15:E820 data buffer
+E820Buf resd 6 ; INT 15:E820 data buffer
E820Mem resd 1 ; Memory detected by E820
E820Max resd 1 ; Is E820 memory capped?
HighMemSize resd 1 ; End of memory pointer (bytes)
diff --git a/memdisk/e820.h b/memdisk/e820.h
index 04b44484..429b98c2 100644
--- a/memdisk/e820.h
+++ b/memdisk/e820.h
@@ -21,6 +21,7 @@
struct e820range {
uint64_t start;
uint32_t type;
+ uint32_t extattr;
} __attribute__((packed));
extern struct e820range ranges[];
@@ -28,6 +29,6 @@ extern int nranges;
extern uint32_t dos_mem, low_mem, high_mem;
extern void e820map_init(void);
-extern void insertrange(uint64_t, uint64_t, uint32_t);
+extern void insertrange(uint64_t, uint64_t, uint32_t, uint32_t);
extern void get_mem(void);
extern void parse_mem(void);
diff --git a/memdisk/e820data b/memdisk/e820data
index 34ab566d..14320aac 100644
--- a/memdisk/e820data
+++ b/memdisk/e820data
@@ -1,13 +1,15 @@
-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
+0000000000000000 000000000009bc00 1 1
+000000000009bc00 0000000000004400 2 1
+00000000000e9800 0000000000016800 2 1
+00000000000e9800 000000000000b400 2 1
+00000000000f5000 000000000000b000 2 9
+0000000000100000 0000000006ee0000 1 1
+0000000006fe0000 000000000000fc00 3 1
+0000000006fefc00 0000000000000400 4 1
+0000000006ff0000 0000000000002000 2 1
+0000000006ff2000 000000000000e000 1 1
+0000000007000000 0000000000100000 2 1
+00000000fff00000 0000000000100000 2 1
-0000000000586000 0000000000168000 2
-000000000009ba00 0000000000000200 2
+0000000000586000 0000000000168000 2 1
+000000000009ba00 0000000000000200 2 1
diff --git a/memdisk/e820func.c b/memdisk/e820func.c
index 577469b7..a6896745 100644
--- a/memdisk/e820func.c
+++ b/memdisk/e820func.c
@@ -17,7 +17,11 @@
*/
#include <stdint.h>
+#ifdef TEST
+#include <string.h>
+#else
#include "memdisk.h" /* For memset() */
+#endif
#include "e820.h"
#define MAXRANGES 1024
@@ -33,25 +37,28 @@ void e820map_init(void)
ranges[1].type = -1;
}
-static void insertrange_at(int where, uint64_t start, uint32_t type)
+static void insertrange_at(int where, uint64_t start,
+ uint32_t type, uint32_t extattr)
{
int i;
for ( i = nranges ; i > where ; i-- )
ranges[i] = ranges[i-1];
- ranges[where].start = start;
- ranges[where].type = type;
+ ranges[where].start = start;
+ ranges[where].type = type;
+ ranges[where].extattr = extattr;
nranges++;
- ranges[nranges].start = 0ULL;
- ranges[nranges].type = (uint32_t)-1;
+ ranges[nranges].start = 0ULL;
+ ranges[nranges].type = (uint32_t)-1;
+ ranges[nranges].extattr = 0;
}
-void insertrange(uint64_t start, uint64_t len, uint32_t type)
+void insertrange(uint64_t start, uint64_t len, uint32_t type, uint32_t extattr)
{
uint64_t last;
- uint32_t oldtype;
+ uint32_t oldtype, oldattr;
int i, j;
/* Remove this to make len == 0 mean all of memory */
@@ -61,35 +68,42 @@ void insertrange(uint64_t start, uint64_t len, uint32_t type)
last = start+len-1; /* May roll over */
i = 0;
- oldtype = -2;
- while ( start > ranges[i].start && ranges[i].type != -1 ) {
+ oldtype = -2U;
+ oldattr = 0;
+ while ( start > ranges[i].start && ranges[i].type != -1U ) {
oldtype = ranges[i].type;
+ oldattr = ranges[i].extattr;
i++;
}
/* Consider the replacement policy. This current one is "overwrite." */
- if ( start < ranges[i].start || ranges[i].type == -1 )
- insertrange_at(i++, start, type);
+ if ( start < ranges[i].start || ranges[i].type == -1U )
+ insertrange_at(i++, start, type, extattr);
while ( i == 0 || last > ranges[i].start-1 ) {
oldtype = ranges[i].type;
- ranges[i].type = type;
+ oldattr = ranges[i].extattr;
+ ranges[i].type = type;
+ ranges[i].extattr = extattr;
i++;
}
if ( last < ranges[i].start-1 )
- insertrange_at(i, last+1, oldtype);
+ insertrange_at(i, last+1, oldtype, oldattr);
/* 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;
+ oldattr = ranges[0].extattr;
while ( i < nranges ) {
- if ( ranges[i].type == oldtype ) {
+ if ( ranges[i].type == oldtype &&
+ ranges[i].extattr == oldattr ) {
i++;
} else {
oldtype = ranges[i].type;
+ oldattr = ranges[i].extattr;
if ( i != j )
ranges[j] = ranges[i];
i++; j++;
diff --git a/memdisk/e820test.c b/memdisk/e820test.c
index c2be7437..41fee007 100644
--- a/memdisk/e820test.c
+++ b/memdisk/e820test.c
@@ -36,17 +36,17 @@ void printranges(void) {
int i;
for ( i = 0 ; i < nranges ; i++ ) {
- printf("%016llx %016llx %d\n",
+ printf("%016llx %016llx %d %x\n",
ranges[i].start,
ranges[i+1].start - ranges[i].start,
- ranges[i].type);
+ ranges[i].type, ranges[i].extattr);
}
}
int main(void)
{
uint64_t start, len;
- uint32_t type;
+ uint32_t type, extattr;
char line[BUFSIZ], *p;
e820map_init();
@@ -55,11 +55,12 @@ int main(void)
while ( fgets(line, BUFSIZ, stdin) ) {
p = strchr(line, ':');
p = p ? p+1 : line;
- if ( sscanf(p, " %llx %llx %d", &start, &len, &type) == 3 ) {
+ extattr = 1;
+ if ( sscanf(p, " %llx %llx %d %x", &start, &len, &type, &extattr) >= 3 ) {
putchar('\n');
- printf("%016llx %016llx %d <-\n", start, len, type);
+ printf("%016llx %016llx %d %x <-\n", start, len, type, extattr);
putchar('\n');
- insertrange(start, len, type);
+ insertrange(start, len, type, extattr);
printranges();
}
}
@@ -73,7 +74,7 @@ int main(void)
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 */
+ insertrange(dos_mem-2048, 2048, 2, 1); /* Type 2 = reserved */
printranges();
parse_mem();
diff --git a/memdisk/memdisk.asm b/memdisk/memdisk.asm
index eb4370ab..47b55fce 100644
--- a/memdisk/memdisk.asm
+++ b/memdisk/memdisk.asm
@@ -530,38 +530,46 @@ EDDEject:
;
int15_e820:
cmp edx,534D4150h ; "SMAP"
- jne near oldint15
+ jne oldint15
cmp ecx,20 ; Need 20 bytes
jb err86
push ds
push cs
pop ds
+ push edx ; "SMAP"
and ebx,ebx
jne .renew
mov ebx,E820Table
.renew:
- add bx,12 ; Advance to next
- mov eax,[bx-4] ; Type
+ add bx,16 ; Advance to next
+ mov eax,[bx-8] ; Type
and eax,eax ; Null type?
jz .renew ; If so advance to next
mov [es:di+16],eax
- mov eax,[bx-12] ; Start addr (low)
+ and cl,~3
+ cmp ecx,24
+ jb .no_extattr
+ mov eax,[bx-4] ; Extended attributes
+ mov [es:di+20],eax
+ mov ecx,24 ; Bytes loaded
+.no_extattr:
+ push ecx
+ mov eax,[bx-16] ; Start addr (low)
mov [es:di],eax
- mov ecx,[bx-8] ; Start addr (high)
- mov [es:di+4],ecx
+ mov ecx,[bx-12] ; Start addr (high)
+ mov [es:di+4],edx
mov eax,[bx] ; End addr (low)
- mov ecx,[bx+4] ; End addr (high)
- sub eax,[bx-12] ; Derive the length
- sbb ecx,[bx-8]
+ mov edx,[bx+4] ; End addr (high)
+ sub eax,[bx-16] ; Derive the length
+ sbb edx,[bx-12]
mov [es:di+8],eax ; Length (low)
mov [es:di+12],ecx ; Length (high)
cmp dword [bx+8],-1 ; Type of next = end?
jne .notdone
xor ebx,ebx ; Done with table
.notdone:
- mov eax,edx ; "SMAP"
+ pop eax ; "SMAP"
pop ds
- mov ecx,20 ; Bytes loaded
int15_success:
mov byte [bp+6], 02h ; Clear CF
pop bp
diff --git a/memdisk/msetup.c b/memdisk/msetup.c
index 12ba2179..f126d878 100644
--- a/memdisk/msetup.c
+++ b/memdisk/msetup.c
@@ -27,6 +27,7 @@ static inline int get_e820(void)
uint64_t base;
uint64_t len;
uint32_t type;
+ uint32_t extattr;
} *buf = sys_bounce;
uint32_t copied;
int range_count = 0;
@@ -47,12 +48,18 @@ static inline int get_e820(void)
if ( regs.eax.l != 0x534d4150 || copied < 20 )
break;
- printf("e820: %08x%08x %08x%08x %d\n",
+ if ( copied < 24 )
+ buf->extattr = 1;
+
+ printf("e820: %08x%08x %08x%08x %d [%x]\n",
(uint32_t)(buf->base >> 32), (uint32_t)buf->base,
(uint32_t)(buf->len >> 32), (uint32_t)buf->len,
- buf->type);
+ buf->type, buf->extattr);
+
+ if ( !(buf->extattr & 1) )
+ continue; /* Disabled range, just ignore */
- insertrange(buf->base, buf->len, buf->type);
+ insertrange(buf->base, buf->len, buf->type, buf->extattr);
range_count++;
} while ( regs.ebx.l );
@@ -66,7 +73,7 @@ static inline void get_dos_mem(void)
memset(&regs, 0, sizeof regs);
syscall(0x12, &regs, &regs);
- insertrange(0, (uint64_t)((uint32_t)regs.eax.w[0] << 10), 1);
+ insertrange(0, (uint64_t)((uint32_t)regs.eax.w[0] << 10), 1, 1);
printf(" DOS: %d K\n", regs.eax.w[0]);
}
@@ -82,10 +89,10 @@ static inline int get_e801(void)
if ( !(err = regs.eflags.l & 1) ) {
if ( regs.eax.w[0] ) {
- insertrange(0x100000, (uint64_t)((uint32_t)regs.eax.w[0] << 10), 1);
+ insertrange(0x100000, (uint64_t)((uint32_t)regs.eax.w[0] << 10), 1, 1);
}
if ( regs.ebx.w[0] ) {
- insertrange(0x1000000, (uint64_t)((uint32_t)regs.ebx.w[0] << 16), 1);
+ insertrange(0x1000000, (uint64_t)((uint32_t)regs.ebx.w[0] << 16), 1, 1);
}
printf("e801: %04x %04x\n", regs.eax.w[0], regs.ebx.w[0]);
@@ -107,7 +114,7 @@ static inline int get_88(void)
if ( !(err = regs.eflags.l & 1) ) {
if ( regs.eax.w[0] ) {
- insertrange(0x100000, (uint64_t)((uint32_t)regs.eax.w[0] << 10), 1);
+ insertrange(0x100000, (uint64_t)((uint32_t)regs.eax.w[0] << 10), 1, 1);
}
printf(" 88: %04x\n", regs.eax.w[0]);
diff --git a/memdisk/setup.c b/memdisk/setup.c
index 583570ea..a52f136c 100644
--- a/memdisk/setup.c
+++ b/memdisk/setup.c
@@ -654,7 +654,7 @@ __cdecl void setup(__cdecl syscall_t cs_syscall, void *cs_bounce)
do_edd ? "on" : "off");
/* Reserve the ramdisk memory */
- insertrange(ramdisk_image, ramdisk_size, 2);
+ insertrange(ramdisk_image, ramdisk_size, 2, 1);
parse_mem(); /* Recompute variables */
/* Figure out where it needs to go */
@@ -772,7 +772,7 @@ __cdecl void setup(__cdecl syscall_t cs_syscall, void *cs_bounce)
/* Reserve this range of memory */
wrz_16(BIOS_BASEMEM, driveraddr >> 10);
- insertrange(driveraddr, dos_mem-driveraddr, 2);
+ insertrange(driveraddr, dos_mem-driveraddr, 2, 1);
parse_mem();
pptr->mem1mb = low_mem >> 10;