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