Chameleon

Chameleon Svn Source Tree

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

Archive Download this file

Revision: 20