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

Archive Download this file

Revision: 1119