Chameleon

Chameleon Svn Source Tree

Root/branches/xZenu/src/modules/Disk/i386/BiosDisk.cpp

Source at commit 1288 created 12 years 8 months ago.
By meklort, Add BiosDisk.cpp to i386 builds
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
51extern "C"
52{
53#include "libsaio.h"
54#include "stdio.h"
55}
56
57BiosDisk::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
91BiosDisk::~BiosDisk()
92{
93 if(mDriveInfo) free(mDriveInfo);
94}
95
96IOReturn 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) == kIOReturnSuccess)
102 {
103 bcopy((void*)BIOS_ADDR, buffer, size * mBytesPerSector);
104 return kIOReturnSuccess;
105 }
106 else return kIOReturnIOError;
107}
108
109
110IOReturn 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
125UInt8 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
160UInt8 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
204UInt8 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
249UInt8 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;
256int ret = 0;
257
258#if UNUSED
259if (maxhd == 0) {
260bb.intno = 0x13;
261bb.eax.r.h = 0x08;
262bb.edx.r.l = 0x80;
263bios(&bb);
264if (bb.flags.cf == 0)
265maxhd = 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. */
274bb.intno = 0x13;
275bb.eax.r.h = 0x41;
276bb.edx.r.l = mDiskID;
277bb.ebx.rr = 0x55aa;
278bios(&bb);
279
280if ((bb.ebx.rr == 0xaa55) && (bb.flags.cf == 0)) {
281/* Get flags for supported operations. */
282mUsesEBIOS = bb.ecx.r.l;
283}
284
285if (mUsesEBIOS & (EBIOS_ENHANCED_DRIVE_INFO | EBIOS_LOCKING_ACCESS | EBIOS_FIXED_DISK_ACCESS)) {
286/* Get EBIOS drive info. */
287
288mDriveInfo->params.buf_size = sizeof(mDriveInfo->params);
289bb.intno = 0x13;
290bb.eax.r.h = 0x48;
291bb.edx.r.l = mDiskID;
292bb.esi.rr = NORMALIZED_OFFSET((unsigned)&mDriveInfo->params);
293bb.ds = NORMALIZED_SEGMENT((unsigned)&mDriveInfo->params);
294bios(&bb);
295
296if (bb.flags.cf != 0 /* || params.phys_sectors < 2097152 */) {
297mUsesEBIOS = 0;
298mDriveInfo->params.buf_size = 1;
299}
300else
301{
302if (mDiskID >= BASE_HD_DRIVE &&
303(mUsesEBIOS & EBIOS_ENHANCED_DRIVE_INFO) &&
304mDriveInfo->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
349if (ret == 0) {
350mValid = 1;
351}
352
353 bcopy(mDriveInfo, actualInfo, sizeof(boot_drive_info_t));
354 mDriveInfo = actualInfo;
355
356return ret;
357}
358
359

Archive Download this file

Revision: 1288