Chameleon

Chameleon Svn Source Tree

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

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
51BiosDisk::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
85BiosDisk::~BiosDisk()
86{
87 if(mDriveInfo) free(mDriveInfo);
88}
89
90IOReturn 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
104IOReturn 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
119UInt8 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
154UInt8 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
198UInt8 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
243UInt8 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;
250int ret = 0;
251
252#if UNUSED
253if (maxhd == 0) {
254bb.intno = 0x13;
255bb.eax.r.h = 0x08;
256bb.edx.r.l = 0x80;
257bios(&bb);
258if (bb.flags.cf == 0)
259maxhd = 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. */
268bb.intno = 0x13;
269bb.eax.r.h = 0x41;
270bb.edx.r.l = mDiskID;
271bb.ebx.rr = 0x55aa;
272bios(&bb);
273
274if ((bb.ebx.rr == 0xaa55) && (bb.flags.cf == 0)) {
275/* Get flags for supported operations. */
276mUsesEBIOS = bb.ecx.r.l;
277}
278
279if (mUsesEBIOS & (EBIOS_ENHANCED_DRIVE_INFO | EBIOS_LOCKING_ACCESS | EBIOS_FIXED_DISK_ACCESS)) {
280/* Get EBIOS drive info. */
281
282mDriveInfo->params.buf_size = sizeof(mDriveInfo->params);
283bb.intno = 0x13;
284bb.eax.r.h = 0x48;
285bb.edx.r.l = mDiskID;
286bb.esi.rr = NORMALIZED_OFFSET((unsigned)&mDriveInfo->params);
287bb.ds = NORMALIZED_SEGMENT((unsigned)&mDriveInfo->params);
288bios(&bb);
289
290if (bb.flags.cf != 0 /* || params.phys_sectors < 2097152 */) {
291mUsesEBIOS = 0;
292mDriveInfo->params.buf_size = 1;
293}
294else
295{
296if (mDiskID >= BASE_HD_DRIVE &&
297(mUsesEBIOS & EBIOS_ENHANCED_DRIVE_INFO) &&
298mDriveInfo->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
343if (ret == 0) {
344mValid = 1;
345}
346
347 bcopy(mDriveInfo, actualInfo, sizeof(boot_drive_info_t));
348 mDriveInfo = actualInfo;
349
350return ret;
351}
352
353

Archive Download this file

Revision: 1297