Support "extended attributes" for INT 15h, AX=E820h
authorH. Peter Anvin <hpa@zytor.com>
Fri, 10 Oct 2008 19:10:24 +0000 (12:10 -0700)
committerH. Peter Anvin <hpa@zytor.com>
Mon, 13 Oct 2008 19:26:58 +0000 (12:26 -0700)
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>
com32/lib/syslinux/memmap.c
core/highmem.inc
memdisk/e820.h
memdisk/e820data
memdisk/e820func.c
memdisk/e820test.c
memdisk/memdisk.asm
memdisk/msetup.c
memdisk/setup.c

index 5a0a34f..c5f1b25 100644 (file)
@@ -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;
index 1cd46dd..7341bf2 100644 (file)
@@ -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)
index 04b4448..429b98c 100644 (file)
@@ -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);
index 34ab566..14320aa 100644 (file)
@@ -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
index 577469b..a689674 100644 (file)
  */
 
 #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++;
index c2be743..41fee00 100644 (file)
@@ -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();
index eb4370a..47b55fc 100644 (file)
@@ -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
index 12ba217..f126d87 100644 (file)
@@ -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]);
index 583570e..a52f136 100644 (file)
@@ -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;