Chameleon

Chameleon Svn Source Tree

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

Archive Download this file

Revision: 1804