Chameleon

Chameleon Svn Source Tree

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

Archive Download this file

Revision: 994