]> git.saurik.com Git - apple/boot.git/blame - i386/libsaio/biosfn.c
boot-132.tar.gz
[apple/boot.git] / i386 / libsaio / biosfn.c
CommitLineData
14c7c974 1/*
57c72a9a 2 * Copyright (c) 1999-2003 Apple Computer, Inc. All rights reserved.
14c7c974
A
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
57c72a9a 6 * Portions Copyright (c) 1999-2003 Apple Computer, Inc. All Rights
4f6e3300
A
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
57c72a9a 9 * Source License Version 2.0 (the "License"). You may not use this file
4f6e3300
A
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.
14c7c974
A
13 *
14 * The Original Code and all software distributed under the License are
4f6e3300 15 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14c7c974
A
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
4f6e3300
A
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.
14c7c974
A
21 *
22 * @APPLE_LICENSE_HEADER_END@
23 */
24/*
25 * Copyright 1993 NeXT Computer, Inc.
26 * All rights reserved.
27 */
28
f083c6c3 29#include "bootstruct.h"
14c7c974 30#include "libsaio.h"
14c7c974 31
f083c6c3
A
32#define MAX_DRIVES 8
33
14c7c974 34static biosBuf_t bb;
14c7c974
A
35
36int bgetc(void)
37{
38 bb.intno = 0x16;
39 bb.eax.r.h = 0x00;
40 bios(&bb);
41 return bb.eax.rr;
42}
43
44int readKeyboardStatus(void)
45{
46 bb.intno = 0x16;
47 bb.eax.r.h = 0x01;
48 bios(&bb);
49 if (bb.flags.zf) {
75b89a82 50 return 0;
14c7c974 51 } else {
75b89a82 52 return bb.eax.rr;
14c7c974
A
53 }
54}
55
56int readKeyboardShiftFlags(void)
57{
58 bb.intno = 0x16;
59 bb.eax.r.h = 0x02;
60 bios(&bb);
61 return bb.eax.r.l;
62}
63
64unsigned int time18(void)
65{
66 union {
75b89a82
A
67 struct {
68 unsigned int low:16;
69 unsigned int high:16;
70 } s;
71 unsigned int i;
14c7c974
A
72 } time;
73
74 bb.intno = 0x1a;
75 bb.eax.r.h = 0x00;
76 bios(&bb);
77 time.s.low = bb.edx.rr;
78 time.s.high = bb.ecx.rr;
79 return time.i;
80}
81
f083c6c3
A
82unsigned long getMemoryMap( MemoryRange * rangeArray,
83 unsigned long maxRangeCount,
84 unsigned long * conMemSizePtr,
85 unsigned long * extMemSizePtr )
14c7c974 86{
f083c6c3
A
87 #define kMemoryMapSignature 'SMAP'
88 #define kDescriptorSizeMin 20
89
bba600dd 90 MemoryRange * range = (MemoryRange *)BIOS_ADDR;
f083c6c3
A
91 unsigned long count = 0;
92 unsigned long long conMemSize = 0;
57c72a9a 93 unsigned long long extMemSize = 0;
f083c6c3 94
f083c6c3
A
95 // Prepare for the INT15 E820h call. Each call returns a single
96 // memory range. A continuation value is returned that must be
97 // provided on a subsequent call to fetch the next range.
98 //
99 // Certain BIOSes (Award 6.00PG) expect the upper word in EAX
100 // to be cleared on entry, otherwise only a single range will
101 // be reported.
102 //
103 // Some BIOSes will simply ignore the value of ECX on entry.
104 // Probably best to keep its value at 20 to avoid surprises.
105
bba600dd
A
106 //printf("Get memory map 0x%x, %d\n", rangeArray);getc();
107 if (maxRangeCount > (BIOS_LEN / sizeof(MemoryRange))) {
108 maxRangeCount = (BIOS_LEN / sizeof(MemoryRange));
109 }
f083c6c3
A
110 bb.ebx.rx = 0; // Initial continuation value must be zero.
111
112 while ( count < maxRangeCount )
47b0a8bd 113 {
f083c6c3
A
114 bb.intno = 0x15;
115 bb.eax.rx = 0xe820;
116 bb.ecx.rx = kDescriptorSizeMin;
117 bb.edx.rx = kMemoryMapSignature;
118 bb.edi.rr = OFFSET( (unsigned long) range );
119 bb.es = SEGMENT( (unsigned long) range );
120 bios(&bb);
47b0a8bd 121
f083c6c3 122 // Check for errors.
47b0a8bd 123
f083c6c3
A
124 if ( bb.flags.cf
125 || bb.eax.rx != kMemoryMapSignature
bba600dd
A
126 || bb.ecx.rx != kDescriptorSizeMin ) {
127 //printf("Got an error %x %x %x\n", bb.flags.cf,
128 // bb.eax.rx, bb.ecx.rx);
129 break;
130 }
47b0a8bd 131
f083c6c3 132 // Tally up the conventional/extended memory sizes.
47b0a8bd 133
f083c6c3
A
134 if ( range->type == kMemoryRangeUsable ||
135 range->type == kMemoryRangeACPI ||
136 range->type == kMemoryRangeNVS )
137 {
138 // Tally the conventional memory ranges.
57c72a9a 139 if ( range->base + range->length <= 0xa0000 ) {
f083c6c3 140 conMemSize += range->length;
57c72a9a 141 }
f083c6c3
A
142
143 // Record the top of extended memory.
57c72a9a
A
144 if ( range->base >= EXTENDED_ADDR ) {
145 extMemSize += range->length;
146 }
f083c6c3
A
147 }
148
149 range++;
150 count++;
151
152 // Is this the last address range?
153
bba600dd
A
154 if ( bb.ebx.rx == 0 ) {
155 //printf("last range\n");
156 break;
157 }
14c7c974 158 }
f083c6c3 159 *conMemSizePtr = conMemSize / 1024; // size in KB
57c72a9a
A
160 *extMemSizePtr = extMemSize / 1024; // size in KB
161
bba600dd
A
162 // Copy out data
163 bcopy((char *)BIOS_ADDR, rangeArray, ((char *)range - (char *)BIOS_ADDR));
164
57c72a9a
A
165#if DEBUG
166 {
bba600dd
A
167 int i;
168 printf("%d total ranges\n", count);getc();
169 for (i=0, range = rangeArray; i<count; i++, range++) {
170 printf("range: type %d, base 0x%x, length 0x%x\n",
171 range->type, (unsigned int)range->base, (unsigned int)range->length); getc();
57c72a9a
A
172 }
173 }
174#endif
f083c6c3
A
175
176 return count;
177}
178
179unsigned long getExtendedMemorySize()
180{
181 // Get extended memory size for large configurations. Not used unless
182 // the INT15, E820H call (Get System Address Map) failed.
183 //
184 // Input:
185 //
186 // AX Function Code E801h
187 //
188 // Outputs:
189 //
190 // CF Carry Flag Carry cleared indicates no error.
191 // AX Extended 1 Number of contiguous KB between 1 and 16 MB,
192 // maximum 0x3C00 = 15 MB.
193 // BX Extended 2 Number of contiguous 64 KB blocks between
194 // 16 MB and 4 GB.
195 // CX Configured 1 Number of contiguous KB between 1 and 16 MB,
196 // maximum 0x3C00 = 15 MB.
197 // DX Configured 2 Number of contiguous 64 KB blocks between
198 // 16 MB and 4 GB.
199
200 bb.intno = 0x15;
201 bb.eax.rx = 0xe801;
202 bios(&bb);
203
204 // Return the size of memory above 1MB (extended memory) in kilobytes.
205
206 if ( bb.flags.cf == 0 ) return (bb.ebx.rr * 64 + bb.eax.rr);
207
208 // Get Extended memory size. Called on last resort since the return
209 // value is limited to 16-bits (a little less than 64MB max). May
210 // not be supported by modern BIOSes.
211 //
212 // Input:
213 //
214 // AX Function Code E801h
215 //
216 // Outputs:
217 //
218 // CF Carry Flag Carry cleared indicates no error.
219 // AX Memory Count Number of contiguous KB above 1MB.
220
221 bb.intno = 0x15;
222 bb.eax.rx = 0x88;
223 bios(&bb);
224
225 // Return the size of memory above 1MB (extended memory) in kilobytes.
226
227 return bb.flags.cf ? 0 : bb.eax.rr;
228}
229
230unsigned long getConventionalMemorySize()
231{
232 bb.intno = 0x12;
233 bios(&bb);
234 return bb.eax.rr; // kilobytes
14c7c974
A
235}
236
237void video_mode(int mode)
238{
239 bb.intno = 0x10;
240 bb.eax.r.h = 0x00;
241 bb.eax.r.l = mode;
242 bios(&bb);
243}
244
245int biosread(int dev, int cyl, int head, int sec, int num)
246{
247 int i;
248
249 bb.intno = 0x13;
75b89a82 250 sec += 1; /* sector numbers start at 1 */
14c7c974
A
251
252 for (i=0;;) {
75b89a82
A
253 bb.ecx.r.h = cyl;
254 bb.ecx.r.l = ((cyl & 0x300) >> 2) | (sec & 0x3F);
255 bb.edx.r.h = head;
256 bb.edx.r.l = dev;
257 bb.eax.r.l = num;
258 bb.ebx.rr = OFFSET(ptov(BIOS_ADDR));
259 bb.es = SEGMENT(ptov(BIOS_ADDR));
260
261 bb.eax.r.h = 0x02;
262 bios(&bb);
14c7c974 263
75b89a82
A
264 if ((bb.eax.r.h == 0x00) || (i++ >= 5))
265 break;
14c7c974 266
75b89a82
A
267 /* reset disk subsystem and try again */
268 bb.eax.r.h = 0x00;
269 bios(&bb);
14c7c974
A
270 }
271 return bb.eax.r.h;
272}
273
274int ebiosread(int dev, long sec, int count)
275{
276 int i;
75b89a82
A
277 static struct {
278 unsigned char size;
279 unsigned char reserved;
280 unsigned char numblocks;
281 unsigned char reserved2;
282 unsigned short bufferOffset;
283 unsigned short bufferSegment;
284 unsigned long long startblock;
57c72a9a 285 } addrpacket __attribute__((aligned(16))) = {0};
14c7c974
A
286 addrpacket.size = sizeof(addrpacket);
287
288 for (i=0;;) {
75b89a82 289 bb.intno = 0x13;
14c7c974
A
290 bb.eax.r.h = 0x42;
291 bb.edx.r.l = dev;
75b89a82
A
292 bb.esi.rr = OFFSET((unsigned)&addrpacket);
293 bb.ds = SEGMENT((unsigned)&addrpacket);
294 addrpacket.reserved = addrpacket.reserved2 = 0;
295 addrpacket.numblocks = count;
296 addrpacket.bufferOffset = OFFSET(ptov(BIOS_ADDR));
297 addrpacket.bufferSegment = SEGMENT(ptov(BIOS_ADDR));
298 addrpacket.startblock = sec;
14c7c974
A
299 bios(&bb);
300 if ((bb.eax.r.h == 0x00) || (i++ >= 5))
301 break;
302
303 /* reset disk subsystem and try again */
304 bb.eax.r.h = 0x00;
305 bios(&bb);
306 }
307 return bb.eax.r.h;
308}
309
57c72a9a
A
310int ebioswrite(int dev, long sec, int count)
311{
312 int i;
313 static struct {
314 unsigned char size;
315 unsigned char reserved;
316 unsigned char numblocks;
317 unsigned char reserved2;
318 unsigned short bufferOffset;
319 unsigned short bufferSegment;
320 unsigned long long startblock;
321 } addrpacket __attribute__((aligned(16))) = {0};
322 addrpacket.size = sizeof(addrpacket);
323
324 for (i=0;;) {
325 bb.intno = 0x13;
326 bb.eax.r.l = 0; /* Don't verify */
327 bb.eax.r.h = 0x43;
328 bb.edx.r.l = dev;
329 bb.esi.rr = OFFSET((unsigned)&addrpacket);
330 bb.ds = SEGMENT((unsigned)&addrpacket);
331 addrpacket.reserved = addrpacket.reserved2 = 0;
332 addrpacket.numblocks = count;
333 addrpacket.bufferOffset = OFFSET(ptov(BIOS_ADDR));
334 addrpacket.bufferSegment = SEGMENT(ptov(BIOS_ADDR));
335 addrpacket.startblock = sec;
336 bios(&bb);
337 if ((bb.eax.r.h == 0x00) || (i++ >= 5))
338 break;
339
340 /* reset disk subsystem and try again */
341 bb.eax.r.h = 0x00;
342 bios(&bb);
343 }
344 return bb.eax.r.h;
345}
346
14c7c974
A
347void putc(int ch)
348{
349 bb.intno = 0x10;
75b89a82
A
350 bb.ebx.r.h = 0x00; /* background black */
351 bb.ebx.r.l = 0x0F; /* foreground white */
14c7c974
A
352 bb.eax.r.h = 0x0e;
353 bb.eax.r.l = ch;
354 bios(&bb);
355}
356
75b89a82
A
357void putca(int ch, int attr, int repeat)
358{
359 bb.intno = 0x10;
360 bb.ebx.r.h = 0x00; /* page number */
361 bb.ebx.r.l = attr; /* attribute */
362 bb.eax.r.h = 0x9;
363 bb.eax.r.l = ch;
364 bb.ecx.rx = repeat; /* repeat count */
365 bios(&bb);
366}
367
f083c6c3
A
368/* Check to see if the passed-in drive is in El Torito no-emulation mode. */
369int is_no_emulation(int drive)
14c7c974 370{
f083c6c3
A
371 struct packet {
372 unsigned char packet_size;
373 unsigned char media_type;
374 unsigned char drive_num;
375 unsigned char ctrlr_index;
376 unsigned long lba;
377 unsigned short device_spec;
378 unsigned short buffer_segment;
379 unsigned short load_segment;
380 unsigned short sector_count;
381 unsigned char cyl_count;
382 unsigned char sec_count;
383 unsigned char head_count;
384 unsigned char reseved;
57c72a9a 385 } __attribute__((packed));
f083c6c3 386 static struct packet pkt;
14c7c974 387
f083c6c3
A
388 bzero(&pkt, sizeof(pkt));
389 pkt.packet_size = 0x13;
390
391 bb.intno = 0x13;
392 bb.eax.r.h = 0x4b;
393 bb.eax.r.l = 0x01; // subfunc: get info
394 bb.edx.r.l = drive;
395 bb.esi.rr = OFFSET((unsigned)&pkt);
396 bb.ds = SEGMENT((unsigned)&pkt);
397
398 bios(&bb);
399#if DEBUG
400 printf("el_torito info drive %x\n", drive);
401
402 printf("--> cf %x, eax %x\n", bb.flags.cf, bb.eax.rr);
14c7c974 403
f083c6c3
A
404 printf("pkt_size: %x\n", pkt.packet_size);
405 printf("media_type: %x\n", pkt.media_type);
406 printf("drive_num: %x\n", pkt.drive_num);
407 printf("device_spec: %x\n", pkt.device_spec);
408 printf("press a key->\n");getc();
409#endif
410
411 /* Some BIOSes erroneously return cf = 1 */
412 /* Just check to see if the drive number is the same. */
413 if (pkt.drive_num == drive) {
414 if ((pkt.media_type & 0x0F) == 0) {
415 /* We are in no-emulation mode. */
416 return 1;
417 }
418 }
419
420 return 0;
421}
422
423#if DEBUG
424/*
425 * BIOS drive information.
426 */
427void print_drive_info(boot_drive_info_t *dp)
428{
429 // printf("buf_size = %x\n", dp->params.buf_size);
430 printf("info_flags = %x\n", dp->params.info_flags);
431 printf(" phys_cyls = %lx\n", dp->params. phys_cyls);
432 printf(" phys_heads = %lx\n", dp->params. phys_heads);
433 printf(" phys_spt = %lx\n", dp->params. phys_spt);
434 printf("phys_sectors = %lx%lx\n", ((unsigned long *)(&dp->params.phys_sectors))[1],
435 ((unsigned long *)(&dp->params.phys_sectors))[0]);
436 printf("phys_nbps = %x\n", dp->params.phys_nbps);
437 // printf("dpte_offset = %x\n", dp->params.dpte_offset);
438 // printf("dpte_segment = %x\n", dp->params.dpte_segment);
439 // printf("key = %x\n", dp->params.key);
440 // printf("path_len = %x\n", dp->params. path_len);
441 // printf("reserved1 = %x\n", dp->params. reserved1);
442 // printf("reserved2 = %x\n", dp->params.reserved2);
443 //printf("bus_type[4] = %x\n", dp->params. bus_type[4]);
444 //printf("interface_type[8] = %x\n", dp->params. interface_type[8]);
445 //printf("interface_path[8] = %x\n", dp->params. interface_path[8]);
446 //printf("dev_path[8] = %x\n", dp->params. dev_path[8]);
447 // printf("reserved3 = %x\n", dp->params. reserved3);
448 // printf("checksum = %x\n", dp->params. checksum);
449
450 printf(" io_port_base = %x\n", dp->dpte.io_port_base);
451 printf(" control_port_base = %x\n", dp->dpte.control_port_base);
452 printf(" head_flags = %x\n", dp->dpte. head_flags);
453 printf(" vendor_info = %x\n", dp->dpte. vendor_info);
454 printf(" irq = %x\n", dp->dpte. irq);
455 // printf(" irq_unused = %x\n", dp->dpte. irq_unused);
456 printf(" block_count = %x\n", dp->dpte. block_count);
457 printf(" dma_channe = %x\n", dp->dpte. dma_channel);
458 printf(" dma_type = %x\n", dp->dpte. dma_type);
459 printf(" pio_type = %x\n", dp->dpte. pio_type);
460 printf(" pio_unused = %x\n", dp->dpte. pio_unused);
461 printf(" option_flags = %x\n", dp->dpte.option_flags);
462 // printf(" reserved = %x\n", dp->dpte.reserved);
463 printf(" revision = %x\n", dp->dpte. revision);
464 // printf(" checksum = %x\n", dp->dpte. checksum);
465}
466
467#endif
468
469int get_drive_info(int drive, struct driveInfo *dp)
470{
471 boot_drive_info_t *di = &dp->di;
472 int ret = 0;
473
57c72a9a 474#if UNUSED
14c7c974 475 if (maxhd == 0) {
75b89a82
A
476 bb.intno = 0x13;
477 bb.eax.r.h = 0x08;
478 bb.edx.r.l = 0x80;
479 bios(&bb);
480 if (bb.flags.cf == 0)
481 maxhd = 0x7f + bb.edx.r.l;
14c7c974
A
482 };
483
484 if (drive > maxhd)
75b89a82 485 return 0;
f083c6c3
A
486#endif
487
488 bzero(dp, sizeof(struct driveInfo));
489 dp->biosdev = drive;
490
491 /* Check for El Torito no-emulation mode. */
492 dp->no_emulation = is_no_emulation(drive);
14c7c974
A
493
494 /* Check drive for EBIOS support. */
495 bb.intno = 0x13;
496 bb.eax.r.h = 0x41;
497 bb.edx.r.l = drive;
498 bb.ebx.rr = 0x55aa;
499 bios(&bb);
f083c6c3 500 if((bb.ebx.rr == 0xaa55) && (bb.flags.cf == 0)) {
75b89a82 501 /* Get flags for supported operations. */
f083c6c3 502 dp->uses_ebios = bb.ecx.r.l;
75b89a82 503 }
14c7c974 504
f083c6c3 505 if (dp->uses_ebios & (EBIOS_ENHANCED_DRIVE_INFO | EBIOS_LOCKING_ACCESS | EBIOS_FIXED_DISK_ACCESS)) {
14c7c974 506 /* Get EBIOS drive info. */
f083c6c3
A
507 static struct drive_params params;
508
509 params.buf_size = sizeof(params);
14c7c974
A
510 bb.intno = 0x13;
511 bb.eax.r.h = 0x48;
512 bb.edx.r.l = drive;
f083c6c3
A
513 bb.esi.rr = OFFSET((unsigned)&params);
514 bb.ds = SEGMENT((unsigned)&params);
14c7c974 515 bios(&bb);
f083c6c3
A
516 if(bb.flags.cf != 0 /* || params.phys_sectors < 2097152 */) {
517 dp->uses_ebios = 0;
518 di->params.buf_size = 1;
519 } else {
520 bcopy(&params, &di->params, sizeof(params));
521
522 if (drive >= BASE_HD_DRIVE &&
523 (dp->uses_ebios & EBIOS_ENHANCED_DRIVE_INFO) &&
524 di->params.buf_size >= 30 &&
525 !(di->params.dpte_offset == 0xFFFF && di->params.dpte_segment == 0xFFFF)) {
526 void *ptr = (void *)(di->params.dpte_offset + ((unsigned int)di->params.dpte_segment << 4));
527 bcopy(ptr, &di->dpte, sizeof(di->dpte));
528 }
529 }
14c7c974
A
530 }
531
f083c6c3
A
532 if (di->params.phys_heads == 0 || di->params.phys_spt == 0) {
533 /* Either it's not EBIOS, or EBIOS didn't tell us. */
534 bb.intno = 0x13;
535 bb.eax.r.h = 0x08;
536 bb.edx.r.l = drive;
537 bios(&bb);
538 if (bb.flags.cf == 0 && bb.eax.r.h == 0) {
539 unsigned long cyl;
540 unsigned long sec;
541 unsigned long hds;
542
543 hds = bb.edx.r.h;
544 sec = bb.ecx.r.l & 0x3F;
545 if((dp->uses_ebios & EBIOS_ENHANCED_DRIVE_INFO) && (sec != 0)) {
546 cyl = (di->params.phys_sectors / ((hds + 1) * sec)) - 1;
547 }
548 else {
549 cyl = bb.ecx.r.h | ((bb.ecx.r.l & 0xC0) << 2);
550 }
551 di->params.phys_heads = hds;
552 di->params.phys_spt = sec;
553 di->params.phys_cyls = cyl;
554 } else {
555 ret = -1;
556 }
557 }
558
559 if (dp->no_emulation) {
560 /* Some BIOSes give us erroneous EBIOS support information.
561 * Assume that if you're on a CD, then you can use
562 * EBIOS disk calls.
563 */
564 dp->uses_ebios |= EBIOS_FIXED_DISK_ACCESS;
565 }
566#if DEBUG
567 print_drive_info(di);
568 printf("uses_ebios = 0x%x\n", dp->uses_ebios);
bba600dd 569 printf("result %d\n", ret);
f083c6c3
A
570 printf("press a key->\n");getc();
571#endif
572
573 if (ret == 0) {
574 dp->valid = 1;
14c7c974 575 }
f083c6c3 576 return ret;
14c7c974
A
577}
578
75b89a82 579void setCursorPosition(int x, int y, int page)
14c7c974
A
580{
581 bb.intno = 0x10;
582 bb.eax.r.h = 0x02;
75b89a82 583 bb.ebx.r.h = page; /* page 0 for graphics */
14c7c974
A
584 bb.edx.r.l = x;
585 bb.edx.r.h = y;
586 bios(&bb);
587}
588
75b89a82
A
589void setCursorType(int type)
590{
591 bb.intno = 0x10;
592 bb.eax.r.h = 0x01;
593 bb.ecx.rr = type;
594 bios(&bb);
595}
596
597void getCursorPositionAndType(int * x, int * y, int * type)
598{
599 bb.intno = 0x10;
600 bb.eax.r.h = 0x03;
601 bios(&bb);
602 *x = bb.edx.r.l;
603 *y = bb.edx.r.h;
604 *type = bb.ecx.rr;
605}
606
607void scollPage(int x1, int y1, int x2, int y2, int attr, int rows, int dir)
608{
609 bb.intno = 0x10;
610 bb.eax.r.h = (dir > 0) ? 0x06 : 0x07;
611 bb.eax.r.l = rows;
612 bb.ebx.r.h = attr;
613 bb.ecx.r.h = y1;
614 bb.ecx.r.l = x1;
615 bb.edx.r.h = y2;
616 bb.edx.r.l = x2;
617 bios(&bb);
618}
619
620void clearScreenRows( int y1, int y2 )
621{
622 scollPage( 0, y1, 80 - 1, y2, 0x07, y2 - y1 + 1, 1 );
623}
624
625void setActiveDisplayPage( int page )
626{
627 bb.intno = 0x10;
628 bb.eax.r.h = 5;
629 bb.eax.r.l = page;
630 bios(&bb);
631}
632
14c7c974
A
633#if DEBUG
634
75b89a82
A
635int terminateDiskEmulation()
636{
f083c6c3 637 static char cd_spec[0x13];
75b89a82
A
638
639 bb.intno = 0x13;
640 bb.eax.r.h = 0x4b;
641 bb.eax.r.l = 0; // subfunc: terminate emulation
642 bb.esi.rr = OFFSET((unsigned)&cd_spec);
643 bb.ds = SEGMENT((unsigned)&cd_spec);
644 bios(&bb);
645 return bb.eax.r.h;
646}
647
14c7c974
A
648int readDriveParameters(int drive, struct driveParameters *dp)
649{
650 bb.intno = 0x13;
651 bb.edx.r.l = drive;
652 bb.eax.r.h = 0x08;
653 bios(&bb);
654 if (bb.eax.r.h == 0) {
75b89a82
A
655 dp->heads = bb.edx.r.h;
656 dp->sectors = bb.ecx.r.l & 0x3F;
657 dp->cylinders = bb.ecx.r.h | ((bb.ecx.r.l & 0xC0) << 2);
658 dp->totalDrives = bb.edx.r.l;
14c7c974 659 } else {
75b89a82 660 bzero(dp, sizeof(*dp));
14c7c974
A
661 }
662 return bb.eax.r.h;
663
664}
665#endif
666
57c72a9a
A
667#ifdef APM_SUPPORT
668
75b89a82
A
669#define APM_INTNO 0x15
670#define APM_INTCODE 0x53
14c7c974
A
671
672int
673APMPresent(void)
674{
14c7c974
A
675 bb.intno = APM_INTNO;
676 bb.eax.r.h = APM_INTCODE;
677 bb.eax.r.l = 0x00;
678 bb.ebx.rr = 0x0000;
679 bios(&bb);
680 if ((bb.flags.cf == 0) &&
75b89a82
A
681 (bb.ebx.r.h == 'P') &&
682 (bb.ebx.r.l == 'M')) {
683 /* Success */
f083c6c3
A
684 bootArgs->apmConfig.major_vers = bb.eax.r.h;
685 bootArgs->apmConfig.minor_vers = bb.eax.r.l;
686 bootArgs->apmConfig.flags.data = bb.ecx.rr;
75b89a82 687 return 1;
14c7c974
A
688 }
689 return 0;
690}
691
692int
693APMConnect32(void)
694{
14c7c974
A
695 bb.intno = APM_INTNO;
696 bb.eax.r.h = APM_INTCODE;
697 bb.eax.r.l = 0x03;
698 bb.ebx.rr = 0x0000;
699 bios(&bb);
700 if (bb.flags.cf == 0) {
75b89a82 701 /* Success */
f083c6c3
A
702 bootArgs->apmConfig.cs32_base = (bb.eax.rr) << 4;
703 bootArgs->apmConfig.entry_offset = bb.ebx.rx;
704 bootArgs->apmConfig.cs16_base = (bb.ecx.rr) << 4;
705 bootArgs->apmConfig.ds_base = (bb.edx.rr) << 4;
706 if (bootArgs->apmConfig.major_vers >= 1 &&
707 bootArgs->apmConfig.minor_vers >= 1) {
708 bootArgs->apmConfig.cs_length = bb.esi.rr;
709 bootArgs->apmConfig.ds_length = bb.edi.rr;
75b89a82 710 } else {
f083c6c3
A
711 bootArgs->apmConfig.cs_length =
712 bootArgs->apmConfig.ds_length = 64 * 1024;
75b89a82 713 }
f083c6c3 714 bootArgs->apmConfig.connected = 1;
75b89a82 715 return 1;
14c7c974
A
716 }
717 return 0;
718}
719
57c72a9a
A
720#endif /* APM_SUPPORT */
721
75b89a82 722#ifdef EISA_SUPPORT
14c7c974
A
723BOOL
724eisa_present(
725 void
726)
727{
75b89a82
A
728 static BOOL checked;
729 static BOOL isEISA;
14c7c974
A
730
731 if (!checked) {
75b89a82
A
732 if (strncmp((char *)0xfffd9, "EISA", 4) == 0)
733 isEISA = TRUE;
734
735 checked = TRUE;
14c7c974
A
736 }
737
738 return (isEISA);
739}
740
741int
742ReadEISASlotInfo(EISA_slot_info_t *ep, int slot)
743{
744 union {
75b89a82
A
745 struct {
746 unsigned char char2h :2;
747 unsigned char char1 :5;
748 unsigned char char3 :5;
749 unsigned char char2l :3;
750 unsigned char d2 :4;
751 unsigned char d1 :4;
752 unsigned char d4 :4;
753 unsigned char d3 :4;
754 } s;
755 unsigned char data[4];
14c7c974
A
756 } u;
757 static char hex[0x10] = "0123456789ABCDEF";
75b89a82 758
14c7c974
A
759
760 bb.intno = 0x15;
761 bb.eax.r.h = 0xd8;
762 bb.eax.r.l = 0x00;
763 bb.ecx.r.l = slot;
764 bios(&bb);
765 if (bb.flags.cf)
75b89a82 766 return bb.eax.r.h;
14c7c974
A
767 ep->u_ID.d = bb.eax.r.l;
768 ep->configMajor = bb.ebx.r.h;
769 ep->configMinor = bb.ebx.r.l;
770 ep->checksum = bb.ecx.rr;
771 ep->numFunctions = bb.edx.r.h;
772 ep->u_resources.d = bb.edx.r.l;
773 u.data[0] = bb.edi.r.l;
774 u.data[1] = bb.edi.r.h;
775 u.data[2] = bb.esi.r.l;
776 u.data[3] = bb.esi.r.h;
777 ep->id[0] = u.s.char1 + ('A' - 1);
778 ep->id[1] = (u.s.char2l | (u.s.char2h << 3)) + ('A' - 1);
779 ep->id[2] = u.s.char3 + ('A' - 1);
780 ep->id[3] = hex[u.s.d1];
781 ep->id[4] = hex[u.s.d2];
782 ep->id[5] = hex[u.s.d3];
783 ep->id[6] = hex[u.s.d4];
784 ep->id[7] = 0;
785 return 0;
786}
787
788/*
789 * Note: ep must point to an address below 64k.
790 */
791
792int
793ReadEISAFuncInfo(EISA_func_info_t *ep, int slot, int function)
794{
795 bb.intno = 0x15;
796 bb.eax.r.h = 0xd8;
797 bb.eax.r.l = 0x01;
798 bb.ecx.r.l = slot;
799 bb.ecx.r.h = function;
800 bb.esi.rr = (unsigned int)ep->data;
801 bios(&bb);
802 if (bb.eax.r.h == 0) {
75b89a82
A
803 ep->slot = slot;
804 ep->function = function;
14c7c974
A
805 }
806 return bb.eax.r.h;
807}
75b89a82 808#endif /* EISA_SUPPORT */
14c7c974
A
809
810#define PCI_SIGNATURE 0x20494350 /* "PCI " */
811
812int
813ReadPCIBusInfo(PCI_bus_info_t *pp)
814{
815 bb.intno = 0x1a;
816 bb.eax.r.h = 0xb1;
817 bb.eax.r.l = 0x01;
818 bios(&bb);
819 if ((bb.eax.r.h == 0) && (bb.edx.rx == PCI_SIGNATURE)) {
75b89a82
A
820 pp->BIOSPresent = 1;
821 pp->u_bus.d = bb.eax.r.l;
822 pp->majorVersion = bb.ebx.r.h;
823 pp->minorVersion = bb.ebx.r.l;
824 pp->maxBusNum = bb.ecx.r.l;
825 return 0;
14c7c974
A
826 }
827 return -1;
828}
f083c6c3
A
829
830void sleep(int n)
831{
832 unsigned int endtime = (time18() + 18*n);
833 while (time18() < endtime);
834}
835
836void delay(int ms)
837{
838 bb.intno = 0x15;
839 bb.eax.r.h = 0x86;
840 bb.ecx.rr = ms >> 16;
841 bb.edx.rr = ms & 0xFFFF;
842 bios(&bb);
843}
57c72a9a 844