Chameleon

Chameleon Svn Source Tree

Root/branches/azimutz/trunkAutoResolution/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); getc(); //Azi: 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); getc(); //Azi: 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); getc(); //Azi: 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);
512//printf("press a key->\n"); getc(); //Azi: getchar();
513pause();
514#endif
515
516/* Some BIOSes erroneously return cf = 1 */
517/* Just check to see if the drive number is the same. */
518if (pkt.drive_num == drive) {
519if ((pkt.media_type & 0x0F) == 0) {
520/* We are in no-emulation mode. */
521return 1;
522}
523}
524return 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);
534printf("info_flags = %x\n", dp->params.info_flags);
535printf("phys_cyls = %lx\n", dp->params. phys_cyls);
536printf("phys_heads = %lx\n", dp->params. phys_heads);
537printf("phys_spt = %lx\n", dp->params. phys_spt);
538printf("phys_sectors = %lx%lx\n", ((unsigned long *)(&dp->params.phys_sectors))[1],
539 ((unsigned long *)(&dp->params.phys_sectors))[0]);
540printf("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);
553printf("io_port_base = %x\n", dp->dpte.io_port_base);
554printf("control_port_base = %x\n", dp->dpte.control_port_base);
555printf("head_flags = %x\n", dp->dpte. head_flags);
556printf("vendor_info = %x\n", dp->dpte. vendor_info);
557printf("irq = %x\n", dp->dpte. irq);
558//printf("irq_unused = %x\n", dp->dpte. irq_unused);
559printf("block_count = %x\n", dp->dpte. block_count);
560printf("dma_channe = %x\n", dp->dpte. dma_channel);
561printf("dma_type = %x\n", dp->dpte. dma_type);
562printf("pio_type = %x\n", dp->dpte. pio_type);
563printf("pio_unused = %x\n", dp->dpte. pio_unused);
564printf("option_flags = %x\n", dp->dpte.option_flags);
565//printf("reserved = %x\n", dp->dpte.reserved);
566printf("revision = %x\n", dp->dpte. revision);
567//printf("checksum = %x\n", dp->dpte. checksum);
568}
569
570#endif
571
572int get_drive_info(int drive, struct driveInfo *dp)
573{
574boot_drive_info_t *di = &dp->di;
575int ret = 0;
576
577#if UNUSED
578if (maxhd == 0) {
579bb.intno = 0x13;
580bb.eax.r.h = 0x08;
581bb.edx.r.l = 0x80;
582bios(&bb);
583if (bb.flags.cf == 0)
584maxhd = 0x7f + bb.edx.r.l;
585};
586
587if (drive > maxhd)
588return 0;
589#endif
590
591bzero(dp, sizeof(struct driveInfo));
592dp->biosdev = drive;
593
594/* Check for El Torito no-emulation mode. */
595dp->no_emulation = is_no_emulation(drive);
596
597/* Check drive for EBIOS support. */
598bb.intno = 0x13;
599bb.eax.r.h = 0x41;
600bb.edx.r.l = drive;
601bb.ebx.rr = 0x55aa;
602bios(&bb);
603
604if ((bb.ebx.rr == 0xaa55) && (bb.flags.cf == 0)) {
605/* Get flags for supported operations. */
606dp->uses_ebios = bb.ecx.r.l;
607}
608
609if (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
613params.buf_size = sizeof(params);
614bb.intno = 0x13;
615bb.eax.r.h = 0x48;
616bb.edx.r.l = drive;
617bb.esi.rr = NORMALIZED_OFFSET((unsigned)&params);
618bb.ds = NORMALIZED_SEGMENT((unsigned)&params);
619bios(&bb);
620
621if (bb.flags.cf != 0 /* || params.phys_sectors < 2097152 */) {
622dp->uses_ebios = 0;
623di->params.buf_size = 1;
624}
625else
626{
627bcopy(&params, &di->params, sizeof(params));
628
629if (drive >= BASE_HD_DRIVE &&
630(dp->uses_ebios & EBIOS_ENHANCED_DRIVE_INFO) &&
631di->params.buf_size >= 30 &&
632!(di->params.dpte_offset == 0xFFFF && di->params.dpte_segment == 0xFFFF)) {
633void *ptr = (void *)(di->params.dpte_offset + ((unsigned int)di->params.dpte_segment << 4));
634bcopy(ptr, &di->dpte, sizeof(di->dpte));
635}
636}
637}
638
639/*
640 * zef: This code will fail on recent JMicron and Intel option ROMs
641 */
642//if (di->params.phys_heads == 0 || di->params.phys_spt == 0) {
643///* Either it's not EBIOS, or EBIOS didn't tell us. */
644//bb.intno = 0x13;
645//bb.eax.r.h = 0x08;
646//bb.edx.r.l = drive;
647//bios(&bb);
648//if (bb.flags.cf == 0 && bb.eax.r.h == 0) {
649//unsigned long cyl;
650//unsigned long sec;
651//unsigned long hds;
652//
653//hds = bb.edx.r.h;
654//sec = bb.ecx.r.l & 0x3F;
655//if ((dp->uses_ebios & EBIOS_ENHANCED_DRIVE_INFO) && (sec != 0)) {
656//cyl = (di->params.phys_sectors / ((hds + 1) * sec)) - 1;
657//} else {
658//cyl = bb.ecx.r.h | ((bb.ecx.r.l & 0xC0) << 2);
659//}
660//di->params.phys_heads = hds;
661//di->params.phys_spt = sec;
662//di->params.phys_cyls = cyl;
663//} else {
664//ret = -1;
665//}
666//}
667
668if (dp->no_emulation) {
669/* Some BIOSes give us erroneous EBIOS support information.
670 * Assume that if you're on a CD, then you can use
671 * EBIOS disk calls.
672 */
673dp->uses_ebios |= EBIOS_FIXED_DISK_ACCESS;
674}
675#if DEBUG
676print_drive_info(di);
677printf("uses_ebios = 0x%x\n", dp->uses_ebios);
678printf("result %d\n", ret);
679//printf("press a key->\n"); getc(); //Azi: getchar();
680pause();
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: 1022