• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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  **/
read_mbr(int drive,void * buf)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  **/
dev_read(int drive,void * buf,unsigned int lba,int sectors)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  **/
read_sectors(struct driveinfo * drive_info,void * data,const unsigned int lba,const int sectors)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