source: bootcd/isolinux/syslinux-6.03/com32/gpllib/disk/geom.c @ 26ffad7

Last change on this file since 26ffad7 was e16e8f2, checked in by Edwin Eefting <edwin@datux.nl>, 3 years ago

bootstuff

  • Property mode set to 100644
File size: 9.1 KB
Line 
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 <string.h>
17#include <stdio.h>
18#include <disk/geom.h>
19
20#include <stdio.h>
21
22/**
23 * lba_to_chs - split given lba into cylinders/heads/sectors
24 **/
25void lba_to_chs(const struct driveinfo *drive_info, const int lba,
26                unsigned int *cylinder, unsigned int *head,
27                unsigned int *sector)
28{
29    unsigned int track;
30
31    /* Use EDD, if valid */
32    if (drive_info->edd_params.sectors_per_track > 0 &&
33        drive_info->edd_params.heads > 0) {
34        *cylinder = (lba % drive_info->edd_params.sectors_per_track) + 1;
35        track = lba / drive_info->edd_params.sectors_per_track;
36        *head = track % drive_info->edd_params.heads;
37        *sector = track / drive_info->edd_params.heads;
38    } else if (drive_info->cbios) {
39        *cylinder = (lba % drive_info->legacy_sectors_per_track) + 1;
40        track = lba / drive_info->legacy_sectors_per_track;
41        *head = track % (drive_info->legacy_max_head + 1);
42        *sector = track / (drive_info->legacy_max_head + 1);
43    }
44}
45
46/**
47 * detect_extensions - detect if we can use extensions
48 *
49 * INT 13 - IBM/MS INT 13 Extensions - INSTALLATION CHECK
50 *    AH = 41h
51 *    BX = 55AAh
52 *    DL = drive (80h-FFh)
53 *
54 * Return: CF set on error (extensions not supported)
55 *    AH = 01h (invalid function)
56 *    CF clear if successful
57 *    BX = AA55h if installed
58 *    AH = major version of extensions
59 *        01h = 1.x
60 *        20h = 2.0 / EDD-1.0
61 *        21h = 2.1 / EDD-1.1
62 *        30h = EDD-3.0
63 *    AL = internal use
64 *    CX = API subset support bitmap (see #00271)
65 *    DH = extension version (v2.0+ ??? -- not present in 1.x)
66 *
67 * Note: the Phoenix Enhanced Disk Drive Specification v1.0 uses version 2.0 of
68 *       the INT 13 Extensions API
69 *
70 * Bitfields for IBM/MS INT 13 Extensions API support bitmap:
71 * Bit(s)    Description    (Table 00271)
72 *     0 extended disk access functions (AH=42h-44h,47h,48h) supported
73 *     1 removable drive controller functions (AH=45h,46h,48h,49h,INT 15/AH=52h)
74 *       supported
75 *     2 enhanced disk drive (EDD) functions (AH=48h,AH=4Eh) supported
76 *       extended drive parameter table is valid (see #00273,#00278)
77 *     3-15    reserved (0)
78 **/
79static int detect_extensions(struct driveinfo *drive_info)
80{
81    com32sys_t getebios, ebios;
82
83    memset(&getebios, 0, sizeof getebios);
84    memset(&ebios, 0, sizeof ebios);
85
86    getebios.eflags.b[0] = 0x3; /* CF set */
87    getebios.ebx.w[0] = 0x55aa;
88    getebios.edx.b[0] = drive_info->disk;
89    getebios.eax.b[1] = 0x41;
90
91    __intcall(0x13, &getebios, &ebios);
92
93    if (!(ebios.eflags.l & EFLAGS_CF) && ebios.ebx.w[0] == 0xaa55) {
94        drive_info->ebios = 1;
95        drive_info->edd_version = ebios.eax.b[1];
96        drive_info->edd_functionality_subset = ebios.ecx.w[0];
97        return 0;
98    } else
99        return -1;              /* Drive does not exist? */
100}
101
102/**
103 * get_drive_parameters_with_extensions - retrieve disk parameters via AH=48h
104 *
105 * INT 13 - IBM/MS INT 13 Extensions - GET DRIVE PARAMETERS
106 *     AH = 48h
107 *     DL = drive (80h-FFh)
108 *     DS:SI -> buffer for drive parameters
109 * Return: CF clear if successful
110 *     AH = 00h
111 *     DS:SI buffer filled
112 *     CF set on error
113 *     AH = error code (see #00234)
114 * BUG: several different Compaq BIOSes incorrectly report high-numbered
115 *     drives (such as 90h, B0h, D0h, and F0h) as present, giving them the
116 *     same geometry as drive 80h; as a workaround, scan through disk
117 *     numbers, stopping as soon as the number of valid drives encountered
118 *     equals the value in 0040h:0075h
119 **/
120static int get_drive_parameters_with_extensions(struct driveinfo *drive_info)
121{
122    com32sys_t inreg, outreg;
123    struct edd_device_parameters *dp;
124
125    memset(&inreg, 0, sizeof inreg);
126
127    /*
128     * The caller shall set this value to the maximum Result Buffer
129     * length, in bytes. If the length of this buffer is less than 30
130     * bytes, this function shall not return the pointer to Drive Parameter
131     * Table (DPT) extension. If the buffer length is 30 or greater on
132     * entry, it shall be set to 30 on exit. If the buffer length is
133     * between 26 and 29, it shall be set to 26 on exit.
134     * If the buffer length is less than 26 on entry an error shall be
135     * returned.
136     */
137    dp = lmalloc(sizeof *dp);
138    if (!dp)
139        return -1;
140
141    dp->len = sizeof(struct edd_device_parameters);
142
143    inreg.esi.w[0] = OFFS(dp);
144    inreg.ds = SEG(dp);
145    inreg.edx.b[0] = drive_info->disk;
146    inreg.eax.b[1] = 0x48;
147
148    __intcall(0x13, &inreg, &outreg);
149
150    /* CF set on error */
151    if (outreg.eflags.l & EFLAGS_CF) {
152        lfree(dp);
153        return outreg.eax.b[1];
154    }
155
156    memcpy(&drive_info->edd_params, dp, sizeof drive_info->edd_params);
157    lfree(dp);
158
159    return 0;
160}
161
162/**
163 * get_drive_parameters_without_extensions - retrieve drive parameters via AH=08h
164 *
165 * INT 13 - DISK - GET DRIVE PARAMETERS (PC,XT286,CONV,PS,ESDI,SCSI)
166 *     AH = 08h
167 *     DL = drive (bit 7 set for hard disk)
168 *
169 * Return: CF set on error
170 *     AH = status (07h) (see #00234)
171 *     CF clear if successful
172 *     AH = 00h
173 *     AL = 00h on at least some BIOSes
174 *     BL = drive type (AT/PS2 floppies only) (see #00242)
175 *     CH = low eight bits of maximum cylinder number
176 *     CL = maximum sector number (bits 5-0)
177 *          high two bits of maximum cylinder number (bits 7-6)
178 *     DH = maximum head number
179 *     DL = number of drives
180 *     ES:DI -> drive parameter table (floppies only)
181 *
182 * Notes:
183 *   - may return successful even though specified drive is greater than the
184 *     number of attached drives of that type (floppy/hard); check DL to
185 *     ensure validity
186 *   - for systems predating the IBM AT, this call is only valid for hard
187 *     disks, as it is implemented by the hard disk BIOS rather than the
188 *     ROM BIOS
189 *   - Toshiba laptops with HardRAM return DL=02h when called with DL=80h,
190 *     but fail on DL=81h. The BIOS data at 40h:75h correctly reports 01h.
191 *     may indicate only two drives present even if more are attached; to
192 *     ensure a correct count, one can use AH=15h to scan through possible
193 *     drives
194 *   - for BIOSes which reserve the last cylinder for testing purposes, the
195 *     cylinder count is automatically decremented
196 *     on PS/1s with IBM ROM DOS 4, nonexistent drives return CF clear,
197 *     BX=CX=0000h, and ES:DI = 0000h:0000h
198 *   - the PC-Tools PCFORMAT program requires that AL=00h before it will
199 *     proceed with the formatting
200 *
201 * BUG: several different Compaq BIOSes incorrectly report high-numbered
202 *      drives (such as 90h, B0h, D0h, and F0h) as present, giving them the
203 *      same geometry as drive 80h; as a workaround, scan through disk
204 *      numbers, stopping as soon as the number of valid drives encountered
205 *      equals the value in 0040h:0075h
206 *
207 * SeeAlso: AH=06h"Adaptec",AH=13h"SyQuest",AH=48h,AH=15h,INT 1E
208 * SeeAlso: INT 41"HARD DISK 0"
209 **/
210static int get_drive_parameters_without_extensions(struct driveinfo *drive_info)
211{
212    com32sys_t getparm, parm;
213
214    memset(&getparm, 0, sizeof getparm);
215    memset(&parm, 0, sizeof parm);
216
217    /* Ralf Brown recommends setting ES:DI to 0:0 */
218    getparm.esi.w[0] = 0;
219    getparm.ds = 0;
220    getparm.edx.b[0] = drive_info->disk;
221    getparm.eax.b[1] = 0x08;
222
223    __intcall(0x13, &getparm, &parm);
224
225    /* CF set on error */
226    if (parm.eflags.l & EFLAGS_CF)
227        return parm.eax.b[1];
228
229    /* DL contains the maximum drive number (it starts at 0) */
230    drive_info->legacy_max_drive = parm.edx.b[0];
231
232    // XXX broken
233    /* Drive specified greater than the bumber of attached drives */
234    //if (drive_info->disk > drive_info->drives)
235    //      return -1;
236
237    drive_info->legacy_type = parm.ebx.b[0];
238
239    /* DH contains the maximum head number (it starts at 0) */
240    drive_info->legacy_max_head = parm.edx.b[1];
241
242    /* Maximum sector number (bits 5-0) per track */
243    drive_info->legacy_sectors_per_track = parm.ecx.b[0] & 0x3f;
244
245    /*
246     * Maximum cylinder number:
247     *     CH = low eight bits of maximum cylinder number
248     *     CL = high two bits of maximum cylinder number (bits 7-6)
249     */
250    drive_info->legacy_max_cylinder = parm.ecx.b[1] +
251        ((parm.ecx.b[0] & 0xc0) << 2);
252
253    if (drive_info->legacy_sectors_per_track > 0)
254        drive_info->cbios = 1;  /* Valid geometry */
255
256    return 0;
257}
258
259/**
260 * get_drive_parameters - retrieve drive parameters
261 * @drive_info:         driveinfo structure to fill
262 **/
263int get_drive_parameters(struct driveinfo *drive_info)
264{
265    int return_code;
266
267    if (detect_extensions(drive_info))
268        return -1;
269
270    return_code = get_drive_parameters_without_extensions(drive_info);
271
272    /* If geometry isn't valid, no need to try to get more info about the drive */
273    /* Looks like in can confuse some optical drives */
274    if (drive_info->ebios && drive_info->cbios)
275        get_drive_parameters_with_extensions(drive_info);
276
277    return return_code;
278}
Note: See TracBrowser for help on using the repository browser.