Chameleon

Chameleon Svn Source Tree

Root/branches/mozodojo/i386/libsaio/biosfn.c

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

Archive Download this file

Revision: 755