]> git.saurik.com Git - apple/boot.git/blob - i386/libsaio/biosfn.c
8af9bbea36dddf6055539c696f0cd2e3160a22b5
[apple/boot.git] / i386 / libsaio / biosfn.c
1 /*
2 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * Portions Copyright (c) 1999 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 1.1 (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 #include "libsaio.h"
30
31 static biosBuf_t bb;
32 unsigned char uses_ebios[8] = {0, 0, 0, 0, 0, 0, 0, 0};
33
34 int bgetc(void)
35 {
36 bb.intno = 0x16;
37 bb.eax.r.h = 0x00;
38 bios(&bb);
39 return bb.eax.rr;
40 }
41
42 int readKeyboardStatus(void)
43 {
44 bb.intno = 0x16;
45 bb.eax.r.h = 0x01;
46 bios(&bb);
47 if (bb.flags.zf) {
48 return 0;
49 } else {
50 return bb.eax.rr;
51 }
52 }
53
54 int readKeyboardShiftFlags(void)
55 {
56 bb.intno = 0x16;
57 bb.eax.r.h = 0x02;
58 bios(&bb);
59 return bb.eax.r.l;
60 }
61
62 unsigned int time18(void)
63 {
64 union {
65 struct {
66 unsigned int low:16;
67 unsigned int high:16;
68 } s;
69 unsigned int i;
70 } time;
71
72 bb.intno = 0x1a;
73 bb.eax.r.h = 0x00;
74 bios(&bb);
75 time.s.low = bb.edx.rr;
76 time.s.high = bb.ecx.rr;
77 return time.i;
78 }
79
80 int memsize(int which)
81 {
82 int size;
83
84 if ( which )
85 {
86 // Get the total system memory discovered by the
87 // BIOS in kilobytes.
88
89 get_memsize(&bb);
90 size = (bb.edx.rr << 16) | bb.eax.rr;
91
92 // Convert to extended memory size.
93
94 size = ( size > 1024 ) ? size - 1024 : 0;
95 }
96 else
97 {
98 // Get amount of conventional memory available.
99
100 bb.intno = 0x12;
101 bios(&bb);
102 size = bb.eax.rr;
103 }
104 return size;
105 }
106
107 void video_mode(int mode)
108 {
109 bb.intno = 0x10;
110 bb.eax.r.h = 0x00;
111 bb.eax.r.l = mode;
112 bios(&bb);
113 }
114
115 int biosread(int dev, int cyl, int head, int sec, int num)
116 {
117 int i;
118
119 bb.intno = 0x13;
120 sec += 1; /* sector numbers start at 1 */
121
122 for (i=0;;) {
123 bb.ecx.r.h = cyl;
124 bb.ecx.r.l = ((cyl & 0x300) >> 2) | (sec & 0x3F);
125 bb.edx.r.h = head;
126 bb.edx.r.l = dev;
127 bb.eax.r.l = num;
128 bb.ebx.rr = OFFSET(ptov(BIOS_ADDR));
129 bb.es = SEGMENT(ptov(BIOS_ADDR));
130
131 bb.eax.r.h = 0x02;
132 bios(&bb);
133
134 if ((bb.eax.r.h == 0x00) || (i++ >= 5))
135 break;
136
137 /* reset disk subsystem and try again */
138 bb.eax.r.h = 0x00;
139 bios(&bb);
140 }
141 return bb.eax.r.h;
142 }
143
144 int ebiosread(int dev, long sec, int count)
145 {
146 int i;
147 static struct {
148 unsigned char size;
149 unsigned char reserved;
150 unsigned char numblocks;
151 unsigned char reserved2;
152 unsigned short bufferOffset;
153 unsigned short bufferSegment;
154 unsigned long long startblock;
155 } addrpacket = {0};
156 addrpacket.size = sizeof(addrpacket);
157
158 for (i=0;;) {
159 bb.intno = 0x13;
160 bb.eax.r.h = 0x42;
161 bb.edx.r.l = dev;
162 bb.esi.rr = OFFSET((unsigned)&addrpacket);
163 bb.ds = SEGMENT((unsigned)&addrpacket);
164 addrpacket.reserved = addrpacket.reserved2 = 0;
165 addrpacket.numblocks = count;
166 addrpacket.bufferOffset = OFFSET(ptov(BIOS_ADDR));
167 addrpacket.bufferSegment = SEGMENT(ptov(BIOS_ADDR));
168 addrpacket.startblock = sec;
169 bios(&bb);
170 if ((bb.eax.r.h == 0x00) || (i++ >= 5))
171 break;
172
173 /* reset disk subsystem and try again */
174 bb.eax.r.h = 0x00;
175 bios(&bb);
176 }
177 return bb.eax.r.h;
178 }
179
180 void putc(int ch)
181 {
182 bb.intno = 0x10;
183 bb.ebx.r.h = 0x00; /* background black */
184 bb.ebx.r.l = 0x0F; /* foreground white */
185 bb.eax.r.h = 0x0e;
186 bb.eax.r.l = ch;
187 bios(&bb);
188 }
189
190 void putca(int ch, int attr, int repeat)
191 {
192 bb.intno = 0x10;
193 bb.ebx.r.h = 0x00; /* page number */
194 bb.ebx.r.l = attr; /* attribute */
195 bb.eax.r.h = 0x9;
196 bb.eax.r.l = ch;
197 bb.ecx.rx = repeat; /* repeat count */
198 bios(&bb);
199 }
200
201 unsigned int get_diskinfo(int drive)
202 {
203 static struct {
204 unsigned short size;
205 unsigned short flags;
206 unsigned long cylinders;
207 unsigned long heads;
208 unsigned long sectors;
209 unsigned long long total_sectors;
210 unsigned short bps;
211 unsigned long params_p;
212 } ebios = {0};
213 unsigned char useEbios = 0;
214
215 union {
216 compact_diskinfo_t di;
217 unsigned int ui;
218 } ret;
219 static int maxhd = 0;
220
221 ret.ui = 0;
222 if (maxhd == 0) {
223 bb.intno = 0x13;
224 bb.eax.r.h = 0x08;
225 bb.edx.r.l = 0x80;
226 bios(&bb);
227 if (bb.flags.cf == 0)
228 maxhd = 0x7f + bb.edx.r.l;
229 };
230
231 if (drive > maxhd)
232 return 0;
233
234 /* Check drive for EBIOS support. */
235 bb.intno = 0x13;
236 bb.eax.r.h = 0x41;
237 bb.edx.r.l = drive;
238 bb.ebx.rr = 0x55aa;
239 bios(&bb);
240 if(bb.ebx.rr == 0xaa55 && bb.flags.cf == 0) {
241 /* Get flags for supported operations. */
242 useEbios = bb.ecx.r.l;
243 }
244
245 if (useEbios & EBIOS_ENHANCED_DRIVE_INFO) {
246 /* Get EBIOS drive info. */
247 ebios.size = 26;
248 bb.intno = 0x13;
249 bb.eax.r.h = 0x48;
250 bb.edx.r.l = drive;
251 bb.esi.rr = OFFSET((unsigned)&ebios);
252 bb.ds = SEGMENT((unsigned)&ebios);
253 bios(&bb);
254 if(bb.flags.cf != 0) {
255 useEbios = 0;
256 }
257 }
258
259 bb.intno = 0x13;
260 bb.eax.r.h = 0x08;
261 bb.edx.r.l = drive;
262 bios(&bb);
263 if (bb.flags.cf == 0 && bb.eax.r.h == 0) {
264 unsigned long cyl;
265 unsigned long sec;
266 unsigned long hds;
267
268 hds = bb.edx.r.h;
269 sec = bb.ecx.r.l & 0x3F;
270 if(useEbios & EBIOS_ENHANCED_DRIVE_INFO) {
271 cyl = (ebios.total_sectors / ((hds + 1) * sec)) - 1;
272 }
273 else {
274 cyl = bb.ecx.r.h | ((bb.ecx.r.l & 0xC0) << 2);
275 }
276 ret.di.heads = hds;
277 ret.di.sectors = sec;
278 ret.di.cylinders = cyl;
279 }
280 if(drive >= 0x80) uses_ebios[drive - 0x80] = useEbios;
281 return ret.ui;
282 }
283
284 void setCursorPosition(int x, int y, int page)
285 {
286 bb.intno = 0x10;
287 bb.eax.r.h = 0x02;
288 bb.ebx.r.h = page; /* page 0 for graphics */
289 bb.edx.r.l = x;
290 bb.edx.r.h = y;
291 bios(&bb);
292 }
293
294 void setCursorType(int type)
295 {
296 bb.intno = 0x10;
297 bb.eax.r.h = 0x01;
298 bb.ecx.rr = type;
299 bios(&bb);
300 }
301
302 void getCursorPositionAndType(int * x, int * y, int * type)
303 {
304 bb.intno = 0x10;
305 bb.eax.r.h = 0x03;
306 bios(&bb);
307 *x = bb.edx.r.l;
308 *y = bb.edx.r.h;
309 *type = bb.ecx.rr;
310 }
311
312 void scollPage(int x1, int y1, int x2, int y2, int attr, int rows, int dir)
313 {
314 bb.intno = 0x10;
315 bb.eax.r.h = (dir > 0) ? 0x06 : 0x07;
316 bb.eax.r.l = rows;
317 bb.ebx.r.h = attr;
318 bb.ecx.r.h = y1;
319 bb.ecx.r.l = x1;
320 bb.edx.r.h = y2;
321 bb.edx.r.l = x2;
322 bios(&bb);
323 }
324
325 void clearScreenRows( int y1, int y2 )
326 {
327 scollPage( 0, y1, 80 - 1, y2, 0x07, y2 - y1 + 1, 1 );
328 }
329
330 void setActiveDisplayPage( int page )
331 {
332 bb.intno = 0x10;
333 bb.eax.r.h = 5;
334 bb.eax.r.l = page;
335 bios(&bb);
336 }
337
338 #if DEBUG
339
340 int terminateDiskEmulation()
341 {
342 static char cd_spec[0x12];
343
344 bb.intno = 0x13;
345 bb.eax.r.h = 0x4b;
346 bb.eax.r.l = 0; // subfunc: terminate emulation
347 bb.esi.rr = OFFSET((unsigned)&cd_spec);
348 bb.ds = SEGMENT((unsigned)&cd_spec);
349 bios(&bb);
350 return bb.eax.r.h;
351 }
352
353 int readDriveParameters(int drive, struct driveParameters *dp)
354 {
355 bb.intno = 0x13;
356 bb.edx.r.l = drive;
357 bb.eax.r.h = 0x08;
358 bios(&bb);
359 if (bb.eax.r.h == 0) {
360 dp->heads = bb.edx.r.h;
361 dp->sectors = bb.ecx.r.l & 0x3F;
362 dp->cylinders = bb.ecx.r.h | ((bb.ecx.r.l & 0xC0) << 2);
363 dp->totalDrives = bb.edx.r.l;
364 } else {
365 bzero(dp, sizeof(*dp));
366 }
367 return bb.eax.r.h;
368
369 }
370 #endif
371
372 #define APM_INTNO 0x15
373 #define APM_INTCODE 0x53
374
375 int
376 APMPresent(void)
377 {
378 KERNBOOTSTRUCT *kbp = kernBootStruct;
379
380 bb.intno = APM_INTNO;
381 bb.eax.r.h = APM_INTCODE;
382 bb.eax.r.l = 0x00;
383 bb.ebx.rr = 0x0000;
384 bios(&bb);
385 if ((bb.flags.cf == 0) &&
386 (bb.ebx.r.h == 'P') &&
387 (bb.ebx.r.l == 'M')) {
388 /* Success */
389 kbp->apmConfig.major_vers = bb.eax.r.h;
390 kbp->apmConfig.minor_vers = bb.eax.r.l;
391 kbp->apmConfig.flags.data = bb.ecx.rr;
392 return 1;
393 }
394 return 0;
395 }
396
397 int
398 APMConnect32(void)
399 {
400 KERNBOOTSTRUCT *kbp = kernBootStruct;
401
402 bb.intno = APM_INTNO;
403 bb.eax.r.h = APM_INTCODE;
404 bb.eax.r.l = 0x03;
405 bb.ebx.rr = 0x0000;
406 bios(&bb);
407 if (bb.flags.cf == 0) {
408 /* Success */
409 kbp->apmConfig.cs32_base = (bb.eax.rr) << 4;
410 kbp->apmConfig.entry_offset = bb.ebx.rx;
411 kbp->apmConfig.cs16_base = (bb.ecx.rr) << 4;
412 kbp->apmConfig.ds_base = (bb.edx.rr) << 4;
413 if (kbp->apmConfig.major_vers >= 1 &&
414 kbp->apmConfig.minor_vers >= 1) {
415 kbp->apmConfig.cs_length = bb.esi.rr;
416 kbp->apmConfig.ds_length = bb.edi.rr;
417 } else {
418 kbp->apmConfig.cs_length =
419 kbp->apmConfig.ds_length = 64 * 1024;
420 }
421 kbp->apmConfig.connected = 1;
422 return 1;
423 }
424 return 0;
425 }
426
427 #ifdef EISA_SUPPORT
428 BOOL
429 eisa_present(
430 void
431 )
432 {
433 static BOOL checked;
434 static BOOL isEISA;
435
436 if (!checked) {
437 if (strncmp((char *)0xfffd9, "EISA", 4) == 0)
438 isEISA = TRUE;
439
440 checked = TRUE;
441 }
442
443 return (isEISA);
444 }
445
446 int
447 ReadEISASlotInfo(EISA_slot_info_t *ep, int slot)
448 {
449 union {
450 struct {
451 unsigned char char2h :2;
452 unsigned char char1 :5;
453 unsigned char char3 :5;
454 unsigned char char2l :3;
455 unsigned char d2 :4;
456 unsigned char d1 :4;
457 unsigned char d4 :4;
458 unsigned char d3 :4;
459 } s;
460 unsigned char data[4];
461 } u;
462 static char hex[0x10] = "0123456789ABCDEF";
463
464
465 bb.intno = 0x15;
466 bb.eax.r.h = 0xd8;
467 bb.eax.r.l = 0x00;
468 bb.ecx.r.l = slot;
469 bios(&bb);
470 if (bb.flags.cf)
471 return bb.eax.r.h;
472 ep->u_ID.d = bb.eax.r.l;
473 ep->configMajor = bb.ebx.r.h;
474 ep->configMinor = bb.ebx.r.l;
475 ep->checksum = bb.ecx.rr;
476 ep->numFunctions = bb.edx.r.h;
477 ep->u_resources.d = bb.edx.r.l;
478 u.data[0] = bb.edi.r.l;
479 u.data[1] = bb.edi.r.h;
480 u.data[2] = bb.esi.r.l;
481 u.data[3] = bb.esi.r.h;
482 ep->id[0] = u.s.char1 + ('A' - 1);
483 ep->id[1] = (u.s.char2l | (u.s.char2h << 3)) + ('A' - 1);
484 ep->id[2] = u.s.char3 + ('A' - 1);
485 ep->id[3] = hex[u.s.d1];
486 ep->id[4] = hex[u.s.d2];
487 ep->id[5] = hex[u.s.d3];
488 ep->id[6] = hex[u.s.d4];
489 ep->id[7] = 0;
490 return 0;
491 }
492
493 /*
494 * Note: ep must point to an address below 64k.
495 */
496
497 int
498 ReadEISAFuncInfo(EISA_func_info_t *ep, int slot, int function)
499 {
500 bb.intno = 0x15;
501 bb.eax.r.h = 0xd8;
502 bb.eax.r.l = 0x01;
503 bb.ecx.r.l = slot;
504 bb.ecx.r.h = function;
505 bb.esi.rr = (unsigned int)ep->data;
506 bios(&bb);
507 if (bb.eax.r.h == 0) {
508 ep->slot = slot;
509 ep->function = function;
510 }
511 return bb.eax.r.h;
512 }
513 #endif /* EISA_SUPPORT */
514
515 #define PCI_SIGNATURE 0x20494350 /* "PCI " */
516
517 int
518 ReadPCIBusInfo(PCI_bus_info_t *pp)
519 {
520 bb.intno = 0x1a;
521 bb.eax.r.h = 0xb1;
522 bb.eax.r.l = 0x01;
523 bios(&bb);
524 if ((bb.eax.r.h == 0) && (bb.edx.rx == PCI_SIGNATURE)) {
525 pp->BIOSPresent = 1;
526 pp->u_bus.d = bb.eax.r.l;
527 pp->majorVersion = bb.ebx.r.h;
528 pp->minorVersion = bb.ebx.r.l;
529 pp->maxBusNum = bb.ecx.r.l;
530 return 0;
531 }
532 return -1;
533 }