aboutsummaryrefslogtreecommitdiffstats
path: root/memdisk
diff options
context:
space:
mode:
authorH. Peter Anvin <hpa@linux.intel.com>2009-03-16 13:18:49 -0700
committerH. Peter Anvin <hpa@linux.intel.com>2009-03-16 13:18:49 -0700
commit3ec9e0ec1012ff5699d0dd68f4926e36e62cfe3a (patch)
tree383fdee3714fa378d21c030c509fe2dea5bb092b /memdisk
parentbf366cd045b9abaf52f7f1c83d603e8e34cbe9ce (diff)
downloadsyslinux.git-3ec9e0ec1012ff5699d0dd68f4926e36e62cfe3a.tar.gz
syslinux.git-3ec9e0ec1012ff5699d0dd68f4926e36e62cfe3a.tar.xz
syslinux.git-3ec9e0ec1012ff5699d0dd68f4926e36e62cfe3a.zip
memdisk: auto-detect large floppy geometry if it is FAT
If a "large floppy" image is formatted with a FAT filesystem, we can use the headers in the FAT image to derive the geometry. This is nice and user-friendly, so do it that way.
Diffstat (limited to 'memdisk')
-rw-r--r--memdisk/setup.c153
1 files changed, 113 insertions, 40 deletions
diff --git a/memdisk/setup.c b/memdisk/setup.c
index 7b1f4566..c30a11f8 100644
--- a/memdisk/setup.c
+++ b/memdisk/setup.c
@@ -1,6 +1,6 @@
/* ----------------------------------------------------------------------- *
*
- * Copyright 2001-2008 H. Peter Anvin - All Rights Reserved
+ * Copyright 2001-2009 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
@@ -384,7 +384,49 @@ struct ptab_entry {
uint8_t end_h, end_s, end_c;
uint32_t start;
uint32_t size;
-};
+} __attribute__((packed));
+
+/* Format of a FAT filesystem superblock */
+struct fat_extra {
+ uint8_t bs_drvnum;
+ uint8_t bs_resv1;
+ uint8_t bs_bootsig;
+ uint32_t bs_volid;
+ char bs_vollab[11];
+ char bs_filsystype[8];
+} __attribute__((packed));
+struct fat_super {
+ uint8_t bs_jmpboot[3];
+ char bs_oemname[8];
+ uint16_t bpb_bytspersec;
+ uint8_t bpb_secperclus;
+ uint16_t bpb_rsvdseccnt;
+ uint8_t bpb_numfats;
+ uint16_t bpb_rootentcnt;
+ uint16_t bpb_totsec16;
+ uint8_t bpb_media;
+ uint16_t bpb_fatsz16;
+ uint16_t bpb_secpertrk;
+ uint16_t bpb_numheads;
+ uint32_t bpb_hiddsec;
+ uint32_t bpb_totsec32;
+ union {
+ struct {
+ struct fat_extra extra;
+ } fat16;
+ struct {
+ uint32_t bpb_fatsz32;
+ uint16_t bpb_extflags;
+ uint16_t bpb_fsver;
+ uint32_t bpb_rootclus;
+ uint16_t bpb_fsinfo;
+ uint16_t bpb_bkbootsec;
+ char bpb_reserved[12];
+ /* Clever, eh? Same fields, different offset... */
+ struct fat_extra extra;
+ } fat32 __attribute__((packed));
+ } x;
+} __attribute__((packed));
/* Format of a DOSEMU header */
struct dosemu_header {
@@ -401,13 +443,10 @@ struct dosemu_header {
const struct geometry *get_disk_image_geometry(uint32_t where, uint32_t size)
{
static struct geometry hd_geometry;
- struct ptab_entry ptab[4]; /* Partition table buffer */
struct dosemu_header dosemu;
unsigned int sectors, v;
- unsigned int max_c, max_h, max_s;
- unsigned int c, h, s, offset;
+ unsigned int offset;
int i;
- int drive_specified;
const char *p;
printf("command line: %s\n", shdr->cmdline);
@@ -425,6 +464,7 @@ const struct geometry *get_disk_image_geometry(uint32_t where, uint32_t size)
while (!ok) {
/* Assume it's a floppy drive, guess a geometry */
unsigned int type, track;
+ int c, h, s;
if (xsectors < 320*2) {
c = 40; h = 1; type = 1;
@@ -488,44 +528,64 @@ const struct geometry *get_disk_image_geometry(uint32_t where, uint32_t size)
if ( CMD_HASDATA(p = getcmditem("s")) && (v = atou(p)) )
hd_geometry.s = v;
- if ( (p = getcmditem("floppy")) != CMD_NOTFOUND ) {
- hd_geometry.driveno = CMD_HASDATA(p) ? atou(p) & 0x7f : 0;
- if ( hd_geometry.type == 0 )
- hd_geometry.type = 0x10; /* ATAPI floppy, e.g. LS-120 */
- drive_specified = 1;
- } else if ( (p = getcmditem("harddisk")) != CMD_NOTFOUND ) {
- hd_geometry.driveno = CMD_HASDATA(p) ? atou(p) | 0x80 : 0x80;
- hd_geometry.type = 0;
- drive_specified = 1;
- }
+ if ( !hd_geometry.c || !hd_geometry.h || !hd_geometry.s ) {
+ int h, s, max_h, max_s;
+
+ max_h = max_s = 0;
+
+ if ( hd_geometry.driveno & 0x80 ) {
+ /* Hard disk image, need to examine the partition table for geometry */
+ const struct ptab_entry *ptab = (const struct ptab_entry *)
+ ((char *)where+hd_geometry.offset+(512-2-4*16));
+
+ for ( i = 0 ; i < 4 ; i++ ) {
+ if ( ptab[i].type ) {
+ s = (ptab[i].start_s & 0x3f);
+ h = ptab[i].start_h + 1;
+
+ if ( max_h < h ) max_h = h;
+ if ( max_s < s ) max_s = s;
+
+ s = (ptab[i].end_s & 0x3f);
+ h = ptab[i].end_h + 1;
+
+ if ( max_h < h ) max_h = h;
+ if ( max_s < s ) max_s = s;
+ }
+ }
+ }
- if ( (hd_geometry.c == 0) || (hd_geometry.h == 0) ||
- (hd_geometry.s == 0) ) {
- /* Hard disk image, need to examine the partition table for geometry */
- memcpy(&ptab, (char *)where+hd_geometry.offset+(512-2-4*16), sizeof ptab);
-
- max_c = max_h = 0; max_s = 1;
- for ( i = 0 ; i < 4 ; i++ ) {
- if ( ptab[i].type ) {
- c = ptab[i].start_c + (ptab[i].start_s >> 6);
- s = (ptab[i].start_s & 0x3f);
- h = ptab[i].start_h;
-
- if ( max_c < c ) max_c = c;
- if ( max_h < h ) max_h = h;
- if ( max_s < s ) max_s = s;
-
- c = ptab[i].end_c + (ptab[i].end_s >> 6);
- s = (ptab[i].end_s & 0x3f);
- h = ptab[i].end_h;
-
- if ( max_c < c ) max_c = c;
- if ( max_h < h ) max_h = h;
- if ( max_s < s ) max_s = s;
+ if (!max_h && !max_s) {
+ /* Floppy image, or unpartitioned hard disk... look for a FAT
+ superblock and if we find something that looks enough like one,
+ use geometry from that. */
+ const struct fat_extra *extra = NULL;
+ const struct fat_super *fs = (const struct fat_super *)
+ ((char *)where+hd_geometry.offset);
+
+ if ((fs->bpb_media == 0xf0 || fs->bpb_media >= 0xf8) &&
+ (fs->bs_jmpboot[0] == 0xe9 || fs->bs_jmpboot[0] == 0xeb) &&
+ fs->bpb_bytspersec == 512 &&
+ fs->bpb_numheads >= 1 && fs->bpb_numheads <= 256 &&
+ fs->bpb_secpertrk >= 1 && fs->bpb_secpertrk <= 63) {
+ extra = fs->bpb_fatsz16 ? &fs->x.fat16.extra : &fs->x.fat32.extra;
+ if (!(extra->bs_bootsig == 0x29 &&
+ extra->bs_filsystype[0] == 'F' &&
+ extra->bs_filsystype[1] == 'A' &&
+ extra->bs_filsystype[2] == 'T'))
+ extra = NULL;
+ }
+ if (extra) {
+ hd_geometry.driveno = extra->bs_drvnum & 0x80;
+ max_h = fs->bpb_numheads;
+ max_s = fs->bpb_secpertrk;
}
}
- max_c++; max_h++; /* Convert to count (1-based) */
+ if (!max_h)
+ max_h = sectors > 2097152 ? 255 : 64;
+ if (!max_s)
+ max_s = sectors > 2097152 ? 63 : 32;
if ( !hd_geometry.h )
hd_geometry.h = max_h;
@@ -535,6 +595,19 @@ const struct geometry *get_disk_image_geometry(uint32_t where, uint32_t size)
hd_geometry.c = sectors/(hd_geometry.h*hd_geometry.s);
}
+ if ( (p = getcmditem("floppy")) != CMD_NOTFOUND ) {
+ hd_geometry.driveno = CMD_HASDATA(p) ? atou(p) & 0x7f : 0;
+ } else if ( (p = getcmditem("harddisk")) != CMD_NOTFOUND ) {
+ hd_geometry.driveno = CMD_HASDATA(p) ? atou(p) | 0x80 : 0x80;
+ }
+
+ if (hd_geometry.driveno & 0x80) {
+ hd_geometry.type = 0; /* Type = hard disk */
+ } else {
+ if (hd_geometry.type == 0)
+ hd_geometry.type = 0x10; /* ATAPI floppy, e.g. LS-120 */
+ }
+
if ( (size-hd_geometry.offset) & 0x1ff ) {
puts("MEMDISK: Image has fractional end sector\n");
}