Chameleon

Chameleon Svn Source Tree

Root/branches/rewrite/i386/modules/BiosDisk/BiosDisk.cpp

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
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 return kIOReturnSuccess;
100}
101
102
103IOReturn BiosDisk::Write(UInt64 sector, UInt64 size, UInt8* buffer)
104{
105 if(!isValid()) return kIOReturnNoDevice;
106 return kIOReturnNotWritable;
107}
108
109
110UInt8 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
145UInt8 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
189UInt8 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
234UInt8 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;
241int ret = 0;
242
243#if UNUSED
244if (maxhd == 0) {
245bb.intno = 0x13;
246bb.eax.r.h = 0x08;
247bb.edx.r.l = 0x80;
248bios(&bb);
249if (bb.flags.cf == 0)
250maxhd = 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. */
259bb.intno = 0x13;
260bb.eax.r.h = 0x41;
261bb.edx.r.l = mDiskID;
262bb.ebx.rr = 0x55aa;
263bios(&bb);
264
265if ((bb.ebx.rr == 0xaa55) && (bb.flags.cf == 0)) {
266/* Get flags for supported operations. */
267mUsesEBIOS = bb.ecx.r.l;
268}
269
270if (mUsesEBIOS & (EBIOS_ENHANCED_DRIVE_INFO | EBIOS_LOCKING_ACCESS | EBIOS_FIXED_DISK_ACCESS)) {
271/* Get EBIOS drive info. */
272
273mDriveInfo->params.buf_size = sizeof(mDriveInfo->params);
274bb.intno = 0x13;
275bb.eax.r.h = 0x48;
276bb.edx.r.l = mDiskID;
277bb.esi.rr = NORMALIZED_OFFSET((unsigned)&mDriveInfo->params);
278bb.ds = NORMALIZED_SEGMENT((unsigned)&mDriveInfo->params);
279bios(&bb);
280
281if (bb.flags.cf != 0 /* || params.phys_sectors < 2097152 */) {
282mUsesEBIOS = 0;
283mDriveInfo->params.buf_size = 1;
284}
285else
286{
287if (mDiskID >= BASE_HD_DRIVE &&
288(mUsesEBIOS & EBIOS_ENHANCED_DRIVE_INFO) &&
289mDriveInfo->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
334if (ret == 0) {
335mValid = 1;
336}
337
338 bcopy(mDriveInfo, actualInfo, sizeof(boot_drive_info_t));
339 mDriveInfo = actualInfo;
340
341return ret;
342}
343
344

Archive Download this file

Revision: 1083