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