Root/
Source at commit 1297 created 12 years 8 months ago. By meklort, Removed libsaioh from all modules. Removed i386 includes from modules. | |
---|---|
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 | #include <stdio.h>␊ |
49 | #include <BiosDisk.hpp>␊ |
50 | ␊ |
51 | BiosDisk::BiosDisk(const char* name)␊ |
52 | {␊ |
53 | // Initialize␊ |
54 | mValid = false;␊ |
55 | mDiskID = 0;␊ |
56 | mUsesEBIOS = 0;␊ |
57 | mNoEmulation = false;␊ |
58 | mBytesPerSector = 0;␊ |
59 | ␊ |
60 | ␊ |
61 | // The correct format should be:␊ |
62 | // bios:/hdX/␊ |
63 | mBusType = "bios";␊ |
64 | ␊ |
65 | if(strncmp(mBusType, name, 4) != 0) name = NULL;␊ |
66 | ␊ |
67 | mName = name;␊ |
68 | ␊ |
69 | sscanf(name, "bios:/hd%d/", &mDiskID);␊ |
70 | mDiskID += 0x80; // 0x80 = fixed disk␊ |
71 | ␊ |
72 | mDriveInfo = (boot_drive_info_t*)malloc(sizeof(boot_drive_info_t));␊ |
73 | ␊ |
74 | if(BIOSRead(0, 0, 1, 1) == 0 && GetDriveInfo() == 0) ␊ |
75 | {␊ |
76 | mBytesPerSector = mDriveInfo->params.phys_nbps;␊ |
77 | printf("Disk: 0x%X (%d sectors)\n", mDiskID, mBytesPerSector); ␊ |
78 | }␊ |
79 | else␊ |
80 | {␊ |
81 | mValid = 0; // force invalid.␊ |
82 | }␊ |
83 | }␊ |
84 | ␊ |
85 | BiosDisk::~BiosDisk()␊ |
86 | {␊ |
87 | if(mDriveInfo) free(mDriveInfo);␊ |
88 | }␊ |
89 | ␊ |
90 | IOReturn BiosDisk::Read(UInt64 sector, UInt64 size, UInt8* buffer)␊ |
91 | {␊ |
92 | if(!isValid()) return kIOReturnNoDevice;␊ |
93 | ␊ |
94 | // Assume EBIOS capable for now...␊ |
95 | if(EBIOSRead(sector, size) == kIOReturnSuccess)␊ |
96 | {␊ |
97 | bcopy((void*)BIOS_ADDR, buffer, size * mBytesPerSector);␊ |
98 | return kIOReturnSuccess;␊ |
99 | }␊ |
100 | else return kIOReturnIOError;␊ |
101 | }␊ |
102 | ␊ |
103 | ␊ |
104 | IOReturn BiosDisk::Write(UInt64 sector, UInt64 size, UInt8* buffer)␊ |
105 | {␊ |
106 | ␊ |
107 | if(!isValid()) return kIOReturnNoDevice;␊ |
108 | ␊ |
109 | bcopy(buffer, (void*)BIOS_ADDR, size * mBytesPerSector);␊ |
110 | ␊ |
111 | if(EBIOSWrite(sector, size) == 0)␊ |
112 | {␊ |
113 | return kIOReturnSuccess;␊ |
114 | }␊ |
115 | else return kIOReturnIOError;␊ |
116 | }␊ |
117 | ␊ |
118 | ␊ |
119 | UInt8 BiosDisk::BIOSRead(UInt16 cylinder, UInt8 head, UInt8 sector, UInt8 count)␊ |
120 | {␊ |
121 | sector++; // starts at 1␊ |
122 | ␊ |
123 | biosBuf_t bb;␊ |
124 | int i;␊ |
125 | ␊ |
126 | bb.intno = 0x13;␊ |
127 | bb.eax.r.h = 0x02;␊ |
128 | ␊ |
129 | for (i=0;;)␊ |
130 | {␊ |
131 | bb.ecx.r.h = cylinder;␊ |
132 | bb.ecx.r.l = ((cylinder & 0x300) >> 2) | (sector & 0x3F);␊ |
133 | bb.edx.r.h = head;␊ |
134 | bb.edx.r.l = mDiskID;␊ |
135 | bb.eax.r.l = count;␊ |
136 | bb.ebx.rr = OFFSET(ptov(BIOS_ADDR));␊ |
137 | bb.es = SEGMENT(ptov(BIOS_ADDR));␊ |
138 | ␊ |
139 | bios(&bb);␊ |
140 | ␊ |
141 | /* In case of a successful call, make sure we set AH (return code) to zero. */␊ |
142 | if (bb.flags.cf == 0) bb.eax.r.h = 0;␊ |
143 | ␊ |
144 | /* Now we can really check for the return code (AH) value. */␊ |
145 | if ((bb.eax.r.h == 0x00) || (i++ >= 5)) break;␊ |
146 | ␊ |
147 | /* reset disk subsystem and try again */␊ |
148 | bb.eax.r.h = 0x00;␊ |
149 | bios(&bb);␊ |
150 | }␊ |
151 | return bb.eax.r.h;␊ |
152 | }␊ |
153 | ␊ |
154 | UInt8 BiosDisk::EBIOSRead(UInt64 sector, UInt8 count)␊ |
155 | {␊ |
156 | biosBuf_t bb;␊ |
157 | ␊ |
158 | UInt8 i;␊ |
159 | struct {␊ |
160 | UInt8 size;␊ |
161 | UInt8 reserved;␊ |
162 | UInt8 numblocks;␊ |
163 | UInt8 reserved2;␊ |
164 | UInt16 bufferOffset;␊ |
165 | UInt16 bufferSegment;␊ |
166 | UInt64 startblock;␊ |
167 | } addrpacket __attribute__((aligned(16))) = {0};␊ |
168 | addrpacket.size = sizeof(addrpacket);␊ |
169 | ␊ |
170 | for (i=0;;) {␊ |
171 | bb.intno = 0x13;␊ |
172 | bb.eax.r.h = 0x42;␊ |
173 | bb.edx.r.l = mDiskID;␊ |
174 | bb.esi.rr = NORMALIZED_OFFSET((unsigned)&addrpacket);␊ |
175 | bb.ds = NORMALIZED_SEGMENT((unsigned)&addrpacket);␊ |
176 | addrpacket.reserved = addrpacket.reserved2 = 0;␊ |
177 | addrpacket.numblocks = count;␊ |
178 | addrpacket.bufferOffset = OFFSET(ptov(BIOS_ADDR));␊ |
179 | addrpacket.bufferSegment = SEGMENT(ptov(BIOS_ADDR));␊ |
180 | addrpacket.startblock = sector;␊ |
181 | bios(&bb);␊ |
182 | ␊ |
183 | /* In case of a successful call, make sure we set AH (return code) to zero. */␊ |
184 | if (bb.flags.cf == 0)␊ |
185 | bb.eax.r.h = 0;␊ |
186 | ␊ |
187 | /* Now we can really check for the return code (AH) value. */␊ |
188 | if ((bb.eax.r.h == 0x00) || (i++ >= 5))␊ |
189 | break;␊ |
190 | ␊ |
191 | /* reset disk subsystem and try again */␊ |
192 | bb.eax.r.h = 0x00;␊ |
193 | bios(&bb);␊ |
194 | }␊ |
195 | return bb.eax.r.h;␊ |
196 | }␊ |
197 | ␊ |
198 | UInt8 BiosDisk::EBIOSWrite(UInt64 sector, UInt8 count)␊ |
199 | {␊ |
200 | biosBuf_t bb;␊ |
201 | ␊ |
202 | UInt8 i;␊ |
203 | static struct {␊ |
204 | UInt8 size;␊ |
205 | UInt8 reserved;␊ |
206 | UInt8 numblocks;␊ |
207 | UInt8 reserved2;␊ |
208 | UInt16 bufferOffset;␊ |
209 | UInt16 bufferSegment;␊ |
210 | UInt64 startblock;␊ |
211 | } addrpacket __attribute__((aligned(16))) = {0};␊ |
212 | addrpacket.size = sizeof(addrpacket);␊ |
213 | ␊ |
214 | for (i=0;;) {␊ |
215 | bb.intno = 0x13;␊ |
216 | bb.eax.r.l = 0; /* Don't verify */␊ |
217 | bb.eax.r.h = 0x43;␊ |
218 | bb.edx.r.l = mDiskID;␊ |
219 | bb.esi.rr = NORMALIZED_OFFSET((unsigned)&addrpacket);␊ |
220 | bb.ds = NORMALIZED_SEGMENT((unsigned)&addrpacket);␊ |
221 | addrpacket.reserved = addrpacket.reserved2 = 0;␊ |
222 | addrpacket.numblocks = count;␊ |
223 | addrpacket.bufferOffset = OFFSET(ptov(BIOS_ADDR));␊ |
224 | addrpacket.bufferSegment = SEGMENT(ptov(BIOS_ADDR));␊ |
225 | addrpacket.startblock = sector;␊ |
226 | bios(&bb);␊ |
227 | ␊ |
228 | /* In case of a successful call, make sure we set AH (return code) to zero. */␊ |
229 | if (bb.flags.cf == 0)␊ |
230 | bb.eax.r.h = 0;␊ |
231 | ␊ |
232 | /* Now we can really check for the return code (AH) value. */␊ |
233 | if ((bb.eax.r.h == 0x00) || (i++ >= 5))␊ |
234 | break;␊ |
235 | ␊ |
236 | /* reset disk subsystem and try again */␊ |
237 | bb.eax.r.h = 0x00;␊ |
238 | bios(&bb);␊ |
239 | }␊ |
240 | return bb.eax.r.h;␊ |
241 | }␊ |
242 | ␊ |
243 | UInt8 BiosDisk::GetDriveInfo()␊ |
244 | {␊ |
245 | // we use the BIOS_ADDR (disk buffer) to ensure that the buffer␊ |
246 | // is in low mem␊ |
247 | boot_drive_info_t* actualInfo = mDriveInfo;␊ |
248 | mDriveInfo = (boot_drive_info_t*)BIOS_ADDR;␊ |
249 | biosBuf_t bb;␊ |
250 | ␉int ret = 0;␊ |
251 | ␉␊ |
252 | #if UNUSED␊ |
253 | ␉if (maxhd == 0) {␊ |
254 | ␉␉bb.intno = 0x13;␊ |
255 | ␉␉bb.eax.r.h = 0x08;␊ |
256 | ␉␉bb.edx.r.l = 0x80;␊ |
257 | ␉␉bios(&bb);␊ |
258 | ␉␉if (bb.flags.cf == 0)␊ |
259 | ␉␉␉maxhd = 0x7f + bb.edx.r.l;␊ |
260 | ␉};␊ |
261 | ␉␊ |
262 | #endif␊ |
263 | ␉␊ |
264 | ␉/* Check for El Torito no-emulation mode. */␊ |
265 | ␉//dp->no_emulation = is_no_emulation(drive);␊ |
266 | ␊ |
267 | ␉/* Check drive for EBIOS support. */␊ |
268 | ␉bb.intno = 0x13;␊ |
269 | ␉bb.eax.r.h = 0x41;␊ |
270 | ␉bb.edx.r.l = mDiskID;␊ |
271 | ␉bb.ebx.rr = 0x55aa;␊ |
272 | ␉bios(&bb);␊ |
273 | ␉␊ |
274 | ␉if ((bb.ebx.rr == 0xaa55) && (bb.flags.cf == 0)) {␊ |
275 | ␉␉/* Get flags for supported operations. */␊ |
276 | ␉␉mUsesEBIOS = bb.ecx.r.l;␊ |
277 | ␉}␊ |
278 | ␉␊ |
279 | ␉if (mUsesEBIOS & (EBIOS_ENHANCED_DRIVE_INFO | EBIOS_LOCKING_ACCESS | EBIOS_FIXED_DISK_ACCESS)) {␊ |
280 | ␉␉/* Get EBIOS drive info. */␊ |
281 | ␉␉␊ |
282 | ␉␉mDriveInfo->params.buf_size = sizeof(mDriveInfo->params);␊ |
283 | ␉␉bb.intno = 0x13;␊ |
284 | ␉␉bb.eax.r.h = 0x48;␊ |
285 | ␉␉bb.edx.r.l = mDiskID;␊ |
286 | ␉␉bb.esi.rr = NORMALIZED_OFFSET((unsigned)&mDriveInfo->params);␊ |
287 | ␉␉bb.ds␉ = NORMALIZED_SEGMENT((unsigned)&mDriveInfo->params);␊ |
288 | ␉␉bios(&bb);␊ |
289 | ␊ |
290 | ␉␉if (bb.flags.cf != 0 /* || params.phys_sectors < 2097152 */) {␊ |
291 | ␉␉␉mUsesEBIOS = 0;␊ |
292 | ␉␉␉mDriveInfo->params.buf_size = 1;␊ |
293 | ␉␉}␊ |
294 | ␉␉else␊ |
295 | ␉␉{␊ |
296 | ␉␉␉if (mDiskID >= BASE_HD_DRIVE &&␊ |
297 | ␉␉␉␉(mUsesEBIOS & EBIOS_ENHANCED_DRIVE_INFO) &&␊ |
298 | ␉␉␉␉mDriveInfo->params.buf_size >= 30 &&␊ |
299 | ␉␉␉␉!(mDriveInfo->params.dpte_offset == 0xFFFF && mDriveInfo->params.dpte_segment == 0xFFFF)) {␊ |
300 | void *ptr = (void *)(mDriveInfo->params.dpte_offset + ((unsigned int)mDriveInfo->params.dpte_segment << 4));␊ |
301 | bcopy(ptr, &mDriveInfo->dpte, sizeof(mDriveInfo->dpte));␊ |
302 | ␉␉␉}␊ |
303 | ␉␉}␊ |
304 | ␉}␊ |
305 | ␊ |
306 | /*␊ |
307 | * zef: This code will fail on recent JMicron and Intel option ROMs␊ |
308 | */ ␊ |
309 | //␉if (mDriveInfo->params.phys_heads == 0 || mDriveInfo->params.phys_spt == 0) {␊ |
310 | //␉␉/* Either it's not EBIOS, or EBIOS didn't tell us. */␊ |
311 | //␉␉bb.intno = 0x13;␊ |
312 | //␉␉bb.eax.r.h = 0x08;␊ |
313 | //␉␉bb.edx.r.l = drive;␊ |
314 | //␉␉bios(&bb);␊ |
315 | //␉␉if (bb.flags.cf == 0 && bb.eax.r.h == 0) {␊ |
316 | //␉␉␉unsigned long cyl;␊ |
317 | //␉␉␉unsigned long sec;␊ |
318 | //␉␉␉unsigned long hds;␊ |
319 | //␉␉␊ |
320 | //␉␉␉hds = bb.edx.r.h;␊ |
321 | //␉␉␉sec = bb.ecx.r.l & 0x3F;␊ |
322 | //␉␉␉if ((dp->uses_ebios & EBIOS_ENHANCED_DRIVE_INFO) && (sec != 0)) {␊ |
323 | //␉␉␉␉cyl = (mDriveInfo->params.phys_sectors / ((hds + 1) * sec)) - 1;␊ |
324 | //␉␉␉} else {␊ |
325 | //␉␉␉␉cyl = bb.ecx.r.h | ((bb.ecx.r.l & 0xC0) << 2);␊ |
326 | //␉␉␉}␊ |
327 | //␉␉␉mDriveInfo->params.phys_heads = hds; ␊ |
328 | //␉␉␉mDriveInfo->params.phys_spt = sec;␊ |
329 | //␉␉␉mDriveInfo->params.phys_cyls = cyl;␊ |
330 | //␉␉} else {␊ |
331 | //␉␉␉ret = -1;␊ |
332 | //␉␉}␊ |
333 | //␉}␊ |
334 | /*␊ |
335 | if (dp->no_emulation) {␊ |
336 | // Some BIOSes give us erroneous EBIOS support information.␊ |
337 | // Assume that if you're on a CD, then you can use␊ |
338 | // EBIOS disk calls.␊ |
339 | //␊ |
340 | dp->uses_ebios |= EBIOS_FIXED_DISK_ACCESS;␊ |
341 | }*/␊ |
342 | ␊ |
343 | ␉if (ret == 0) {␊ |
344 | ␉␉mValid = 1;␊ |
345 | ␉}␊ |
346 | ␊ |
347 | bcopy(mDriveInfo, actualInfo, sizeof(boot_drive_info_t));␊ |
348 | mDriveInfo = actualInfo;␊ |
349 | ␊ |
350 | ␉return ret;␊ |
351 | }␊ |
352 | ␊ |
353 |