[syslinux] [PATCH 2/2 v2] com32/disk: Improve flow at disk_write_sectors and disk_read_sectors.

Raphael S.Carvalho raphael.scarv at gmail.com
Fri Sep 6 00:00:16 PDT 2013


This patch will improve the flow at disk_write_sectors and disk_read_sectors.
It does that by creating a table of values respective to the operation.

Besides, read and write operations are pretty similar to each other,
so I redesigned the routines to avoid duplication.

Signed-off-by: Raphael S.Carvalho <raphael.scarv at gmail.com>
---
 com32/include/syslinux/disk.h |   18 ++++
 com32/lib/syslinux/disk.c     |  179 +++++++++++++++++++++-------------------
 2 files changed, 112 insertions(+), 85 deletions(-)

diff --git a/com32/include/syslinux/disk.h b/com32/include/syslinux/disk.h
index f96ca68..348d1ae 100644
--- a/com32/include/syslinux/disk.h
+++ b/com32/include/syslinux/disk.h
@@ -52,6 +52,19 @@ struct disk_info {
     uint32_t spt;
 };
 
+struct disk_ops {
+    uint8_t ah;
+    void *(*op)(const struct disk_info *const, com32sys_t *, 
+		uint64_t, uint8_t);
+};
+
+enum disk_op_codes {
+    EBIOS_READ_CODE = 0x42, /* Extended read */
+    EBIOS_WRITE_CODE = 0x43, /* Extended write */
+    CHS_READ_CODE = 0x02,
+    CHS_WRITE_CODE = 0x03,
+};
+
 struct disk_ebios_dapa {
     uint16_t len;
     uint16_t count;
@@ -177,4 +190,9 @@ extern void disk_gpt_part_dump(const struct disk_gpt_part_entry *const
 			       gpt_part);
 extern void disk_gpt_header_dump(const struct disk_gpt_header *const gpt);
 
+static inline void *ebios_disk_op(const struct disk_info *const, 
+				  com32sys_t *, uint64_t, uint8_t);
+static inline void *chs_disk_op(const struct disk_info *const, 
+				com32sys_t *, uint64_t, uint8_t);
+
 #endif /* _SYSLINUX_DISK_H */
diff --git a/com32/lib/syslinux/disk.c b/com32/lib/syslinux/disk.c
index 554bed3..96e32e7 100644
--- a/com32/lib/syslinux/disk.c
+++ b/com32/lib/syslinux/disk.c
@@ -3,6 +3,7 @@
  *   Copyright 2003-2009 H. Peter Anvin - All Rights Reserved
  *   Copyright 2009-2010 Intel Corporation; author: H. Peter Anvin
  *   Copyright (C) 2010 Shao Miller
+ *   Copyright (C) 2013 Raphael S. Carvalho
  *
  *   Permission is hereby granted, free of charge, to any person
  *   obtaining a copy of this software and associated documentation
@@ -159,6 +160,81 @@ out:
 }
 
 /**
+ * Fill inreg based on EBIOS addressing properties.
+ *
+ * @v diskinfo			The disk drive to read from
+ * @v inreg			Register data structure to be filled.
+ * @v lba			The logical block address to begin reading at
+ * @v count			The number of sectors to read
+ * @ret 			lmalloc'd buf upon success, NULL upon failure
+ */
+static inline void *
+ebios_disk_op(const struct disk_info *const diskinfo, 
+	      com32sys_t *inreg, uint64_t lba, uint8_t count)
+{
+    static struct disk_ebios_dapa dapa;
+    void *buf;
+    
+    buf = lmalloc(count * diskinfo->bps);
+    if (!buf)
+	return NULL;
+    
+    dapa.len = sizeof(dapa);
+    dapa.count = count;
+    dapa.off = OFFS(buf);
+    dapa.seg = SEG(buf);
+    dapa.lba = lba;
+
+    inreg->esi.w[0] = OFFS(&dapa);
+    inreg->ds = SEG(&dapa);
+    inreg->edx.b[0] = diskinfo->disk;   
+    
+    return buf;
+}
+
+/**
+ * Fill inreg based on CHS addressing properties.
+ *
+ * @v diskinfo			The disk drive to read from
+ * @v inreg			Register data structure to be filled.
+ * @v lba			The logical block address to begin reading at
+ * @v count			The number of sectors to read
+ * @ret 			lmalloc'd buf upon success, NULL upon failure
+ */
+static inline void *
+chs_disk_op(const struct disk_info *const diskinfo, 
+	    com32sys_t *inreg, uint64_t lba, uint8_t count)
+{
+    unsigned int c, h, s, t;
+    void *buf;
+    
+    buf = lmalloc(count * diskinfo->bps);
+    if (!buf)
+	return NULL;
+    
+    /*
+     * if we passed lba + count check and we get here, that means that
+     * lbacnt was calculated from chs geometry (or faked from 1/1/1), thus
+     * 32bits are perfectly enough and lbacnt corresponds to cylinder
+     * boundary
+     */
+    s = lba % diskinfo->spt;
+    t = lba / diskinfo->spt;
+    h = t % diskinfo->head;
+    c = t / diskinfo->head;
+
+    inreg->eax.b[0] = count;
+    inreg->ecx.b[1] = c;
+    inreg->ecx.b[0] = ((c & 0x300) >> 2) | (s+1);
+    inreg->edx.b[1] = h;
+    inreg->edx.b[0] = diskinfo->disk;
+    inreg->ebx.w[0] = OFFS(buf);
+    inreg->es = SEG(buf);
+    
+    return buf;
+}
+
+/**
  * Get disk block(s) and return a malloc'd buffer.
  *
  * @v diskinfo			The disk drive to read from
@@ -173,11 +249,14 @@ void *disk_read_sectors(const struct disk_info *const diskinfo, uint64_t lba,
 			uint8_t count)
 {
     com32sys_t inreg;
-    struct disk_ebios_dapa *dapa;
     void *buf;
     void *data = NULL;
-    uint32_t maxcnt;
+    uint32_t idx, maxcnt;
     uint32_t size = 65536;
+    static struct disk_ops read_ops[2] = {
+	{ CHS_READ_CODE, &chs_disk_op },
+	{ EBIOS_READ_CODE, &ebios_disk_op }
+    };
 
     maxcnt = (size - diskinfo->bps) / diskinfo->bps;
     if (!count || count > maxcnt || lba + count > diskinfo->lbacnt)
@@ -185,48 +264,12 @@ void *disk_read_sectors(const struct disk_info *const diskinfo, uint64_t lba,
 
     memset(&inreg, 0, sizeof inreg);
 
-    buf = lmalloc(count * diskinfo->bps);
+    idx = diskinfo->ebios & 1; /* at most 1 */
+    inreg.eax.b[1] = read_ops[idx].ah;
+    buf = read_ops[idx].op(diskinfo, &inreg, lba, count);
     if (!buf)
 	return NULL;
 
-    dapa = lmalloc(sizeof(*dapa));
-    if (!dapa)
-	goto out;
-
-    if (diskinfo->ebios) {
-	dapa->len = sizeof(*dapa);
-	dapa->count = count;
-	dapa->off = OFFS(buf);
-	dapa->seg = SEG(buf);
-	dapa->lba = lba;
-
-	inreg.esi.w[0] = OFFS(dapa);
-	inreg.ds = SEG(dapa);
-	inreg.edx.b[0] = diskinfo->disk;
-	inreg.eax.b[1] = 0x42;	/* Extended read */
-    } else {
-	unsigned int c, h, s, t;
-	/*
-	 * if we passed lba + count check and we get here, that means that
-	 * lbacnt was calculated from chs geometry (or faked from 1/1/1), thus
-	 * 32bits are perfectly enough and lbacnt corresponds to cylinder
-	 * boundary
-	 */
-	s = lba % diskinfo->spt;
-	t = lba / diskinfo->spt;
-	h = t % diskinfo->head;
-	c = t / diskinfo->head;
-
-	inreg.eax.b[0] = count;
-	inreg.eax.b[1] = 0x02;	/* Read */
-	inreg.ecx.b[1] = c;
-	inreg.ecx.b[0] = ((c & 0x300) >> 2) | (s+1);
-	inreg.edx.b[1] = h;
-	inreg.edx.b[0] = diskinfo->disk;
-	inreg.ebx.w[0] = OFFS(buf);
-	inreg.es = SEG(buf);
-    }
-
     if (disk_int13_retry(&inreg, NULL))
 	goto out;
 
@@ -234,7 +277,6 @@ void *disk_read_sectors(const struct disk_info *const diskinfo, uint64_t lba,
     if (data)
 	memcpy(data, buf, count * diskinfo->bps);
 out:
-    lfree(dapa);
     lfree(buf);
     return data;
 }
@@ -255,67 +297,34 @@ int disk_write_sectors(const struct disk_info *const diskinfo, uint64_t lba,
 		       const void *data, uint8_t count)
 {
     com32sys_t inreg;
-    struct disk_ebios_dapa *dapa;
     void *buf;
-    uint32_t maxcnt;
+    uint32_t idx, maxcnt;
     uint32_t size = 65536;
     int rv = -1;
+    static struct disk_ops write_ops[2] = {
+	{ CHS_WRITE_CODE, &chs_disk_op },
+	{ EBIOS_WRITE_CODE, &ebios_disk_op }
+    };
 
     maxcnt = (size - diskinfo->bps) / diskinfo->bps;
     if (!count || count > maxcnt || lba + count > diskinfo->lbacnt)
 	return -1;
+    
+    memset(&inreg, 0, sizeof inreg);
 
-    buf = lmalloc(count * diskinfo->bps);
+    idx = diskinfo->ebios & 1; /* at most 1 */
+    inreg.eax.b[1] = write_ops[idx].ah;
+    buf = write_ops[idx].op(diskinfo, &inreg, lba, count);
     if (!buf)
 	return -1;
 
     memcpy(buf, data, count * diskinfo->bps);
-    memset(&inreg, 0, sizeof inreg);
-
-    dapa = lmalloc(sizeof(*dapa));
-    if (!dapa)
-	goto out;
-
-    if (diskinfo->ebios) {
-	dapa->len = sizeof(*dapa);
-	dapa->count = count;
-	dapa->off = OFFS(buf);
-	dapa->seg = SEG(buf);
-	dapa->lba = lba;
-
-	inreg.esi.w[0] = OFFS(dapa);
-	inreg.ds = SEG(dapa);
-	inreg.edx.b[0] = diskinfo->disk;
-	inreg.eax.b[1] = 0x43;	/* Extended write */
-    } else {
-	unsigned int c, h, s, t;
-	/*
-	 * if we passed lba + count check and we get here, that means that
-	 * lbacnt was calculated from chs geometry (or faked from 1/1/1), thus
-	 * 32bits are perfectly enough and lbacnt corresponds to cylinder
-	 * boundary
-	 */
-	s = lba % diskinfo->spt;
-	t = lba / diskinfo->spt;
-	h = t % diskinfo->head;
-	c = t / diskinfo->head;
-
-	inreg.eax.b[0] = count;
-	inreg.eax.b[1] = 0x03;	/* Write */
-	inreg.ecx.b[1] = c;
-	inreg.ecx.b[0] = ((c & 0x300) >> 2) | (s+1);
-	inreg.edx.b[1] = h;
-	inreg.edx.b[0] = diskinfo->disk;
-	inreg.ebx.w[0] = OFFS(buf);
-	inreg.es = SEG(buf);
-    }
 
     if (disk_int13_retry(&inreg, NULL))
 	goto out;
 
     rv = 0;			/* ok */
 out:
-    lfree(dapa);
     lfree(buf);
     return rv;
 }
-- 
1.7.2.5



More information about the Syslinux mailing list