Chameleon

Chameleon Svn Source Tree

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

Archive Download this file

Revision: 2585