[Top][All Lists]
[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, §ors);
+ int cylinders, heads, sectors, nonide;
+ bdrv_get_geometry_hint(hd, &cylinders, &heads, §ors, &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,
§ors);
+ bdrv_get_geometry_hint(hd_table[i], &cylinders, &heads,
+ §ors, &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