Skip to contentSkip to conversation

Refactor CHS guessing to be usable outside of IDE

PATCH In review Anthony Liguori 1 participant 1 message Dec 5, 2007

lore
Share & tools
lore
#0 lore raw

PATCH 1/2 Refactor CHS guessing to be usable outside of IDE

The next patch I post will require this patch. It refactors the CHS guessing so it can be used by devices other than IDE.

Regards,

Anthony Liguori

block.c +116 -0
Index: qemu/block.c
===================================================================
@@ -738,6 +738,122 @@
     memset(bs->boot_sector_data + size, 0, 512 - size);
 }
 
+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)
 {
block.h +1 -0
Index: qemu/block.h
===================================================================
@@ -73,6 +73,7 @@
 int bdrv_truncate(BlockDriverState *bs, int64_t offset);
 int64_t bdrv_getlength(BlockDriverState *bs);
 void bdrv_get_geometry(BlockDriverState *bs, int64_t *nb_sectors_ptr);
+void bdrv_guess_geometry(BlockDriverState *bs, int *pcyls, int *pheads, int *psecs);
 int bdrv_commit(BlockDriverState *bs);
 void bdrv_set_boot_sector(BlockDriverState *bs, const uint8_t *data, int size);
 /* async block I/O */
hw/ide.c +6 -104

129 lines not on this page · raw message