Chameleon

Chameleon Svn Source Tree

Root/branches/azimutz/trunkGraphicsEnablerModules/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 "bootstruct.h"
44#include "libsaio.h"
45
46
47#define MAX_DRIVES 8
48
49static biosBuf_t bb;
50
51int bgetc(void)
52{
53 /* Poll for the next character. Most real BIOS do not need this as the
54 INT 16h,AH=0h function will block until one is received.
55 Unfortunately, Apple's EFI CSM will never wake up. This idea is lifted
56 from the grub-a20.patch to GRUB's stage2/asm.S file.
57 */
58 while(!readKeyboardStatus())
59 ;
60 bb.intno = 0x16;
61 bb.eax.r.h = 0x00;
62 bios(&bb);
63 return bb.eax.rr;
64}
65
66int readKeyboardStatus(void)
67{
68 bb.intno = 0x16;
69 bb.eax.r.h = 0x01;
70 bios(&bb);
71 if (bb.flags.zf) {
72 return 0;
73 } else {
74 return bb.eax.rr;
75 }
76}
77
78int readKeyboardShiftFlags(void)
79{
80 bb.intno = 0x16;
81 bb.eax.r.h = 0x02;
82 bios(&bb);
83 return bb.eax.r.l;
84}
85
86unsigned int time18(void)
87{
88 union {
89 struct {
90 unsigned int low:16;
91 unsigned int high:16;
92 } s;
93 unsigned int i;
94 } time;
95
96 bb.intno = 0x1a;
97 bb.eax.r.h = 0x00;
98 bios(&bb);
99 time.s.low = bb.edx.rr;
100 time.s.high = bb.ecx.rr;
101 return time.i;
102}
103
104#if 0
105static unsigned long rerangeMemoryMap(unsigned long count)
106{
107int i, still_changing, newcount = count;
108
109MemoryRange * range = (MemoryRange *)BIOS_ADDR;
110struct MemoryRange change_tmp;
111
112/* sort map list by memory addresses (low -> high) */
113still_changing = 1;
114while (still_changing) {
115still_changing = 0;
116for (i=1; i<count; i++) {
117/* if <current_addr> > <last_addr>, swap */
118if (range[i].base < range[i-1].base) {
119change_tmp.base = range[i].base;
120change_tmp.length = range[i].length;
121change_tmp.type = range[i].type;
122
123range[i].base = range[i-1].base;
124range[i].length = range[i-1].length;
125range[i].type = range[i-1].type;
126
127range[i-1].base = change_tmp.base;
128range[i-1].length = change_tmp.length;
129range[i-1].type = change_tmp.type;
130
131still_changing=1;
132}
133}
134}
135
136/* clear overlaps */
137/* linux's arch/i386/kern/setup.c may have better algorithm */
138for (i=1; i<count; i++) {
139if ( range[i-1].base + range[i-1].length > range[i].base ) {
140range[newcount].base = range[i].base + range[i].length;
141range[newcount].length = range[i-1].base + range[i-1].length - range[newcount].base;
142range[newcount].type = range[i-1].type;
143newcount++;
144
145range[i-1].length = range[i].base - range[i-1].base;
146}
147}
148
149/*
150 * 0xb0000000 : 0x10000000 NG
151 * 0xc0000400 NG
152 * 0xf2000000 NG
153 */
154range[newcount].base = 0xb0000000;
155range[newcount].length = 0x0f000000;
156range[newcount].type = kMemoryRangeUsable;
157newcount++;
158
159return newcount;
160}
161#endif
162
163unsigned long getMemoryMap( MemoryRange * rangeArray,
164 unsigned long maxRangeCount,
165 unsigned long * conMemSizePtr,
166 unsigned long * extMemSizePtr )
167{
168 #define kMemoryMapSignature 'SMAP'
169 #define kDescriptorSizeMin 20
170
171 MemoryRange *range = (MemoryRange *)BIOS_ADDR;
172 unsigned longcount = 0;
173 // unsigned longrerangedCount;
174 unsigned long longconMemSize = 0;
175 unsigned long longextMemSize = 0;
176
177 // Prepare for the INT15 E820h call. Each call returns a single
178 // memory range. A continuation value is returned that must be
179 // provided on a subsequent call to fetch the next range.
180 //
181 // Certain BIOSes (Award 6.00PG) expect the upper word in EAX
182 // to be cleared on entry, otherwise only a single range will
183 // be reported.
184 //
185 // Some BIOSes will simply ignore the value of ECX on entry.
186 // Probably best to keep its value at 20 to avoid surprises.
187
188 //printf("Get memory map 0x%x, %d\n", rangeArray); getchar();
189 if (maxRangeCount > (BIOS_LEN / sizeof(MemoryRange))) {
190 maxRangeCount = (BIOS_LEN / sizeof(MemoryRange));
191 }
192 bb.ebx.rx = 0; // Initial continuation value must be zero.
193
194 while ( count < maxRangeCount )
195 {
196 bb.intno = 0x15;
197 bb.eax.rx = 0xe820;
198 bb.ecx.rx = kDescriptorSizeMin;
199 bb.edx.rx = kMemoryMapSignature;
200 bb.edi.rr = NORMALIZED_OFFSET( (unsigned long) range );
201 bb.es = NORMALIZED_SEGMENT( (unsigned long) range );
202 bios(&bb);
203
204 // Check for errors.
205
206 if ( bb.flags.cf
207 || bb.eax.rx != kMemoryMapSignature
208 || bb.ecx.rx != kDescriptorSizeMin ) {
209 //printf("Got an error %x %x %x\n", bb.flags.cf,
210 // bb.eax.rx, bb.ecx.rx);
211 break;
212 }
213
214 // Tally up the conventional/extended memory sizes.
215
216 if ( range->type == kMemoryRangeUsable ||
217 range->type == kMemoryRangeACPI ||
218 range->type == kMemoryRangeNVS )
219 {
220 // Tally the conventional memory ranges.
221 if ( range->base + range->length <= 0xa0000 ) {
222 conMemSize += range->length;
223 }
224
225 // Record the top of extended memory.
226 if ( range->base >= EXTENDED_ADDR ) {
227 extMemSize += range->length;
228 }
229 }
230
231 range++;
232 count++;
233
234 // Is this the last address range?
235
236 if ( bb.ebx.rx == 0 ) {
237 //printf("last range\n");
238 break;
239 }
240 }
241 *conMemSizePtr = conMemSize / 1024; // size in KB
242 *extMemSizePtr = extMemSize / 1024; // size in KB
243
244#if 0
245 rerangedCount = rerangeMemoryMap(count);
246 range += rerangedCount - count;
247#endif
248
249 // Copy out data
250 bcopy((char *)BIOS_ADDR, rangeArray, ((char *)range - (char *)BIOS_ADDR));
251
252#if DEBUG
253 {
254 int i;
255 printf("%d total ranges\n", count); getchar();
256 for (i=0, range = rangeArray; i<count; i++, range++) {
257 printf("range: type %d, base 0x%x, length 0x%x\n",
258 range->type, (unsigned int)range->base, (unsigned int)range->length); getchar();
259 }
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 bios_putchar(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{
475struct 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));
490static struct packet pkt;
491
492bzero(&pkt, sizeof(pkt));
493pkt.packet_size = 0x13;
494
495bb.intno= 0x13;
496bb.eax.r.h= 0x4b;
497bb.eax.r.l= 0x01; // subfunc: get info
498bb.edx.r.l= drive;
499bb.esi.rr= NORMALIZED_OFFSET((unsigned)&pkt);
500bb.ds= NORMALIZED_SEGMENT((unsigned)&pkt);
501
502bios(&bb);
503#if DEBUG
504printf("el_torito info drive %x\n", drive);
505
506printf("--> cf %x, eax %x\n", bb.flags.cf, bb.eax.rr);
507
508printf("pkt_size: %x\n", pkt.packet_size);
509printf("media_type: %x\n", pkt.media_type);
510printf("drive_num: %x\n", pkt.drive_num);
511printf("device_spec: %x\n", pkt.device_spec);
512printf("press a key->\n"); getchar();
513#endif
514
515/* Some BIOSes erroneously return cf = 1 */
516/* Just check to see if the drive number is the same. */
517if (pkt.drive_num == drive) {
518if ((pkt.media_type & 0x0F) == 0) {
519/* We are in no-emulation mode. */
520return 1;
521}
522}
523return 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);
533printf("info_flags = %x\n", dp->params.info_flags);
534printf("phys_cyls = %lx\n", dp->params. phys_cyls);
535printf("phys_heads = %lx\n", dp->params. phys_heads);
536printf("phys_spt = %lx\n", dp->params. phys_spt);
537printf("phys_sectors = %lx%lx\n", ((unsigned long *)(&dp->params.phys_sectors))[1],
538 ((unsigned long *)(&dp->params.phys_sectors))[0]);
539printf("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);
552printf("io_port_base = %x\n", dp->dpte.io_port_base);
553printf("control_port_base = %x\n", dp->dpte.control_port_base);
554printf("head_flags = %x\n", dp->dpte. head_flags);
555printf("vendor_info = %x\n", dp->dpte. vendor_info);
556printf("irq = %x\n", dp->dpte. irq);
557//printf("irq_unused = %x\n", dp->dpte. irq_unused);
558printf("block_count = %x\n", dp->dpte. block_count);
559printf("dma_channe = %x\n", dp->dpte. dma_channel);
560printf("dma_type = %x\n", dp->dpte. dma_type);
561printf("pio_type = %x\n", dp->dpte. pio_type);
562printf("pio_unused = %x\n", dp->dpte. pio_unused);
563printf("option_flags = %x\n", dp->dpte.option_flags);
564//printf("reserved = %x\n", dp->dpte.reserved);
565printf("revision = %x\n", dp->dpte. revision);
566//printf("checksum = %x\n", dp->dpte. checksum);
567}
568
569#endif
570
571int get_drive_info(int drive, struct driveInfo *dp)
572{
573boot_drive_info_t *di = &dp->di;
574int ret = 0;
575
576#if UNUSED
577if (maxhd == 0) {
578bb.intno = 0x13;
579bb.eax.r.h = 0x08;
580bb.edx.r.l = 0x80;
581bios(&bb);
582if (bb.flags.cf == 0)
583maxhd = 0x7f + bb.edx.r.l;
584};
585
586if (drive > maxhd)
587return 0;
588#endif
589
590bzero(dp, sizeof(struct driveInfo));
591dp->biosdev = drive;
592
593/* Check for El Torito no-emulation mode. */
594dp->no_emulation = is_no_emulation(drive);
595
596/* Check drive for EBIOS support. */
597bb.intno = 0x13;
598bb.eax.r.h = 0x41;
599bb.edx.r.l = drive;
600bb.ebx.rr = 0x55aa;
601bios(&bb);
602
603if ((bb.ebx.rr == 0xaa55) && (bb.flags.cf == 0)) {
604/* Get flags for supported operations. */
605dp->uses_ebios = bb.ecx.r.l;
606}
607
608if (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
612params.buf_size = sizeof(params);
613bb.intno = 0x13;
614bb.eax.r.h = 0x48;
615bb.edx.r.l = drive;
616bb.esi.rr = NORMALIZED_OFFSET((unsigned)&params);
617bb.ds = NORMALIZED_SEGMENT((unsigned)&params);
618bios(&bb);
619
620if (bb.flags.cf != 0 /* || params.phys_sectors < 2097152 */) {
621dp->uses_ebios = 0;
622di->params.buf_size = 1;
623}
624else
625{
626bcopy(&params, &di->params, sizeof(params));
627
628if (drive >= BASE_HD_DRIVE &&
629(dp->uses_ebios & EBIOS_ENHANCED_DRIVE_INFO) &&
630di->params.buf_size >= 30 &&
631!(di->params.dpte_offset == 0xFFFF && di->params.dpte_segment == 0xFFFF)) {
632void *ptr = (void *)(di->params.dpte_offset + ((unsigned int)di->params.dpte_segment << 4));
633bcopy(ptr, &di->dpte, sizeof(di->dpte));
634}
635}
636}
637
638/*
639 * zef: This code will fail on recent JMicron and Intel option ROMs
640 */
641//if (di->params.phys_heads == 0 || di->params.phys_spt == 0) {
642///* Either it's not EBIOS, or EBIOS didn't tell us. */
643//bb.intno = 0x13;
644//bb.eax.r.h = 0x08;
645//bb.edx.r.l = drive;
646//bios(&bb);
647//if (bb.flags.cf == 0 && bb.eax.r.h == 0) {
648//unsigned long cyl;
649//unsigned long sec;
650//unsigned long hds;
651//
652//hds = bb.edx.r.h;
653//sec = bb.ecx.r.l & 0x3F;
654//if ((dp->uses_ebios & EBIOS_ENHANCED_DRIVE_INFO) && (sec != 0)) {
655//cyl = (di->params.phys_sectors / ((hds + 1) * sec)) - 1;
656//} else {
657//cyl = bb.ecx.r.h | ((bb.ecx.r.l & 0xC0) << 2);
658//}
659//di->params.phys_heads = hds;
660//di->params.phys_spt = sec;
661//di->params.phys_cyls = cyl;
662//} else {
663//ret = -1;
664//}
665//}
666
667if (dp->no_emulation) {
668/* Some BIOSes give us erroneous EBIOS support information.
669 * Assume that if you're on a CD, then you can use
670 * EBIOS disk calls.
671 */
672dp->uses_ebios |= EBIOS_FIXED_DISK_ACCESS;
673}
674#if DEBUG
675print_drive_info(di);
676printf("uses_ebios = 0x%x\n", dp->uses_ebios);
677printf("result %d\n", ret);
678printf("press a key->\n"); getchar();
679#endif
680
681if (ret == 0) {
682dp->valid = 1;
683}
684return ret;
685}
686
687int ebiosEjectMedia(int biosdev)
688{
689 bb.intno = 0x13;
690 bb.eax.r.h = 0x46;
691 bb.eax.r.l = 0;
692 bb.edx.rx = biosdev;
693 bios(&bb);
694 return bb.eax.r.h;
695}
696
697void setCursorPosition(int x, int y, int page)
698{
699 bb.intno = 0x10;
700 bb.eax.r.h = 0x02;
701 bb.ebx.r.h = page; /* page 0 for graphics */
702 bb.edx.r.l = x;
703 bb.edx.r.h = y;
704 bios(&bb);
705}
706
707void setCursorType(int type)
708{
709 bb.intno = 0x10;
710 bb.eax.r.h = 0x01;
711 bb.ecx.rr = type;
712 bios(&bb);
713}
714
715void getCursorPositionAndType(int * x, int * y, int * type)
716{
717 bb.intno = 0x10;
718 bb.eax.r.h = 0x03;
719 bios(&bb);
720 *x = bb.edx.r.l;
721 *y = bb.edx.r.h;
722 *type = bb.ecx.rr;
723}
724
725void scollPage(int x1, int y1, int x2, int y2, int attr, int rows, int dir)
726{
727 bb.intno = 0x10;
728 bb.eax.r.h = (dir > 0) ? 0x06 : 0x07;
729 bb.eax.r.l = rows;
730 bb.ebx.r.h = attr;
731 bb.ecx.r.h = y1;
732 bb.ecx.r.l = x1;
733 bb.edx.r.h = y2;
734 bb.edx.r.l = x2;
735 bios(&bb);
736}
737
738void clearScreenRows( int y1, int y2 )
739{
740 scollPage( 0, y1, 80 - 1, y2, 0x07, y2 - y1 + 1, 1 );
741}
742
743void setActiveDisplayPage( int page )
744{
745 bb.intno = 0x10;
746 bb.eax.r.h = 5;
747 bb.eax.r.l = page;
748 bios(&bb);
749}
750
751#if DEBUG
752
753int terminateDiskEmulation()
754{
755 static char cd_spec[0x13];
756
757 bb.intno = 0x13;
758 bb.eax.r.h = 0x4b;
759 bb.eax.r.l = 0; // subfunc: terminate emulation
760 bb.esi.rr = NORMALIZED_OFFSET((unsigned)&cd_spec);
761 bb.ds = NORMALIZED_SEGMENT((unsigned)&cd_spec);
762 bios(&bb);
763 return bb.eax.r.h;
764}
765
766int readDriveParameters(int drive, struct driveParameters *dp)
767{
768 bb.intno = 0x13;
769 bb.edx.r.l = drive;
770 bb.eax.r.h = 0x08;
771 bios(&bb);
772 if (bb.eax.r.h == 0) {
773 dp->heads = bb.edx.r.h;
774 dp->sectors = bb.ecx.r.l & 0x3F;
775 dp->cylinders = bb.ecx.r.h | ((bb.ecx.r.l & 0xC0) << 2);
776 dp->totalDrives = bb.edx.r.l;
777 } else {
778 bzero(dp, sizeof(*dp));
779 }
780 return bb.eax.r.h;
781
782}
783#endif
784
785#ifdef APM_SUPPORT
786
787#define APM_INTNO 0x15
788#define APM_INTCODE 0x53
789
790int
791APMPresent(void)
792{
793 bb.intno = APM_INTNO;
794 bb.eax.r.h = APM_INTCODE;
795 bb.eax.r.l = 0x00;
796 bb.ebx.rr = 0x0000;
797 bios(&bb);
798 if ((bb.flags.cf == 0) &&
799 (bb.ebx.r.h == 'P') &&
800 (bb.ebx.r.l == 'M')) {
801 /* Success */
802 bootArgs->apmConfig.major_vers = bb.eax.r.h;
803 bootArgs->apmConfig.minor_vers = bb.eax.r.l;
804 bootArgs->apmConfig.flags.data = bb.ecx.rr;
805 return 1;
806 }
807 return 0;
808}
809
810int
811APMConnect32(void)
812{
813 bb.intno = APM_INTNO;
814 bb.eax.r.h = APM_INTCODE;
815 bb.eax.r.l = 0x03;
816 bb.ebx.rr = 0x0000;
817 bios(&bb);
818 if (bb.flags.cf == 0) {
819 /* Success */
820 bootArgs->apmConfig.cs32_base = (bb.eax.rr) << 4;
821 bootArgs->apmConfig.entry_offset = bb.ebx.rx;
822 bootArgs->apmConfig.cs16_base = (bb.ecx.rr) << 4;
823 bootArgs->apmConfig.ds_base = (bb.edx.rr) << 4;
824 if (bootArgs->apmConfig.major_vers >= 1 &&
825 bootArgs->apmConfig.minor_vers >= 1) {
826 bootArgs->apmConfig.cs_length = bb.esi.rr;
827 bootArgs->apmConfig.ds_length = bb.edi.rr;
828 } else {
829 bootArgs->apmConfig.cs_length =
830 bootArgs->apmConfig.ds_length = 64 * 1024;
831 }
832 bootArgs->apmConfig.connected = 1;
833 return 1;
834 }
835 return 0;
836}
837
838#endif /* APM_SUPPORT */
839
840#ifdef EISA_SUPPORT
841bool eisa_present(void)
842{
843 static bool checked = false;
844 static bool isEISA;
845
846 if (!checked) {
847 if (strncmp((char *)0xfffd9, "EISA", 4) == 0)
848 isEISA = true;
849
850 checked = true;
851 }
852
853 return (isEISA);
854}
855
856int
857ReadEISASlotInfo(EISA_slot_info_t *ep, int slot)
858{
859 union {
860 struct {
861 unsigned char char2h :2;
862 unsigned char char1 :5;
863 unsigned char char3 :5;
864 unsigned char char2l :3;
865 unsigned char d2 :4;
866 unsigned char d1 :4;
867 unsigned char d4 :4;
868 unsigned char d3 :4;
869 } s;
870 unsigned char data[4];
871 } u;
872 static char hex[0x10] = "0123456789ABCDEF";
873
874
875 bb.intno = 0x15;
876 bb.eax.r.h = 0xd8;
877 bb.eax.r.l = 0x00;
878 bb.ecx.r.l = slot;
879 bios(&bb);
880 if (bb.flags.cf)
881 return bb.eax.r.h;
882 ep->u_ID.d = bb.eax.r.l;
883 ep->configMajor = bb.ebx.r.h;
884 ep->configMinor = bb.ebx.r.l;
885 ep->checksum = bb.ecx.rr;
886 ep->numFunctions = bb.edx.r.h;
887 ep->u_resources.d = bb.edx.r.l;
888 u.data[0] = bb.edi.r.l;
889 u.data[1] = bb.edi.r.h;
890 u.data[2] = bb.esi.r.l;
891 u.data[3] = bb.esi.r.h;
892 ep->id[0] = u.s.char1 + ('A' - 1);
893 ep->id[1] = (u.s.char2l | (u.s.char2h << 3)) + ('A' - 1);
894 ep->id[2] = u.s.char3 + ('A' - 1);
895 ep->id[3] = hex[u.s.d1];
896 ep->id[4] = hex[u.s.d2];
897 ep->id[5] = hex[u.s.d3];
898 ep->id[6] = hex[u.s.d4];
899 ep->id[7] = 0;
900 return 0;
901}
902
903/*
904 * Note: ep must point to an address below 64k.
905 */
906
907int
908ReadEISAFuncInfo(EISA_func_info_t *ep, int slot, int function)
909{
910 bb.intno = 0x15;
911 bb.eax.r.h = 0xd8;
912 bb.eax.r.l = 0x01;
913 bb.ecx.r.l = slot;
914 bb.ecx.r.h = function;
915 bb.esi.rr = (unsigned int)ep->data;
916 bios(&bb);
917 if (bb.eax.r.h == 0) {
918 ep->slot = slot;
919 ep->function = function;
920 }
921 return bb.eax.r.h;
922}
923#endif /* EISA_SUPPORT */
924
925#define PCI_SIGNATURE 0x20494350 /* "PCI " */
926
927int
928ReadPCIBusInfo(PCI_bus_info_t *pp)
929{
930 bb.intno = 0x1a;
931 bb.eax.r.h = 0xb1;
932 bb.eax.r.l = 0x01;
933 bios(&bb);
934 if ((bb.eax.r.h == 0) && (bb.edx.rx == PCI_SIGNATURE)) {
935 pp->BIOSPresent = 1;
936 pp->u_bus.d = bb.eax.r.l;
937 pp->majorVersion = bb.ebx.r.h;
938 pp->minorVersion = bb.ebx.r.l;
939 pp->maxBusNum = bb.ecx.r.l;
940 return 0;
941 }
942 return -1;
943}
944
945void sleep(int n)
946{
947 unsigned int endtime = (time18() + 18*n);
948 while (time18() < endtime);
949}
950
951void delay(int ms)
952{
953 bb.intno = 0x15;
954 bb.eax.r.h = 0x86;
955 bb.ecx.rr = ms >> 16;
956 bb.edx.rr = ms & 0xFFFF;
957 bios(&bb);
958}
959
960

Archive Download this file

Revision: 1009