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