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/common.h>
     20 #include <disk/errno_disk.h>
     21 #include <disk/read.h>
     22 #include <disk/util.h>
     23 #include <disk/write.h>
     24 
     25 /**
     26  * write_sectors - write several sectors from disk
     27  * @drive_info:		driveinfo struct describing the disk
     28  * @lba:		Position to write
     29  * @data:		Buffer to write
     30  * @size:		Size of the buffer (number of sectors)
     31  *
     32  * Return the number of sectors write on success or -1 on failure.
     33  * errno_disk contains the error number.
     34  **/
     35 int write_sectors(const struct driveinfo *drive_info, const unsigned int lba,
     36 		  const void *data, const int size)
     37 {
     38     com32sys_t inreg, outreg;
     39     struct ebios_dapa *dapa;
     40     void *buf;
     41     int rv = -1;
     42 
     43     buf = lmalloc(size);
     44     if (!buf)
     45 	return -1;
     46 
     47     dapa = lmalloc(sizeof(*dapa));
     48     if (!dapa)
     49 	goto out;
     50 
     51     memcpy(buf, data, size);
     52     memset(&inreg, 0, sizeof inreg);
     53 
     54     if (drive_info->ebios) {
     55 	dapa->len = sizeof(*dapa);
     56 	dapa->count = size;
     57 	dapa->off = OFFS(buf);
     58 	dapa->seg = SEG(buf);
     59 	dapa->lba = lba;
     60 
     61 	inreg.esi.w[0] = OFFS(dapa);
     62 	inreg.ds = SEG(dapa);
     63 	inreg.edx.b[0] = drive_info->disk;
     64 	inreg.eax.w[0] = 0x4300;	/* Extended write */
     65     } else {
     66 	unsigned int c, h, s;
     67 
     68 	if (!drive_info->cbios) {	// XXX errno
     69 	    /* We failed to get the geometry */
     70 	    if (lba)
     71 		goto out;	/* Can only write MBR */
     72 
     73 	    s = 1;
     74 	    h = 0;
     75 	    c = 0;
     76 	} else
     77 	    lba_to_chs(drive_info, lba, &s, &h, &c);
     78 
     79 	// XXX errno
     80 	if (s > 63 || h > 256 || c > 1023)
     81 	    goto out;
     82 
     83 	inreg.eax.w[0] = 0x0301;	/* Write one sector */
     84 	inreg.ecx.b[1] = c & 0xff;
     85 	inreg.ecx.b[0] = s + (c >> 6);
     86 	inreg.edx.b[1] = h;
     87 	inreg.edx.b[0] = drive_info->disk;
     88 	inreg.ebx.w[0] = OFFS(buf);
     89 	inreg.es = SEG(buf);
     90     }
     91 
     92     /* Perform the write */
     93     if (int13_retry(&inreg, &outreg)) {
     94 	errno_disk = outreg.eax.b[1];	/* Give up */
     95     } else
     96 	rv = size;
     97 out:
     98     lfree(dapa);
     99     lfree(buf);
    100     return rv;
    101 }
    102 
    103 /**
    104  * write_verify_sectors - write several sectors from disk
    105  * @drive_info:		driveinfo struct describing the disk
    106  * @lba:		Position to write
    107  * @data:		Buffer to write
    108  **/
    109 int write_verify_sector(struct driveinfo *drive_info,
    110 			const unsigned int lba, const void *data)
    111 {
    112     return write_verify_sectors(drive_info, lba, data, SECTOR);
    113 }
    114 
    115 /**
    116  * write_verify_sectors - write several sectors from disk
    117  * @drive_info:		driveinfo struct describing the disk
    118  * @lba:		Position to write
    119  * @data:		Buffer to write
    120  * @size:		Size of the buffer (number of sectors)
    121  **/
    122 int write_verify_sectors(struct driveinfo *drive_info,
    123 			 const unsigned int lba,
    124 			 const void *data, const int size)
    125 {
    126     char *rb = malloc(SECTOR * size * sizeof(char));
    127     int status;
    128 
    129     if (write_sectors(drive_info, lba, data, size) == -1)
    130 	return -1;		/* Write failure */
    131 
    132     if (read_sectors(drive_info, rb, lba, size) == -1)
    133 	return -1;		/* Readback failure */
    134 
    135     status = memcmp(data, rb, SECTOR * size);
    136     free(rb);
    137     return status ? -1 : 0;
    138 }
    139