MEMDISK: algorithmic determination of floppy formats
authorH. Peter Anvin <hpa@zytor.com>
Sat, 7 Jun 2008 21:39:01 +0000 (14:39 -0700)
committerH. Peter Anvin <hpa@zytor.com>
Sat, 7 Jun 2008 21:39:01 +0000 (14:39 -0700)
Consider all disks < 4 MB to be floppies, and guess their geometry
algorithmically.

NEWS
doc/memdisk.txt
memdisk/fdgeo.pl [new file with mode: 0755]
memdisk/setup.c

diff --git a/NEWS b/NEWS
index 085b5b8..5b841e2 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -29,6 +29,9 @@ Changes in 3.70:
        * Change default dir for auxiliary files from
          /usr/lib/syslinux to /usr/share/syslinux.
        * SYSLINUX: VFAT long filename support.
+       * MEMDISK: Any image less than 4096K (4 MB) is treated as a
+         floppy disk.  The geometry-guessing code will recognize all
+         common extended formats, but 
 
 Changes in 3.64:
        * SYSLINUX/EXTLINUX: support "localboot" with the same feature
index 759a7b2..808a947 100644 (file)
@@ -28,25 +28,44 @@ Note the following:
 
 a) The disk image can be uncompressed or compressed with gzip or zip.
 
-b) If the disk image is one of the following sizes, it's assumed to be a
-   floppy image:
-
-     368,640 bytes -  360K floppy
-     737,280 bytes -  720K floppy
-   1,222,800 bytes - 1200K floppy
-   1,474,560 bytes - 1440K floppy
-   1,720,320 bytes - 1680K floppy (common extended format)
-   1,763,328 bytes - 1722K floppy (common extended format)
-   2,949,120 bytes - 2880K floppy
-   3,932,160 bytes - 3840K floppy (extended format)
-
-   For any other size, the image is assumed to be a hard disk image,
-   and should typically have an MBR and a partition table.  It may
-   optionally have a DOSEMU geometry header; in which case the header
-   is used to determine the C/H/S geometry of the disk.  Otherwise,
-   the geometry is determined by examining the partition table, so the
-   entire image should be partitioned for proper operation (it may be
-   divided between multiple partitions, however.)
+b) If the disk image is less than 4,194,304 bytes (4096K, 4 MB) it is
+   assumed to be a floppy image and MEMDISK will try to guess its
+   geometry based on the size of the file.  MEMDISK recognizes all the
+   standard floppy sizes as well as common extended formats:
+   
+     163,840 bytes  (160K) c=40 h=1 s=8                5.25" SSSD
+     184,320 bytes  (180K) c=40 h=1 s=9                5.25" SSSD
+     327,680 bytes  (320K) c=40 h=2 s=8                5.25" DSDD
+     368,640 bytes  (360K) c=40 h=2 s=9                5.25" DSDD
+     655,360 bytes  (640K) c=80 h=2 s=8                3.5"  DSDD
+     737,280 bytes  (720K) c=80 h=2 s=9                3.5"  DSDD
+   1,222,800 bytes (1200K) c=80 h=2 s=15       5.25" DSHD
+   1,474,560 bytes (1440K) c=80 h=2 s=18       3.5"  DSHD
+   1,638,400 bytes (1600K) c=80 h=2 s=20       3.5"  DSHD (extended)
+   1,720,320 bytes (1680K) c=80 h=2 s=21       3.5"  DSHD (extended)
+   1,763,328 bytes (1722K) c=82 h=2 s=21       3.5"  DSHD (extended)
+   1,784,832 bytes (1743K) c=83 h=2 s=21       3.5"  DSHD (extended)
+   1,802,240 bytes (1760K) c=80 h=2 s=22       3.5"  DSHD (extended)
+   1,884,160 bytes (1840K) c=80 h=2 s=23       3.5"  DSHD (extended)
+   1,966,080 bytes (1920K) c=80 h=2 s=24       3.5"  DSHD (extended)
+   2,949,120 bytes (2880K) c=80 h=2 s=36       3.5"  DSED
+   3,194,880 bytes (3120K) c=80 h=2 s=39       3.5"  DSED (extended)
+   3,276,800 bytes (3200K) c=80 h=2 s=40       3.5"  DSED (extended)
+   3,604,480 bytes (3520K) c=80 h=2 s=44       3.5"  DSED (extended)
+   3,932,160 bytes (3840K) c=80 h=2 s=48       3.5"  DSED (extended)
+
+   A small perl script is included in the MEMDISK directory which can
+   determine the geometry that MEMDISK would select for other sizes;
+   in general MEMDISK will correctly detect most physical extended
+   formats used, with 80 cylinders or slightly more.
+
+   If the image is 4 MB or larger, it is assumed to be a hard disk
+   image, and should typically have an MBR and a partition table.  It
+   may optionally have a DOSEMU geometry header; in which case the
+   header is used to determine the C/H/S geometry of the disk.
+   Otherwise, the geometry is determined by examining the partition
+   table, so the entire image should be partitioned for proper
+   operation (it may be divided between multiple partitions, however.)
 
    You can also specify the geometry manually with the following command
    line options:
diff --git a/memdisk/fdgeo.pl b/memdisk/fdgeo.pl
new file mode 100755 (executable)
index 0000000..47d19af
--- /dev/null
@@ -0,0 +1,54 @@
+#!/usr/bin/perl
+#
+# Try automatic generation of geometries
+#
+
+($k) = @ARGV;
+$sec = int($k*2+0.5);
+
+if ($sec < 320*2) {
+    $c = 40;
+    $h = 1;
+    $type = 1;
+} elsif ($sec < 640*2) {
+    $c = 40;
+    $h = 2;
+    $type = 1;
+} elsif ($sec < 1200*2) {
+    $c = 80;
+    $h = 2;
+    $type = 3;
+} elsif ($sec < 1440*2) {
+    $c = 80;
+    $h = 2;
+    $type = 2;
+} elsif ($sec < 2880*2) {
+    $c = 80;
+    $h = 2;
+    $type = 4;
+} elsif ($sec < 4096*2) {
+    $c = 80;
+    $h = 2;
+    $type = 6;
+} else {
+    printf "%.1fK, %d sectors: ", $sec/2, $sec;
+    print "Considered a hard disk\n";
+}
+
+$ok = 0;
+while ($c < 256) {
+    $s = int($sec/($c*$h)+0.5);
+    if ($s <= 63 && $sec == $c*$h*$s) {
+       $ok = 1;
+       last;
+    }
+    $c++;
+}
+
+printf "%.1fK, %d sectors: ", $sec/2, $sec;
+if ($ok) {
+    print "c=$c, h=$h, s=$s, type=$type\n";
+} else {
+    print "No valid geometry found (MEMDISK will fake it)\n";
+}
+
index 298720a..4d38598 100644 (file)
@@ -362,19 +362,6 @@ struct geometry {
   uint8_t driveno;             /* Drive no */
 };
 
-static const struct geometry geometries[] =
-{
-  {  360*2, 40,  2,  9, 0, 0x01, 0 }, /*  360 K */
-  {  720*2, 80,  2,  9, 0, 0x03, 0 }, /*  720 K*/
-  { 1200*2, 80,  2, 15, 0, 0x02, 0 }, /* 1200 K */
-  { 1440*2, 80,  2, 18, 0, 0x04, 0 }, /* 1440 K */
-  { 1680*2, 80,  2, 21, 0, 0x04, 0 }, /* 1680 K */
-  { 1722*2, 82,  2, 21, 0, 0x04, 0 }, /* 1722 K */
-  { 2880*2, 80,  2, 36, 0, 0x06, 0 }, /* 2880 K */
-  { 3840*2, 80,  2, 48, 0, 0x06, 0 }, /* 3840 K */
-};
-#define known_geometries (sizeof(geometries)/sizeof(struct geometry))
-
 /* Format of a DOS partition table entry */
 struct ptab_entry {
   uint8_t active;
@@ -399,7 +386,7 @@ struct dosemu_header {
 
 const struct geometry *get_disk_image_geometry(uint32_t where, uint32_t size)
 {
-  static struct geometry hd_geometry = { 0, 0, 0, 0, 0, 0, 0x80 };
+  static struct geometry hd_geometry;
   struct ptab_entry ptab[4];   /* Partition table buffer */
   struct dosemu_header dosemu;
   unsigned int sectors, v;
@@ -416,11 +403,52 @@ const struct geometry *get_disk_image_geometry(uint32_t where, uint32_t size)
     offset = v;
 
   sectors = (size-offset) >> 9;
-  for ( i = 0 ; i < known_geometries ; i++ ) {
-    if ( sectors == geometries[i].sectors ) {
-      hd_geometry = geometries[i];
-      break;
+
+  if (sectors < 4096*2) {
+    int ok = 0;
+    unsigned int xsectors = sectors;
+
+    while (!ok) {
+      /* Assume it's a floppy drive, guess a geometry */
+      unsigned int type, track;
+
+      if (xsectors < 320*2) {
+       c = 40; h = 1; type = 1;
+      } else if (xsectors < 640*2) {
+       c = 40; h = 2; type = 1;
+      } else if (xsectors < 1200*2) {
+       c = 80; h = 2; type = 3;
+      } else if (xsectors < 1440*2) {
+       c = 80; h = 2; type = 2;
+    } else if (xsectors < 2880*2) {
+       c = 80; h = 2; type = 4;
+      } else {
+       c = 80; h = 2; type = 6;
+      }
+      track = c*h;
+      while (c < 256) {
+       s = xsectors/track;
+       if (s < 63 && (xsectors % track) == 0) {
+         ok = 1;
+         break;
+       }
+       c++;
+       track += h;
+      }      
+      if (ok) {
+       hd_geometry.driveno = 0;
+       hd_geometry.c = c;
+       hd_geometry.h = h;
+       hd_geometry.s = s;
+      } else {
+       /* No valid floppy geometry, fake it by simulating broken
+          sectors at the end of the image... */
+       xsectors++;
+      }
     }
+  } else {
+    /* Hard disk */
+    hd_geometry.driveno = 0x80;
   }
 
   hd_geometry.sectors = sectors;
@@ -606,10 +634,11 @@ __cdecl void setup(__cdecl syscall_t cs_syscall, void *cs_bounce)
   else
     do_edd = (geometry->driveno & 0x80) ? 1 : 0;
 
-  printf("Disk is %s %d, %u K, C/H/S = %u/%u/%u, EDD %s\n",
+  printf("Disk is %s %d, %u%s K, C/H/S = %u/%u/%u, EDD %s\n",
         (geometry->driveno & 0x80) ? "hard disk" : "floppy",
         geometry->driveno & 0x7f,
         geometry->sectors >> 1,
+        (geometry->sectors & 1) ? ".5" : "",
         geometry->c, geometry->h, geometry->s,
         do_edd ? "on" : "off");