Root/
Source at commit 1083 created 12 years 9 months ago. By meklort, add GetDriveInfo | |
---|---|
1 | /*␊ |
2 | * Copyright (c) 1999-2003 Apple Computer, Inc. All rights reserved.␊ |
3 | *␊ |
4 | * @APPLE_LICENSE_HEADER_START@␊ |
5 | * ␊ |
6 | * Portions Copyright (c) 1999-2003 Apple Computer, Inc. All Rights␊ |
7 | * Reserved. This file contains Original Code and/or Modifications of␊ |
8 | * Original Code as defined in and that are subject to the Apple Public␊ |
9 | * Source License Version 2.0 (the "License"). You may not use this file␊ |
10 | * except in compliance with the License. Please obtain a copy of the␊ |
11 | * License at http://www.apple.com/publicsource and read it before using␊ |
12 | * this file.␊ |
13 | * ␊ |
14 | * The Original Code and all software distributed under the License are␊ |
15 | * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER␊ |
16 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,␊ |
17 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,␊ |
18 | * FITNESS FOR A PARTICULAR PURPOSE OR NON- INFRINGEMENT. Please see the␊ |
19 | * License for the specific language governing rights and limitations␊ |
20 | * under the License.␊ |
21 | * ␊ |
22 | * @APPLE_LICENSE_HEADER_END@␊ |
23 | */␊ |
24 | /*␊ |
25 | * Copyright 1993 NeXT Computer, Inc.␊ |
26 | * All rights reserved.␊ |
27 | */␊ |
28 | ␊ |
29 | /* Copyright 2007 David Elliott␊ |
30 | 2007-12-30 dfe␊ |
31 | - Enhanced code to normalize segment/offset to huge pointers so that any␊ |
32 | linear address within the first MB of memory can be passed to BIOS␊ |
33 | functions. This allows some of the __DATA sections to span into the␊ |
34 | next segment and also allows stack variables to be used whereas the␊ |
35 | old code could only operate on static data in the first 64k.␊ |
36 | NOTE: Requires bios.s change to respect DS.␊ |
37 | */␊ |
38 | /* Copyright 2007 VMware Inc.␊ |
39 | 2007-12-29 dfe␊ |
40 | - Added ebiosEjectMedia␊ |
41 | */␊ |
42 | ␊ |
43 | /*␊ |
44 | * Copyright (c) 2011 Evan Lojewski.␊ |
45 | * - Converted to c++␊ |
46 | * - Converted to UInt* style variable types␊ |
47 | */␊ |
48 | ␊ |
49 | #include <BiosDisk.hpp>␊ |
50 | ␊ |
51 | extern "C"␊ |
52 | {␊ |
53 | #include "libsaio.h"␊ |
54 | #include "stdio.h"␊ |
55 | }␊ |
56 | ␊ |
57 | BiosDisk::BiosDisk(const char* name)␊ |
58 | {␊ |
59 | // Initialize␊ |
60 | mValid = false;␊ |
61 | mDiskID = 0;␊ |
62 | mUsesEBIOS = 0;␊ |
63 | mNoEmulation = false;␊ |
64 | mBytesPerSector = 0;␊ |
65 | ␊ |
66 | ␊ |
67 | // The correct format should be:␊ |
68 | // bios:/hdX/␊ |
69 | mBusType = "bios";␊ |
70 | ␊ |
71 | if(strncmp(mBusType, name, 4) != 0) name = NULL;␊ |
72 | ␊ |
73 | mName = name;␊ |
74 | ␊ |
75 | sscanf(name, "bios:/hd%d/", &mDiskID);␊ |
76 | mDiskID += 0x80; // 0x80 = fixed disk␊ |
77 | ␊ |
78 | mDriveInfo = (boot_drive_info_t*)malloc(sizeof(boot_drive_info_t));␊ |
79 | ␊ |
80 | if(BIOSRead(0, 0, 1, 1) == 0 && GetDriveInfo() == 0) ␊ |
81 | {␊ |
82 | mBytesPerSector = mDriveInfo->params.phys_nbps;␊ |
83 | printf("Disk: 0x%X (%d sectors)\n", mDiskID, mBytesPerSector); ␊ |
84 | }␊ |
85 | else␊ |
86 | {␊ |
87 | mValid = 0; // force invalid.␊ |
88 | }␊ |
89 | }␊ |
90 | ␊ |
91 | BiosDisk::~BiosDisk()␊ |
92 | {␊ |
93 | if(mDriveInfo) free(mDriveInfo);␊ |
94 | }␊ |
95 | ␊ |
96 | IOReturn BiosDisk::Read(UInt64 sector, UInt64 size, UInt8* buffer)␊ |
97 | {␊ |
98 | if(!isValid()) return kIOReturnNoDevice;␊ |
99 | return kIOReturnSuccess;␊ |
100 | }␊ |
101 | ␊ |
102 | ␊ |
103 | IOReturn BiosDisk::Write(UInt64 sector, UInt64 size, UInt8* buffer)␊ |
104 | {␊ |
105 | if(!isValid()) return kIOReturnNoDevice;␊ |
106 | return kIOReturnNotWritable;␊ |
107 | }␊ |
108 | ␊ |
109 | ␊ |
110 | UInt8 BiosDisk::BIOSRead(UInt16 cylinder, UInt8 head, UInt8 sector, UInt8 count)␊ |
111 | {␊ |
112 | if(sector == 0) return -1;␊ |
113 | ␊ |
114 | biosBuf_t bb;␊ |
115 | int i;␊ |
116 | ␊ |
117 | bb.intno = 0x13;␊ |
118 | bb.eax.r.h = 0x02;␊ |
119 | ␊ |
120 | for (i=0;;)␊ |
121 | {␊ |
122 | bb.ecx.r.h = cylinder;␊ |
123 | bb.ecx.r.l = ((cylinder & 0x300) >> 2) | (sector & 0x3F);␊ |
124 | bb.edx.r.h = head;␊ |
125 | bb.edx.r.l = mDiskID;␊ |
126 | bb.eax.r.l = count;␊ |
127 | bb.ebx.rr = OFFSET(ptov(BIOS_ADDR));␊ |
128 | bb.es = SEGMENT(ptov(BIOS_ADDR));␊ |
129 | ␊ |
130 | bios(&bb);␊ |
131 | ␊ |
132 | /* In case of a successful call, make sure we set AH (return code) to zero. */␊ |
133 | if (bb.flags.cf == 0) bb.eax.r.h = 0;␊ |
134 | ␊ |
135 | /* Now we can really check for the return code (AH) value. */␊ |
136 | if ((bb.eax.r.h == 0x00) || (i++ >= 5)) break;␊ |
137 | ␊ |
138 | /* reset disk subsystem and try again */␊ |
139 | bb.eax.r.h = 0x00;␊ |
140 | bios(&bb);␊ |
141 | }␊ |
142 | return bb.eax.r.h;␊ |
143 | }␊ |
144 | ␊ |
145 | UInt8 BiosDisk::EBIOSRead(UInt64 sector, UInt8 count)␊ |
146 | {␊ |
147 | biosBuf_t bb;␊ |
148 | ␊ |
149 | UInt8 i;␊ |
150 | struct {␊ |
151 | UInt8 size;␊ |
152 | UInt8 reserved;␊ |
153 | UInt8 numblocks;␊ |
154 | UInt8 reserved2;␊ |
155 | UInt16 bufferOffset;␊ |
156 | UInt16 bufferSegment;␊ |
157 | UInt64 startblock;␊ |
158 | } addrpacket __attribute__((aligned(16))) = {0};␊ |
159 | addrpacket.size = sizeof(addrpacket);␊ |
160 | ␊ |
161 | for (i=0;;) {␊ |
162 | bb.intno = 0x13;␊ |
163 | bb.eax.r.h = 0x42;␊ |
164 | bb.edx.r.l = mDiskID;␊ |
165 | bb.esi.rr = NORMALIZED_OFFSET((unsigned)&addrpacket);␊ |
166 | bb.ds = NORMALIZED_SEGMENT((unsigned)&addrpacket);␊ |
167 | addrpacket.reserved = addrpacket.reserved2 = 0;␊ |
168 | addrpacket.numblocks = count;␊ |
169 | addrpacket.bufferOffset = OFFSET(ptov(BIOS_ADDR));␊ |
170 | addrpacket.bufferSegment = SEGMENT(ptov(BIOS_ADDR));␊ |
171 | addrpacket.startblock = sector;␊ |
172 | bios(&bb);␊ |
173 | ␊ |
174 | /* In case of a successful call, make sure we set AH (return code) to zero. */␊ |
175 | if (bb.flags.cf == 0)␊ |
176 | bb.eax.r.h = 0;␊ |
177 | ␊ |
178 | /* Now we can really check for the return code (AH) value. */␊ |
179 | if ((bb.eax.r.h == 0x00) || (i++ >= 5))␊ |
180 | break;␊ |
181 | ␊ |
182 | /* reset disk subsystem and try again */␊ |
183 | bb.eax.r.h = 0x00;␊ |
184 | bios(&bb);␊ |
185 | }␊ |
186 | return bb.eax.r.h;␊ |
187 | }␊ |
188 | ␊ |
189 | UInt8 BiosDisk::EBIOSWrite(UInt64 sector, UInt8 count)␊ |
190 | {␊ |
191 | biosBuf_t bb;␊ |
192 | ␊ |
193 | UInt8 i;␊ |
194 | static struct {␊ |
195 | UInt8 size;␊ |
196 | UInt8 reserved;␊ |
197 | UInt8 numblocks;␊ |
198 | UInt8 reserved2;␊ |
199 | UInt16 bufferOffset;␊ |
200 | UInt16 bufferSegment;␊ |
201 | UInt64 startblock;␊ |
202 | } addrpacket __attribute__((aligned(16))) = {0};␊ |
203 | addrpacket.size = sizeof(addrpacket);␊ |
204 | ␊ |
205 | for (i=0;;) {␊ |
206 | bb.intno = 0x13;␊ |
207 | bb.eax.r.l = 0; /* Don't verify */␊ |
208 | bb.eax.r.h = 0x43;␊ |
209 | bb.edx.r.l = mDiskID;␊ |
210 | bb.esi.rr = NORMALIZED_OFFSET((unsigned)&addrpacket);␊ |
211 | bb.ds = NORMALIZED_SEGMENT((unsigned)&addrpacket);␊ |
212 | addrpacket.reserved = addrpacket.reserved2 = 0;␊ |
213 | addrpacket.numblocks = count;␊ |
214 | addrpacket.bufferOffset = OFFSET(ptov(BIOS_ADDR));␊ |
215 | addrpacket.bufferSegment = SEGMENT(ptov(BIOS_ADDR));␊ |
216 | addrpacket.startblock = sector;␊ |
217 | bios(&bb);␊ |
218 | ␊ |
219 | /* In case of a successful call, make sure we set AH (return code) to zero. */␊ |
220 | if (bb.flags.cf == 0)␊ |
221 | bb.eax.r.h = 0;␊ |
222 | ␊ |
223 | /* Now we can really check for the return code (AH) value. */␊ |
224 | if ((bb.eax.r.h == 0x00) || (i++ >= 5))␊ |
225 | break;␊ |
226 | ␊ |
227 | /* reset disk subsystem and try again */␊ |
228 | bb.eax.r.h = 0x00;␊ |
229 | bios(&bb);␊ |
230 | }␊ |
231 | return bb.eax.r.h;␊ |
232 | }␊ |
233 | ␊ |
234 | UInt8 BiosDisk::GetDriveInfo()␊ |
235 | {␊ |
236 | // we use the BIOS_ADDR (disk buffer) to ensure that the buffer␊ |
237 | // is in low mem␊ |
238 | boot_drive_info_t* actualInfo = mDriveInfo;␊ |
239 | mDriveInfo = (boot_drive_info_t*)BIOS_ADDR;␊ |
240 | biosBuf_t bb;␊ |
241 | ␉int ret = 0;␊ |
242 | ␉␊ |
243 | #if UNUSED␊ |
244 | ␉if (maxhd == 0) {␊ |
245 | ␉␉bb.intno = 0x13;␊ |
246 | ␉␉bb.eax.r.h = 0x08;␊ |
247 | ␉␉bb.edx.r.l = 0x80;␊ |
248 | ␉␉bios(&bb);␊ |
249 | ␉␉if (bb.flags.cf == 0)␊ |
250 | ␉␉␉maxhd = 0x7f + bb.edx.r.l;␊ |
251 | ␉};␊ |
252 | ␉␊ |
253 | #endif␊ |
254 | ␉␊ |
255 | ␉/* Check for El Torito no-emulation mode. */␊ |
256 | ␉//dp->no_emulation = is_no_emulation(drive);␊ |
257 | ␊ |
258 | ␉/* Check drive for EBIOS support. */␊ |
259 | ␉bb.intno = 0x13;␊ |
260 | ␉bb.eax.r.h = 0x41;␊ |
261 | ␉bb.edx.r.l = mDiskID;␊ |
262 | ␉bb.ebx.rr = 0x55aa;␊ |
263 | ␉bios(&bb);␊ |
264 | ␉␊ |
265 | ␉if ((bb.ebx.rr == 0xaa55) && (bb.flags.cf == 0)) {␊ |
266 | ␉␉/* Get flags for supported operations. */␊ |
267 | ␉␉mUsesEBIOS = bb.ecx.r.l;␊ |
268 | ␉}␊ |
269 | ␉␊ |
270 | ␉if (mUsesEBIOS & (EBIOS_ENHANCED_DRIVE_INFO | EBIOS_LOCKING_ACCESS | EBIOS_FIXED_DISK_ACCESS)) {␊ |
271 | ␉␉/* Get EBIOS drive info. */␊ |
272 | ␉␉␊ |
273 | ␉␉mDriveInfo->params.buf_size = sizeof(mDriveInfo->params);␊ |
274 | ␉␉bb.intno = 0x13;␊ |
275 | ␉␉bb.eax.r.h = 0x48;␊ |
276 | ␉␉bb.edx.r.l = mDiskID;␊ |
277 | ␉␉bb.esi.rr = NORMALIZED_OFFSET((unsigned)&mDriveInfo->params);␊ |
278 | ␉␉bb.ds␉ = NORMALIZED_SEGMENT((unsigned)&mDriveInfo->params);␊ |
279 | ␉␉bios(&bb);␊ |
280 | ␊ |
281 | ␉␉if (bb.flags.cf != 0 /* || params.phys_sectors < 2097152 */) {␊ |
282 | ␉␉␉mUsesEBIOS = 0;␊ |
283 | ␉␉␉mDriveInfo->params.buf_size = 1;␊ |
284 | ␉␉}␊ |
285 | ␉␉else␊ |
286 | ␉␉{␊ |
287 | ␉␉␉if (mDiskID >= BASE_HD_DRIVE &&␊ |
288 | ␉␉␉␉(mUsesEBIOS & EBIOS_ENHANCED_DRIVE_INFO) &&␊ |
289 | ␉␉␉␉mDriveInfo->params.buf_size >= 30 &&␊ |
290 | ␉␉␉␉!(mDriveInfo->params.dpte_offset == 0xFFFF && mDriveInfo->params.dpte_segment == 0xFFFF)) {␊ |
291 | void *ptr = (void *)(mDriveInfo->params.dpte_offset + ((unsigned int)mDriveInfo->params.dpte_segment << 4));␊ |
292 | bcopy(ptr, &mDriveInfo->dpte, sizeof(mDriveInfo->dpte));␊ |
293 | ␉␉␉}␊ |
294 | ␉␉}␊ |
295 | ␉}␊ |
296 | ␊ |
297 | /*␊ |
298 | * zef: This code will fail on recent JMicron and Intel option ROMs␊ |
299 | */ ␊ |
300 | //␉if (mDriveInfo->params.phys_heads == 0 || mDriveInfo->params.phys_spt == 0) {␊ |
301 | //␉␉/* Either it's not EBIOS, or EBIOS didn't tell us. */␊ |
302 | //␉␉bb.intno = 0x13;␊ |
303 | //␉␉bb.eax.r.h = 0x08;␊ |
304 | //␉␉bb.edx.r.l = drive;␊ |
305 | //␉␉bios(&bb);␊ |
306 | //␉␉if (bb.flags.cf == 0 && bb.eax.r.h == 0) {␊ |
307 | //␉␉␉unsigned long cyl;␊ |
308 | //␉␉␉unsigned long sec;␊ |
309 | //␉␉␉unsigned long hds;␊ |
310 | //␉␉␊ |
311 | //␉␉␉hds = bb.edx.r.h;␊ |
312 | //␉␉␉sec = bb.ecx.r.l & 0x3F;␊ |
313 | //␉␉␉if ((dp->uses_ebios & EBIOS_ENHANCED_DRIVE_INFO) && (sec != 0)) {␊ |
314 | //␉␉␉␉cyl = (mDriveInfo->params.phys_sectors / ((hds + 1) * sec)) - 1;␊ |
315 | //␉␉␉} else {␊ |
316 | //␉␉␉␉cyl = bb.ecx.r.h | ((bb.ecx.r.l & 0xC0) << 2);␊ |
317 | //␉␉␉}␊ |
318 | //␉␉␉mDriveInfo->params.phys_heads = hds; ␊ |
319 | //␉␉␉mDriveInfo->params.phys_spt = sec;␊ |
320 | //␉␉␉mDriveInfo->params.phys_cyls = cyl;␊ |
321 | //␉␉} else {␊ |
322 | //␉␉␉ret = -1;␊ |
323 | //␉␉}␊ |
324 | //␉}␊ |
325 | /*␊ |
326 | if (dp->no_emulation) {␊ |
327 | // Some BIOSes give us erroneous EBIOS support information.␊ |
328 | // Assume that if you're on a CD, then you can use␊ |
329 | // EBIOS disk calls.␊ |
330 | //␊ |
331 | dp->uses_ebios |= EBIOS_FIXED_DISK_ACCESS;␊ |
332 | }*/␊ |
333 | ␊ |
334 | ␉if (ret == 0) {␊ |
335 | ␉␉mValid = 1;␊ |
336 | ␉}␊ |
337 | ␊ |
338 | bcopy(mDriveInfo, actualInfo, sizeof(boot_drive_info_t));␊ |
339 | mDriveInfo = actualInfo;␊ |
340 | ␊ |
341 | ␉return ret;␊ |
342 | }␊ |
343 | ␊ |
344 |