Chameleon

Chameleon Svn Source Tree

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

Archive Download this file

Revision: 1047