Checkpoint: add printf() for debugging, remove query of E881 (seems
authorhpa <hpa>
Tue, 11 Dec 2001 01:14:19 +0000 (01:14 +0000)
committerhpa <hpa>
Tue, 11 Dec 2001 01:14:19 +0000 (01:14 +0000)
to hang some systems), move E820 table to conventional memory
(sized dynamically), use BIOS memory pointer to determine where in
DOS memory to put our routine.

memdisk/Makefile
memdisk/conio.c
memdisk/conio.h
memdisk/e820test.c
memdisk/init.S16
memdisk/memdisk.asm
memdisk/memdisk.h [new file with mode: 0644]
memdisk/msetup.c
memdisk/setup.c

index 83b2210..d5884c0 100644 (file)
@@ -12,7 +12,7 @@
 ## -----------------------------------------------------------------------
 
 CC      = gcc
-CFLAGS  = -g -O2 -fomit-frame-pointer -march=i386 \
+CFLAGS  = -O2 -fomit-frame-pointer -march=i386 \
          -malign-functions=0 -malign-jumps=0 -malign-loops=0
 LDFLAGS = 
 AS      = as
@@ -33,8 +33,7 @@ clean:
        $(AS) -o $@ $<
 
 %.s16: %.s
-       echo '.code16' > $@
-       sed -e 's/\bcall\b/calll/g' -e 's/\bret\b/retl/g' < $< >> $@
+       echo '.code16gcc' | cat - $< > $@
 
 %.s: %.S
        $(CC) -x c $(CFLAGS) -Wp,-traditional -E -o $@ $<
index c2f8616..8599ddd 100644 (file)
@@ -52,3 +52,313 @@ int puts(const char *s)
 
   return count;
 }
+
+/*
+ * Oh, it's a waste of space, but oh-so-yummy for debugging.  It's just
+ * initialization code anyway, so it doesn't take up space when we're
+ * actually running.  This version of printf() does not include 64-bit
+ * support.  "Live with it."
+ *
+ * Most of this code was shamelessly snarfed from the Linux kernel, then
+ * modified.
+ */
+
+static inline int
+isdigit(int ch)
+{
+  return (ch >= '0') && (ch <= '9');
+}
+
+static int skip_atoi(const char **s)
+{
+  int i=0;
+  
+  while (isdigit(**s))
+    i = i*10 + *((*s)++) - '0';
+  return i;
+}
+
+static int strnlen(const char *s, int maxlen)
+{
+  const char *es = s;
+  while ( *es && maxlen ) {
+    es++; maxlen--;
+  }
+
+  return (es-s);
+}
+
+#define ZEROPAD        1               /* pad with zero */
+#define SIGN   2               /* unsigned/signed long */
+#define PLUS   4               /* show plus */
+#define SPACE  8               /* space if plus */
+#define LEFT   16              /* left justified */
+#define SPECIAL        32              /* 0x */
+#define LARGE  64              /* use 'ABCDEF' instead of 'abcdef' */
+
+#define do_div(n,base) ({ \
+int __res; \
+__res = ((unsigned long) n) % (unsigned) base; \
+n = ((unsigned long) n) / (unsigned) base; \
+__res; })
+
+static char * number(char * str, long num, int base, int size, int precision
+       ,int type)
+{
+  char c,sign,tmp[66];
+  const char *digits="0123456789abcdefghijklmnopqrstuvwxyz";
+  int i;
+  
+  if (type & LARGE)
+    digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+  if (type & LEFT)
+    type &= ~ZEROPAD;
+  if (base < 2 || base > 36)
+    return 0;
+  c = (type & ZEROPAD) ? '0' : ' ';
+  sign = 0;
+  if (type & SIGN) {
+    if (num < 0) {
+      sign = '-';
+      num = -num;
+      size--;
+    } else if (type & PLUS) {
+      sign = '+';
+      size--;
+    } else if (type & SPACE) {
+      sign = ' ';
+      size--;
+    }
+  }
+  if (type & SPECIAL) {
+    if (base == 16)
+      size -= 2;
+    else if (base == 8)
+      size--;
+  }
+  i = 0;
+  if (num == 0)
+    tmp[i++]='0';
+  else while (num != 0)
+    tmp[i++] = digits[do_div(num,base)];
+  if (i > precision)
+    precision = i;
+  size -= precision;
+  if (!(type&(ZEROPAD+LEFT)))
+    while(size-->0)
+      *str++ = ' ';
+  if (sign)
+    *str++ = sign;
+  if (type & SPECIAL) {
+    if (base==8)
+      *str++ = '0';
+    else if (base==16) {
+      *str++ = '0';
+      *str++ = digits[33];
+    }
+  }
+  if (!(type & LEFT))
+    while (size-- > 0)
+      *str++ = c;
+  while (i < precision--)
+    *str++ = '0';
+  while (i-- > 0)
+    *str++ = tmp[i];
+  while (size-- > 0)
+    *str++ = ' ';
+  return str;
+}
+
+/* Forward decl. needed for IP address printing stuff... */
+int sprintf(char * buf, const char *fmt, ...);
+
+int vsprintf(char *buf, const char *fmt, va_list args)
+{
+  int len;
+  unsigned long num;
+  int i, base;
+  char * str;
+  const char *s;
+  
+  int flags;           /* flags to number() */
+  
+  int field_width;     /* width of output field */
+  int precision;               /* min. # of digits for integers; max
+                                  number of chars for from string */
+  int qualifier;               /* 'h', 'l', or 'L' for integer fields */
+  
+  for (str=buf ; *fmt ; ++fmt) {
+    if (*fmt != '%') {
+      *str++ = *fmt;
+      continue;
+    }
+    
+    /* process flags */
+    flags = 0;
+  repeat:
+    ++fmt;             /* this also skips first '%' */
+    switch (*fmt) {
+    case '-': flags |= LEFT; goto repeat;
+    case '+': flags |= PLUS; goto repeat;
+    case ' ': flags |= SPACE; goto repeat;
+    case '#': flags |= SPECIAL; goto repeat;
+    case '0': flags |= ZEROPAD; goto repeat;
+    }
+    
+    /* get field width */
+    field_width = -1;
+    if (isdigit(*fmt))
+      field_width = skip_atoi(&fmt);
+    else if (*fmt == '*') {
+      ++fmt;
+      /* it's the next argument */
+      field_width = va_arg(args, int);
+      if (field_width < 0) {
+       field_width = -field_width;
+       flags |= LEFT;
+      }
+    }
+    
+    /* get the precision */
+    precision = -1;
+    if (*fmt == '.') {
+      ++fmt;   
+      if (isdigit(*fmt))
+       precision = skip_atoi(&fmt);
+      else if (*fmt == '*') {
+       ++fmt;
+       /* it's the next argument */
+       precision = va_arg(args, int);
+      }
+      if (precision < 0)
+       precision = 0;
+    }
+    
+    /* get the conversion qualifier */
+    qualifier = -1;
+    if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L') {
+      qualifier = *fmt;
+      ++fmt;
+    }
+    
+    /* default base */
+    base = 10;
+    
+    switch (*fmt) {
+    case 'c':
+      if (!(flags & LEFT))
+       while (--field_width > 0)
+         *str++ = ' ';
+      *str++ = (unsigned char) va_arg(args, int);
+      while (--field_width > 0)
+       *str++ = ' ';
+      continue;
+      
+    case 's':
+      s = va_arg(args, char *);
+      if (!s)
+       s = "(null)";
+      
+      len = strnlen(s, precision);
+      
+      if (!(flags & LEFT))
+       while (len < field_width--)
+         *str++ = ' ';
+      for (i = 0; i < len; ++i)
+       *str++ = *s++;
+      while (len < field_width--)
+       *str++ = ' ';
+      continue;
+      
+    case 'p':
+      if (field_width == -1) {
+       field_width = 2*sizeof(void *);
+       flags |= ZEROPAD;
+      }
+      str = number(str,
+                  (unsigned long) va_arg(args, void *), 16,
+                  field_width, precision, flags);
+      continue;
+      
+      
+    case 'n':
+      if (qualifier == 'l') {
+       long * ip = va_arg(args, long *);
+       *ip = (str - buf);
+      } else {
+       int * ip = va_arg(args, int *);
+       *ip = (str - buf);
+      }
+      continue;
+      
+    case '%':
+      *str++ = '%';
+      continue;
+      
+      /* integer number formats - set up the flags and "break" */
+    case 'o':
+      base = 8;
+      break;
+      
+    case 'X':
+      flags |= LARGE;
+    case 'x':
+      base = 16;
+      break;
+      
+    case 'd':
+    case 'i':
+      flags |= SIGN;
+    case 'u':
+      break;
+      
+    default:
+      *str++ = '%';
+      if (*fmt)
+       *str++ = *fmt;
+      else
+       --fmt;
+      continue;
+    }
+    if (qualifier == 'l')
+      num = va_arg(args, unsigned long);
+    else if (qualifier == 'h') {
+      num = (unsigned short) va_arg(args, int);
+      if (flags & SIGN)
+       num = (short) num;
+    } else if (flags & SIGN)
+      num = va_arg(args, int);
+    else
+      num = va_arg(args, unsigned int);
+    str = number(str, num, base, field_width, precision, flags);
+  }
+  *str = '\0';
+  return str-buf;
+}
+
+int sprintf(char * buf, const char *fmt, ...)
+{
+  va_list args;
+  int i;
+  
+  va_start(args, fmt);
+  i=vsprintf(buf,fmt,args);
+  va_end(args);
+  return i;
+}
+
+int printf(const char *fmt, ...)
+{
+  char printf_buf[1024];
+  va_list args;
+  int printed;
+
+  va_start(args, fmt);
+  printed = vsprintf(printf_buf, fmt, args);
+  va_end(args);
+
+  puts(printf_buf);
+
+  return printed;
+}
+
index ced7c2c..7f823ae 100644 (file)
 #ifndef CONIO_H
 #define CONIO_H
 
+#include <stdint.h>
+#include <stdarg.h>
+
 int putchar(int);
 int puts(const char *);
+int printf(const char *, ...);
 
 #endif
index 2717fdc..2d8be07 100644 (file)
 extern void parse_mem(void);
 extern uint32_t dos_mem, low_mem, high_mem;
 
+void __attribute__((noreturn)) die(void)
+{
+  abort();
+}
+
 void printranges(void) {
   int i;
 
index 1cdff31..955e872 100644 (file)
@@ -19,7 +19,7 @@
  * This module *MUST* get linked first into the image
  */
 
-               .section ".text", "ax"
+               .text
                .code16
 
 /*
@@ -114,28 +114,38 @@ ramdisk_max:      .long 0xffffffff        # Load ramdisk as high as
 
 /* ------------------- End of setup header --------------------------- */
 
-/*
- * Canonicalize CS to match the other segments
- */
-start:
-               pushw %ds
-               pushw $start2
-               lret
+LOWSEG = 0x0800                # 0x8000 physical
 
-start2:
 /*
- * Set up the operating environment expected by the C code.
+ * Move ourselves down in memory to reduce the risk of conflicts;
+ * the canonicalize CS to match the other segments...
+ *
  * The C code uses 32-bit registers to make sure the high part of
  * %esp is zero.
  *
- * The C code expects %cs == %ds == %es, and %fs == 0.
+ * The C code expects %cs == %ds == %es == %ss, and %fs == 0.
+ */
+start:
+               movw $LOWSEG,%ax
+               movw %ax,%es
+               movzbw setup_sects,%cx
+               inc %cx                 # Add one for the boot sector
+               shlw $7,%cx             # Convert to dwords
+               xorw %si,%si
+               xorw %di,%di
+               movw %si,%fs            # %fs -> zero segment
+               cld
+               rep ; movsl %ds:(%si),%es:(%di)
+               movw %ax,%ds
+               movw %ax,%ss
+               xorl %esp,%esp          # Stack at the top of the segment
+               ljmp $LOWSEG, $startc
+
+startc:
+/*
+ * Set up the operating environment expected by the C code.
  */
-               .byte 0x66,0x0f,0xb7,0xe4       # movzwl %sp,%esp
-               pushw %ds
-               popw %es
-               xorw %ax,%ax
-               movw %ax,%fs
-               sti                     # We may want to kill this?
+               sti                     # Maybe not?
                calll setup             # Call the C code
                # The setup function returns the drive number,
                # which should be returned in %dl
index 3c9513d..ddaf100 100644 (file)
@@ -239,41 +239,37 @@ setup_regs:
                ret
 
 int15_e820:
-               cmp edx,534D4150h
+               cmp edx,534D4150h       ; "SMAP"
                jne near oldint15
                cmp ecx,20              ; Need 20 bytes
                jb err86
+               push ds
+               push cs
+               pop ds
                push edx                ; "SMAP"
-               push esi
-               push edi
                and ebx,ebx
                jne .renew
-               mov ebx,[E820Table]
-.renew:                mov esi,ebx
-               xor edi,edi
-               mov di,cs
-               shr di,4
-               add edi,E820Buf
-               mov ecx,24/2
-               call bcopy
-               add ebx, byte 12
-               pop edi
-               pop esi
-               mov eax,[cs:E820Buf]
+               mov ebx,E820Table
+.renew:
+               add bx, byte 12         ; Advance to next
+               mov eax,[bx-12]         ; Start addr (low)
                mov [es:di],eax
-               mov eax,[cs:E820Buf+4]
-               mov [es:di+4],eax
-               mov eax,[cs:E820Buf+12]
-               mov [es:di+8],eax
-               mov eax,[cs:E820Buf+16]
-               mov [es:di+12],eax
-               mov eax,[cs:E820Buf+8]
+               mov ecx,[bx-8]          ; Start addr (high)
+               mov [es:di+4],ecx
+               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 [es:di+8],eax       ; Length (low)
+               mov [es:di+12],ecx      ; Length (high)
+               mov eax,[bx-4]          ; Type
                mov [es:di+16],eax
-               cmp dword [cs:E820Buf+20], byte -1
+               cmp dword [bx+8], byte -1       ; Type of next = end?
                jne .notdone
                xor ebx,ebx             ; Done with table
 .notdone:
                pop eax                 ; "SMAP"
+               pop ds
                mov ecx,20              ; Bytes loaded
 int15_success:
                mov byte [bp+12], 02h   ; Clear CF
@@ -412,33 +408,34 @@ Mover_dst2:       db 0                    ; High 8 bits of source addy
 
 LastStatus     db 0                    ; Last return status
 
-               section .bss
-               alignb 4
+               alignb 4, db 0
 PatchArea      equ $                   ; This gets filled in by the installer
 
-Cylinders      resw 1                  ; Cylinder count
-Heads          resw 1                  ; Head count
-Sectors                resd 1                  ; Sector count (zero-extended)
-DiskSize       resd 1                  ; Size of disk in blocks
-DiskBuf                resd 1                  ; Linear address of high memory disk
+Cylinders      dw 0                    ; Cylinder count
+Heads          dw 0                    ; Head count
+Sectors                dd 0                    ; Sector count (zero-extended)
+DiskSize       dd 0                    ; Size of disk in blocks
+DiskBuf                dd 0                    ; Linear address of high memory disk
 
-E820Table      resd 1                  ; E820 table in high memory
-Mem1MB         resd 1                  ; 1MB-16MB memory amount (1K)
-Mem16MB                resd 1                  ; 16MB-4G memory amount (64K)
-MemInt1588     resd 1                  ; 1MB-65MB memory amount (1K)
+Mem1MB         dd 0                    ; 1MB-16MB memory amount (1K)
+Mem16MB                dd 0                    ; 16MB-4G memory amount (64K)
+MemInt1588     dd 0                    ; 1MB-65MB memory amount (1K)
 
-OldInt13       resd 1                  ; INT 13h in chain
-OldInt15       resd 1                  ; INT 15h in chain
+OldInt13       dd 0                    ; INT 13h in chain
+OldInt15       dd 0                    ; INT 15h in chain
 
-OldDosMem      resw 1                  ; Old position of DOS mem end
+OldDosMem      dw 0                    ; Old position of DOS mem end
 
-DriveNo                resb 1                  ; Our drive number
-DriveType      resb 1                  ; Our drive type (floppies)
+DriveNo                db 0                    ; Our drive number
+DriveType      db 0                    ; Our drive type (floppies)
 
                ; End patch area
 
-Stack          resd 2                  ; Saved SS:ESP on invocation
-E820Buf                resd 6                  ; E820 fetch buffer
-SavedAX                resw 1                  ; AX saved on invocation
+Stack          dd 0                    ; Saved SS:ESP on invocation
+               dw 0
+SavedAX                dw 0                    ; AX saved on invocation
+
+               alignb 4, db 0          ; We *MUST* end on a dword boundary
 
+E820Table      equ $                   ; The installer loads the E820 table here
 TotalSize      equ $                   ; End pointer
diff --git a/memdisk/memdisk.h b/memdisk/memdisk.h
new file mode 100644 (file)
index 0000000..b54968d
--- /dev/null
@@ -0,0 +1,26 @@
+#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.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * memdisk.h
+ *
+ * Miscellaneous header definitions
+ */
+
+#ifndef MEMDISK_H
+#define MEMDISK_H
+
+/* What to call when we're dead */
+extern void __attribute__((noreturn)) die(void);
+
+#endif
index c37169b..ccb4352 100644 (file)
@@ -18,6 +18,8 @@
  */
 
 #include <stdint.h>
+#include "memdisk.h"
+#include "conio.h"
 #include "e820.h"
 
 static inline int get_e820(void)
@@ -26,28 +28,36 @@ static inline int get_e820(void)
     uint64_t base;
     uint64_t len;
     uint32_t type;
-  } __attribute__((packed));
+  };
   struct e820_info buf;
   uint32_t lastptr = 0;
-  int copied;
-  int range_count;
+  uint32_t copied;
+  int range_count = 0;
   
   do {
+    puts("Calling INT 15 E820...\n");
     asm volatile("int $0x15 ; "
                 "jc 1f ; "
                 "cmpl $0x534d4150, %%eax ; "
                 "je 2f\n"
                 "1:\n\t"
-                "xorl %%ecx, %%ecx\n"
+                "xorl %0,%0\n"
                 "2:"
-                : "=c" (copied), "=&b" (lastptr)
+                : "=c" (copied), "+b" (lastptr)
                 : "a" (0x0000e820), "d" (0x534d4150),
-                "c" (20), "D" (&buf)
-                : "esi", "ebp");
+                "c" (sizeof(buf)), "D" (&buf)
+                : "eax", "edx", "esi", "edi", "ebp");
 
     if ( copied < 20 )
       break;
 
+    printf("BIOS e820: %08x%08x %08x%08x %u\n",
+          (uint32_t)(buf.base >> 32),
+          (uint32_t)buf.base,
+          (uint32_t)(buf.len >> 32),
+          (uint32_t)buf.len,
+          buf.type);
+
     insertrange(buf.base, buf.len, buf.type);
     range_count++;
 
@@ -60,42 +70,22 @@ static inline void get_dos_mem(void)
 {
   uint16_t dos_kb;
 
+  puts("Calling INT 12...\n");
   asm volatile("int $0x12" : "=a" (dos_kb)
               :: "ebx", "ecx", "edx", "esi", "edi", "ebp");
+
+  printf("BIOS 12:   %u K DOS memory\n", dos_kb);
   
   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;
 
+  puts("Calling INT 15 E801...\n");
   asm volatile("movw $0xe801, %%ax ; "
               "int $0x15 ; "
               "setc %2"
@@ -103,6 +93,9 @@ static inline int get_e801(void)
               :: "ecx", "esi", "edi", "ebp");
 
   if ( !err ) {
+    printf("BIOS e801: %u K low mem, %u K high mem\n",
+          low_mem, high_mem << 6);
+
     if ( low_mem ) {
       insertrange(0x100000, (uint64_t)((uint32_t)low_mem << 10), 1);
     }
@@ -119,6 +112,7 @@ static inline int get_88(void)
   uint16_t low_mem;
   uint8_t err;
 
+  puts("Calling INT 15 88...\n");
   asm volatile("movb $0x88,%%ah ; "
               "int $0x15 ; "
               "setc %1"
@@ -126,6 +120,8 @@ static inline int get_88(void)
               :: "ebx", "ecx", "esi", "edi", "ebp");
 
   if ( !err ) {
+    printf("BIOS 88:    %u K extended memory\n", low_mem);
+
     if ( low_mem ) {
       insertrange(0x100000, (uint64_t)((uint32_t)low_mem << 10), 1);
     }
@@ -142,11 +138,10 @@ void get_mem(void)
 {
   if ( get_e820() ) {
     get_dos_mem();
-    if ( get_e881() ) {
-      if ( get_e801() ) {
-       if ( get_88() ) {
-         /* Running out of ideas here... */
-       }
+    if ( get_e801() ) {
+      if ( get_88() ) {
+       puts("MEMDISK: Unable to obtain memory map\n");
+       die();
       }
     }
   }
index 64d66ec..196f33b 100644 (file)
@@ -32,7 +32,6 @@ struct patch_area {
   uint32_t disksize;
   uint32_t diskbuf;
 
-  uint32_t e820table;
   uint32_t mem1mb;
   uint32_t mem16mb;
   uint32_t memint1588;
@@ -88,7 +87,7 @@ wrz_16(uint32_t addr, uint16_t data)
   asm volatile("movw %0,%%fs:%1" :: "ri" (data), "m" (*(uint16_t *)addr));
 }
 static inline void
-wrz_32(uint32_t addr, uint16_t data)
+wrz_32(uint32_t addr, uint32_t data)
 {
   asm volatile("movl %0,%%fs:%1" :: "ri" (data), "m" (*(uint32_t *)addr));
 }
@@ -173,41 +172,70 @@ const struct geometry *get_disk_image_geometry(uint32_t where, uint32_t size)
 }
 
 /*
+ * Jump here if all hope is gone...
+ */
+void __attribute__((noreturn)) die(void)
+{
+  asm volatile("sti");
+  for(;;)
+    asm volatile("hlt");
+}
+
+/*
  * Actual setup routine
  * Returns the drive number (which is then passed in %dl to the
  * called routine.)
  */
 uint32_t setup(void)
 {
-  unsigned int size = (int) &_binary_memdisk_bin_size;
+  unsigned int bin_size = (int) &_binary_memdisk_bin_size;
   struct memdisk_header *hptr;
   struct patch_area *pptr;
   uint16_t driverseg;
   uint32_t driverptr, driveraddr;
+  uint16_t dosmem_k;
+  uint32_t stddosmem;
   uint8_t driveno = 0;
   uint8_t status;
   uint16_t exitcode;
   const struct geometry *geometry;
+  int total_size;
 
   /* Show signs of life */
-  puts("Memdisk: hello, world!\n");
+  puts("Memdisk: Hello, World!\n");
+
+  if ( !shdr->ramdisk_image || !shdr->ramdisk_size ) {
+    puts("MEMDISK: No ramdisk image specified!\n");
+    die();
+  }
+
+  printf("Test of simple printf...\n");
+  printf("Ramdisk at 0x%08x, length 0x%08x\n",
+        shdr->ramdisk_image, shdr->ramdisk_size);
 
-  for(;;);
+  /* Reserve the ramdisk memory */
+  insertrange(shdr->ramdisk_image, shdr->ramdisk_size, 2);
 
   geometry = get_disk_image_geometry(shdr->ramdisk_image, shdr->ramdisk_size);
 
   get_mem();
   parse_mem();
 
+  printf("dos_mem  = %#10x (%u K)\n"
+        "low_mem  = %#10x (%u K)\n"
+        "high_mem = %#10x (%u K)\n",
+        dos_mem, dos_mem >> 10,
+        low_mem, low_mem >> 10,
+        high_mem, high_mem >> 10);
+
   /* Figure out where it needs to go */
   hptr = (struct memdisk_header *) &_binary_memdisk_bin_start;
   pptr = (struct patch_area *)(_binary_memdisk_bin_start + hptr->patch_offs);
 
-  if ( hptr->total_size > dos_mem ) {
-    /* Badness... */
-  }
+  dosmem_k = rdz_16(BIOS_BASEMEM);
+  pptr->olddosmem = dosmem_k;
+  stddosmem = dosmem_k << 10;
 
-  pptr->olddosmem = rdz_16(BIOS_BASEMEM);
   pptr->driveno   = geometry->driveno;
   pptr->drivetype = geometry->type;
   pptr->cylinders = geometry->c;
@@ -216,9 +244,25 @@ uint32_t setup(void)
   pptr->disksize  = geometry->sectors;
   pptr->diskbuf   = shdr->ramdisk_image;
 
-  driveraddr  = dos_mem - hptr->total_size;
+  /* The size is given by hptr->total_size plus the size of the
+     E820 map -- 12 bytes per range; we may need as many as
+     2 additional ranges plus the terminating range, over what
+     nranges currently show. */
+
+  total_size = hptr->total_size + (nranges+3)*12;
+  printf("Total size needed = %u bytes\n", total_size);
+
+  if ( total_size > dos_mem ) {
+    puts("MEMDISK: Insufficient low memory\n");
+    die();
+  }
+
+  driveraddr  = stddosmem - total_size;
   driveraddr &= ~0x3FF;
 
+  printf("Old dos memory at 0x%05x (map says 0x%05x), loading at 0x%05x\n",
+        stddosmem, dos_mem, driveraddr);
+
   /* Reserve this range of memory */
   insertrange(driveraddr, dos_mem-driveraddr, 2);
   parse_mem();
@@ -238,12 +282,19 @@ uint32_t setup(void)
   /* Claim the memory and copy the driver into place */
   wrz_16(BIOS_BASEMEM, dos_mem >> 10);
 
+  /* Copy driver followed by E820 table */
   asm volatile("pushw %%es ; "
               "movw %0,%%es ; "
+              "cld ; "
+              "rep ; movsl %%ds:(%%si), %%es:(%%di) ; "
+              "movw %2,%%cx ; "
+              "movw %1,%%si ; "
               "rep ; movsl %%ds:(%%si), %%es:(%%di) ; "
               "popw %%es"
               :: "r" (driverseg),
-              "c" (size >> 2),
+              "g" ((uint16_t)((nranges+1)*3)), /* 3 dwords/range */
+              "g" ((uint16_t)ranges),
+              "c" (bin_size >> 2),
               "S" (&_binary_memdisk_bin_start),
               "D" (0));
 
@@ -266,7 +317,8 @@ uint32_t setup(void)
               : "ebx", "ecx", "edx", "esi", "edi", "ebp");
 
   if ( status ) {
-    /* Badness... */
+    puts("MEMDISK: Failed to load new boot sector\n");
+    die();
   }
   
   /* On return the assembly code will jump to the boot vector */