Chameleon

Chameleon Svn Source Tree

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

Archive Download this file

Revision: 1984