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/* 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 /* COMMENTED */
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 /* COMMENTED */
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;
186unsigned 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 /* COMMENTED */
257rerangedCount = rerangeMemoryMap(count);
258range += rerangedCount - count;
259//#endif /* COMMENTED */
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}
399
400return bb.eax.r.h;
401}
402
403
404//==============================================================================
405
406int ebiosread(int dev, unsigned long long sec, int count)
407{
408int i;
409
410static struct {
411unsigned char size;
412unsigned char reserved;
413unsigned char numblocks;
414unsigned char reserved2;
415unsigned short bufferOffset;
416unsigned short bufferSegment;
417unsigned long long startblock;
418} addrpacket __attribute__((aligned(16))) = {0};
419addrpacket.size = sizeof(addrpacket);
420
421for (i = 0; ;) {
422bb.intno = 0x13;
423bb.eax.r.h = 0x42;
424bb.edx.r.l = dev;
425bb.esi.rr = NORMALIZED_OFFSET((unsigned)&addrpacket);
426bb.ds = NORMALIZED_SEGMENT((unsigned)&addrpacket);
427addrpacket.reserved = addrpacket.reserved2 = 0;
428addrpacket.numblocks = count;
429addrpacket.bufferOffset = OFFSET(ptov(BIOS_ADDR));
430addrpacket.bufferSegment = SEGMENT(ptov(BIOS_ADDR));
431addrpacket.startblock = sec;
432bios(&bb);
433
434// In case of a successful call, make sure we set AH (return code) to zero.
435if (bb.flags.cf == 0) {
436bb.eax.r.h = 0;
437}
438
439// Now we can really check for the return code (AH) value.
440if ((bb.eax.r.h == 0x00) || (i++ >= 5)) {
441break;
442}
443
444// Reset disk subsystem and try again.
445bb.eax.r.h = 0x00;
446bios(&bb);
447}
448
449return bb.eax.r.h;
450}
451
452//==============================================================================
453
454int ebioswrite(int dev, long sec, int count)
455{
456int i;
457static struct {
458unsigned char size;
459unsigned char reserved;
460unsigned char numblocks;
461unsigned char reserved2;
462unsigned short bufferOffset;
463unsigned short bufferSegment;
464unsigned long long startblock;
465} addrpacket __attribute__((aligned(16))) = {0};
466addrpacket.size = sizeof(addrpacket);
467
468for (i=0;;) {
469bb.intno = 0x13;
470bb.eax.r.l = 0; /* Don't verify */
471bb.eax.r.h = 0x43;
472bb.edx.r.l = dev;
473bb.esi.rr = NORMALIZED_OFFSET((unsigned)&addrpacket);
474bb.ds = NORMALIZED_SEGMENT((unsigned)&addrpacket);
475addrpacket.reserved = addrpacket.reserved2 = 0;
476addrpacket.numblocks = count;
477addrpacket.bufferOffset = OFFSET(ptov(BIOS_ADDR));
478addrpacket.bufferSegment = SEGMENT(ptov(BIOS_ADDR));
479addrpacket.startblock = sec;
480bios(&bb);
481
482/* In case of a successful call, make sure we set AH (return code) to zero. */
483if (bb.flags.cf == 0)
484bb.eax.r.h = 0;
485
486/* Now we can really check for the return code (AH) value. */
487if ((bb.eax.r.h == 0x00) || (i++ >= 5))
488break;
489
490/* reset disk subsystem and try again */
491bb.eax.r.h = 0x00;
492bios(&bb);
493}
494return bb.eax.r.h;
495}
496
497void bios_putchar(int ch)
498{
499bb.intno = 0x10;
500bb.ebx.r.h = 0x00; /* background black */
501bb.ebx.r.l = 0x0F; /* foreground white */
502bb.eax.r.h = 0x0e;
503bb.eax.r.l = ch;
504bios(&bb);
505}
506
507
508//==============================================================================
509
510void putca(int ch, int attr, int repeat)
511{
512bb.intno = 0x10;
513bb.ebx.r.h = 0x00; /* page number */
514bb.ebx.r.l = attr; /* attribute */
515bb.eax.r.h = 0x9;
516bb.eax.r.l = ch;
517bb.ecx.rx = repeat; /* repeat count */
518bios(&bb);
519}
520
521
522//==============================================================================
523// Check to see if the passed-in drive is in El Torito no-emulation mode.
524
525int is_no_emulation(int drive)
526{
527struct packet {
528unsigned char packet_size;
529unsigned char media_type;
530unsigned char drive_num;
531unsigned char ctrlr_index;
532unsigned long lba;
533unsigned short device_spec;
534unsigned short buffer_segment;
535unsigned short load_segment;
536unsigned short sector_count;
537unsigned char cyl_count;
538unsigned char sec_count;
539unsigned char head_count;
540unsigned char reseved;
541} __attribute__((packed));
542static struct packet pkt;
543
544bzero(&pkt, sizeof(pkt));
545pkt.packet_size = 0x13;
546
547bb.intno = 0x13;
548bb.eax.r.h = 0x4b;
549bb.eax.r.l = 0x01; // subfunc: get info
550bb.edx.r.l = drive;
551bb.esi.rr = NORMALIZED_OFFSET((unsigned)&pkt);
552bb.ds = NORMALIZED_SEGMENT((unsigned)&pkt);
553
554bios(&bb);
555
556#if DEBUG
557printf("el_torito info drive %x\n", drive);
558printf("--> cf %x, eax %x\n", bb.flags.cf, bb.eax.rr);
559printf("pkt_size: %x\n", pkt.packet_size);
560printf("media_type: %x\n", pkt.media_type);
561printf("drive_num: %x\n", pkt.drive_num);
562printf("device_spec: %x\n", pkt.device_spec);
563
564pause();
565#endif
566
567/* Some BIOSes erroneously return cf = 1 */
568/* Just check to see if the drive number is the same. */
569if (pkt.drive_num == drive) {
570if ((pkt.media_type & 0x0F) == 0) {
571/* We are in no-emulation mode. */
572return 1;
573}
574}
575return 0;
576}
577
578#if DEBUG
579/*
580 * BIOS drive information.
581 */
582void print_drive_info(boot_drive_info_t *dp)
583{
584//printf("buf_size = %x\n", dp->params.buf_size);
585printf("info_flags = %x\n", dp->params.info_flags);
586printf("phys_cyls = %lx\n", dp->params. phys_cyls);
587printf("phys_heads = %lx\n", dp->params. phys_heads);
588printf("phys_spt = %lx\n", dp->params. phys_spt);
589printf("phys_sectors = %lx%lx\n", ((unsigned long *)(&dp->params.phys_sectors))[1],
590 ((unsigned long *)(&dp->params.phys_sectors))[0]);
591printf("phys_nbps = %x\n", dp->params.phys_nbps);
592//printf("dpte_offset = %x\n", dp->params.dpte_offset);
593//printf("dpte_segment = %x\n", dp->params.dpte_segment);
594//printf("key = %x\n", dp->params.key);
595//printf("path_len = %x\n", dp->params. path_len);
596//printf("reserved1 = %x\n", dp->params. reserved1);
597//printf("reserved2 = %x\n", dp->params.reserved2);
598//printf("bus_type[4] = %x\n", dp->params. bus_type[4]);
599//printf("interface_type[8] = %x\n", dp->params. interface_type[8]);
600//printf("interface_path[8] = %x\n", dp->params. interface_path[8]);
601//printf("dev_path[8] = %x\n", dp->params. dev_path[8]);
602//printf("reserved3 = %x\n", dp->params. reserved3);
603//printf("checksum = %x\n", dp->params. checksum);
604printf("io_port_base = %x\n", dp->dpte.io_port_base);
605printf("control_port_base = %x\n", dp->dpte.control_port_base);
606printf("head_flags = %x\n", dp->dpte. head_flags);
607printf("vendor_info = %x\n", dp->dpte. vendor_info);
608printf("irq = %x\n", dp->dpte. irq);
609//printf("irq_unused = %x\n", dp->dpte. irq_unused);
610printf("block_count = %x\n", dp->dpte. block_count);
611printf("dma_channe = %x\n", dp->dpte. dma_channel);
612printf("dma_type = %x\n", dp->dpte. dma_type);
613printf("pio_type = %x\n", dp->dpte. pio_type);
614printf("pio_unused = %x\n", dp->dpte. pio_unused);
615printf("option_flags = %x\n", dp->dpte.option_flags);
616//printf("reserved = %x\n", dp->dpte.reserved);
617printf("revision = %x\n", dp->dpte. revision);
618//printf("checksum = %x\n", dp->dpte. checksum);
619}
620
621#endif
622
623//==============================================================================
624
625int get_drive_info(int drive, struct driveInfo *dp)
626{
627int ret = 0;
628
629boot_drive_info_t *di = &dp->di;
630
631#if UNUSED
632if (maxhd == 0) {
633bb.intno = 0x13;
634bb.eax.r.h = 0x08;
635bb.edx.r.l = 0x80;
636bios(&bb);
637
638if (bb.flags.cf == 0) {
639maxhd = 0x7f + bb.edx.r.l;
640}
641};
642
643if (drive > maxhd) {
644return 0;
645}
646#endif
647
648bzero(dp, sizeof(struct driveInfo));
649dp->biosdev = drive;
650
651/* Check for El Torito no-emulation mode. */
652dp->no_emulation = is_no_emulation(drive);
653
654/* Check drive for EBIOS support. */
655bb.intno = 0x13;
656bb.eax.r.h = 0x41;
657bb.edx.r.l = drive;
658bb.ebx.rr = 0x55aa;
659bios(&bb);
660
661if ((bb.ebx.rr == 0xaa55) && (bb.flags.cf == 0)) {
662/* Get flags for supported operations. */
663dp->uses_ebios = bb.ecx.r.l;
664}
665
666if (dp->uses_ebios & (EBIOS_ENHANCED_DRIVE_INFO | EBIOS_LOCKING_ACCESS | EBIOS_FIXED_DISK_ACCESS)) {
667/* Get EBIOS drive info. */
668static struct drive_params params;
669
670params.buf_size = sizeof(params);
671bb.intno = 0x13;
672bb.eax.r.h = 0x48;
673bb.edx.r.l = drive;
674bb.esi.rr = NORMALIZED_OFFSET((unsigned)&params);
675bb.ds = NORMALIZED_SEGMENT((unsigned)&params);
676bios(&bb);
677
678if (bb.flags.cf != 0 /* || params.phys_sectors < 2097152 */) {
679dp->uses_ebios = 0;
680di->params.buf_size = 1;
681} else {
682bcopy(&params, &di->params, sizeof(params));
683
684if (drive >= BASE_HD_DRIVE &&
685(dp->uses_ebios & EBIOS_ENHANCED_DRIVE_INFO) &&
686di->params.buf_size >= 30 &&
687!(di->params.dpte_offset == 0xFFFF && di->params.dpte_segment == 0xFFFF)) {
688void *ptr = (void *)(di->params.dpte_offset + ((unsigned int)di->params.dpte_segment << 4));
689bcopy(ptr, &di->dpte, sizeof(di->dpte));
690}
691}
692}
693
694/*
695 * zef: This code will fail on recent JMicron and Intel option ROMs
696 */
697//if (di->params.phys_heads == 0 || di->params.phys_spt == 0) {
698///* Either it's not EBIOS, or EBIOS didn't tell us. */
699//bb.intno = 0x13;
700//bb.eax.r.h = 0x08;
701//bb.edx.r.l = drive;
702//bios(&bb);
703//if (bb.flags.cf == 0 && bb.eax.r.h == 0) {
704//unsigned long cyl;
705//unsigned long sec;
706//unsigned long hds;
707//
708//hds = bb.edx.r.h;
709//sec = bb.ecx.r.l & 0x3F;
710//if ((dp->uses_ebios & EBIOS_ENHANCED_DRIVE_INFO) && (sec != 0)) {
711//cyl = (di->params.phys_sectors / ((hds + 1) * sec)) - 1;
712//} else {
713//cyl = bb.ecx.r.h | ((bb.ecx.r.l & 0xC0) << 2);
714//}
715//di->params.phys_heads = hds;
716//di->params.phys_spt = sec;
717//di->params.phys_cyls = cyl;
718//} else {
719//ret = -1;
720//}
721//}
722
723if (dp->no_emulation) {
724/* Some BIOSes give us erroneous EBIOS support information.
725 * Assume that if you're on a CD, then you can use
726 * EBIOS disk calls.
727 */
728dp->uses_ebios |= EBIOS_FIXED_DISK_ACCESS;
729}
730#if DEBUG
731print_drive_info(di);
732printf("uses_ebios = 0x%x\n", dp->uses_ebios);
733printf("result %d\n", ret);
734pause();
735#endif
736
737if (ret == 0) {
738dp->valid = 1;
739}
740return ret;
741}
742
743//==============================================================================
744
745int ebiosEjectMedia(int biosdev)
746{
747bb.intno = 0x13;
748bb.eax.r.h = 0x46;
749bb.eax.r.l = 0;
750bb.edx.rx = biosdev;
751bios(&bb);
752return bb.eax.r.h;
753}
754
755void setCursorPosition(int x, int y, int page)
756{
757bb.intno = 0x10;
758bb.eax.r.h = 0x02;
759bb.ebx.r.h = page; /* page 0 for graphics */
760bb.edx.r.l = x;
761bb.edx.r.h = y;
762bios(&bb);
763}
764
765void setCursorType(int type)
766{
767bb.intno = 0x10;
768bb.eax.r.h = 0x01;
769bb.ecx.rr = type;
770bios(&bb);
771}
772
773void getCursorPositionAndType(int * x, int * y, int * type)
774{
775bb.intno = 0x10;
776bb.eax.r.h = 0x03;
777bios(&bb);
778*x = bb.edx.r.l;
779*y = bb.edx.r.h;
780*type = bb.ecx.rr;
781}
782
783void scollPage(int x1, int y1, int x2, int y2, int attr, int rows, int dir)
784{
785bb.intno = 0x10;
786bb.eax.r.h = (dir > 0) ? 0x06 : 0x07;
787bb.eax.r.l = rows;
788bb.ebx.r.h = attr;
789bb.ecx.r.h = y1;
790bb.ecx.r.l = x1;
791bb.edx.r.h = y2;
792bb.edx.r.l = x2;
793bios(&bb);
794}
795
796void clearScreenRows( int y1, int y2 )
797{
798scollPage( 0, y1, 80 - 1, y2, 0x07, y2 - y1 + 1, 1 );
799}
800
801void setActiveDisplayPage( int page )
802{
803bb.intno = 0x10;
804bb.eax.r.h = 5;
805bb.eax.r.l = page;
806bios(&bb);
807}
808
809#if DEBUG
810
811int terminateDiskEmulation()
812{
813static char cd_spec[0x13];
814
815bb.intno = 0x13;
816bb.eax.r.h = 0x4b;
817bb.eax.r.l = 0; // subfunc: terminate emulation
818bb.esi.rr = NORMALIZED_OFFSET((unsigned)&cd_spec);
819bb.ds = NORMALIZED_SEGMENT((unsigned)&cd_spec);
820bios(&bb);
821return bb.eax.r.h;
822}
823
824int readDriveParameters(int drive, struct driveParameters *dp)
825{
826bb.intno = 0x13;
827bb.edx.r.l = drive;
828bb.eax.r.h = 0x08;
829bios(&bb);
830if (bb.eax.r.h == 0) {
831dp->heads = bb.edx.r.h;
832dp->sectors = bb.ecx.r.l & 0x3F;
833dp->cylinders = bb.ecx.r.h | ((bb.ecx.r.l & 0xC0) << 2);
834dp->totalDrives = bb.edx.r.l;
835} else {
836bzero(dp, sizeof(*dp));
837}
838return bb.eax.r.h;
839}
840#endif
841
842#ifdef APM_SUPPORT
843
844#define APM_INTNO 0x15
845#define APM_INTCODE 0x53
846
847int
848APMPresent(void)
849{
850bb.intno = APM_INTNO;
851bb.eax.r.h = APM_INTCODE;
852bb.eax.r.l = 0x00;
853bb.ebx.rr = 0x0000;
854bios(&bb);
855if ((bb.flags.cf == 0) && (bb.ebx.r.h == 'P') && (bb.ebx.r.l == 'M')) {
856/* Success */
857bootArgs->apmConfig.major_vers = bb.eax.r.h;
858bootArgs->apmConfig.minor_vers = bb.eax.r.l;
859bootArgs->apmConfig.flags.data = bb.ecx.rr;
860return 1;
861}
862return 0;
863}
864
865int
866APMConnect32(void)
867{
868bb.intno = APM_INTNO;
869bb.eax.r.h = APM_INTCODE;
870bb.eax.r.l = 0x03;
871bb.ebx.rr = 0x0000;
872bios(&bb);
873if (bb.flags.cf == 0) {
874/* Success */
875bootArgs->apmConfig.cs32_base = (bb.eax.rr) << 4;
876bootArgs->apmConfig.entry_offset = bb.ebx.rx;
877bootArgs->apmConfig.cs16_base = (bb.ecx.rr) << 4;
878bootArgs->apmConfig.ds_base = (bb.edx.rr) << 4;
879if (bootArgs->apmConfig.major_vers >= 1 && bootArgs->apmConfig.minor_vers >= 1) {
880bootArgs->apmConfig.cs_length = bb.esi.rr;
881bootArgs->apmConfig.ds_length = bb.edi.rr;
882} else {
883bootArgs->apmConfig.cs_length =
884bootArgs->apmConfig.ds_length = 64 * 1024;
885}
886bootArgs->apmConfig.connected = 1;
887return 1;
888}
889return 0;
890}
891
892#endif /* APM_SUPPORT */
893
894#ifdef EISA_SUPPORT
895bool eisa_present(void)
896{
897static bool checked = false;
898static bool isEISA;
899
900if (!checked) {
901if (strncmp((char *)0xfffd9, "EISA", 4) == 0) {
902isEISA = true;
903}
904checked = true;
905}
906
907return (isEISA);
908}
909
910int
911ReadEISASlotInfo(EISA_slot_info_t *ep, int slot)
912{
913union
914{
915struct
916{
917unsigned char char2h :2;
918unsigned char char1 :5;
919unsigned char char3 :5;
920unsigned char char2l :3;
921unsigned char d2 :4;
922unsigned char d1 :4;
923unsigned char d4 :4;
924unsigned char d3 :4;
925} s;
926unsigned char data[4];
927} u;
928static char hex[0x10] = "0123456789ABCDEF";
929
930
931bb.intno = 0x15;
932bb.eax.r.h = 0xd8;
933bb.eax.r.l = 0x00;
934bb.ecx.r.l = slot;
935bios(&bb);
936if (bb.flags.cf)
937return bb.eax.r.h;
938ep->u_ID.d = bb.eax.r.l;
939ep->configMajor = bb.ebx.r.h;
940ep->configMinor = bb.ebx.r.l;
941ep->checksum = bb.ecx.rr;
942ep->numFunctions = bb.edx.r.h;
943ep->u_resources.d = bb.edx.r.l;
944u.data[0] = bb.edi.r.l;
945u.data[1] = bb.edi.r.h;
946u.data[2] = bb.esi.r.l;
947u.data[3] = bb.esi.r.h;
948ep->id[0] = u.s.char1 + ('A' - 1);
949ep->id[1] = (u.s.char2l | (u.s.char2h << 3)) + ('A' - 1);
950ep->id[2] = u.s.char3 + ('A' - 1);
951ep->id[3] = hex[u.s.d1];
952ep->id[4] = hex[u.s.d2];
953ep->id[5] = hex[u.s.d3];
954ep->id[6] = hex[u.s.d4];
955ep->id[7] = 0;
956return 0;
957}
958
959/*
960 * Note: ep must point to an address below 64k.
961 */
962
963int
964ReadEISAFuncInfo(EISA_func_info_t *ep, int slot, int function)
965{
966bb.intno = 0x15;
967bb.eax.r.h = 0xd8;
968bb.eax.r.l = 0x01;
969bb.ecx.r.l = slot;
970bb.ecx.r.h = function;
971bb.esi.rr = (unsigned int)ep->data;
972bios(&bb);
973if (bb.eax.r.h == 0)
974{
975ep->slot = slot;
976ep->function = function;
977}
978return bb.eax.r.h;
979}
980#endif /* EISA_SUPPORT */
981
982#define PCI_SIGNATURE 0x20494350 /* "PCI " */
983
984int
985ReadPCIBusInfo(PCI_bus_info_t *pp)
986{
987bb.intno = 0x1a;
988bb.eax.r.h = 0xb1;
989bb.eax.r.l = 0x01;
990bios(&bb);
991if ((bb.eax.r.h == 0) && (bb.edx.rx == PCI_SIGNATURE))
992{
993pp->BIOSPresent = 1;
994pp->u_bus.d = bb.eax.r.l;
995pp->majorVersion = bb.ebx.r.h;
996pp->minorVersion = bb.ebx.r.l;
997pp->maxBusNum = bb.ecx.r.l;
998return 0;
999}
1000return -1;
1001}
1002
1003void sleep(int n)
1004{
1005 unsigned int endtime = (time18() + 18*n);
1006 while (time18() < endtime);
1007}
1008
1009
1010//==============================================================================
1011
1012void delay(int ms)
1013{
1014 bb.intno = 0x15;
1015 bb.eax.r.h = 0x86;
1016 bb.ecx.rr = ms >> 16;
1017 bb.edx.rr = ms & 0xFFFF;
1018 bios(&bb);
1019}
1020
1021

Archive Download this file

Revision: 2323