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

Archive Download this file

Revision: 2037