[syslinux] [PATCH] com32/disk: add UEFI support

Paulo Alcantara pcacjr at gmail.com
Thu Sep 24 15:22:34 PDT 2015


Rework disk library to work on a firmware independent way. Each specific
implementation goes through subdirs like "bios/" and "efi/"
respectively.

Signed-off-by: Paulo Alcantara <pcacjr at zytor.com>
---
 com32/include/syslinux/disk.h       |  50 +++-
 com32/lib/Makefile                  |   2 +
 com32/lib/syslinux/disk.c           | 583 ------------------------------------
 com32/lib/syslinux/disk/bios/disk.c | 364 ++++++++++++++++++++++
 com32/lib/syslinux/disk/common.c    | 259 ++++++++++++++++
 com32/lib/syslinux/disk/efi/disk.c  | 351 ++++++++++++++++++++++
 efi/Makefile                        |   1 +
 efi/check-gnu-efi.sh                |   2 +
 mk/lib.mk                           | 104 +++++--
 9 files changed, 1092 insertions(+), 624 deletions(-)
 delete mode 100644 com32/lib/syslinux/disk.c
 create mode 100644 com32/lib/syslinux/disk/bios/disk.c
 create mode 100644 com32/lib/syslinux/disk/common.c
 create mode 100644 com32/lib/syslinux/disk/efi/disk.c

diff --git a/com32/include/syslinux/disk.h b/com32/include/syslinux/disk.h
index b8361fe..ff95d9f 100644
--- a/com32/include/syslinux/disk.h
+++ b/com32/include/syslinux/disk.h
@@ -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) 2015 Paulo Alcantara <pcacjr at zytor.com>
  *
  *   Permission is hereby granted, free of charge, to any person
  *   obtaining a copy of this software and associated documentation
@@ -33,8 +34,8 @@
  * Deal with disks and partitions
  */
 
-#ifndef _SYSLINUX_DISK_H
-#define _SYSLINUX_DISK_H
+#ifndef _SYSLINUX_DISK_H_
+#define _SYSLINUX_DISK_H_
 
 #include <com32.h>
 #include <stdint.h>
@@ -50,15 +51,24 @@ enum disk_op_codes {
 
 struct disk_info {
     int disk;
-    int ebios;			/* EBIOS supported on this disk */
-    int cbios;			/* CHS geometry is valid */
-    uint32_t bps;		/* bytes per sector */
-    uint64_t lbacnt;		/* total amount of sectors */
+    uint32_t bps;	/* bytes per sector */
+    uint64_t lbacnt;    /* total amount of sectors */
     uint32_t cyl;
     uint32_t head;
     uint32_t spt;
+    union {
+        struct { /* BIOS-specific information */
+            int ebios; /* EBIOS supported on this disk */
+            int cbios; /* CHS geometry is valid */
+        };
+        struct { /* EFI-specific information */
+            void *biop; /* EFI_BLOCK_IO_PROTOCOL pointer */
+        };
+    };
 };
 
+#ifndef SYSLINUX_EFI
+
 struct disk_ebios_dapa {
     uint16_t len;
     uint16_t count;
@@ -87,6 +97,8 @@ struct disk_ebios_eparam {
     uint8_t  checksum;
 } __attribute__ ((packed));
 
+#endif
+
 /**
  * CHS (cylinder, head, sector) value extraction macros.
  * Taken from WinVBlock.  None expand to an lvalue.
@@ -169,19 +181,25 @@ struct disk_gpt_header {
 } __attribute__ ((packed));
 static const char disk_gpt_sig_magic[] = "EFI PART";
 
+/* common.c */
+extern void disk_dos_part_dump(const struct disk_dos_part_entry *const part);
+extern void guid_to_str(char *buf, const struct guid *const id);
+extern int str_to_guid(const char *buf, struct guid *const id);
+extern void disk_gpt_part_dump(const struct disk_gpt_part_entry *const
+                               gpt_part);
+
+/* disk.c */
+#ifndef SYSLINUX_EFI
 extern int disk_int13_retry(const com32sys_t * inreg, com32sys_t * outreg);
+#endif
+
 extern int disk_get_params(int disk, struct disk_info *const diskinfo);
 extern void *disk_read_sectors(const struct disk_info *const diskinfo,
-			       uint64_t lba, uint8_t count);
+                               uint64_t lba, uint8_t count);
 extern int disk_write_sectors(const struct disk_info *const diskinfo,
-			      uint64_t lba, const void *data, uint8_t count);
+                              uint64_t lba, const void *data, uint8_t count);
 extern int disk_write_verify_sectors(const struct disk_info *const diskinfo,
-				     uint64_t lba, const void *buf, uint8_t count);
-extern void disk_dos_part_dump(const struct disk_dos_part_entry *const part);
-extern void guid_to_str(char *buf, const struct guid *const id);
-extern int str_to_guid(const char *buf, struct guid *const id);
-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);
+                                     uint64_t lba, const void *buf,
+                                     uint8_t count);
 
-#endif /* _SYSLINUX_DISK_H */
+#endif /* _SYSLINUX_DISK_H_ */
diff --git a/com32/lib/Makefile b/com32/lib/Makefile
index 1624ae7..7c54fa2 100644
--- a/com32/lib/Makefile
+++ b/com32/lib/Makefile
@@ -56,6 +56,8 @@ MINLIBOBJS = \
 	syslinux/ipappend.o \
 	syslinux/dsinfo.o \
 	$(LIBOTHER_OBJS) \
+	$(LIBSYS_OBJS) \
+	$(LIBPCI_OBJS) \
 	$(LIBGCC_OBJS) \
 	$(LIBCONSOLE_OBJS) \
 	$(LIBLOAD_OBJS) \
diff --git a/com32/lib/syslinux/disk.c b/com32/lib/syslinux/disk.c
deleted file mode 100644
index afbfc84..0000000
--- a/com32/lib/syslinux/disk.c
+++ /dev/null
@@ -1,583 +0,0 @@
-/* ----------------------------------------------------------------------- *
- *
- *   Copyright 2003-2009 H. Peter Anvin - All Rights Reserved
- *   Copyright 2009-2010 Intel Corporation; author: H. Peter Anvin
- *   Copyright (C) 2010 Shao Miller
- *
- *   Permission is hereby granted, free of charge, to any person
- *   obtaining a copy of this software and associated documentation
- *   files (the "Software"), to deal in the Software without
- *   restriction, including without limitation the rights to use,
- *   copy, modify, merge, publish, distribute, sublicense, and/or
- *   sell copies of the Software, and to permit persons to whom
- *   the Software is furnished to do so, subject to the following
- *   conditions:
- *
- *   The above copyright notice and this permission notice shall
- *   be included in all copies or substantial portions of the Software.
- *
- *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- *   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
- *   OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- *   NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
- *   HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
- *   WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- *   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- *   OTHER DEALINGS IN THE SOFTWARE.
- *
- * ----------------------------------------------------------------------- */
-
-/**
- * @file disk.c
- *
- * Deal with disks and partitions
- */
-
-#include <core.h>
-#include <dprintf.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <syslinux/disk.h>
-
-/**
- * Call int 13h, but with retry on failure.  Especially floppies need this.
- *
- * @v inreg			CPU register settings upon INT call
- * @v outreg			CPU register settings returned by INT call
- * @ret (int)			0 upon success, -1 upon failure
- */
-int disk_int13_retry(const com32sys_t * inreg, com32sys_t * outreg)
-{
-    int retry = 6;		/* Number of retries */
-    com32sys_t tmpregs;
-
-    if (!outreg)
-	outreg = &tmpregs;
-
-    while (retry--) {
-	__intcall(0x13, inreg, outreg);
-	if (!(outreg->eflags.l & EFLAGS_CF))
-	    return 0;		/* CF=0, OK */
-    }
-
-    return -1;			/* Error */
-}
-
-/**
- * Query disk parameters and EBIOS availability for a particular disk.
- *
- * @v disk			The INT 0x13 disk drive number to process
- * @v diskinfo			The structure to save the queried params to
- * @ret (int)			0 upon success, -1 upon failure
- */
-int disk_get_params(int disk, struct disk_info *const diskinfo)
-{
-    static com32sys_t inreg, outreg;
-    struct disk_ebios_eparam *eparam;
-    int rv = 0;
-
-    memset(diskinfo, 0, sizeof *diskinfo);
-    diskinfo->disk = disk;
-    diskinfo->bps = SECTOR;
-
-    /* Get EBIOS support */
-    memset(&inreg, 0, sizeof inreg);
-    inreg.eax.b[1] = 0x41;
-    inreg.ebx.w[0] = 0x55aa;
-    inreg.edx.b[0] = disk;
-    inreg.eflags.b[0] = 0x3;	/* CF set */
-
-    __intcall(0x13, &inreg, &outreg);
-
-    if (!(outreg.eflags.l & EFLAGS_CF) &&
-	outreg.ebx.w[0] == 0xaa55 && (outreg.ecx.b[0] & 1)) {
-	diskinfo->ebios = 1;
-    }
-
-    eparam = lmalloc(sizeof *eparam);
-    if (!eparam)
-	return -1;
-
-    /* Get extended disk parameters if ebios == 1 */
-    if (diskinfo->ebios) {
-	memset(&inreg, 0, sizeof inreg);
-	inreg.eax.b[1] = 0x48;
-	inreg.edx.b[0] = disk;
-	inreg.esi.w[0] = OFFS(eparam);
-	inreg.ds = SEG(eparam);
-
-	memset(eparam, 0, sizeof *eparam);
-	eparam->len = sizeof *eparam;
-
-	__intcall(0x13, &inreg, &outreg);
-
-	if (!(outreg.eflags.l & EFLAGS_CF)) {
-	    diskinfo->lbacnt = eparam->lbacnt;
-	    if (eparam->bps)
-		diskinfo->bps = eparam->bps;
-	    /*
-	     * don't think about using geometry data returned by
-	     * 48h, as it can differ from 08h a lot ...
-	     */
-	}
-    }
-    /*
-     * Get disk parameters the old way - really only useful for hard
-     * disks, but if we have a partitioned floppy it's actually our best
-     * chance...
-     */
-    memset(&inreg, 0, sizeof inreg);
-    inreg.eax.b[1] = 0x08;
-    inreg.edx.b[0] = disk;
-
-    __intcall(0x13, &inreg, &outreg);
-
-    if (outreg.eflags.l & EFLAGS_CF) {
-	rv = diskinfo->ebios ? 0 : -1;
-	goto out;
-    }
-
-    diskinfo->spt = 0x3f & outreg.ecx.b[0];
-    diskinfo->head = 1 + outreg.edx.b[1];
-    diskinfo->cyl = 1 + (outreg.ecx.b[1] | ((outreg.ecx.b[0] & 0xc0u) << 2));
-
-    if (diskinfo->spt)
-	diskinfo->cbios = 1;	/* Valid geometry */
-    else {
-	diskinfo->head = 1;
-	diskinfo->spt = 1;
-	diskinfo->cyl = 1;
-    }
-
-    if (!diskinfo->lbacnt)
-	diskinfo->lbacnt = diskinfo->cyl * diskinfo->head * diskinfo->spt;
-
-out:
-    lfree(eparam);
-    return rv;
-}
-
-/**
- * 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
- * @v op_code			Code to write/read operation
- * @ret 			lmalloc'd buf upon success, NULL upon failure
- */
-static void *ebios_setup(const struct disk_info *const diskinfo, com32sys_t *inreg,
-			 uint64_t lba, uint8_t count, uint8_t op_code)
-{
-    static struct disk_ebios_dapa *dapa = NULL;
-    void *buf;
-
-    if (!dapa) {
-	dapa = lmalloc(sizeof *dapa);
-	if (!dapa)
-	    return NULL;
-    }
-
-    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->eax.b[1] = op_code;
-    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
- * @v op_code			Code to write/read operation
- * @ret 			lmalloc'd buf upon success, NULL upon failure
- */
-static void *chs_setup(const struct disk_info *const diskinfo, com32sys_t *inreg,
-		       uint64_t lba, uint8_t count, uint8_t op_code)
-{
-    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;
-
-    memset(inreg, 0, sizeof *inreg);
-    inreg->eax.b[0] = count;
-    inreg->eax.b[1] = op_code;
-    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
- * @v lba			The logical block address to begin reading at
- * @v count			The number of sectors to read
- * @ret data			An allocated buffer with the read data
- *
- * Uses the disk number and information from diskinfo.  Read count sectors
- * from drive, starting at lba.  Return a new buffer, or NULL upon failure.
- */
-void *disk_read_sectors(const struct disk_info *const diskinfo, uint64_t lba,
-			uint8_t count)
-{
-    com32sys_t inreg;
-    void *buf;
-    void *data = NULL;
-    uint32_t maxcnt;
-    uint32_t size = 65536;
-
-    maxcnt = (size - diskinfo->bps) / diskinfo->bps;
-    if (!count || count > maxcnt || lba + count > diskinfo->lbacnt)
-	return NULL;
-
-    memset(&inreg, 0, sizeof inreg);
-
-    if (diskinfo->ebios)
-	buf = ebios_setup(diskinfo, &inreg, lba, count, EBIOS_READ_CODE);
-    else
-	buf = chs_setup(diskinfo, &inreg, lba, count, CHS_READ_CODE);
-
-    if (!buf)
-	return NULL;
-
-    if (disk_int13_retry(&inreg, NULL))
-	goto out;
-
-    data = malloc(count * diskinfo->bps);
-    if (data)
-	memcpy(data, buf, count * diskinfo->bps);
-out:
-    lfree(buf);
-    return data;
-}
-
-/**
- * Write disk block(s).
- *
- * @v diskinfo			The disk drive to write to
- * @v lba			The logical block address to begin writing at
- * @v data			The data to write
- * @v count			The number of sectors to write
- * @ret (int)			0 upon success, -1 upon failure
- *
- * Uses the disk number and information from diskinfo.
- * Write sector(s) to a disk drive, starting at lba.
- */
-int disk_write_sectors(const struct disk_info *const diskinfo, uint64_t lba,
-		       const void *data, uint8_t count)
-{
-    com32sys_t inreg;
-    void *buf;
-    uint32_t maxcnt;
-    uint32_t size = 65536;
-    int rv = -1;
-
-    maxcnt = (size - diskinfo->bps) / diskinfo->bps;
-    if (!count || count > maxcnt || lba + count > diskinfo->lbacnt)
-	return -1;
-
-    memset(&inreg, 0, sizeof inreg);
-
-    if (diskinfo->ebios)
-	buf = ebios_setup(diskinfo, &inreg, lba, count, EBIOS_WRITE_CODE);
-    else
-	buf = chs_setup(diskinfo, &inreg, lba, count, CHS_WRITE_CODE);
-
-    if (!buf)
-	return -1;
-
-    memcpy(buf, data, count * diskinfo->bps);
-
-    if (disk_int13_retry(&inreg, NULL))
-	goto out;
-
-    rv = 0;			/* ok */
-out:
-    lfree(buf);
-    return rv;
-}
-
-/**
- * Write disk blocks and verify they were written.
- *
- * @v diskinfo			The disk drive to write to
- * @v lba			The logical block address to begin writing at
- * @v buf			The data to write
- * @v count			The number of sectors to write
- * @ret rv			0 upon success, -1 upon failure
- *
- * Uses the disk number and information from diskinfo.
- * Writes sectors to a disk drive starting at lba, then reads them back
- * to verify they were written correctly.
- */
-int disk_write_verify_sectors(const struct disk_info *const diskinfo,
-			      uint64_t lba, const void *buf, uint8_t count)
-{
-    char *rb;
-    int rv;
-
-    rv = disk_write_sectors(diskinfo, lba, buf, count);
-    if (rv)
-	return rv;		/* Write failure */
-    rb = disk_read_sectors(diskinfo, lba, count);
-    if (!rb)
-	return -1;		/* Readback failure */
-    rv = memcmp(buf, rb, count * diskinfo->bps);
-    free(rb);
-    return rv ? -1 : 0;
-}
-
-/**
- * Dump info about a DOS partition entry
- *
- * @v part			The 16-byte partition entry to examine
- */
-void disk_dos_part_dump(const struct disk_dos_part_entry *const part)
-{
-    (void)part;
-    dprintf("Partition status _____ : 0x%.2x\n"
-	    "Partition CHS start\n"
-	    "  Cylinder ___________ : 0x%.4x (%u)\n"
-	    "  Head _______________ : 0x%.2x (%u)\n"
-	    "  Sector _____________ : 0x%.2x (%u)\n"
-	    "Partition type _______ : 0x%.2x\n"
-	    "Partition CHS end\n"
-	    "  Cylinder ___________ : 0x%.4x (%u)\n"
-	    "  Head _______________ : 0x%.2x (%u)\n"
-	    "  Sector _____________ : 0x%.2x (%u)\n"
-	    "Partition LBA start __ : 0x%.8x (%u)\n"
-	    "Partition LBA count __ : 0x%.8x (%u)\n"
-	    "-------------------------------\n",
-	    part->active_flag,
-	    chs_cylinder(part->start),
-	    chs_cylinder(part->start),
-	    chs_head(part->start),
-	    chs_head(part->start),
-	    chs_sector(part->start),
-	    chs_sector(part->start),
-	    part->ostype,
-	    chs_cylinder(part->end),
-	    chs_cylinder(part->end),
-	    chs_head(part->end),
-	    chs_head(part->end),
-	    chs_sector(part->end),
-	    chs_sector(part->end),
-	    part->start_lba, part->start_lba, part->length, part->length);
-}
-
-/* Trivial error message output */
-static inline void error(const char *msg)
-{
-    fputs(msg, stderr);
-}
-
-/**
- * This walk-map effectively reverses the little-endian
- * portions of a GPT disk/partition GUID for a string representation.
- * There might be a better header for this...
- */
-static const char guid_le_walk_map[] = {
-    3, -1, -1, -1, 0,
-    5, -1, 0,
-    3, -1, 0,
-    2, 1, 0,
-    1, 1, 1, 1, 1, 1
-};
-
-/**
- * Fill a buffer with a textual GUID representation.
- *
- * @v buf			Points to a minimum array of 37 chars
- * @v id			The GUID to represent as text
- *
- * The buffer must be >= char[37] and will be populated
- * with an ASCII NUL C string terminator.
- * Example: 11111111-2222-3333-4444-444444444444
- * Endian:  LLLLLLLL-LLLL-LLLL-BBBB-BBBBBBBBBBBB
- */
-void guid_to_str(char *buf, const struct guid *const id)
-{
-    unsigned int i = 0;
-    const char *walker = (const char *)id;
-
-    while (i < sizeof(guid_le_walk_map)) {
-	walker += guid_le_walk_map[i];
-	if (!guid_le_walk_map[i])
-	    *buf = '-';
-	else {
-	    *buf = ((*walker & 0xF0) >> 4) + '0';
-	    if (*buf > '9')
-		*buf += 'A' - '9' - 1;
-	    buf++;
-	    *buf = (*walker & 0x0F) + '0';
-	    if (*buf > '9')
-		*buf += 'A' - '9' - 1;
-	}
-	buf++;
-	i++;
-    }
-    *buf = 0;
-}
-
-/**
- * Create a GUID structure from a textual GUID representation.
- *
- * @v buf			Points to a GUID string to parse
- * @v id			Points to a GUID to be populated
- * @ret (int)			Returns 0 upon success, -1 upon failure
- *
- * The input buffer must be >= 32 hexadecimal chars and be
- * terminated with an ASCII NUL.  Returns non-zero on failure.
- * Example: 11111111-2222-3333-4444-444444444444
- * Endian:  LLLLLLLL-LLLL-LLLL-BBBB-BBBBBBBBBBBB
- */
-int str_to_guid(const char *buf, struct guid *const id)
-{
-    char guid_seq[sizeof(struct guid) * 2];
-    unsigned int i = 0;
-    char *walker = (char *)id;
-
-    while (*buf && i < sizeof(guid_seq)) {
-	switch (*buf) {
-	    /* Skip these three characters */
-	case '{':
-	case '}':
-	case '-':
-	    break;
-	default:
-	    /* Copy something useful to the temp. sequence */
-	    if ((*buf >= '0') && (*buf <= '9'))
-		guid_seq[i] = *buf - '0';
-	    else if ((*buf >= 'A') && (*buf <= 'F'))
-		guid_seq[i] = *buf - 'A' + 10;
-	    else if ((*buf >= 'a') && (*buf <= 'f'))
-		guid_seq[i] = *buf - 'a' + 10;
-	    else {
-		/* Or not */
-		error("Illegal character in GUID!\n");
-		return -1;
-	    }
-	    i++;
-	}
-	buf++;
-    }
-    /* Check for insufficient valid characters */
-    if (i < sizeof(guid_seq)) {
-	error("Too few GUID characters!\n");
-	return -1;
-    }
-    buf = guid_seq;
-    i = 0;
-    while (i < sizeof(guid_le_walk_map)) {
-	if (!guid_le_walk_map[i])
-	    i++;
-	walker += guid_le_walk_map[i];
-	*walker = *buf << 4;
-	buf++;
-	*walker |= *buf;
-	buf++;
-	i++;
-    }
-    return 0;
-}
-
-/**
- * Display GPT partition details.
- *
- * @v gpt_part			The GPT partition entry to display
- */
-void disk_gpt_part_dump(const struct disk_gpt_part_entry *const gpt_part)
-{
-    unsigned int i;
-    char guid_text[37];
-
-    dprintf("----------------------------------\n"
-	    "GPT part. LBA first __ : 0x%.16" PRIx64 "x\n"
-	    "GPT part. LBA last ___ : 0x%.16" PRIx64 "x\n"
-	    "GPT part. attribs ____ : 0x%.16" PRIx64 "x\n"
-	    "GPT part. name _______ : '",
-	    gpt_part->lba_first, gpt_part->lba_last, gpt_part->attribs);
-    for (i = 0; i < sizeof(gpt_part->name); i++) {
-	if (gpt_part->name[i])
-	    dprintf("%c", gpt_part->name[i]);
-    }
-    dprintf("'");
-    guid_to_str(guid_text, &gpt_part->type);
-    dprintf("GPT part. type GUID __ : {%s}\n", guid_text);
-    guid_to_str(guid_text, &gpt_part->uid);
-    dprintf("GPT part. unique ID __ : {%s}\n", guid_text);
-}
-
-/**
- * Display GPT header details.
- *
- * @v gpt			The GPT header to display
- */
-void disk_gpt_header_dump(const struct disk_gpt_header *const gpt)
-{
-    char guid_text[37];
-
-    printf("GPT sig ______________ : '%8.8s'\n"
-	   "GPT major revision ___ : 0x%.4x\n"
-	   "GPT minor revision ___ : 0x%.4x\n"
-	   "GPT header size ______ : 0x%.8x\n"
-	   "GPT header checksum __ : 0x%.8x\n"
-	   "GPT reserved _________ : '%4.4s'\n"
-	   "GPT LBA current ______ : 0x%.16" PRIx64 "x\n"
-	   "GPT LBA alternative __ : 0x%.16" PRIx64 "x\n"
-	   "GPT LBA first usable _ : 0x%.16" PRIx64 "x\n"
-	   "GPT LBA last usable __ : 0x%.16" PRIx64 "x\n"
-	   "GPT LBA part. table __ : 0x%.16" PRIx64 "x\n"
-	   "GPT partition count __ : 0x%.8x\n"
-	   "GPT partition size ___ : 0x%.8x\n"
-	   "GPT part. table chksum : 0x%.8x\n",
-	   gpt->sig,
-	   gpt->rev.fields.major,
-	   gpt->rev.fields.minor,
-	   gpt->hdr_size,
-	   gpt->chksum,
-	   gpt->reserved1,
-	   gpt->lba_cur,
-	   gpt->lba_alt,
-	   gpt->lba_first_usable,
-	   gpt->lba_last_usable,
-	   gpt->lba_table, gpt->part_count, gpt->part_size, gpt->table_chksum);
-    guid_to_str(guid_text, &gpt->disk_guid);
-    printf("GPT disk GUID ________ : {%s}\n", guid_text);
-}
diff --git a/com32/lib/syslinux/disk/bios/disk.c b/com32/lib/syslinux/disk/bios/disk.c
new file mode 100644
index 0000000..76e98c6
--- /dev/null
+++ b/com32/lib/syslinux/disk/bios/disk.c
@@ -0,0 +1,364 @@
+/* ----------------------------------------------------------------------- *
+ *
+ *   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) 2015 Paulo Alcantara <pcacjr at zytor.com>
+ *
+ *   Permission is hereby granted, free of charge, to any person
+ *   obtaining a copy of this software and associated documentation
+ *   files (the "Software"), to deal in the Software without
+ *   restriction, including without limitation the rights to use,
+ *   copy, modify, merge, publish, distribute, sublicense, and/or
+ *   sell copies of the Software, and to permit persons to whom
+ *   the Software is furnished to do so, subject to the following
+ *   conditions:
+ *
+ *   The above copyright notice and this permission notice shall
+ *   be included in all copies or substantial portions of the Software.
+ *
+ *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ *   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ *   OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ *   NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ *   HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ *   WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ *   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ *   OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * ----------------------------------------------------------------------- */
+
+/**
+ * @file disk.c
+ *
+ * Deal with disks and partitions
+ */
+
+#include <core.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslinux/disk.h>
+
+/**
+ * Call int 13h, but with retry on failure.  Especially floppies need this.
+ *
+ * @v inreg			CPU register settings upon INT call
+ * @v outreg			CPU register settings returned by INT call
+ * @ret (int)			0 upon success, -1 upon failure
+ */
+int disk_int13_retry(const com32sys_t * inreg, com32sys_t * outreg)
+{
+    int retry = 6;		/* Number of retries */
+    com32sys_t tmpregs;
+
+    if (!outreg)
+	outreg = &tmpregs;
+
+    while (retry--) {
+	__intcall(0x13, inreg, outreg);
+	if (!(outreg->eflags.l & EFLAGS_CF))
+	    return 0;		/* CF=0, OK */
+    }
+
+    return -1;			/* Error */
+}
+
+/**
+ * Query disk parameters and EBIOS availability for a particular disk.
+ *
+ * @v disk			The INT 0x13 disk drive number to process
+ * @v diskinfo			The structure to save the queried params to
+ * @ret (int)			0 upon success, -1 upon failure
+ */
+int disk_get_params(int disk, struct disk_info *const diskinfo)
+{
+    static com32sys_t inreg, outreg;
+    struct disk_ebios_eparam *eparam;
+    int rv = 0;
+
+    memset(diskinfo, 0, sizeof *diskinfo);
+    diskinfo->disk = disk;
+    diskinfo->bps = SECTOR;
+
+    /* Get EBIOS support */
+    memset(&inreg, 0, sizeof inreg);
+    inreg.eax.b[1] = 0x41;
+    inreg.ebx.w[0] = 0x55aa;
+    inreg.edx.b[0] = disk;
+    inreg.eflags.b[0] = 0x3;	/* CF set */
+
+    __intcall(0x13, &inreg, &outreg);
+
+    if (!(outreg.eflags.l & EFLAGS_CF) &&
+	outreg.ebx.w[0] == 0xaa55 && (outreg.ecx.b[0] & 1)) {
+	diskinfo->ebios = 1;
+    }
+
+    eparam = lmalloc(sizeof *eparam);
+    if (!eparam)
+	return -1;
+
+    /* Get extended disk parameters if ebios == 1 */
+    if (diskinfo->ebios) {
+	memset(&inreg, 0, sizeof inreg);
+	inreg.eax.b[1] = 0x48;
+	inreg.edx.b[0] = disk;
+	inreg.esi.w[0] = OFFS(eparam);
+	inreg.ds = SEG(eparam);
+
+	memset(eparam, 0, sizeof *eparam);
+	eparam->len = sizeof *eparam;
+
+	__intcall(0x13, &inreg, &outreg);
+
+	if (!(outreg.eflags.l & EFLAGS_CF)) {
+	    diskinfo->lbacnt = eparam->lbacnt;
+	    if (eparam->bps)
+		diskinfo->bps = eparam->bps;
+	    /*
+	     * don't think about using geometry data returned by
+	     * 48h, as it can differ from 08h a lot ...
+	     */
+	}
+    }
+    /*
+     * Get disk parameters the old way - really only useful for hard
+     * disks, but if we have a partitioned floppy it's actually our best
+     * chance...
+     */
+    memset(&inreg, 0, sizeof inreg);
+    inreg.eax.b[1] = 0x08;
+    inreg.edx.b[0] = disk;
+
+    __intcall(0x13, &inreg, &outreg);
+
+    if (outreg.eflags.l & EFLAGS_CF) {
+	rv = diskinfo->ebios ? 0 : -1;
+	goto out;
+    }
+
+    diskinfo->spt = 0x3f & outreg.ecx.b[0];
+    diskinfo->head = 1 + outreg.edx.b[1];
+    diskinfo->cyl = 1 + (outreg.ecx.b[1] | ((outreg.ecx.b[0] & 0xc0u) << 2));
+
+    if (diskinfo->spt)
+	diskinfo->cbios = 1;	/* Valid geometry */
+    else {
+	diskinfo->head = 1;
+	diskinfo->spt = 1;
+	diskinfo->cyl = 1;
+    }
+
+    if (!diskinfo->lbacnt)
+	diskinfo->lbacnt = diskinfo->cyl * diskinfo->head * diskinfo->spt;
+
+out:
+    lfree(eparam);
+    return rv;
+}
+
+/**
+ * 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
+ * @v op_code			Code to write/read operation
+ * @ret 			lmalloc'd buf upon success, NULL upon failure
+ */
+static void *ebios_setup(const struct disk_info *const diskinfo, com32sys_t *inreg,
+			 uint64_t lba, uint8_t count, uint8_t op_code)
+{
+    static struct disk_ebios_dapa *dapa = NULL;
+    void *buf;
+
+    if (!dapa) {
+	dapa = lmalloc(sizeof *dapa);
+	if (!dapa)
+	    return NULL;
+    }
+
+    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->eax.b[1] = op_code;
+    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
+ * @v op_code			Code to write/read operation
+ * @ret 			lmalloc'd buf upon success, NULL upon failure
+ */
+static void *chs_setup(const struct disk_info *const diskinfo, com32sys_t *inreg,
+		       uint64_t lba, uint8_t count, uint8_t op_code)
+{
+    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;
+
+    memset(inreg, 0, sizeof *inreg);
+    inreg->eax.b[0] = count;
+    inreg->eax.b[1] = op_code;
+    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
+ * @v lba			The logical block address to begin reading at
+ * @v count			The number of sectors to read
+ * @ret data			An allocated buffer with the read data
+ *
+ * Uses the disk number and information from diskinfo.  Read count sectors
+ * from drive, starting at lba.  Return a new buffer, or NULL upon failure.
+ */
+void *disk_read_sectors(const struct disk_info *const diskinfo, uint64_t lba,
+			uint8_t count)
+{
+    com32sys_t inreg;
+    void *buf;
+    void *data = NULL;
+    uint32_t maxcnt;
+    uint32_t size = 65536;
+
+    maxcnt = (size - diskinfo->bps) / diskinfo->bps;
+    if (!count || count > maxcnt || lba + count > diskinfo->lbacnt)
+	return NULL;
+
+    memset(&inreg, 0, sizeof inreg);
+
+    if (diskinfo->ebios)
+	buf = ebios_setup(diskinfo, &inreg, lba, count, EBIOS_READ_CODE);
+    else
+	buf = chs_setup(diskinfo, &inreg, lba, count, CHS_READ_CODE);
+
+    if (!buf)
+	return NULL;
+
+    if (disk_int13_retry(&inreg, NULL))
+	goto out;
+
+    data = malloc(count * diskinfo->bps);
+    if (data)
+	memcpy(data, buf, count * diskinfo->bps);
+out:
+    lfree(buf);
+    return data;
+}
+
+/**
+ * Write disk block(s).
+ *
+ * @v diskinfo			The disk drive to write to
+ * @v lba			The logical block address to begin writing at
+ * @v data			The data to write
+ * @v count			The number of sectors to write
+ * @ret (int)			0 upon success, -1 upon failure
+ *
+ * Uses the disk number and information from diskinfo.
+ * Write sector(s) to a disk drive, starting at lba.
+ */
+int disk_write_sectors(const struct disk_info *const diskinfo, uint64_t lba,
+		       const void *data, uint8_t count)
+{
+    com32sys_t inreg;
+    void *buf;
+    uint32_t maxcnt;
+    uint32_t size = 65536;
+    int rv = -1;
+
+    maxcnt = (size - diskinfo->bps) / diskinfo->bps;
+    if (!count || count > maxcnt || lba + count > diskinfo->lbacnt)
+	return -1;
+
+    memset(&inreg, 0, sizeof inreg);
+
+    if (diskinfo->ebios)
+	buf = ebios_setup(diskinfo, &inreg, lba, count, EBIOS_WRITE_CODE);
+    else
+	buf = chs_setup(diskinfo, &inreg, lba, count, CHS_WRITE_CODE);
+
+    if (!buf)
+	return -1;
+
+    memcpy(buf, data, count * diskinfo->bps);
+
+    if (disk_int13_retry(&inreg, NULL))
+	goto out;
+
+    rv = 0;			/* ok */
+out:
+    lfree(buf);
+    return rv;
+}
+
+/**
+ * Write disk blocks and verify they were written.
+ *
+ * @v diskinfo			The disk drive to write to
+ * @v lba			The logical block address to begin writing at
+ * @v buf			The data to write
+ * @v count			The number of sectors to write
+ * @ret rv			0 upon success, -1 upon failure
+ *
+ * Uses the disk number and information from diskinfo.
+ * Writes sectors to a disk drive starting at lba, then reads them back
+ * to verify they were written correctly.
+ */
+int disk_write_verify_sectors(const struct disk_info *const diskinfo,
+			      uint64_t lba, const void *buf, uint8_t count)
+{
+    char *rb;
+    int rv;
+
+    rv = disk_write_sectors(diskinfo, lba, buf, count);
+    if (rv)
+	return rv;		/* Write failure */
+    rb = disk_read_sectors(diskinfo, lba, count);
+    if (!rb)
+	return -1;		/* Readback failure */
+    rv = memcmp(buf, rb, count * diskinfo->bps);
+    free(rb);
+    return rv ? -1 : 0;
+}
diff --git a/com32/lib/syslinux/disk/common.c b/com32/lib/syslinux/disk/common.c
new file mode 100644
index 0000000..727f576
--- /dev/null
+++ b/com32/lib/syslinux/disk/common.c
@@ -0,0 +1,259 @@
+/* ----------------------------------------------------------------------- *
+ *
+ *   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) 2015 Paulo Alcantara <pcacjr at zytor.com>
+ *
+ *   Permission is hereby granted, free of charge, to any person
+ *   obtaining a copy of this software and associated documentation
+ *   files (the "Software"), to deal in the Software without
+ *   restriction, including without limitation the rights to use,
+ *   copy, modify, merge, publish, distribute, sublicense, and/or
+ *   sell copies of the Software, and to permit persons to whom
+ *   the Software is furnished to do so, subject to the following
+ *   conditions:
+ *
+ *   The above copyright notice and this permission notice shall
+ *   be included in all copies or substantial portions of the Software.
+ *
+ *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ *   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ *   OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ *   NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ *   HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ *   WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ *   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ *   OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * ----------------------------------------------------------------------- */
+
+#include <core.h>
+#include <dprintf.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <syslinux/disk.h>
+
+/**
+ * Dump info about a DOS partition entry
+ *
+ * @v part			The 16-byte partition entry to examine
+ */
+void disk_dos_part_dump(const struct disk_dos_part_entry *const part)
+{
+    (void)part;
+    dprintf("Partition status _____ : 0x%.2x\n"
+	    "Partition CHS start\n"
+	    "  Cylinder ___________ : 0x%.4x (%u)\n"
+	    "  Head _______________ : 0x%.2x (%u)\n"
+	    "  Sector _____________ : 0x%.2x (%u)\n"
+	    "Partition type _______ : 0x%.2x\n"
+	    "Partition CHS end\n"
+	    "  Cylinder ___________ : 0x%.4x (%u)\n"
+	    "  Head _______________ : 0x%.2x (%u)\n"
+	    "  Sector _____________ : 0x%.2x (%u)\n"
+	    "Partition LBA start __ : 0x%.8x (%u)\n"
+	    "Partition LBA count __ : 0x%.8x (%u)\n"
+	    "-------------------------------\n",
+	    part->active_flag,
+	    chs_cylinder(part->start),
+	    chs_cylinder(part->start),
+	    chs_head(part->start),
+	    chs_head(part->start),
+	    chs_sector(part->start),
+	    chs_sector(part->start),
+	    part->ostype,
+	    chs_cylinder(part->end),
+	    chs_cylinder(part->end),
+	    chs_head(part->end),
+	    chs_head(part->end),
+	    chs_sector(part->end),
+	    chs_sector(part->end),
+	    part->start_lba, part->start_lba, part->length, part->length);
+}
+
+/* Trivial error message output */
+static inline void error(const char *msg)
+{
+    fprintf(stderr, msg);
+}
+
+/**
+ * This walk-map effectively reverses the little-endian
+ * portions of a GPT disk/partition GUID for a string representation.
+ * There might be a better header for this...
+ */
+static const char guid_le_walk_map[] = {
+    3, -1, -1, -1, 0,
+    5, -1, 0,
+    3, -1, 0,
+    2, 1, 0,
+    1, 1, 1, 1, 1, 1
+};
+
+/**
+ * Fill a buffer with a textual GUID representation.
+ *
+ * @v buf			Points to a minimum array of 37 chars
+ * @v id			The GUID to represent as text
+ *
+ * The buffer must be >= char[37] and will be populated
+ * with an ASCII NUL C string terminator.
+ * Example: 11111111-2222-3333-4444-444444444444
+ * Endian:  LLLLLLLL-LLLL-LLLL-BBBB-BBBBBBBBBBBB
+ */
+void guid_to_str(char *buf, const struct guid *const id)
+{
+    unsigned int i = 0;
+    const char *walker = (const char *)id;
+
+    while (i < sizeof(guid_le_walk_map)) {
+	walker += guid_le_walk_map[i];
+	if (!guid_le_walk_map[i])
+	    *buf = '-';
+	else {
+	    *buf = ((*walker & 0xF0) >> 4) + '0';
+	    if (*buf > '9')
+		*buf += 'A' - '9' - 1;
+	    buf++;
+	    *buf = (*walker & 0x0F) + '0';
+	    if (*buf > '9')
+		*buf += 'A' - '9' - 1;
+	}
+	buf++;
+	i++;
+    }
+    *buf = 0;
+}
+
+/**
+ * Create a GUID structure from a textual GUID representation.
+ *
+ * @v buf			Points to a GUID string to parse
+ * @v id			Points to a GUID to be populated
+ * @ret (int)			Returns 0 upon success, -1 upon failure
+ *
+ * The input buffer must be >= 32 hexadecimal chars and be
+ * terminated with an ASCII NUL.  Returns non-zero on failure.
+ * Example: 11111111-2222-3333-4444-444444444444
+ * Endian:  LLLLLLLL-LLLL-LLLL-BBBB-BBBBBBBBBBBB
+ */
+int str_to_guid(const char *buf, struct guid *const id)
+{
+    char guid_seq[sizeof(struct guid) * 2];
+    unsigned int i = 0;
+    char *walker = (char *)id;
+
+    while (*buf && i < sizeof(guid_seq)) {
+	switch (*buf) {
+	    /* Skip these three characters */
+	case '{':
+	case '}':
+	case '-':
+	    break;
+	default:
+	    /* Copy something useful to the temp. sequence */
+	    if ((*buf >= '0') && (*buf <= '9'))
+		guid_seq[i] = *buf - '0';
+	    else if ((*buf >= 'A') && (*buf <= 'F'))
+		guid_seq[i] = *buf - 'A' + 10;
+	    else if ((*buf >= 'a') && (*buf <= 'f'))
+		guid_seq[i] = *buf - 'a' + 10;
+	    else {
+		/* Or not */
+		error("Illegal character in GUID!\n");
+		return -1;
+	    }
+	    i++;
+	}
+	buf++;
+    }
+    /* Check for insufficient valid characters */
+    if (i < sizeof(guid_seq)) {
+	error("Too few GUID characters!\n");
+	return -1;
+    }
+    buf = guid_seq;
+    i = 0;
+    while (i < sizeof(guid_le_walk_map)) {
+	if (!guid_le_walk_map[i])
+	    i++;
+	walker += guid_le_walk_map[i];
+	*walker = *buf << 4;
+	buf++;
+	*walker |= *buf;
+	buf++;
+	i++;
+    }
+    return 0;
+}
+
+/**
+ * Display GPT partition details.
+ *
+ * @v gpt_part			The GPT partition entry to display
+ */
+void disk_gpt_part_dump(const struct disk_gpt_part_entry *const gpt_part)
+{
+    unsigned int i;
+    unsigned int k;
+    static char part_name[73];
+    char guid_text[37];
+
+    dprintf("----------------------------------\n"
+	    "GPT part. LBA first __ : 0x%.16" PRIx64 "x\n"
+	    "GPT part. LBA last ___ : 0x%.16" PRIx64 "x\n"
+	    "GPT part. attribs ____ : 0x%.16" PRIx64 "x\n"
+	    "GPT part. name _______ : '",
+	    gpt_part->lba_first, gpt_part->lba_last, gpt_part->attribs);
+    for (i = 0, k = 0; i < sizeof(gpt_part->name); i++) {
+	if (gpt_part->name[i])
+            part_name[k++] = gpt_part->name[i];
+    }
+    part_name[k] = '\0';
+    dprintf("%s'", part_name);
+    guid_to_str(guid_text, &gpt_part->type);
+    dprintf("GPT part. type GUID __ : {%s}\n", guid_text);
+    guid_to_str(guid_text, &gpt_part->uid);
+    dprintf("GPT part. unique ID __ : {%s}\n", guid_text);
+}
+
+/**
+ * Display GPT header details.
+ *
+ * @v gpt			The GPT header to display
+ */
+void disk_gpt_header_dump(const struct disk_gpt_header *const gpt)
+{
+    char guid_text[37];
+
+    printf("GPT sig ______________ : '%8.8s'\n"
+	   "GPT major revision ___ : 0x%.4x\n"
+	   "GPT minor revision ___ : 0x%.4x\n"
+	   "GPT header size ______ : 0x%.8x\n"
+	   "GPT header checksum __ : 0x%.8x\n"
+	   "GPT reserved _________ : '%4.4s'\n"
+	   "GPT LBA current ______ : 0x%.16" PRIx64 "x\n"
+	   "GPT LBA alternative __ : 0x%.16" PRIx64 "x\n"
+	   "GPT LBA first usable _ : 0x%.16" PRIx64 "x\n"
+	   "GPT LBA last usable __ : 0x%.16" PRIx64 "x\n"
+	   "GPT LBA part. table __ : 0x%.16" PRIx64 "x\n"
+	   "GPT partition count __ : 0x%.8x\n"
+	   "GPT partition size ___ : 0x%.8x\n"
+	   "GPT part. table chksum : 0x%.8x\n",
+	   gpt->sig,
+	   gpt->rev.fields.major,
+	   gpt->rev.fields.minor,
+	   gpt->hdr_size,
+	   gpt->chksum,
+	   gpt->reserved1,
+	   gpt->lba_cur,
+	   gpt->lba_alt,
+	   gpt->lba_first_usable,
+	   gpt->lba_last_usable,
+	   gpt->lba_table, gpt->part_count, gpt->part_size, gpt->table_chksum);
+    guid_to_str(guid_text, &gpt->disk_guid);
+    printf("GPT disk GUID ________ : {%s}\n", guid_text);
+}
diff --git a/com32/lib/syslinux/disk/efi/disk.c b/com32/lib/syslinux/disk/efi/disk.c
new file mode 100644
index 0000000..2361724
--- /dev/null
+++ b/com32/lib/syslinux/disk/efi/disk.c
@@ -0,0 +1,351 @@
+/* ----------------------------------------------------------------------- *
+ *
+ *   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) 2015 Paulo Alcantara <pcacjr at zytor.com>
+ *
+ *   Permission is hereby granted, free of charge, to any person
+ *   obtaining a copy of this software and associated documentation
+ *   files (the "Software"), to deal in the Software without
+ *   restriction, including without limitation the rights to use,
+ *   copy, modify, merge, publish, distribute, sublicense, and/or
+ *   sell copies of the Software, and to permit persons to whom
+ *   the Software is furnished to do so, subject to the following
+ *   conditions:
+ *
+ *   The above copyright notice and this permission notice shall
+ *   be included in all copies or substantial portions of the Software.
+ *
+ *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ *   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ *   OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ *   NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ *   HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ *   WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ *   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ *   OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * ----------------------------------------------------------------------- */
+
+/**
+ * @file disk.c
+ *
+ * Deal with disks and partitions
+ */
+
+#include <core.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <efi.h>
+#include <efilib.h>
+
+#include <syslinux/disk.h>
+
+#define DISKS_MAX 0x80
+
+static EFI_HANDLE disk_dev_handles[DISKS_MAX] = { NULL, };
+
+/* Find all device handles that support EFI_BLOCK_IO_PROTOCOL */
+static EFI_STATUS find_all_block_devs(EFI_HANDLE **bdevs,
+                                      unsigned long *bdevsno)
+{
+    EFI_STATUS status;
+    unsigned long len = 0;
+
+    *bdevsno = 0;
+
+    status = uefi_call_wrapper(BS->LocateHandle, 5, ByProtocol,
+                               &BlockIoProtocol, NULL, &len, NULL);
+    if (EFI_ERROR(status) && status != EFI_BUFFER_TOO_SMALL) {
+        printf("%s: failed to locate BlockIo device handles\n", __func__);
+        return status;
+    }
+
+    *bdevs = malloc(len);
+    if (!*bdevs) {
+        status = EFI_OUT_OF_RESOURCES;
+        return status;
+    }
+
+    status = uefi_call_wrapper(BS->LocateHandle, 5, ByProtocol,
+                               &BlockIoProtocol, NULL, &len, *bdevs);
+    if (EFI_ERROR(status)) {
+        printf("%s: failed to locate BlockIo device handles\n", __func__);
+        free(*bdevs);
+        return status;
+    }
+
+    *bdevsno = len / sizeof(EFI_HANDLE);
+
+    return status;
+}
+
+#if 0
+static void __print_dev_path(const CHAR16 *str)
+{
+    unsigned char *start = (unsigned char *)(uintptr_t)str;
+    unsigned char *end = (unsigned char *)((uintptr_t)start + StrSize(str));
+
+    while (start < end) {
+        if (*start)
+            printf("%c", *start);
+        start++;
+    }
+    printf("\n");
+}
+
+static void print_dev_path(const EFI_DEVICE_PATH *path)
+{
+    CHAR16 *s;
+
+    s = DevicePathToStr(path);
+    __print_dev_path(s);
+    FreePool(s);
+}
+#endif
+
+static EFI_DEVICE_PATH *find_hdd_pci_dev_path(EFI_HANDLE dh)
+{
+    EFI_DEVICE_PATH *path;
+    EFI_DEVICE_PATH *cur;
+
+    path = DuplicateDevicePath(DevicePathFromHandle(dh));
+    cur = path;
+    do {
+        if (DevicePathType(cur) == MEDIA_DEVICE_PATH &&
+            DevicePathSubType(cur) == MEDIA_HARDDRIVE_DP) {
+            cur->Type = END_DEVICE_PATH_TYPE;
+            cur->SubType = END_ENTIRE_DEVICE_PATH_SUBTYPE;
+            return path;
+        }
+        cur = NextDevicePathNode(cur);
+    } while (!IsDevicePathEnd(cur));
+
+    return NULL;
+}
+
+static int add_disk_dev_handle(EFI_DEVICE_PATH *path)
+{
+    EFI_STATUS status;
+    EFI_DEVICE_PATH *rempath = path;
+    EFI_HANDLE dh = NULL;
+    unsigned int i;
+
+    status = uefi_call_wrapper(BS->LocateDevicePath, 3, &BlockIoProtocol,
+                               &rempath, &dh);
+    if (EFI_ERROR(status)) {
+        printf("%s: failed to locate PCI device handle\n", __func__);
+        return -1;
+    }
+
+    for (i = 0; i < DISKS_MAX && disk_dev_handles[i]; i++) {
+        if (disk_dev_handles[i] == dh)
+            break;
+    }
+
+    if (__unlikely(i == DISKS_MAX))
+        return 0;
+
+    if (!disk_dev_handles[i])
+        disk_dev_handles[i] = dh;
+    return 0;
+}
+
+static int do_enumerate_disks(void)
+{
+    EFI_STATUS status;
+    EFI_HANDLE *bdevs = NULL;
+    unsigned long bdevsno = 0;
+    unsigned long i;
+    int ret = -1;
+    EFI_DEVICE_PATH *path;
+
+    status = find_all_block_devs(&bdevs, &bdevsno);
+    if (EFI_ERROR(status)) {
+        printf("%s: failed to locate BlockIo device handles\n", __func__);
+        return -1;
+    }
+
+    for (i = 0; i < bdevsno; i++) {
+        path = find_hdd_pci_dev_path(bdevs[i]);
+        if (path) {
+            if (add_disk_dev_handle(path)) {
+                free(path);
+                goto out;
+            }
+            free(path);
+        }
+    }
+
+    ret = 0;
+
+out:
+    free(bdevs);
+    return ret;
+}
+
+/**
+ * Query disk parameters for a particular disk.
+ *
+ * @v disk			The disk drive number
+ * @v diskinfo			The structure to save the queried params to
+ * @ret (int)			0 upon success, -1 upon failure
+ */
+int disk_get_params(int disk, struct disk_info *const diskinfo)
+{
+    int ret;
+    EFI_STATUS status;
+    EFI_BLOCK_IO *bio;
+
+    memset(diskinfo, 0, sizeof(*diskinfo));
+    diskinfo->disk = disk;
+
+    if (disk >= DISKS_MAX)
+        return -1;
+
+    if (!disk_dev_handles[0]) {
+        ret = do_enumerate_disks();
+        if (ret)
+            return ret;
+    }
+
+    status = uefi_call_wrapper(BS->HandleProtocol, 3,
+                               disk_dev_handles[disk], &BlockIoProtocol,
+                               &bio);
+    if (EFI_ERROR(status)) {
+        printf("%s: failed to get BlockIo protocol pointer\n", __func__);
+        return -1;
+    }
+
+    diskinfo->bps = bio->Media->BlockSize;
+    diskinfo->lbacnt = bio->Media->LastBlock + 1;
+    diskinfo->cyl = 1;
+    diskinfo->head = 1;
+    diskinfo->spt = 1;
+
+    diskinfo->biop = bio;
+
+    return 0;
+}
+
+/**
+ * Get disk block(s) and return a malloc'd buffer.
+ *
+ * @v diskinfo			The disk drive to read from
+ * @v lba			The logical block address to begin reading at
+ * @v count			The number of sectors to read
+ * @ret data			An allocated buffer with the read data
+ *
+ * Uses the disk number and information from diskinfo.  Read count sectors
+ * from drive, starting at lba.  Return a new buffer, or NULL upon failure.
+ */
+void *disk_read_sectors(const struct disk_info *const diskinfo, uint64_t lba,
+			uint8_t count)
+{
+    EFI_STATUS status;
+    unsigned long len;
+    void *data;
+    EFI_BLOCK_IO *bio;
+
+    if (lba + count > diskinfo->lbacnt)
+        count = diskinfo->lbacnt - lba; /* truncate read */
+
+    len = count * diskinfo->bps;
+    data = lmalloc(count * diskinfo->bps);
+    if (!data)
+        return NULL;
+
+    bio = (EFI_BLOCK_IO *)diskinfo->biop;
+
+    status = uefi_call_wrapper(bio->ReadBlocks, 5, bio, bio->Media->MediaId,
+                               lba, len, data);
+    if (EFI_ERROR(status)) {
+        printf("%s: failed to read blocks from disk %d\n", __func__,
+               diskinfo->disk);
+        free(data);
+        return NULL;
+    }
+
+    return data;
+}
+
+/**
+ * Write disk block(s).
+ *
+ * @v diskinfo			The disk drive to write to
+ * @v lba			The logical block address to begin writing at
+ * @v data			The data to write
+ * @v count			The number of sectors to write
+ * @ret (int)			0 upon success, -1 upon failure
+ *
+ * Uses the disk number and information from diskinfo.
+ * Write sector(s) to a disk drive, starting at lba.
+ */
+int disk_write_sectors(const struct disk_info *const diskinfo, uint64_t lba,
+		       const void *data, uint8_t count)
+{
+    EFI_BLOCK_IO *bio;
+    EFI_STATUS status;
+    unsigned long len;
+
+    bio = (EFI_BLOCK_IO *)diskinfo->biop;
+    if (bio->Media->ReadOnly) {
+        printf("%s: media %d is marked read-only\n", __func__, diskinfo->disk);
+        return -1;
+    }
+
+    if (lba + count > diskinfo->lbacnt)
+        count = diskinfo->lbacnt - lba; /* truncate write */
+
+    len = count * diskinfo->bps;
+
+    status = uefi_call_wrapper(bio->WriteBlocks, 5, bio, bio->Media->MediaId,
+                               lba, len, data);
+    if (EFI_ERROR(status)) {
+        printf("%s: failed to write blocks from disk %d\n", __func__,
+               diskinfo->disk);
+        return -1;
+    }
+
+    status = uefi_call_wrapper(bio->FlushBlocks, 1, bio);
+    if (EFI_ERROR(status)) {
+        printf("%s: failed to flush out blocks from disk %d\n", __func__,
+               diskinfo->disk);
+        return -1;
+    }
+
+    return 0;
+}
+
+/**
+ * Write disk blocks and verify they were written.
+ *
+ * @v diskinfo			The disk drive to write to
+ * @v lba			The logical block address to begin writing at
+ * @v buf			The data to write
+ * @v count			The number of sectors to write
+ * @ret rv			0 upon success, -1 upon failure
+ *
+ * Uses the disk number and information from diskinfo.
+ * Writes sectors to a disk drive starting at lba, then reads them back
+ * to verify they were written correctly.
+ */
+int disk_write_verify_sectors(const struct disk_info *const diskinfo,
+			      uint64_t lba, const void *buf, uint8_t count)
+{
+    int ret;
+    void *rb;
+
+    ret = disk_write_sectors(diskinfo, lba, buf, count);
+    if (ret)
+        return ret;
+    rb = disk_read_sectors(diskinfo, lba, count);
+    if (!rb)
+        return -1;
+    ret = memcmp(buf, rb, count * diskinfo->bps);
+    free(rb);
+    return ret ? -1 : 0;
+}
diff --git a/efi/Makefile b/efi/Makefile
index bbf23f2..0c18d14 100644
--- a/efi/Makefile
+++ b/efi/Makefile
@@ -42,6 +42,7 @@ CORE_OBJS += $(addprefix $(OBJ)/../core/, \
 	fs/pxe/ftp.o fs/pxe/ftp_readdir.o fs/pxe/http.o fs/pxe/http_readdir.o)
 
 LIB_OBJS = $(addprefix $(objdir)/com32/lib/,$(CORELIBOBJS)) \
+	$(addprefix $(objdir)/com32/lib/,$(LIBOTHER_OBJS)) \
 	$(LIBEFI)
 
 CSRC = $(wildcard $(SRC)/*.c)
diff --git a/efi/check-gnu-efi.sh b/efi/check-gnu-efi.sh
index 7d99e9a..67fe67d 100755
--- a/efi/check-gnu-efi.sh
+++ b/efi/check-gnu-efi.sh
@@ -25,6 +25,7 @@ if [ ! \( -f "$objdir/include/efi/$ARCH/efibind.h" -a -f "$objdir/lib/libefi.a"
     # Syslinux disables built-in implicit rules.
     export MAKEFLAGS=
 
+    pushd "$objdir/efi" >/dev/null
     ../../efi/build-gnu-efi.sh $ARCH "$objdir"
     if [ $? -ne 0 ]; then
 	printf "Failed to build gnu-efi. "
@@ -33,6 +34,7 @@ if [ ! \( -f "$objdir/include/efi/$ARCH/efibind.h" -a -f "$objdir/lib/libefi.a"
 
 	exit 1
     fi
+    popd >/dev/null
 else
     printf "skip gnu-efi build/install\n"
 fi
diff --git a/mk/lib.mk b/mk/lib.mk
index ceb95bd..f00dd94 100644
--- a/mk/lib.mk
+++ b/mk/lib.mk
@@ -38,6 +38,31 @@ LIBFLAGS = -DDYNAMIC_CRC_TABLE -DPNG_NO_CONSOLE_IO \
 	   -DPNG_NO_MNG_FEATURES \
 	   -DPNG_NO_READ_tIME -DPNG_NO_WRITE_tIME
 
+ifdef EFI_BUILD
+
+ifeq ($(ARCH),i386)
+	ARCHOPT = -m32 -march=i386
+	EFI_SUBARCH = ia32
+endif
+ifeq ($(ARCH),x86_64)
+	ARCHOPT = -m64 -march=x86-64
+	EFI_SUBARCH = $(ARCH)
+endif
+
+EFI_OBJDIR = $(OBJ)/../..
+EFIINC = $(EFI_OBJDIR)/include/efi
+
+FW_SUBDIR = efi
+FWFLAGS = -I$(EFIINC) -I$(EFIINC)/$(EFI_SUBARCH) -I$(EFIINC)/protocol \
+	-DEFI_FUNCTION_WRAPPER -fPIC -fshort-wchar -ffreestanding \
+	-std=gnu99 -DSYSLINUX_EFI
+else
+
+FW_SUBDIR = bios
+FWFLAGS =
+
+endif # ifdef EFI_BUILD
+
 # We need some features in libpng which apparently aren't available in the
 # fixed-point versions.  It's OK, because we have to have a non-graphical
 # fallback anyway, just use that on old machines...
@@ -52,13 +77,37 @@ OPTFLAGS  = -Os -march=$(MARCH) -falign-functions=0 -falign-jumps=0 \
 	    -falign-labels=0 -ffast-math -fomit-frame-pointer
 WARNFLAGS = $(GCCWARN) -Wpointer-arith -Wwrite-strings -Wstrict-prototypes -Winline
 
-CFLAGS  = $(OPTFLAGS) $(REQFLAGS) $(WARNFLAGS) $(LIBFLAGS)
+CFLAGS  = $(OPTFLAGS) $(REQFLAGS) $(WARNFLAGS) $(LIBFLAGS) $(FWFLAGS)
 
 ifndef EFI_BUILD
 CFLAGS += -mregparm=3 -DREGPARM=3
 endif
 
 VPATH = $(SRC)
+
+LIBSYS_OBJS = \
+	sys/line_input.o				\
+	sys/colortable.o sys/screensize.o				\
+	\
+	sys/stdcon_read.o sys/stdcon_write.o sys/rawcon_read.o		\
+	sys/rawcon_write.o		\
+	sys/null_read.o sys/null_write.o sys/serial_write.o		\
+	\
+	sys/xserial_write.o						\
+	\
+	sys/ansi.o							\
+	\
+	sys/ansicon_write.o sys/ansiserial_write.o			\
+	\
+	sys/x86_init_fpu.o math/pow.o math/strtod.o			\
+	\
+	syslinux/setup_data.o
+
+LIBPCI_OBJS = \
+	pci/cfgtype.o pci/scan.o pci/bios.o \
+	pci/readb.o pci/readw.o pci/readl.o \
+	pci/writeb.o pci/writew.o pci/writel.o
+
 LIBOTHER_OBJS = \
 	atoi.o atol.o atoll.o calloc.o creat.o		\
 	fgets.o fprintf.o fputc.o	\
@@ -86,29 +135,7 @@ LIBOTHER_OBJS = \
 	\
 	suffix_number.o							\
 	\
-	getcwd.o fdopendir.o	\
-	\
-	sys/line_input.o				\
-	sys/colortable.o sys/screensize.o				\
-	\
-	sys/stdcon_read.o sys/stdcon_write.o sys/rawcon_read.o		\
-	sys/rawcon_write.o		\
-	sys/null_read.o sys/null_write.o sys/serial_write.o		\
-	\
-	sys/xserial_write.o						\
-	\
-	sys/ansi.o							\
-	\
-	sys/ansicon_write.o sys/ansiserial_write.o			\
-	\
-	pci/cfgtype.o pci/scan.o pci/bios.o					\
-	pci/readb.o pci/readw.o pci/readl.o			\
-	pci/writeb.o pci/writew.o pci/writel.o	\
-	\
-	sys/x86_init_fpu.o math/pow.o math/strtod.o			\
-	syslinux/disk.o							\
-	\
-	syslinux/setup_data.o
+	getcwd.o fdopendir.o
 
 ## CORE OBJECTS, INCLUDED IN THE ROOT COM32 MODULE
 LIBENTRY_OBJS = \
@@ -175,10 +202,16 @@ LIBZLIB_OBJS = \
 	zlib/inflate.o zlib/infback.o zlib/inftrees.o zlib/inffast.o	\
 	sys/zfile.o sys/zfopen.o
 
+LIBDISK_OBJS = \
+	syslinux/disk/common.o \
+	syslinux/disk/$(FW_SUBDIR)/disk.o
+
 MINLIBOBJS = \
 	$(addprefix $(OBJ)/,syslinux/ipappend.o \
 	syslinux/dsinfo.o \
 	$(LIBOTHER_OBJS) \
+	$(LIBSYS_OBJS) \
+	$(LIBPCI_OBJS) \
 	$(LIBGCC_OBJS) \
 	$(LIBCONSOLE_OBJS) \
 	$(LIBLOAD_OBJS) \
@@ -201,7 +234,28 @@ CORELIBOBJS = \
 	libgcc/__divdi3.o libgcc/__moddi3.o				\
 	syslinux/debug.o						\
 	$(LIBENTRY_OBJS) \
-	$(LIBMODULE_OBJS)
+	$(LIBMODULE_OBJS) \
+	$(LIBDISK_OBJS)
+
+ifdef EFI_BUILD
+
+.PHONY: subdirs
+subdirs:
+	@mkdir -p $(EFI_OBJDIR)/efi
+
+LIBEFI = $(EFI_OBJDIR)/lib/libefi.a
+
+$(LIBEFI): subdirs
+	@echo Building gnu-efi for $(EFI_SUBARCH)
+	$(topdir)/efi/check-gnu-efi.sh $(EFI_SUBARCH) $(EFI_OBJDIR)
+
+# add library objects which support both BIOS and UEFI implementations
+MULTI_FW_SUP_LIB_OBJS = $(LIBDISK_OBJS)
+
+# make parallel build happy
+$(MULTI_FW_SUP_LIB_OBJS): $(LIBEFI)
+
+endif # ifdef EFI_BUILD
 
 LDFLAGS	= -m elf_$(ARCH) --hash-style=gnu -T $(com32)/lib/$(ARCH)/elf.ld
 
-- 
2.4.3



More information about the Syslinux mailing list