better BIOS ATA translation support
authorbellard <bellard@c046a42c-6fe2-441c-8c8c-71466251a162>
Tue, 16 Nov 2004 01:45:27 +0000 (01:45 +0000)
committerbellard <bellard@c046a42c-6fe2-441c-8c8c-71466251a162>
Tue, 16 Nov 2004 01:45:27 +0000 (01:45 +0000)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1153 c046a42c-6fe2-441c-8c8c-71466251a162

block.c
block_int.h
hw/ide.c
hw/pc.c
qemu-doc.texi
vl.c
vl.h

diff --git a/block.c b/block.c
index 0e42b5e..a77a3e5 100644 (file)
--- a/block.c
+++ b/block.c
@@ -348,6 +348,11 @@ void bdrv_set_type_hint(BlockDriverState *bs, int type)
                       type == BDRV_TYPE_FLOPPY));
 }
 
+void bdrv_set_translation_hint(BlockDriverState *bs, int translation)
+{
+    bs->translation = translation;
+}
+
 void bdrv_get_geometry_hint(BlockDriverState *bs, 
                             int *pcyls, int *pheads, int *psecs)
 {
@@ -361,6 +366,11 @@ int bdrv_get_type_hint(BlockDriverState *bs)
     return bs->type;
 }
 
+int bdrv_get_translation_hint(BlockDriverState *bs)
+{
+    return bs->translation;
+}
+
 int bdrv_is_removable(BlockDriverState *bs)
 {
     return bs->removable;
index 9d047c4..03744f7 100644 (file)
@@ -68,7 +68,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;
+    int cyls, heads, secs, translation;
     int type;
     char device_name[32];
     BlockDriverState *next;
index bc7ebd3..e922e7b 100644 (file)
--- a/hw/ide.c
+++ b/hw/ide.c
@@ -1826,11 +1826,11 @@ struct partition {
        uint32_t nr_sects;              /* nr of sectors in partition */
 } __attribute__((packed));
 
-/* try to guess the IDE geometry from the MSDOS partition table */
+/* try to guess the IDE physical geometry from the MSDOS partition table */
 static void ide_guess_geometry(IDEState *s)
 {
     uint8_t buf[512];
-    int ret, i;
+    int ret, i, heads, sectors, cylinders;
     struct partition *p;
     uint32_t nr_sects;
 
@@ -1848,9 +1848,18 @@ static void ide_guess_geometry(IDEState *s)
         if (nr_sects && p->end_head) {
             /* We make the assumption that the partition terminates on
                a cylinder boundary */
-            s->heads = p->end_head + 1;
-            s->sectors = p->end_sector & 63;
-            s->cylinders = s->nb_sectors / (s->heads * s->sectors);
+            heads = p->end_head + 1;
+            if (heads < 1 || heads > 16)
+                continue;
+            sectors = p->end_sector & 63;
+            if (sectors == 0)
+                continue;
+            cylinders = s->nb_sectors / (heads * sectors);
+            if (cylinders < 1 || cylinders > 16383)
+                continue;
+            s->heads = heads;
+            s->sectors = sectors;
+            s->cylinders = cylinders;
 #if 0
             printf("guessed partition: CHS=%d %d %d\n", 
                    s->cylinders, s->heads, s->sectors);
@@ -1885,7 +1894,7 @@ static void ide_init2(IDEState *ide_state, int irq,
             } else {
                 ide_guess_geometry(s);
                 if (s->cylinders == 0) {
-                    /* if no geometry, use a LBA compatible one */
+                    /* if no geometry, use a standard physical disk geometry */
                     cylinders = nb_sectors / (16 * 63);
                     if (cylinders > 16383)
                         cylinders = 16383;
diff --git a/hw/pc.c b/hw/pc.c
index 06ec7b1..64b6180 100644 (file)
--- a/hw/pc.c
+++ b/hw/pc.c
@@ -217,19 +217,23 @@ static void cmos_init(int ram_size, int boot_device, BlockDriverState **hd_table
     val = 0;
     for (i = 0; i < 4; i++) {
         if (hd_table[i]) {
-            int cylinders, heads, sectors;
-            uint8_t translation;
-            /* NOTE: bdrv_get_geometry_hint() returns the geometry
-               that the hard disk returns. It is always such that: 1 <=
-               sects <= 63, 1 <= heads <= 16, 1 <= cylinders <=
-               16383. The BIOS geometry can be different. */
-            bdrv_get_geometry_hint(hd_table[i], &cylinders, &heads, &sectors);
-            if (cylinders <= 1024 && heads <= 16 && sectors <= 63) {
-                /* No translation. */
-                translation = 0;
+            int cylinders, heads, sectors, 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);
+                if (cylinders <= 1024 && heads <= 16 && sectors <= 63) {
+                    /* No translation. */
+                    translation = 0;
+                } else {
+                    /* LBA translation. */
+                    translation = 1;
+                }
             } else {
-                /* LBA translation. */
-                translation = 1;
+                translation--;
             }
             val |= translation << (i * 2);
         }
index 732f40f..9436965 100644 (file)
@@ -343,6 +343,12 @@ Change gdb connection port.
 Do not start CPU at startup (you must type 'c' in the monitor).
 @item -d             
 Output log in /tmp/qemu.log
+@item -hdachs c,h,s,[,t]
+Force hard disk 0 physical geometry (1 <= @var{c} <= 16383, 1 <=
+@var{h} <= 16, 1 <= @var{s} <= 63) and optionally force the BIOS
+translation mode (@var{t}=none, lba or auto). Usually QEMU can guess
+all thoses parameters. This option is useful for old MS-DOS disk
+images.
 @item -isa
 Simulate an ISA-only system (default is PCI system).
 @item -std-vga
diff --git a/vl.c b/vl.c
index 6b24871..018fc31 100644 (file)
--- a/vl.c
+++ b/vl.c
@@ -2537,7 +2537,8 @@ void help(void)
            "-s              wait gdb connection to port %d\n"
            "-p port         change gdb connection port\n"
            "-d item1,...    output log to %s (use -d ? for a list of log items)\n"
-           "-hdachs c,h,s   force hard disk 0 geometry (usually qemu can guess it)\n"
+           "-hdachs c,h,s[,t]  force hard disk 0 physical geometry and the optional BIOS\n"
+           "                translation (t=none or lba) (usually qemu can guess them)\n"
            "-L path         set the directory for the BIOS and VGA BIOS\n"
 #ifdef USE_CODE_COPY
            "-no-code-copy   disable code copy acceleration\n"
@@ -2753,7 +2754,7 @@ int main(int argc, char **argv)
     const char *hd_filename[MAX_DISKS], *fd_filename[MAX_FD];
     const char *kernel_filename, *kernel_cmdline;
     DisplayState *ds = &display_state;
-    int cyls, heads, secs;
+    int cyls, heads, secs, translation;
     int start_emulation = 1;
     uint8_t macaddr[6];
     int net_if_type, nb_tun_fds, tun_fds[MAX_NICS];
@@ -2788,6 +2789,7 @@ int main(int argc, char **argv)
     kernel_cmdline = "";
     has_cdrom = 1;
     cyls = heads = secs = 0;
+    translation = BIOS_ATA_TRANSLATION_AUTO;
     pstrcpy(monitor_device, sizeof(monitor_device), "vc");
 
     pstrcpy(serial_devices[0], sizeof(serial_devices[0]), "vc");
@@ -2857,17 +2859,34 @@ int main(int argc, char **argv)
                     const char *p;
                     p = optarg;
                     cyls = strtol(p, (char **)&p, 0);
+                    if (cyls < 1 || cyls > 16383)
+                        goto chs_fail;
                     if (*p != ',')
                         goto chs_fail;
                     p++;
                     heads = strtol(p, (char **)&p, 0);
+                    if (heads < 1 || heads > 16)
+                        goto chs_fail;
                     if (*p != ',')
                         goto chs_fail;
                     p++;
                     secs = strtol(p, (char **)&p, 0);
-                    if (*p != '\0') {
+                    if (secs < 1 || secs > 63)
+                        goto chs_fail;
+                    if (*p == ',') {
+                        p++;
+                        if (!strcmp(p, "none"))
+                            translation = BIOS_ATA_TRANSLATION_NONE;
+                        else if (!strcmp(p, "lba"))
+                            translation = BIOS_ATA_TRANSLATION_LBA;
+                        else if (!strcmp(p, "auto"))
+                            translation = BIOS_ATA_TRANSLATION_AUTO;
+                        else
+                            goto chs_fail;
+                    } else if (*p != '\0') {
                     chs_fail:
-                        cyls = 0;
+                        fprintf(stderr, "qemu: invalid physical CHS format\n");
+                        exit(1);
                     }
                 }
                 break;
@@ -3230,8 +3249,10 @@ int main(int argc, char **argv)
                         hd_filename[i]);
                 exit(1);
             }
-            if (i == 0 && cyls != 0) 
+            if (i == 0 && cyls != 0) {
                 bdrv_set_geometry_hint(bs_table[i], cyls, heads, secs);
+                bdrv_set_translation_hint(bs_table[i], translation);
+            }
         }
     }
 
diff --git a/vl.h b/vl.h
index 268f72c..2f69899 100644 (file)
--- a/vl.h
+++ b/vl.h
@@ -383,13 +383,18 @@ void bdrv_set_boot_sector(BlockDriverState *bs, const uint8_t *data, int size);
 #define BDRV_TYPE_HD     0
 #define BDRV_TYPE_CDROM  1
 #define BDRV_TYPE_FLOPPY 2
+#define BIOS_ATA_TRANSLATION_AUTO 0
+#define BIOS_ATA_TRANSLATION_NONE 1
+#define BIOS_ATA_TRANSLATION_LBA  2
 
 void bdrv_set_geometry_hint(BlockDriverState *bs, 
                             int cyls, int heads, int secs);
 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 bdrv_get_type_hint(BlockDriverState *bs);
+int bdrv_get_translation_hint(BlockDriverState *bs);
 int bdrv_is_removable(BlockDriverState *bs);
 int bdrv_is_read_only(BlockDriverState *bs);
 int bdrv_is_inserted(BlockDriverState *bs);