diff --git a/block.c b/block.c index 0e42b5e0d67a5fe3c2991125315d707e6a0bf600..a77a3e55b7ac84d933fa8286de3f710546c656b1 100644 --- 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; diff --git a/block_int.h b/block_int.h index 9d047c4ff37e91384d5f5a259146b5d8270b6250..03744f73401e7edb8c1bd6098e0b3c7fef291310 100644 --- a/block_int.h +++ b/block_int.h @@ -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; diff --git a/hw/ide.c b/hw/ide.c index bc7ebd3205e9b3a1c175cc62bb6edd24bac46a83..e922e7ba7ce5ff762411ef1a5134ca4ebbb2c745 100644 --- 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 06ec7b1b6990ea05b7fbb01a96fd2ef9b5858e5b..64b6180a3d0f6c46da95bde22aa041ee15785c25 100644 --- 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, §ors); - 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, §ors); + 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); } diff --git a/qemu-doc.texi b/qemu-doc.texi index 732f40f36733047fe62edc5a87d913bc10c0f579..9436965eb3c8cc94053889302dbd1a5d216c5ca8 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -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 6b24871ddbb64bee6a5479a73ca46845a6acc2e2..018fc314347dfba2fab0fe969d0951f21ada712c 100644 --- 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 268f72c5672e4100686ffa4b4598fe9db3ec26b3..2f69899da9fe7ffde059f48b11b2c1ae8686c882 100644 --- 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);