Home | History | Annotate | Download | only in disk
      1 /* ----------------------------------------------------------------------- *
      2  *
      3  *   Copyright 2009 Pierre-Alexandre Meyer
      4  *
      5  *   Some parts borrowed from chain.c32:
      6  *
      7  *   Copyright 2003-2009 H. Peter Anvin - All Rights Reserved
      8  *   Copyright 2009 Intel Corporation; author: H. Peter Anvin
      9  *
     10  *   This file is part of Syslinux, and is made available under
     11  *   the terms of the GNU General Public License version 2.
     12  *
     13  * ----------------------------------------------------------------------- */
     14 
     15 #include <com32.h>
     16 #include <stdlib.h>
     17 #include <string.h>
     18 
     19 #include <disk/errno_disk.h>
     20 #include <disk/geom.h>
     21 #include <disk/read.h>
     22 #include <disk/util.h>
     23 #include <disk/common.h>
     24 
     25 /*
     26  * TODO: implement file descriptors to cache metadata (geometry, ...)
     27  */
     28 
     29 /**
     30  * read_mbr - return a pointer to a malloced buffer containing the mbr
     31  * @drive:	Drive number
     32  * @buf:	Pre-allocated buffer for output
     33  *
     34  * Return the number of sectors read on success or -1 on failure.
     35  * errno_disk contains the error number.
     36  **/
     37 int read_mbr(int drive, void *buf)
     38 {
     39     struct driveinfo drive_info;
     40     drive_info.disk = drive;
     41 
     42     /* MBR: lba = 0, 1 sector */
     43     return read_sectors(&drive_info, buf, 0, 1);
     44 }
     45 
     46 /**
     47  * dev_read - read from a drive
     48  * @drive:	Drive number
     49  * @buf:	Pre-allocated buffer for output
     50  * @lba:	Position to start reading from
     51  * @sectors:	Number of sectors to read
     52  *
     53  * High-level routine to read from a hard drive.
     54  * Return the number of sectors read on success or -1 on failure.
     55  * errno_disk contains the error number.
     56  **/
     57 int dev_read(int drive, void *buf, unsigned int lba, int sectors)
     58 {
     59     struct driveinfo drive_info;
     60     drive_info.disk = drive;
     61 
     62     return read_sectors(&drive_info, buf, lba, sectors);
     63 }
     64 
     65 /**
     66  * read_sectors - read several sectors from disk
     67  * @drive_info:		driveinfo struct describing the disk
     68  * @data:		Pre-allocated buffer for output
     69  * @lba:		Position to read
     70  * @sectors:		Number of sectors to read
     71  *
     72  * Return the number of sectors read on success or -1 on failure.
     73  * errno_disk contains the error number.
     74  **/
     75 int read_sectors(struct driveinfo *drive_info, void *data,
     76 		 const unsigned int lba, const int sectors)
     77 {
     78     com32sys_t inreg, outreg;
     79     struct ebios_dapa *dapa;
     80     void *buf;
     81     char *bufp = data;
     82     int rv = -1;
     83 
     84     if (get_drive_parameters(drive_info) == -1)
     85 	return -1;
     86 
     87     buf = lmalloc(sectors * SECTOR);
     88     if (!buf)
     89 	return -1;
     90 
     91     dapa = lmalloc(sizeof(*dapa));
     92     if (!dapa)
     93 	goto fail;
     94 
     95     memset(&inreg, 0, sizeof inreg);
     96 
     97     if (drive_info->ebios) {
     98 	dapa->len = sizeof(*dapa);
     99 	dapa->count = sectors;
    100 	dapa->off = OFFS(buf);
    101 	dapa->seg = SEG(buf);
    102 	dapa->lba = lba;
    103 
    104 	inreg.esi.w[0] = OFFS(dapa);
    105 	inreg.ds = SEG(dapa);
    106 	inreg.edx.b[0] = drive_info->disk;
    107 	inreg.eax.b[1] = 0x42;	/* Extended read */
    108     } else {
    109 	unsigned int c, h, s;
    110 
    111 	if (!drive_info->cbios) {	// XXX errno
    112 	    /* We failed to get the geometry */
    113 	    if (lba)
    114 		goto fail;	/* Can only read MBR */
    115 
    116 	    s = 1;
    117 	    h = 0;
    118 	    c = 0;
    119 	} else
    120 	    lba_to_chs(drive_info, lba, &s, &h, &c);
    121 
    122 	// XXX errno
    123 	if (s > 63 || h > 256 || c > 1023)
    124 	    goto fail;
    125 
    126 	inreg.eax.w[0] = 0x0201;	/* Read one sector */
    127 	inreg.ecx.b[1] = c & 0xff;
    128 	inreg.ecx.b[0] = s + (c >> 6);
    129 	inreg.edx.b[1] = h;
    130 	inreg.edx.b[0] = drive_info->disk;
    131 	inreg.ebx.w[0] = OFFS(buf);
    132 	inreg.es = SEG(buf);
    133     }
    134 
    135     /* Perform the read */
    136     if (int13_retry(&inreg, &outreg)) {
    137 	errno_disk = outreg.eax.b[1];
    138 	goto fail;		/* Give up */
    139     }
    140 
    141     memcpy(bufp, buf, sectors * SECTOR);
    142     rv = sectors;
    143 
    144 fail:
    145     lfree(dapa);
    146     lfree(buf);
    147     return rv;
    148 }
    149