Chameleon

Chameleon Svn Source Tree

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

Archive Download this file

Revision: 399