Chameleon

Chameleon Svn Source Tree

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

Archive Download this file

Revision: 2602