* [Qemu-devel] How to get beyond the 16 head limit?
@ 2008-06-04 17:16 Erik Mouw
2008-06-11 17:42 ` Erik Mouw
0 siblings, 1 reply; 3+ messages in thread
From: Erik Mouw @ 2008-06-04 17:16 UTC (permalink / raw)
To: qemu-devel
Hi,
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:
erik@zurix:~/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?
Regards,
Erik
PS: I am using qemu-0.9.1 for this experiment
--
+-- 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. KvK Utrecht: 30160549
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [Qemu-devel] How to get beyond the 16 head limit?
2008-06-04 17:16 [Qemu-devel] How to get beyond the 16 head limit? Erik Mouw
@ 2008-06-11 17:42 ` Erik Mouw
2008-06-11 20:46 ` Fabrice Bellard
0 siblings, 1 reply; 3+ messages in thread
From: Erik Mouw @ 2008-06-11 17:42 UTC (permalink / raw)
To: qemu-devel
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:
>
> erik@zurix:~/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
^ permalink raw reply related [flat|nested] 3+ messages in thread
* Re: [Qemu-devel] How to get beyond the 16 head limit?
2008-06-11 17:42 ` Erik Mouw
@ 2008-06-11 20:46 ` Fabrice Bellard
0 siblings, 0 replies; 3+ messages in thread
From: Fabrice Bellard @ 2008-06-11 20:46 UTC (permalink / raw)
To: qemu-devel
Erik Mouw wrote:
> 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:
>>
>> erik@zurix:~/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?
At the IDE hardware level, you cannot have more than 16 heads, so your
problem is a BIOS issue.
Fabrice.
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2008-06-11 20:47 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2008-06-04 17:16 [Qemu-devel] How to get beyond the 16 head limit? Erik Mouw
2008-06-11 17:42 ` Erik Mouw
2008-06-11 20:46 ` Fabrice Bellard
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).