Chameleon

Chameleon Svn Source Tree

Root/branches/ErmaC/Trunk/i386/libsaio/biosfn.c

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

Archive Download this file

Revision: 2045