diff --git a/block.c b/block.c index 0f1734ebca..dadf3cd849 100644 --- a/block.c +++ b/block.c @@ -739,6 +739,122 @@ void bdrv_get_geometry(BlockDriverState *bs, uint64_t *nb_sectors_ptr) *nb_sectors_ptr = length; } +struct partition { + uint8_t boot_ind; /* 0x80 - active */ + uint8_t head; /* starting head */ + uint8_t sector; /* starting sector */ + uint8_t cyl; /* starting cylinder */ + uint8_t sys_ind; /* What partition type */ + uint8_t end_head; /* end head */ + uint8_t end_sector; /* end sector */ + uint8_t end_cyl; /* end cylinder */ + uint32_t start_sect; /* starting sector counting from 0 */ + uint32_t nr_sects; /* nr of sectors in partition */ +} __attribute__((packed)); + +/* try to guess the disk logical geometry from the MSDOS partition table. Return 0 if OK, -1 if could not guess */ +static int guess_disk_lchs(BlockDriverState *bs, + int *pcylinders, int *pheads, int *psectors) +{ + uint8_t buf[512]; + int ret, i, heads, sectors, cylinders; + struct partition *p; + uint32_t nr_sects; + int64_t nb_sectors; + + bdrv_get_geometry(bs, &nb_sectors); + + ret = bdrv_read(bs, 0, buf, 1); + if (ret < 0) + return -1; + /* test msdos magic */ + if (buf[510] != 0x55 || buf[511] != 0xaa) + return -1; + for(i = 0; i < 4; i++) { + p = ((struct partition *)(buf + 0x1be)) + i; + nr_sects = le32_to_cpu(p->nr_sects); + if (nr_sects && p->end_head) { + /* We make the assumption that the partition terminates on + a cylinder boundary */ + heads = p->end_head + 1; + sectors = p->end_sector & 63; + if (sectors == 0) + continue; + cylinders = nb_sectors / (heads * sectors); + if (cylinders < 1 || cylinders > 16383) + continue; + *pheads = heads; + *psectors = sectors; + *pcylinders = cylinders; +#if 0 + printf("guessed geometry: LCHS=%d %d %d\n", + cylinders, heads, sectors); +#endif + return 0; + } + } + return -1; +} + +void bdrv_guess_geometry(BlockDriverState *bs, int *pcyls, int *pheads, int *psecs) +{ + int translation, lba_detected = 0; + int cylinders, heads, secs; + int64_t nb_sectors; + + /* if a geometry hint is available, use it */ + bdrv_get_geometry(bs, &nb_sectors); + bdrv_get_geometry_hint(bs, &cylinders, &heads, &secs); + translation = bdrv_get_translation_hint(bs); + if (cylinders != 0) { + *pcyls = cylinders; + *pheads = heads; + *psecs = secs; + } else { + if (guess_disk_lchs(bs, &cylinders, &heads, &secs) == 0) { + 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; + goto default_geometry; + } else { + *pcyls = cylinders; + *pheads = heads; + *psecs = secs; + /* disable any translation to be in sync with + the logical geometry */ + if (translation == BIOS_ATA_TRANSLATION_AUTO) { + bdrv_set_translation_hint(bs, + BIOS_ATA_TRANSLATION_NONE); + } + } + } else { + default_geometry: + /* if no geometry, use a standard physical disk geometry */ + cylinders = nb_sectors / (16 * 63); + + if (cylinders > 16383) + cylinders = 16383; + else if (cylinders < 2) + cylinders = 2; + *pcyls = cylinders; + *pheads = 16; + *psecs = 63; + if ((lba_detected == 1) && (translation == BIOS_ATA_TRANSLATION_AUTO)) { + if ((*pcyls * *pheads) <= 131072) { + bdrv_set_translation_hint(bs, + BIOS_ATA_TRANSLATION_LARGE); + } else { + bdrv_set_translation_hint(bs, + BIOS_ATA_TRANSLATION_LBA); + } + } + } + bdrv_set_geometry_hint(bs, *pcyls, *pheads, *psecs); + } +} + void bdrv_set_geometry_hint(BlockDriverState *bs, int cyls, int heads, int secs) { diff --git a/block.h b/block.h index 12053d9f1e..99d3a1e17b 100644 --- a/block.h +++ b/block.h @@ -78,6 +78,7 @@ int bdrv_pwrite(BlockDriverState *bs, int64_t offset, int bdrv_truncate(BlockDriverState *bs, int64_t offset); int64_t bdrv_getlength(BlockDriverState *bs); void bdrv_get_geometry(BlockDriverState *bs, uint64_t *nb_sectors_ptr); +void bdrv_guess_geometry(BlockDriverState *bs, int *pcyls, int *pheads, int *psecs); int bdrv_commit(BlockDriverState *bs); /* async block I/O */ typedef struct BlockDriverAIOCB BlockDriverAIOCB; diff --git a/hw/ide.c b/hw/ide.c index 9f217cc574..132d16246c 100644 --- a/hw/ide.c +++ b/hw/ide.c @@ -2676,69 +2676,13 @@ static void ide_reset(IDEState *s) s->media_changed = 0; } -struct partition { - uint8_t boot_ind; /* 0x80 - active */ - uint8_t head; /* starting head */ - uint8_t sector; /* starting sector */ - uint8_t cyl; /* starting cylinder */ - uint8_t sys_ind; /* What partition type */ - uint8_t end_head; /* end head */ - uint8_t end_sector; /* end sector */ - uint8_t end_cyl; /* end cylinder */ - uint32_t start_sect; /* starting sector counting from 0 */ - uint32_t nr_sects; /* nr of sectors in partition */ -} __attribute__((packed)); - -/* try to guess the disk logical geometry from the MSDOS partition table. Return 0 if OK, -1 if could not guess */ -static int guess_disk_lchs(IDEState *s, - int *pcylinders, int *pheads, int *psectors) -{ - uint8_t *buf = s->io_buffer; - int ret, i, heads, sectors, cylinders; - struct partition *p; - uint32_t nr_sects; - - ret = bdrv_read(s->bs, 0, buf, 1); - if (ret < 0) { - return -1; - } - /* test msdos magic */ - if (buf[510] != 0x55 || buf[511] != 0xaa) { - return -1; - } - for(i = 0; i < 4; i++) { - p = ((struct partition *)(buf + 0x1be)) + i; - nr_sects = le32_to_cpu(p->nr_sects); - if (nr_sects && p->end_head) { - /* We make the assumption that the partition terminates on - a cylinder boundary */ - heads = p->end_head + 1; - sectors = p->end_sector & 63; - if (sectors == 0) - continue; - cylinders = s->nb_sectors / (heads * sectors); - if (cylinders < 1 || cylinders > 16383) - continue; - *pheads = heads; - *psectors = sectors; - *pcylinders = cylinders; -#if 0 - printf("guessed geometry: LCHS=%d %d %d\n", - cylinders, heads, sectors); -#endif - return 0; - } - } - return -1; -} - static void ide_init2(IDEState *ide_state, BlockDriverState *hd0, BlockDriverState *hd1, qemu_irq irq) { IDEState *s; static int drive_serial = 1; - int i, cylinders, heads, secs, translation, lba_detected = 0; + int i, cylinders, heads, secs; uint64_t nb_sectors; for(i = 0; i < 2; i++) { @@ -2750,56 +2694,12 @@ static void ide_init2(IDEState *ide_state, s->bs = hd1; if (s->bs) { bdrv_get_geometry(s->bs, &nb_sectors); + bdrv_guess_geometry(s->bs, &cylinders, &heads, &secs); + s->cylinders = cylinders; + s->heads = heads; + s->sectors = secs; s->nb_sectors = nb_sectors; - /* if a geometry hint is available, use it */ - bdrv_get_geometry_hint(s->bs, &cylinders, &heads, &secs); - translation = bdrv_get_translation_hint(s->bs); - if (cylinders != 0) { - s->cylinders = cylinders; - s->heads = heads; - s->sectors = secs; - } else { - if (guess_disk_lchs(s, &cylinders, &heads, &secs) == 0) { - 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; - goto default_geometry; - } else { - s->cylinders = cylinders; - s->heads = heads; - s->sectors = secs; - /* disable any translation to be in sync with - the logical geometry */ - if (translation == BIOS_ATA_TRANSLATION_AUTO) { - bdrv_set_translation_hint(s->bs, - BIOS_ATA_TRANSLATION_NONE); - } - } - } else { - default_geometry: - /* if no geometry, use a standard physical disk geometry */ - cylinders = nb_sectors / (16 * 63); - if (cylinders > 16383) - cylinders = 16383; - else if (cylinders < 2) - cylinders = 2; - s->cylinders = cylinders; - s->heads = 16; - s->sectors = 63; - if ((lba_detected == 1) && (translation == BIOS_ATA_TRANSLATION_AUTO)) { - if ((s->cylinders * s->heads) <= 131072) { - bdrv_set_translation_hint(s->bs, - BIOS_ATA_TRANSLATION_LARGE); - } else { - bdrv_set_translation_hint(s->bs, - BIOS_ATA_TRANSLATION_LBA); - } - } - } - bdrv_set_geometry_hint(s->bs, s->cylinders, s->heads, s->sectors); - } + if (bdrv_get_type_hint(s->bs) == BDRV_TYPE_CDROM) { s->is_cdrom = 1; bdrv_set_change_cb(s->bs, cdrom_change_cb, s);