Chameleon

Chameleon Svn Source Tree

Root/branches/ErmaC/Enoch_Modules/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 /* COMMENTED */
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 /* COMMENTED */
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;
191unsigned 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 /* COMMENTED */
264rerangedCount = rerangeMemoryMap(count);
265range += rerangedCount - count;
266//#endif /* COMMENTED */
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{
648int ret = 0;
649
650boot_drive_info_t *di = &dp->di;
651
652#if UNUSED
653if (maxhd == 0)
654{
655bb.intno = 0x13;
656bb.eax.r.h = 0x08;
657bb.edx.r.l = 0x80;
658bios(&bb);
659
660if (bb.flags.cf == 0)
661{
662maxhd = 0x7f + bb.edx.r.l;
663}
664};
665
666if (drive > maxhd)
667{
668return 0;
669}
670#endif
671
672bzero(dp, sizeof(struct driveInfo));
673dp->biosdev = drive;
674
675/* Check for El Torito no-emulation mode. */
676dp->no_emulation = is_no_emulation(drive);
677
678/* Check drive for EBIOS support. */
679bb.intno = 0x13;
680bb.eax.r.h = 0x41;
681bb.edx.r.l = drive;
682bb.ebx.rr = 0x55aa;
683bios(&bb);
684
685if ((bb.ebx.rr == 0xaa55) && (bb.flags.cf == 0))
686{
687/* Get flags for supported operations. */
688dp->uses_ebios = bb.ecx.r.l;
689}
690
691if (dp->uses_ebios & (EBIOS_ENHANCED_DRIVE_INFO | EBIOS_LOCKING_ACCESS | EBIOS_FIXED_DISK_ACCESS))
692{
693/* Get EBIOS drive info. */
694static struct drive_params params;
695
696params.buf_size = sizeof(params);
697bb.intno = 0x13;
698bb.eax.r.h = 0x48;
699bb.edx.r.l = drive;
700bb.esi.rr = NORMALIZED_OFFSET((unsigned)&params);
701bb.ds = NORMALIZED_SEGMENT((unsigned)&params);
702bios(&bb);
703
704if (bb.flags.cf != 0 /* || params.phys_sectors < 2097152 */)
705{
706dp->uses_ebios = 0;
707di->params.buf_size = 1;
708}
709else
710{
711bcopy(&params, &di->params, sizeof(params));
712
713if (drive >= BASE_HD_DRIVE &&
714(dp->uses_ebios & EBIOS_ENHANCED_DRIVE_INFO) &&
715di->params.buf_size >= 30 &&
716!(di->params.dpte_offset == 0xFFFF && di->params.dpte_segment == 0xFFFF))
717{
718void *ptr = (void *)(di->params.dpte_offset + ((unsigned int)di->params.dpte_segment << 4));
719bcopy(ptr, &di->dpte, sizeof(di->dpte));
720}
721}
722}
723
724/*
725 * zef: This code will fail on recent JMicron and Intel option ROMs
726 */
727//if (di->params.phys_heads == 0 || di->params.phys_spt == 0) {
728///* Either it's not EBIOS, or EBIOS didn't tell us. */
729//bb.intno = 0x13;
730//bb.eax.r.h = 0x08;
731//bb.edx.r.l = drive;
732//bios(&bb);
733//if (bb.flags.cf == 0 && bb.eax.r.h == 0) {
734//unsigned long cyl;
735//unsigned long sec;
736//unsigned long hds;
737//
738//hds = bb.edx.r.h;
739//sec = bb.ecx.r.l & 0x3F;
740//if ((dp->uses_ebios & EBIOS_ENHANCED_DRIVE_INFO) && (sec != 0)) {
741//cyl = (di->params.phys_sectors / ((hds + 1) * sec)) - 1;
742//} else {
743//cyl = bb.ecx.r.h | ((bb.ecx.r.l & 0xC0) << 2);
744//}
745//di->params.phys_heads = hds;
746//di->params.phys_spt = sec;
747//di->params.phys_cyls = cyl;
748//} else {
749//ret = -1;
750//}
751//}
752
753if (dp->no_emulation)
754{
755/* Some BIOSes give us erroneous EBIOS support information.
756 * Assume that if you're on a CD, then you can use
757 * EBIOS disk calls.
758 */
759dp->uses_ebios |= EBIOS_FIXED_DISK_ACCESS;
760}
761#if DEBUG
762print_drive_info(di);
763printf("uses_ebios = 0x%x\n", dp->uses_ebios);
764printf("result %d\n", ret);
765pause();
766#endif
767
768if (ret == 0)
769{
770dp->valid = 1;
771}
772return ret;
773}
774
775//==============================================================================
776
777int ebiosEjectMedia(int biosdev)
778{
779bb.intno = 0x13;
780bb.eax.r.h = 0x46;
781bb.eax.r.l = 0;
782bb.edx.rx = biosdev;
783bios(&bb);
784return bb.eax.r.h;
785}
786
787void setCursorPosition(int x, int y, int page)
788{
789bb.intno = 0x10;
790bb.eax.r.h = 0x02;
791bb.ebx.r.h = page; /* page 0 for graphics */
792bb.edx.r.l = x;
793bb.edx.r.h = y;
794bios(&bb);
795}
796
797void setCursorType(int type)
798{
799bb.intno = 0x10;
800bb.eax.r.h = 0x01;
801bb.ecx.rr = type;
802bios(&bb);
803}
804
805void getCursorPositionAndType(int * x, int * y, int * type)
806{
807bb.intno = 0x10;
808bb.eax.r.h = 0x03;
809bios(&bb);
810*x = bb.edx.r.l;
811*y = bb.edx.r.h;
812*type = bb.ecx.rr;
813}
814
815void scollPage(int x1, int y1, int x2, int y2, int attr, int rows, int dir)
816{
817bb.intno = 0x10;
818bb.eax.r.h = (dir > 0) ? 0x06 : 0x07;
819bb.eax.r.l = rows;
820bb.ebx.r.h = attr;
821bb.ecx.r.h = y1;
822bb.ecx.r.l = x1;
823bb.edx.r.h = y2;
824bb.edx.r.l = x2;
825bios(&bb);
826}
827
828void clearScreenRows( int y1, int y2 )
829{
830scollPage( 0, y1, 80 - 1, y2, 0x07, y2 - y1 + 1, 1 );
831}
832
833void setActiveDisplayPage( int page )
834{
835bb.intno = 0x10;
836bb.eax.r.h = 5;
837bb.eax.r.l = page;
838bios(&bb);
839}
840
841#if DEBUG
842
843int terminateDiskEmulation()
844{
845static char cd_spec[0x13];
846
847bb.intno = 0x13;
848bb.eax.r.h = 0x4b;
849bb.eax.r.l = 0; // subfunc: terminate emulation
850bb.esi.rr = NORMALIZED_OFFSET((unsigned)&cd_spec);
851bb.ds = NORMALIZED_SEGMENT((unsigned)&cd_spec);
852bios(&bb);
853return bb.eax.r.h;
854}
855
856int readDriveParameters(int drive, struct driveParameters *dp)
857{
858bb.intno = 0x13;
859bb.edx.r.l = drive;
860bb.eax.r.h = 0x08;
861bios(&bb);
862if (bb.eax.r.h == 0)
863{
864dp->heads = bb.edx.r.h;
865dp->sectors = bb.ecx.r.l & 0x3F;
866dp->cylinders = bb.ecx.r.h | ((bb.ecx.r.l & 0xC0) << 2);
867dp->totalDrives = bb.edx.r.l;
868}
869else
870{
871bzero(dp, sizeof(*dp));
872}
873return bb.eax.r.h;
874}
875#endif
876
877#ifdef APM_SUPPORT
878
879#define APM_INTNO 0x15
880#define APM_INTCODE 0x53
881
882int APMPresent(void)
883{
884bb.intno = APM_INTNO;
885bb.eax.r.h = APM_INTCODE;
886bb.eax.r.l = 0x00;
887bb.ebx.rr = 0x0000;
888bios(&bb);
889if ((bb.flags.cf == 0) && (bb.ebx.r.h == 'P') && (bb.ebx.r.l == 'M'))
890{
891/* Success */
892bootArgs->apmConfig.major_vers = bb.eax.r.h;
893bootArgs->apmConfig.minor_vers = bb.eax.r.l;
894bootArgs->apmConfig.flags.data = bb.ecx.rr;
895return 1;
896}
897return 0;
898}
899
900int APMConnect32(void)
901{
902bb.intno = APM_INTNO;
903bb.eax.r.h = APM_INTCODE;
904bb.eax.r.l = 0x03;
905bb.ebx.rr = 0x0000;
906bios(&bb);
907if (bb.flags.cf == 0)
908{
909/* Success */
910bootArgs->apmConfig.cs32_base = (bb.eax.rr) << 4;
911bootArgs->apmConfig.entry_offset = bb.ebx.rx;
912bootArgs->apmConfig.cs16_base = (bb.ecx.rr) << 4;
913bootArgs->apmConfig.ds_base = (bb.edx.rr) << 4;
914if (bootArgs->apmConfig.major_vers >= 1 && bootArgs->apmConfig.minor_vers >= 1)
915{
916bootArgs->apmConfig.cs_length = bb.esi.rr;
917bootArgs->apmConfig.ds_length = bb.edi.rr;
918}
919else
920{
921bootArgs->apmConfig.cs_length =
922bootArgs->apmConfig.ds_length = 64 * 1024;
923}
924bootArgs->apmConfig.connected = 1;
925return 1;
926}
927return 0;
928}
929
930#endif /* APM_SUPPORT */
931
932#ifdef EISA_SUPPORT
933bool eisa_present(void)
934{
935static bool checked = false;
936static bool isEISA;
937
938if (!checked)
939{
940if (strncmp((char *)0xfffd9, "EISA", 4) == 0)
941isEISA = true;
942
943checked = true;
944}
945
946return (isEISA);
947}
948
949int
950ReadEISASlotInfo(EISA_slot_info_t *ep, int slot)
951{
952union
953{
954struct
955{
956unsigned char char2h :2;
957unsigned char char1 :5;
958unsigned char char3 :5;
959unsigned char char2l :3;
960unsigned char d2 :4;
961unsigned char d1 :4;
962unsigned char d4 :4;
963unsigned char d3 :4;
964} s;
965unsigned char data[4];
966} u;
967static char hex[0x10] = "0123456789ABCDEF";
968
969
970bb.intno = 0x15;
971bb.eax.r.h = 0xd8;
972bb.eax.r.l = 0x00;
973bb.ecx.r.l = slot;
974bios(&bb);
975if (bb.flags.cf)
976return bb.eax.r.h;
977ep->u_ID.d = bb.eax.r.l;
978ep->configMajor = bb.ebx.r.h;
979ep->configMinor = bb.ebx.r.l;
980ep->checksum = bb.ecx.rr;
981ep->numFunctions = bb.edx.r.h;
982ep->u_resources.d = bb.edx.r.l;
983u.data[0] = bb.edi.r.l;
984u.data[1] = bb.edi.r.h;
985u.data[2] = bb.esi.r.l;
986u.data[3] = bb.esi.r.h;
987ep->id[0] = u.s.char1 + ('A' - 1);
988ep->id[1] = (u.s.char2l | (u.s.char2h << 3)) + ('A' - 1);
989ep->id[2] = u.s.char3 + ('A' - 1);
990ep->id[3] = hex[u.s.d1];
991ep->id[4] = hex[u.s.d2];
992ep->id[5] = hex[u.s.d3];
993ep->id[6] = hex[u.s.d4];
994ep->id[7] = 0;
995return 0;
996}
997
998/*
999 * Note: ep must point to an address below 64k.
1000 */
1001
1002int
1003ReadEISAFuncInfo(EISA_func_info_t *ep, int slot, int function)
1004{
1005bb.intno = 0x15;
1006bb.eax.r.h = 0xd8;
1007bb.eax.r.l = 0x01;
1008bb.ecx.r.l = slot;
1009bb.ecx.r.h = function;
1010bb.esi.rr = (unsigned int)ep->data;
1011bios(&bb);
1012if (bb.eax.r.h == 0)
1013{
1014ep->slot = slot;
1015ep->function = function;
1016}
1017return bb.eax.r.h;
1018}
1019#endif /* EISA_SUPPORT */
1020
1021#define PCI_SIGNATURE 0x20494350 /* "PCI " */
1022
1023int
1024ReadPCIBusInfo(PCI_bus_info_t *pp)
1025{
1026bb.intno = 0x1a;
1027bb.eax.r.h = 0xb1;
1028bb.eax.r.l = 0x01;
1029bios(&bb);
1030if ((bb.eax.r.h == 0) && (bb.edx.rx == PCI_SIGNATURE))
1031{
1032pp->BIOSPresent = 1;
1033pp->u_bus.d = bb.eax.r.l;
1034pp->majorVersion = bb.ebx.r.h;
1035pp->minorVersion = bb.ebx.r.l;
1036pp->maxBusNum = bb.ecx.r.l;
1037return 0;
1038}
1039return -1;
1040}
1041
1042void sleep(int n)
1043{
1044 unsigned int endtime = (time18() + 18*n);
1045 while (time18() < endtime);
1046}
1047
1048
1049//==============================================================================
1050
1051void delay(int ms)
1052{
1053 bb.intno = 0x15;
1054 bb.eax.r.h = 0x86;
1055 bb.ecx.rr = ms >> 16;
1056 bb.edx.rr = ms & 0xFFFF;
1057 bios(&bb);
1058}
1059
1060

Archive Download this file

Revision: 2238