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

Archive Download this file

Revision: 2687