qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Qemu-devel] How to get beyond the 16 head limit?


From: Erik Mouw
Subject: Re: [Qemu-devel] How to get beyond the 16 head limit?
Date: Wed, 11 Jun 2008 19:42:17 +0200
User-agent: Mutt/1.5.17+20080114 (2008-01-14)

On Wed, Jun 04, 2008 at 07:16:14PM +0200, Erik Mouw wrote: 
> We managed to recover data from an ancient 60 MB ESDI drive. Because
> the interesting data is in some kind of proprietary database system
> (running on top of its own OS) I tried to run the recovered disk
> image in Qemu and let the database export itself to a floppy image.
> 
> The drive has an unusual though valid geometry: 58 cylinders, 64 heads,
> 32 sectors. Qemu refuses to boot the image because it says the CHS
> format is invalid:
> 
> address@hidden:~/qemu > qemu -fda scratch.img -hda bd4467.img \
>       -hdachs 58,64,32 -std-vga -boot c -m 4 -net none
> qemu: invalid physical CHS format
> 
> I increased the head limit in vl.c from 16 to 64 but it appears that is
> not enough to convince Qemu to accept the geometry. Qemu starts, but
> when I check from DOS (in Qemu) it now looks as if the drive geometry
> is 116/16/63. With a partition table patched to match that geometry I
> can boot the database OS bootsector, which happily loads the db OS
> kernel from the wrong location because it uses CHS addressing (instead
> of LBA). Needles to say that won't fly.
> 
> Like I said, I already increased the head limit in vl.c but that is
> apparently not enough. What else do I have to change to get Qemu to use
> my supplied disk geometry?

It wasn't enough, there was also some work needed in hw/ide.c to get
Qemu to accept and use the unual layout (see below for the patch).
Right now Qemu is convinced that the geometry really is 58/64/32, but
when testing in DOS through INT13 the geometry is 116/16/63. I guess
that has to do with the BIOS getting in my way, could somebody confirm
this?


Erik

PS: Patch is against the latest svn version. Obviously needs some
  polishing, at least need to get rid of the debug fprintf()s.

diff --git a/block.c b/block.c
index 2aaefe8..309f9df 100644
--- a/block.c
+++ b/block.c
@@ -750,11 +750,12 @@ void bdrv_set_boot_sector(BlockDriverState *bs, const 
uint8_t *data, int size)
 }
 
 void bdrv_set_geometry_hint(BlockDriverState *bs,
-                            int cyls, int heads, int secs)
+                            int cyls, int heads, int secs, int nonide)
 {
     bs->cyls = cyls;
     bs->heads = heads;
     bs->secs = secs;
+    bs->nonide = nonide;
 }
 
 void bdrv_set_type_hint(BlockDriverState *bs, int type)
@@ -770,11 +771,12 @@ void bdrv_set_translation_hint(BlockDriverState *bs, int 
translation)
 }
 
 void bdrv_get_geometry_hint(BlockDriverState *bs,
-                            int *pcyls, int *pheads, int *psecs)
+                            int *pcyls, int *pheads, int *psecs, int *pnonide)
 {
     *pcyls = bs->cyls;
     *pheads = bs->heads;
     *psecs = bs->secs;
+    *pnonide = bs->nonide;
 }
 
 int bdrv_get_type_hint(BlockDriverState *bs)
diff --git a/block.h b/block.h
index e18f453..1085123 100644
--- a/block.h
+++ b/block.h
@@ -112,11 +112,11 @@ int bdrv_is_allocated(BlockDriverState *bs, int64_t 
sector_num, int nb_sectors,
 #define BIOS_ATA_TRANSLATION_RECHS  4
 
 void bdrv_set_geometry_hint(BlockDriverState *bs,
-                            int cyls, int heads, int secs);
+                            int cyls, int heads, int secs, int nonide);
 void bdrv_set_type_hint(BlockDriverState *bs, int type);
 void bdrv_set_translation_hint(BlockDriverState *bs, int translation);
 void bdrv_get_geometry_hint(BlockDriverState *bs,
-                            int *pcyls, int *pheads, int *psecs);
+                            int *pcyls, int *pheads, int *psecs, int *pnonide);
 int bdrv_get_type_hint(BlockDriverState *bs);
 int bdrv_get_translation_hint(BlockDriverState *bs);
 int bdrv_is_removable(BlockDriverState *bs);
diff --git a/block_int.h b/block_int.h
index 137000e..1d7df6f 100644
--- a/block_int.h
+++ b/block_int.h
@@ -126,7 +126,7 @@ struct BlockDriverState {
 
     /* NOTE: the following infos are only hints for real hardware
        drivers. They are not used by the block driver */
-    int cyls, heads, secs, translation;
+       int cyls, heads, secs, translation, nonide;
     int type;
     char device_name[32];
     BlockDriverState *next;
diff --git a/hw/fdc.c b/hw/fdc.c
index cd00420..16eb46c 100644
--- a/hw/fdc.c
+++ b/hw/fdc.c
@@ -236,12 +236,13 @@ static void fd_revalidate (fdrive_t *drv)
     const fd_format_t *parse;
     uint64_t nb_sectors, size;
     int i, first_match, match;
-    int nb_heads, max_track, last_sect, ro;
+    int nb_heads, max_track, last_sect, nonide, ro;
 
     FLOPPY_DPRINTF("revalidate\n");
     if (drv->bs != NULL && bdrv_is_inserted(drv->bs)) {
         ro = bdrv_is_read_only(drv->bs);
-        bdrv_get_geometry_hint(drv->bs, &nb_heads, &max_track, &last_sect);
+        bdrv_get_geometry_hint(drv->bs, &nb_heads, &max_track, &last_sect,
+                              &nonide);
         if (nb_heads != 0 && max_track != 0 && last_sect != 0) {
             FLOPPY_DPRINTF("User defined disk (%d %d %d)",
                            nb_heads - 1, max_track, last_sect);
diff --git a/hw/ide.c b/hw/ide.c
index dc41982..d55b2c0 100644
--- a/hw/ide.c
+++ b/hw/ide.c
@@ -374,7 +374,7 @@ typedef struct IDEState {
     /* ide config */
     int is_cdrom;
     int is_cf;
-    int cylinders, heads, sectors;
+    int cylinders, heads, sectors, nonide;
     int64_t nb_sectors;
     int mult_sectors;
     int identify_set;
@@ -768,6 +768,10 @@ static int64_t ide_get_sector(IDEState *s)
         sector_num = ((s->hcyl << 8) | s->lcyl) * s->heads * s->sectors +
             (s->select & 0x0f) * s->sectors + (s->sector - 1);
     }
+
+    fprintf(stderr, "ide_get_sector: geometry %d/%d/%d %d, sector %lld\n",
+           s->cylinders, s->heads, s->sectors, s->nonide, sector_num);
+
     return sector_num;
 }
 
@@ -2522,10 +2526,11 @@ static void ide_init2(IDEState *ide_state,
 {
     IDEState *s;
     static int drive_serial = 1;
-    int i, cylinders, heads, secs, translation, lba_detected = 0;
+    int i, cylinders, heads, secs, translation, nonide = 0, lba_detected = 0;
     uint64_t nb_sectors;
 
     for(i = 0; i < 2; i++) {
+       fprintf(stderr, "ide: initializing drive %d\n", i);
         s = ide_state + i;
         s->io_buffer = qemu_memalign(512, IDE_DMA_BUF_SECTORS*512 + 4);
         if (i == 0)
@@ -2536,24 +2541,33 @@ static void ide_init2(IDEState *ide_state,
             bdrv_get_geometry(s->bs, &nb_sectors);
             s->nb_sectors = nb_sectors;
             /* if a geometry hint is available, use it */
-            bdrv_get_geometry_hint(s->bs, &cylinders, &heads, &secs);
+            bdrv_get_geometry_hint(s->bs, &cylinders, &heads, &secs, &nonide);
             translation = bdrv_get_translation_hint(s->bs);
             if (cylinders != 0) {
+               fprintf(stderr, "ide: got geometry: %d/%d/%d %d\n",
+                       cylinders, heads, secs, nonide);
                 s->cylinders = cylinders;
                 s->heads = heads;
                 s->sectors = secs;
+               s->nonide = nonide;
             } else {
+               fprintf(stderr, "ide: didn't get geometry\n");
                 if (guess_disk_lchs(s, &cylinders, &heads, &secs) == 0) {
+                       fprintf(stderr, "ide: guessed geometry: %d/%d/%d %d\n",
+                               cylinders, heads, secs, nonide);
                     if (heads > 16) {
                         /* if heads > 16, it means that a BIOS LBA
                            translation was active, so the default
                            hardware geometry is OK */
                         lba_detected = 1;
+                       fprintf(stderr, "ide: lba detected, going for default 
geometry\n");
                         goto default_geometry;
                     } else {
-                        s->cylinders = cylinders;
+                       fprintf(stderr, "ide: using guessed geometry\n");
+                       s->cylinders = cylinders;
                         s->heads = heads;
                         s->sectors = secs;
+                       s->nonide = 0;
                         /* disable any translation to be in sync with
                            the logical geometry */
                         if (translation == BIOS_ATA_TRANSLATION_AUTO) {
@@ -2572,6 +2586,10 @@ static void ide_init2(IDEState *ide_state,
                     s->cylinders = cylinders;
                     s->heads = 16;
                     s->sectors = 63;
+                   s->nonide = 0;
+
+                   fprintf(stderr, "ide: using default geometry: %d/%d/%d 
%d\n",
+                           s->cylinders, s->heads, s->sectors, s->nonide);
                     if ((lba_detected == 1) && (translation == 
BIOS_ATA_TRANSLATION_AUTO)) {
                       if ((s->cylinders * s->heads) <= 131072) {
                         bdrv_set_translation_hint(s->bs,
@@ -2582,7 +2600,7 @@ static void ide_init2(IDEState *ide_state,
                       }
                     }
                 }
-                bdrv_set_geometry_hint(s->bs, s->cylinders, s->heads, 
s->sectors);
+                bdrv_set_geometry_hint(s->bs, s->cylinders, s->heads, 
s->sectors, s->nonide);
             }
             if (bdrv_get_type_hint(s->bs) == BDRV_TYPE_CDROM) {
                 s->is_cdrom = 1;
diff --git a/hw/pc.c b/hw/pc.c
index 3edeb50..56c6f6b 100644
--- a/hw/pc.c
+++ b/hw/pc.c
@@ -159,8 +159,8 @@ static int cmos_get_fd_drive_type(int fd0)
 static void cmos_init_hd(int type_ofs, int info_ofs, BlockDriverState *hd)
 {
     RTCState *s = rtc_state;
-    int cylinders, heads, sectors;
-    bdrv_get_geometry_hint(hd, &cylinders, &heads, &sectors);
+    int cylinders, heads, sectors, nonide;
+    bdrv_get_geometry_hint(hd, &cylinders, &heads, &sectors, &nonide);
     rtc_set_memory(s, type_ofs, 47);
     rtc_set_memory(s, info_ofs, cylinders);
     rtc_set_memory(s, info_ofs + 1, cylinders >> 8);
@@ -317,14 +317,15 @@ static void cmos_init(ram_addr_t ram_size, ram_addr_t 
above_4g_mem_size,
     val = 0;
     for (i = 0; i < 4; i++) {
         if (hd_table[i]) {
-            int cylinders, heads, sectors, translation;
+               int cylinders, heads, sectors, nonide, translation;
             /* NOTE: bdrv_get_geometry_hint() returns the physical
                 geometry.  It is always such that: 1 <= sects <= 63, 1
                 <= heads <= 16, 1 <= cylinders <= 16383. The BIOS
                 geometry can be different if a translation is done. */
             translation = bdrv_get_translation_hint(hd_table[i]);
             if (translation == BIOS_ATA_TRANSLATION_AUTO) {
-                bdrv_get_geometry_hint(hd_table[i], &cylinders, &heads, 
&sectors);
+                   bdrv_get_geometry_hint(hd_table[i], &cylinders, &heads,
+                                          &sectors, &nonide);
                 if (cylinders <= 1024 && heads <= 16 && sectors <= 63) {
                     /* No translation. */
                     translation = 0;
diff --git a/vl.c b/vl.c
index 671b7a4..456f6ce 100644
--- a/vl.c
+++ b/vl.c
@@ -5013,7 +5013,7 @@ static int drive_init(struct drive_opt *arg, int snapshot,
     BlockInterfaceType type;
     enum { MEDIA_DISK, MEDIA_CDROM } media;
     int bus_id, unit_id;
-    int cyls, heads, secs, translation;
+    int cyls, heads, secs, translation, nonide;
     BlockDriverState *bdrv;
     BlockDriver *drv = NULL;
     int max_devs;
@@ -5032,7 +5032,7 @@ static int drive_init(struct drive_opt *arg, int snapshot,
     }
 
     file[0] = 0;
-    cyls = heads = secs = 0;
+    cyls = heads = secs = nonide = 0;
     bus_id = 0;
     unit_id = -1;
     translation = BIOS_ATA_TRANSLATION_AUTO;
@@ -5075,7 +5075,12 @@ static int drive_init(struct drive_opt *arg, int 
snapshot,
 
     if (get_param_value(buf, sizeof(buf), "if", str)) {
         pstrcpy(devname, sizeof(devname), buf);
-        if (!strcmp(buf, "ide")) {
+        if (!strcmp(buf, "nonide")) {
+           type = IF_IDE;
+            max_devs = MAX_IDE_DEVS;
+           nonide = 1;
+           fprintf(stderr, "ide: using non-standard IDE geometry\n");
+        } else if (!strcmp(buf, "ide")) {
            type = IF_IDE;
             max_devs = MAX_IDE_DEVS;
         } else if (!strcmp(buf, "scsi")) {
@@ -5124,10 +5129,14 @@ static int drive_init(struct drive_opt *arg, int 
snapshot,
             fprintf(stderr, "qemu: '%s' invalid physical cyls number\n", str);
            return -1;
        }
-        if (heads < 1 || heads > 16) {
+        if (heads < 1 || heads > 64) {
             fprintf(stderr, "qemu: '%s' invalid physical heads number\n", str);
            return -1;
        }
+       if (heads > 16) {
+           fprintf(stderr, "qemu: heads > 16, assuming non-IDE drive\n");
+           nonide = 1; 
+       }
         if (secs < 1 || secs > 63) {
             fprintf(stderr, "qemu: '%s' invalid physical secs number\n", str);
            return -1;
@@ -5281,7 +5290,7 @@ static int drive_init(struct drive_opt *arg, int snapshot,
         switch(media) {
        case MEDIA_DISK:
             if (cyls != 0) {
-                bdrv_set_geometry_hint(bdrv, cyls, heads, secs);
+               bdrv_set_geometry_hint(bdrv, cyls, heads, secs, nonide);
                 bdrv_set_translation_hint(bdrv, translation);
             }
            break;
@@ -7680,7 +7689,7 @@ int main(int argc, char **argv)
     const char *kernel_filename, *kernel_cmdline;
     const char *boot_devices = "";
     DisplayState *ds = &display_state;
-    int cyls, heads, secs, translation;
+    int cyls, heads, secs, translation, nonide;
     const char *net_clients[MAX_NET_CLIENTS];
     int nb_net_clients;
     int hda_index;
@@ -7748,7 +7757,7 @@ int main(int argc, char **argv)
     curses = 0;
     kernel_filename = NULL;
     kernel_cmdline = "";
-    cyls = heads = secs = 0;
+    cyls = heads = secs = nonide = 0;
     translation = BIOS_ATA_TRANSLATION_AUTO;
     monitor_device = "vc:800x600";
 
@@ -7881,8 +7890,10 @@ int main(int argc, char **argv)
                         goto chs_fail;
                     p++;
                     heads = strtol(p, (char **)&p, 0);
-                    if (heads < 1 || heads > 16)
+                    if (heads < 1 || heads > 64)
                         goto chs_fail;
+                   if (heads > 16)
+                       nonide = 1;
                     if (*p != ',')
                         goto chs_fail;
                     p++;
@@ -7907,8 +7918,9 @@ int main(int argc, char **argv)
                    if (hda_index != -1)
                         snprintf(drives_opt[hda_index].opt,
                                  sizeof(drives_opt[hda_index].opt),
-                                 HD_ALIAS ",cyls=%d,heads=%d,secs=%d%s",
+                                 HD_ALIAS ",cyls=%d,heads=%d,secs=%d%s%s",
                                  0, cyls, heads, secs,
+                                nonide ? ",if=nonide" : "", 
                                 translation == BIOS_ATA_TRANSLATION_LBA ?
                                    ",trans=lba" :
                                 translation == BIOS_ATA_TRANSLATION_NONE ?


-- 
+-- Erik Mouw -- www.harddisk-recovery.com -- +31 70 370 12 90 --
| Lab address: Delftechpark 26, 2628 XH, Delft, The Netherlands
+-- Datarecovery Services Nederland B.V. Utrecht. KvK: 30160549




reply via email to

[Prev in Thread] Current Thread [Next in Thread]