2 * Copyright (c) 1999-2003 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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
22 * @APPLE_LICENSE_HEADER_END@
25 * Copyright 1993 NeXT Computer, Inc.
26 * All rights reserved.
29 #include "bootstruct.h"
44 int readKeyboardStatus(void)
56 int readKeyboardShiftFlags(void)
64 unsigned int time18(void)
77 time
.s
.low
= bb
.edx
.rr
;
78 time
.s
.high
= bb
.ecx
.rr
;
82 unsigned long getMemoryMap( MemoryRange
* rangeArray
,
83 unsigned long maxRangeCount
,
84 unsigned long * conMemSizePtr
,
85 unsigned long * extMemSizePtr
)
87 #define kMemoryMapSignature 'SMAP'
88 #define kDescriptorSizeMin 20
90 MemoryRange
* range
= (MemoryRange
*)BIOS_ADDR
;
91 unsigned long count
= 0;
92 unsigned long long conMemSize
= 0;
93 unsigned long long extMemSize
= 0;
95 // Prepare for the INT15 E820h call. Each call returns a single
96 // memory range. A continuation value is returned that must be
97 // provided on a subsequent call to fetch the next range.
99 // Certain BIOSes (Award 6.00PG) expect the upper word in EAX
100 // to be cleared on entry, otherwise only a single range will
103 // Some BIOSes will simply ignore the value of ECX on entry.
104 // Probably best to keep its value at 20 to avoid surprises.
106 //printf("Get memory map 0x%x, %d\n", rangeArray);getc();
107 if (maxRangeCount
> (BIOS_LEN
/ sizeof(MemoryRange
))) {
108 maxRangeCount
= (BIOS_LEN
/ sizeof(MemoryRange
));
110 bb
.ebx
.rx
= 0; // Initial continuation value must be zero.
112 while ( count
< maxRangeCount
)
116 bb
.ecx
.rx
= kDescriptorSizeMin
;
117 bb
.edx
.rx
= kMemoryMapSignature
;
118 bb
.edi
.rr
= OFFSET( (unsigned long) range
);
119 bb
.es
= SEGMENT( (unsigned long) range
);
125 || bb
.eax
.rx
!= kMemoryMapSignature
126 || bb
.ecx
.rx
!= kDescriptorSizeMin
) {
127 //printf("Got an error %x %x %x\n", bb.flags.cf,
128 // bb.eax.rx, bb.ecx.rx);
132 // Tally up the conventional/extended memory sizes.
134 if ( range
->type
== kMemoryRangeUsable
||
135 range
->type
== kMemoryRangeACPI
||
136 range
->type
== kMemoryRangeNVS
)
138 // Tally the conventional memory ranges.
139 if ( range
->base
+ range
->length
<= 0xa0000 ) {
140 conMemSize
+= range
->length
;
143 // Record the top of extended memory.
144 if ( range
->base
>= EXTENDED_ADDR
) {
145 extMemSize
+= range
->length
;
152 // Is this the last address range?
154 if ( bb
.ebx
.rx
== 0 ) {
155 //printf("last range\n");
159 *conMemSizePtr
= conMemSize
/ 1024; // size in KB
160 *extMemSizePtr
= extMemSize
/ 1024; // size in KB
163 bcopy((char *)BIOS_ADDR
, rangeArray
, ((char *)range
- (char *)BIOS_ADDR
));
168 printf("%d total ranges\n", count
);getc();
169 for (i
=0, range
= rangeArray
; i
<count
; i
++, range
++) {
170 printf("range: type %d, base 0x%x, length 0x%x\n",
171 range
->type
, (unsigned int)range
->base
, (unsigned int)range
->length
); getc();
179 unsigned long getExtendedMemorySize()
181 // Get extended memory size for large configurations. Not used unless
182 // the INT15, E820H call (Get System Address Map) failed.
186 // AX Function Code E801h
190 // CF Carry Flag Carry cleared indicates no error.
191 // AX Extended 1 Number of contiguous KB between 1 and 16 MB,
192 // maximum 0x3C00 = 15 MB.
193 // BX Extended 2 Number of contiguous 64 KB blocks between
195 // CX Configured 1 Number of contiguous KB between 1 and 16 MB,
196 // maximum 0x3C00 = 15 MB.
197 // DX Configured 2 Number of contiguous 64 KB blocks between
204 // Return the size of memory above 1MB (extended memory) in kilobytes.
206 if ( bb
.flags
.cf
== 0 ) return (bb
.ebx
.rr
* 64 + bb
.eax
.rr
);
208 // Get Extended memory size. Called on last resort since the return
209 // value is limited to 16-bits (a little less than 64MB max). May
210 // not be supported by modern BIOSes.
214 // AX Function Code E801h
218 // CF Carry Flag Carry cleared indicates no error.
219 // AX Memory Count Number of contiguous KB above 1MB.
225 // Return the size of memory above 1MB (extended memory) in kilobytes.
227 return bb
.flags
.cf
? 0 : bb
.eax
.rr
;
230 unsigned long getConventionalMemorySize()
234 return bb
.eax
.rr
; // kilobytes
237 void video_mode(int mode
)
245 int biosread(int dev
, int cyl
, int head
, int sec
, int num
)
250 sec
+= 1; /* sector numbers start at 1 */
254 bb
.ecx
.r
.l
= ((cyl
& 0x300) >> 2) | (sec
& 0x3F);
258 bb
.ebx
.rr
= OFFSET(ptov(BIOS_ADDR
));
259 bb
.es
= SEGMENT(ptov(BIOS_ADDR
));
264 if ((bb
.eax
.r
.h
== 0x00) || (i
++ >= 5))
267 /* reset disk subsystem and try again */
274 int ebiosread(int dev
, long sec
, int count
)
279 unsigned char reserved
;
280 unsigned char numblocks
;
281 unsigned char reserved2
;
282 unsigned short bufferOffset
;
283 unsigned short bufferSegment
;
284 unsigned long long startblock
;
285 } addrpacket
__attribute__((aligned(16))) = {0};
286 addrpacket
.size
= sizeof(addrpacket
);
292 bb
.esi
.rr
= OFFSET((unsigned)&addrpacket
);
293 bb
.ds
= SEGMENT((unsigned)&addrpacket
);
294 addrpacket
.reserved
= addrpacket
.reserved2
= 0;
295 addrpacket
.numblocks
= count
;
296 addrpacket
.bufferOffset
= OFFSET(ptov(BIOS_ADDR
));
297 addrpacket
.bufferSegment
= SEGMENT(ptov(BIOS_ADDR
));
298 addrpacket
.startblock
= sec
;
300 if ((bb
.eax
.r
.h
== 0x00) || (i
++ >= 5))
303 /* reset disk subsystem and try again */
310 int ebioswrite(int dev
, long sec
, int count
)
315 unsigned char reserved
;
316 unsigned char numblocks
;
317 unsigned char reserved2
;
318 unsigned short bufferOffset
;
319 unsigned short bufferSegment
;
320 unsigned long long startblock
;
321 } addrpacket
__attribute__((aligned(16))) = {0};
322 addrpacket
.size
= sizeof(addrpacket
);
326 bb
.eax
.r
.l
= 0; /* Don't verify */
329 bb
.esi
.rr
= OFFSET((unsigned)&addrpacket
);
330 bb
.ds
= SEGMENT((unsigned)&addrpacket
);
331 addrpacket
.reserved
= addrpacket
.reserved2
= 0;
332 addrpacket
.numblocks
= count
;
333 addrpacket
.bufferOffset
= OFFSET(ptov(BIOS_ADDR
));
334 addrpacket
.bufferSegment
= SEGMENT(ptov(BIOS_ADDR
));
335 addrpacket
.startblock
= sec
;
337 if ((bb
.eax
.r
.h
== 0x00) || (i
++ >= 5))
340 /* reset disk subsystem and try again */
350 bb
.ebx
.r
.h
= 0x00; /* background black */
351 bb
.ebx
.r
.l
= 0x0F; /* foreground white */
357 void putca(int ch
, int attr
, int repeat
)
360 bb
.ebx
.r
.h
= 0x00; /* page number */
361 bb
.ebx
.r
.l
= attr
; /* attribute */
364 bb
.ecx
.rx
= repeat
; /* repeat count */
368 /* Check to see if the passed-in drive is in El Torito no-emulation mode. */
369 int is_no_emulation(int drive
)
372 unsigned char packet_size
;
373 unsigned char media_type
;
374 unsigned char drive_num
;
375 unsigned char ctrlr_index
;
377 unsigned short device_spec
;
378 unsigned short buffer_segment
;
379 unsigned short load_segment
;
380 unsigned short sector_count
;
381 unsigned char cyl_count
;
382 unsigned char sec_count
;
383 unsigned char head_count
;
384 unsigned char reseved
;
385 } __attribute__((packed
));
386 static struct packet pkt
;
388 bzero(&pkt
, sizeof(pkt
));
389 pkt
.packet_size
= 0x13;
393 bb
.eax
.r
.l
= 0x01; // subfunc: get info
395 bb
.esi
.rr
= OFFSET((unsigned)&pkt
);
396 bb
.ds
= SEGMENT((unsigned)&pkt
);
400 printf("el_torito info drive %x\n", drive
);
402 printf("--> cf %x, eax %x\n", bb
.flags
.cf
, bb
.eax
.rr
);
404 printf("pkt_size: %x\n", pkt
.packet_size
);
405 printf("media_type: %x\n", pkt
.media_type
);
406 printf("drive_num: %x\n", pkt
.drive_num
);
407 printf("device_spec: %x\n", pkt
.device_spec
);
408 printf("press a key->\n");getc();
411 /* Some BIOSes erroneously return cf = 1 */
412 /* Just check to see if the drive number is the same. */
413 if (pkt
.drive_num
== drive
) {
414 if ((pkt
.media_type
& 0x0F) == 0) {
415 /* We are in no-emulation mode. */
425 * BIOS drive information.
427 void print_drive_info(boot_drive_info_t
*dp
)
429 // printf("buf_size = %x\n", dp->params.buf_size);
430 printf("info_flags = %x\n", dp
->params
.info_flags
);
431 printf(" phys_cyls = %lx\n", dp
->params
. phys_cyls
);
432 printf(" phys_heads = %lx\n", dp
->params
. phys_heads
);
433 printf(" phys_spt = %lx\n", dp
->params
. phys_spt
);
434 printf("phys_sectors = %lx%lx\n", ((unsigned long *)(&dp
->params
.phys_sectors
))[1],
435 ((unsigned long *)(&dp
->params
.phys_sectors
))[0]);
436 printf("phys_nbps = %x\n", dp
->params
.phys_nbps
);
437 // printf("dpte_offset = %x\n", dp->params.dpte_offset);
438 // printf("dpte_segment = %x\n", dp->params.dpte_segment);
439 // printf("key = %x\n", dp->params.key);
440 // printf("path_len = %x\n", dp->params. path_len);
441 // printf("reserved1 = %x\n", dp->params. reserved1);
442 // printf("reserved2 = %x\n", dp->params.reserved2);
443 //printf("bus_type[4] = %x\n", dp->params. bus_type[4]);
444 //printf("interface_type[8] = %x\n", dp->params. interface_type[8]);
445 //printf("interface_path[8] = %x\n", dp->params. interface_path[8]);
446 //printf("dev_path[8] = %x\n", dp->params. dev_path[8]);
447 // printf("reserved3 = %x\n", dp->params. reserved3);
448 // printf("checksum = %x\n", dp->params. checksum);
450 printf(" io_port_base = %x\n", dp
->dpte
.io_port_base
);
451 printf(" control_port_base = %x\n", dp
->dpte
.control_port_base
);
452 printf(" head_flags = %x\n", dp
->dpte
. head_flags
);
453 printf(" vendor_info = %x\n", dp
->dpte
. vendor_info
);
454 printf(" irq = %x\n", dp
->dpte
. irq
);
455 // printf(" irq_unused = %x\n", dp->dpte. irq_unused);
456 printf(" block_count = %x\n", dp
->dpte
. block_count
);
457 printf(" dma_channe = %x\n", dp
->dpte
. dma_channel
);
458 printf(" dma_type = %x\n", dp
->dpte
. dma_type
);
459 printf(" pio_type = %x\n", dp
->dpte
. pio_type
);
460 printf(" pio_unused = %x\n", dp
->dpte
. pio_unused
);
461 printf(" option_flags = %x\n", dp
->dpte
.option_flags
);
462 // printf(" reserved = %x\n", dp->dpte.reserved);
463 printf(" revision = %x\n", dp
->dpte
. revision
);
464 // printf(" checksum = %x\n", dp->dpte. checksum);
469 int get_drive_info(int drive
, struct driveInfo
*dp
)
471 boot_drive_info_t
*di
= &dp
->di
;
480 if (bb
.flags
.cf
== 0)
481 maxhd
= 0x7f + bb
.edx
.r
.l
;
488 bzero(dp
, sizeof(struct driveInfo
));
491 /* Check for El Torito no-emulation mode. */
492 dp
->no_emulation
= is_no_emulation(drive
);
494 /* Check drive for EBIOS support. */
500 if((bb
.ebx
.rr
== 0xaa55) && (bb
.flags
.cf
== 0)) {
501 /* Get flags for supported operations. */
502 dp
->uses_ebios
= bb
.ecx
.r
.l
;
505 if (dp
->uses_ebios
& (EBIOS_ENHANCED_DRIVE_INFO
| EBIOS_LOCKING_ACCESS
| EBIOS_FIXED_DISK_ACCESS
)) {
506 /* Get EBIOS drive info. */
507 static struct drive_params params
;
509 params
.buf_size
= sizeof(params
);
513 bb
.esi
.rr
= OFFSET((unsigned)¶ms
);
514 bb
.ds
= SEGMENT((unsigned)¶ms
);
516 if(bb
.flags
.cf
!= 0 /* || params.phys_sectors < 2097152 */) {
518 di
->params
.buf_size
= 1;
520 bcopy(¶ms
, &di
->params
, sizeof(params
));
522 if (drive
>= BASE_HD_DRIVE
&&
523 (dp
->uses_ebios
& EBIOS_ENHANCED_DRIVE_INFO
) &&
524 di
->params
.buf_size
>= 30 &&
525 !(di
->params
.dpte_offset
== 0xFFFF && di
->params
.dpte_segment
== 0xFFFF)) {
526 void *ptr
= (void *)(di
->params
.dpte_offset
+ ((unsigned int)di
->params
.dpte_segment
<< 4));
527 bcopy(ptr
, &di
->dpte
, sizeof(di
->dpte
));
532 if (di
->params
.phys_heads
== 0 || di
->params
.phys_spt
== 0) {
533 /* Either it's not EBIOS, or EBIOS didn't tell us. */
538 if (bb
.flags
.cf
== 0 && bb
.eax
.r
.h
== 0) {
544 sec
= bb
.ecx
.r
.l
& 0x3F;
545 if((dp
->uses_ebios
& EBIOS_ENHANCED_DRIVE_INFO
) && (sec
!= 0)) {
546 cyl
= (di
->params
.phys_sectors
/ ((hds
+ 1) * sec
)) - 1;
549 cyl
= bb
.ecx
.r
.h
| ((bb
.ecx
.r
.l
& 0xC0) << 2);
551 di
->params
.phys_heads
= hds
;
552 di
->params
.phys_spt
= sec
;
553 di
->params
.phys_cyls
= cyl
;
559 if (dp
->no_emulation
) {
560 /* Some BIOSes give us erroneous EBIOS support information.
561 * Assume that if you're on a CD, then you can use
564 dp
->uses_ebios
|= EBIOS_FIXED_DISK_ACCESS
;
567 print_drive_info(di
);
568 printf("uses_ebios = 0x%x\n", dp
->uses_ebios
);
569 printf("result %d\n", ret
);
570 printf("press a key->\n");getc();
579 void setCursorPosition(int x
, int y
, int page
)
583 bb
.ebx
.r
.h
= page
; /* page 0 for graphics */
589 void setCursorType(int type
)
597 void getCursorPositionAndType(int * x
, int * y
, int * type
)
607 void scollPage(int x1
, int y1
, int x2
, int y2
, int attr
, int rows
, int dir
)
610 bb
.eax
.r
.h
= (dir
> 0) ? 0x06 : 0x07;
620 void clearScreenRows( int y1
, int y2
)
622 scollPage( 0, y1
, 80 - 1, y2
, 0x07, y2
- y1
+ 1, 1 );
625 void setActiveDisplayPage( int page
)
635 int terminateDiskEmulation()
637 static char cd_spec
[0x13];
641 bb
.eax
.r
.l
= 0; // subfunc: terminate emulation
642 bb
.esi
.rr
= OFFSET((unsigned)&cd_spec
);
643 bb
.ds
= SEGMENT((unsigned)&cd_spec
);
648 int readDriveParameters(int drive
, struct driveParameters
*dp
)
654 if (bb
.eax
.r
.h
== 0) {
655 dp
->heads
= bb
.edx
.r
.h
;
656 dp
->sectors
= bb
.ecx
.r
.l
& 0x3F;
657 dp
->cylinders
= bb
.ecx
.r
.h
| ((bb
.ecx
.r
.l
& 0xC0) << 2);
658 dp
->totalDrives
= bb
.edx
.r
.l
;
660 bzero(dp
, sizeof(*dp
));
669 #define APM_INTNO 0x15
670 #define APM_INTCODE 0x53
675 bb
.intno
= APM_INTNO
;
676 bb
.eax
.r
.h
= APM_INTCODE
;
680 if ((bb
.flags
.cf
== 0) &&
681 (bb
.ebx
.r
.h
== 'P') &&
682 (bb
.ebx
.r
.l
== 'M')) {
684 bootArgs
->apmConfig
.major_vers
= bb
.eax
.r
.h
;
685 bootArgs
->apmConfig
.minor_vers
= bb
.eax
.r
.l
;
686 bootArgs
->apmConfig
.flags
.data
= bb
.ecx
.rr
;
695 bb
.intno
= APM_INTNO
;
696 bb
.eax
.r
.h
= APM_INTCODE
;
700 if (bb
.flags
.cf
== 0) {
702 bootArgs
->apmConfig
.cs32_base
= (bb
.eax
.rr
) << 4;
703 bootArgs
->apmConfig
.entry_offset
= bb
.ebx
.rx
;
704 bootArgs
->apmConfig
.cs16_base
= (bb
.ecx
.rr
) << 4;
705 bootArgs
->apmConfig
.ds_base
= (bb
.edx
.rr
) << 4;
706 if (bootArgs
->apmConfig
.major_vers
>= 1 &&
707 bootArgs
->apmConfig
.minor_vers
>= 1) {
708 bootArgs
->apmConfig
.cs_length
= bb
.esi
.rr
;
709 bootArgs
->apmConfig
.ds_length
= bb
.edi
.rr
;
711 bootArgs
->apmConfig
.cs_length
=
712 bootArgs
->apmConfig
.ds_length
= 64 * 1024;
714 bootArgs
->apmConfig
.connected
= 1;
720 #endif /* APM_SUPPORT */
732 if (strncmp((char *)0xfffd9, "EISA", 4) == 0)
742 ReadEISASlotInfo(EISA_slot_info_t
*ep
, int slot
)
746 unsigned char char2h
:2;
747 unsigned char char1
:5;
748 unsigned char char3
:5;
749 unsigned char char2l
:3;
755 unsigned char data
[4];
757 static char hex
[0x10] = "0123456789ABCDEF";
767 ep
->u_ID
.d
= bb
.eax
.r
.l
;
768 ep
->configMajor
= bb
.ebx
.r
.h
;
769 ep
->configMinor
= bb
.ebx
.r
.l
;
770 ep
->checksum
= bb
.ecx
.rr
;
771 ep
->numFunctions
= bb
.edx
.r
.h
;
772 ep
->u_resources
.d
= bb
.edx
.r
.l
;
773 u
.data
[0] = bb
.edi
.r
.l
;
774 u
.data
[1] = bb
.edi
.r
.h
;
775 u
.data
[2] = bb
.esi
.r
.l
;
776 u
.data
[3] = bb
.esi
.r
.h
;
777 ep
->id
[0] = u
.s
.char1
+ ('A' - 1);
778 ep
->id
[1] = (u
.s
.char2l
| (u
.s
.char2h
<< 3)) + ('A' - 1);
779 ep
->id
[2] = u
.s
.char3
+ ('A' - 1);
780 ep
->id
[3] = hex
[u
.s
.d1
];
781 ep
->id
[4] = hex
[u
.s
.d2
];
782 ep
->id
[5] = hex
[u
.s
.d3
];
783 ep
->id
[6] = hex
[u
.s
.d4
];
789 * Note: ep must point to an address below 64k.
793 ReadEISAFuncInfo(EISA_func_info_t
*ep
, int slot
, int function
)
799 bb
.ecx
.r
.h
= function
;
800 bb
.esi
.rr
= (unsigned int)ep
->data
;
802 if (bb
.eax
.r
.h
== 0) {
804 ep
->function
= function
;
808 #endif /* EISA_SUPPORT */
810 #define PCI_SIGNATURE 0x20494350 /* "PCI " */
813 ReadPCIBusInfo(PCI_bus_info_t
*pp
)
819 if ((bb
.eax
.r
.h
== 0) && (bb
.edx
.rx
== PCI_SIGNATURE
)) {
821 pp
->u_bus
.d
= bb
.eax
.r
.l
;
822 pp
->majorVersion
= bb
.ebx
.r
.h
;
823 pp
->minorVersion
= bb
.ebx
.r
.l
;
824 pp
->maxBusNum
= bb
.ecx
.r
.l
;
832 unsigned int endtime
= (time18() + 18*n
);
833 while (time18() < endtime
);
840 bb
.ecx
.rr
= ms
>> 16;
841 bb
.edx
.rr
= ms
& 0xFFFF;