Chameleon

Chameleon Svn Source Tree

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

Archive Download this file

Revision: 2839