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
= rangeArray
;
91 unsigned long count
= 0;
92 unsigned long long conMemSize
= 0;
93 unsigned long long extMemSize
= 0;
95 // The memory pointed by the rangeArray must reside within the
98 // Prepare for the INT15 E820h call. Each call returns a single
99 // memory range. A continuation value is returned that must be
100 // provided on a subsequent call to fetch the next range.
102 // Certain BIOSes (Award 6.00PG) expect the upper word in EAX
103 // to be cleared on entry, otherwise only a single range will
106 // Some BIOSes will simply ignore the value of ECX on entry.
107 // Probably best to keep its value at 20 to avoid surprises.
109 bb
.ebx
.rx
= 0; // Initial continuation value must be zero.
111 while ( count
< maxRangeCount
)
115 bb
.ecx
.rx
= kDescriptorSizeMin
;
116 bb
.edx
.rx
= kMemoryMapSignature
;
117 bb
.edi
.rr
= OFFSET( (unsigned long) range
);
118 bb
.es
= SEGMENT( (unsigned long) range
);
124 || bb
.eax
.rx
!= kMemoryMapSignature
125 || bb
.ecx
.rx
!= kDescriptorSizeMin
) break;
127 // Tally up the conventional/extended memory sizes.
129 if ( range
->type
== kMemoryRangeUsable
||
130 range
->type
== kMemoryRangeACPI
||
131 range
->type
== kMemoryRangeNVS
)
133 // Tally the conventional memory ranges.
134 if ( range
->base
+ range
->length
<= 0xa0000 ) {
135 conMemSize
+= range
->length
;
138 // Record the top of extended memory.
139 if ( range
->base
>= EXTENDED_ADDR
) {
140 extMemSize
+= range
->length
;
147 // Is this the last address range?
149 if ( bb
.ebx
.rx
== 0 ) break;
151 *conMemSizePtr
= conMemSize
/ 1024; // size in KB
152 *extMemSizePtr
= extMemSize
/ 1024; // size in KB
156 for (range
= rangeArray
; range
->length
!= 0; range
++) {
157 printf("range: type %d, base 0x%x, length 0x%x\n",
158 range
->type
, (unsigned int)range
->base
, (unsigned int)range
->length
); getc();
167 unsigned long getExtendedMemorySize()
169 // Get extended memory size for large configurations. Not used unless
170 // the INT15, E820H call (Get System Address Map) failed.
174 // AX Function Code E801h
178 // CF Carry Flag Carry cleared indicates no error.
179 // AX Extended 1 Number of contiguous KB between 1 and 16 MB,
180 // maximum 0x3C00 = 15 MB.
181 // BX Extended 2 Number of contiguous 64 KB blocks between
183 // CX Configured 1 Number of contiguous KB between 1 and 16 MB,
184 // maximum 0x3C00 = 15 MB.
185 // DX Configured 2 Number of contiguous 64 KB blocks between
192 // Return the size of memory above 1MB (extended memory) in kilobytes.
194 if ( bb
.flags
.cf
== 0 ) return (bb
.ebx
.rr
* 64 + bb
.eax
.rr
);
196 // Get Extended memory size. Called on last resort since the return
197 // value is limited to 16-bits (a little less than 64MB max). May
198 // not be supported by modern BIOSes.
202 // AX Function Code E801h
206 // CF Carry Flag Carry cleared indicates no error.
207 // AX Memory Count Number of contiguous KB above 1MB.
213 // Return the size of memory above 1MB (extended memory) in kilobytes.
215 return bb
.flags
.cf
? 0 : bb
.eax
.rr
;
218 unsigned long getConventionalMemorySize()
222 return bb
.eax
.rr
; // kilobytes
225 void video_mode(int mode
)
233 int biosread(int dev
, int cyl
, int head
, int sec
, int num
)
238 sec
+= 1; /* sector numbers start at 1 */
242 bb
.ecx
.r
.l
= ((cyl
& 0x300) >> 2) | (sec
& 0x3F);
246 bb
.ebx
.rr
= OFFSET(ptov(BIOS_ADDR
));
247 bb
.es
= SEGMENT(ptov(BIOS_ADDR
));
252 if ((bb
.eax
.r
.h
== 0x00) || (i
++ >= 5))
255 /* reset disk subsystem and try again */
262 int ebiosread(int dev
, long sec
, int count
)
267 unsigned char reserved
;
268 unsigned char numblocks
;
269 unsigned char reserved2
;
270 unsigned short bufferOffset
;
271 unsigned short bufferSegment
;
272 unsigned long long startblock
;
273 } addrpacket
__attribute__((aligned(16))) = {0};
274 addrpacket
.size
= sizeof(addrpacket
);
280 bb
.esi
.rr
= OFFSET((unsigned)&addrpacket
);
281 bb
.ds
= SEGMENT((unsigned)&addrpacket
);
282 addrpacket
.reserved
= addrpacket
.reserved2
= 0;
283 addrpacket
.numblocks
= count
;
284 addrpacket
.bufferOffset
= OFFSET(ptov(BIOS_ADDR
));
285 addrpacket
.bufferSegment
= SEGMENT(ptov(BIOS_ADDR
));
286 addrpacket
.startblock
= sec
;
288 if ((bb
.eax
.r
.h
== 0x00) || (i
++ >= 5))
291 /* reset disk subsystem and try again */
298 int ebioswrite(int dev
, long sec
, int count
)
303 unsigned char reserved
;
304 unsigned char numblocks
;
305 unsigned char reserved2
;
306 unsigned short bufferOffset
;
307 unsigned short bufferSegment
;
308 unsigned long long startblock
;
309 } addrpacket
__attribute__((aligned(16))) = {0};
310 addrpacket
.size
= sizeof(addrpacket
);
314 bb
.eax
.r
.l
= 0; /* Don't verify */
317 bb
.esi
.rr
= OFFSET((unsigned)&addrpacket
);
318 bb
.ds
= SEGMENT((unsigned)&addrpacket
);
319 addrpacket
.reserved
= addrpacket
.reserved2
= 0;
320 addrpacket
.numblocks
= count
;
321 addrpacket
.bufferOffset
= OFFSET(ptov(BIOS_ADDR
));
322 addrpacket
.bufferSegment
= SEGMENT(ptov(BIOS_ADDR
));
323 addrpacket
.startblock
= sec
;
325 if ((bb
.eax
.r
.h
== 0x00) || (i
++ >= 5))
328 /* reset disk subsystem and try again */
338 bb
.ebx
.r
.h
= 0x00; /* background black */
339 bb
.ebx
.r
.l
= 0x0F; /* foreground white */
345 void putca(int ch
, int attr
, int repeat
)
348 bb
.ebx
.r
.h
= 0x00; /* page number */
349 bb
.ebx
.r
.l
= attr
; /* attribute */
352 bb
.ecx
.rx
= repeat
; /* repeat count */
356 /* Check to see if the passed-in drive is in El Torito no-emulation mode. */
357 int is_no_emulation(int drive
)
360 unsigned char packet_size
;
361 unsigned char media_type
;
362 unsigned char drive_num
;
363 unsigned char ctrlr_index
;
365 unsigned short device_spec
;
366 unsigned short buffer_segment
;
367 unsigned short load_segment
;
368 unsigned short sector_count
;
369 unsigned char cyl_count
;
370 unsigned char sec_count
;
371 unsigned char head_count
;
372 unsigned char reseved
;
373 } __attribute__((packed
));
374 static struct packet pkt
;
376 bzero(&pkt
, sizeof(pkt
));
377 pkt
.packet_size
= 0x13;
381 bb
.eax
.r
.l
= 0x01; // subfunc: get info
383 bb
.esi
.rr
= OFFSET((unsigned)&pkt
);
384 bb
.ds
= SEGMENT((unsigned)&pkt
);
388 printf("el_torito info drive %x\n", drive
);
390 printf("--> cf %x, eax %x\n", bb
.flags
.cf
, bb
.eax
.rr
);
392 printf("pkt_size: %x\n", pkt
.packet_size
);
393 printf("media_type: %x\n", pkt
.media_type
);
394 printf("drive_num: %x\n", pkt
.drive_num
);
395 printf("device_spec: %x\n", pkt
.device_spec
);
396 printf("press a key->\n");getc();
399 /* Some BIOSes erroneously return cf = 1 */
400 /* Just check to see if the drive number is the same. */
401 if (pkt
.drive_num
== drive
) {
402 if ((pkt
.media_type
& 0x0F) == 0) {
403 /* We are in no-emulation mode. */
413 * BIOS drive information.
415 void print_drive_info(boot_drive_info_t
*dp
)
417 // printf("buf_size = %x\n", dp->params.buf_size);
418 printf("info_flags = %x\n", dp
->params
.info_flags
);
419 printf(" phys_cyls = %lx\n", dp
->params
. phys_cyls
);
420 printf(" phys_heads = %lx\n", dp
->params
. phys_heads
);
421 printf(" phys_spt = %lx\n", dp
->params
. phys_spt
);
422 printf("phys_sectors = %lx%lx\n", ((unsigned long *)(&dp
->params
.phys_sectors
))[1],
423 ((unsigned long *)(&dp
->params
.phys_sectors
))[0]);
424 printf("phys_nbps = %x\n", dp
->params
.phys_nbps
);
425 // printf("dpte_offset = %x\n", dp->params.dpte_offset);
426 // printf("dpte_segment = %x\n", dp->params.dpte_segment);
427 // printf("key = %x\n", dp->params.key);
428 // printf("path_len = %x\n", dp->params. path_len);
429 // printf("reserved1 = %x\n", dp->params. reserved1);
430 // printf("reserved2 = %x\n", dp->params.reserved2);
431 //printf("bus_type[4] = %x\n", dp->params. bus_type[4]);
432 //printf("interface_type[8] = %x\n", dp->params. interface_type[8]);
433 //printf("interface_path[8] = %x\n", dp->params. interface_path[8]);
434 //printf("dev_path[8] = %x\n", dp->params. dev_path[8]);
435 // printf("reserved3 = %x\n", dp->params. reserved3);
436 // printf("checksum = %x\n", dp->params. checksum);
438 printf(" io_port_base = %x\n", dp
->dpte
.io_port_base
);
439 printf(" control_port_base = %x\n", dp
->dpte
.control_port_base
);
440 printf(" head_flags = %x\n", dp
->dpte
. head_flags
);
441 printf(" vendor_info = %x\n", dp
->dpte
. vendor_info
);
442 printf(" irq = %x\n", dp
->dpte
. irq
);
443 // printf(" irq_unused = %x\n", dp->dpte. irq_unused);
444 printf(" block_count = %x\n", dp
->dpte
. block_count
);
445 printf(" dma_channe = %x\n", dp
->dpte
. dma_channel
);
446 printf(" dma_type = %x\n", dp
->dpte
. dma_type
);
447 printf(" pio_type = %x\n", dp
->dpte
. pio_type
);
448 printf(" pio_unused = %x\n", dp
->dpte
. pio_unused
);
449 printf(" option_flags = %x\n", dp
->dpte
.option_flags
);
450 // printf(" reserved = %x\n", dp->dpte.reserved);
451 printf(" revision = %x\n", dp
->dpte
. revision
);
452 // printf(" checksum = %x\n", dp->dpte. checksum);
457 int get_drive_info(int drive
, struct driveInfo
*dp
)
459 boot_drive_info_t
*di
= &dp
->di
;
468 if (bb
.flags
.cf
== 0)
469 maxhd
= 0x7f + bb
.edx
.r
.l
;
476 bzero(dp
, sizeof(struct driveInfo
));
479 /* Check for El Torito no-emulation mode. */
480 dp
->no_emulation
= is_no_emulation(drive
);
482 /* Check drive for EBIOS support. */
488 if((bb
.ebx
.rr
== 0xaa55) && (bb
.flags
.cf
== 0)) {
489 /* Get flags for supported operations. */
490 dp
->uses_ebios
= bb
.ecx
.r
.l
;
493 if (dp
->uses_ebios
& (EBIOS_ENHANCED_DRIVE_INFO
| EBIOS_LOCKING_ACCESS
| EBIOS_FIXED_DISK_ACCESS
)) {
494 /* Get EBIOS drive info. */
495 static struct drive_params params
;
497 params
.buf_size
= sizeof(params
);
501 bb
.esi
.rr
= OFFSET((unsigned)¶ms
);
502 bb
.ds
= SEGMENT((unsigned)¶ms
);
504 if(bb
.flags
.cf
!= 0 /* || params.phys_sectors < 2097152 */) {
506 di
->params
.buf_size
= 1;
508 bcopy(¶ms
, &di
->params
, sizeof(params
));
510 if (drive
>= BASE_HD_DRIVE
&&
511 (dp
->uses_ebios
& EBIOS_ENHANCED_DRIVE_INFO
) &&
512 di
->params
.buf_size
>= 30 &&
513 !(di
->params
.dpte_offset
== 0xFFFF && di
->params
.dpte_segment
== 0xFFFF)) {
514 void *ptr
= (void *)(di
->params
.dpte_offset
+ ((unsigned int)di
->params
.dpte_segment
<< 4));
515 bcopy(ptr
, &di
->dpte
, sizeof(di
->dpte
));
520 if (di
->params
.phys_heads
== 0 || di
->params
.phys_spt
== 0) {
521 /* Either it's not EBIOS, or EBIOS didn't tell us. */
526 if (bb
.flags
.cf
== 0 && bb
.eax
.r
.h
== 0) {
532 sec
= bb
.ecx
.r
.l
& 0x3F;
533 if((dp
->uses_ebios
& EBIOS_ENHANCED_DRIVE_INFO
) && (sec
!= 0)) {
534 cyl
= (di
->params
.phys_sectors
/ ((hds
+ 1) * sec
)) - 1;
537 cyl
= bb
.ecx
.r
.h
| ((bb
.ecx
.r
.l
& 0xC0) << 2);
539 di
->params
.phys_heads
= hds
;
540 di
->params
.phys_spt
= sec
;
541 di
->params
.phys_cyls
= cyl
;
547 if (dp
->no_emulation
) {
548 /* Some BIOSes give us erroneous EBIOS support information.
549 * Assume that if you're on a CD, then you can use
552 dp
->uses_ebios
|= EBIOS_FIXED_DISK_ACCESS
;
555 print_drive_info(di
);
556 printf("uses_ebios = 0x%x\n", dp
->uses_ebios
);
557 printf("press a key->\n");getc();
566 void setCursorPosition(int x
, int y
, int page
)
570 bb
.ebx
.r
.h
= page
; /* page 0 for graphics */
576 void setCursorType(int type
)
584 void getCursorPositionAndType(int * x
, int * y
, int * type
)
594 void scollPage(int x1
, int y1
, int x2
, int y2
, int attr
, int rows
, int dir
)
597 bb
.eax
.r
.h
= (dir
> 0) ? 0x06 : 0x07;
607 void clearScreenRows( int y1
, int y2
)
609 scollPage( 0, y1
, 80 - 1, y2
, 0x07, y2
- y1
+ 1, 1 );
612 void setActiveDisplayPage( int page
)
622 int terminateDiskEmulation()
624 static char cd_spec
[0x13];
628 bb
.eax
.r
.l
= 0; // subfunc: terminate emulation
629 bb
.esi
.rr
= OFFSET((unsigned)&cd_spec
);
630 bb
.ds
= SEGMENT((unsigned)&cd_spec
);
635 int readDriveParameters(int drive
, struct driveParameters
*dp
)
641 if (bb
.eax
.r
.h
== 0) {
642 dp
->heads
= bb
.edx
.r
.h
;
643 dp
->sectors
= bb
.ecx
.r
.l
& 0x3F;
644 dp
->cylinders
= bb
.ecx
.r
.h
| ((bb
.ecx
.r
.l
& 0xC0) << 2);
645 dp
->totalDrives
= bb
.edx
.r
.l
;
647 bzero(dp
, sizeof(*dp
));
656 #define APM_INTNO 0x15
657 #define APM_INTCODE 0x53
662 bb
.intno
= APM_INTNO
;
663 bb
.eax
.r
.h
= APM_INTCODE
;
667 if ((bb
.flags
.cf
== 0) &&
668 (bb
.ebx
.r
.h
== 'P') &&
669 (bb
.ebx
.r
.l
== 'M')) {
671 bootArgs
->apmConfig
.major_vers
= bb
.eax
.r
.h
;
672 bootArgs
->apmConfig
.minor_vers
= bb
.eax
.r
.l
;
673 bootArgs
->apmConfig
.flags
.data
= bb
.ecx
.rr
;
682 bb
.intno
= APM_INTNO
;
683 bb
.eax
.r
.h
= APM_INTCODE
;
687 if (bb
.flags
.cf
== 0) {
689 bootArgs
->apmConfig
.cs32_base
= (bb
.eax
.rr
) << 4;
690 bootArgs
->apmConfig
.entry_offset
= bb
.ebx
.rx
;
691 bootArgs
->apmConfig
.cs16_base
= (bb
.ecx
.rr
) << 4;
692 bootArgs
->apmConfig
.ds_base
= (bb
.edx
.rr
) << 4;
693 if (bootArgs
->apmConfig
.major_vers
>= 1 &&
694 bootArgs
->apmConfig
.minor_vers
>= 1) {
695 bootArgs
->apmConfig
.cs_length
= bb
.esi
.rr
;
696 bootArgs
->apmConfig
.ds_length
= bb
.edi
.rr
;
698 bootArgs
->apmConfig
.cs_length
=
699 bootArgs
->apmConfig
.ds_length
= 64 * 1024;
701 bootArgs
->apmConfig
.connected
= 1;
707 #endif /* APM_SUPPORT */
719 if (strncmp((char *)0xfffd9, "EISA", 4) == 0)
729 ReadEISASlotInfo(EISA_slot_info_t
*ep
, int slot
)
733 unsigned char char2h
:2;
734 unsigned char char1
:5;
735 unsigned char char3
:5;
736 unsigned char char2l
:3;
742 unsigned char data
[4];
744 static char hex
[0x10] = "0123456789ABCDEF";
754 ep
->u_ID
.d
= bb
.eax
.r
.l
;
755 ep
->configMajor
= bb
.ebx
.r
.h
;
756 ep
->configMinor
= bb
.ebx
.r
.l
;
757 ep
->checksum
= bb
.ecx
.rr
;
758 ep
->numFunctions
= bb
.edx
.r
.h
;
759 ep
->u_resources
.d
= bb
.edx
.r
.l
;
760 u
.data
[0] = bb
.edi
.r
.l
;
761 u
.data
[1] = bb
.edi
.r
.h
;
762 u
.data
[2] = bb
.esi
.r
.l
;
763 u
.data
[3] = bb
.esi
.r
.h
;
764 ep
->id
[0] = u
.s
.char1
+ ('A' - 1);
765 ep
->id
[1] = (u
.s
.char2l
| (u
.s
.char2h
<< 3)) + ('A' - 1);
766 ep
->id
[2] = u
.s
.char3
+ ('A' - 1);
767 ep
->id
[3] = hex
[u
.s
.d1
];
768 ep
->id
[4] = hex
[u
.s
.d2
];
769 ep
->id
[5] = hex
[u
.s
.d3
];
770 ep
->id
[6] = hex
[u
.s
.d4
];
776 * Note: ep must point to an address below 64k.
780 ReadEISAFuncInfo(EISA_func_info_t
*ep
, int slot
, int function
)
786 bb
.ecx
.r
.h
= function
;
787 bb
.esi
.rr
= (unsigned int)ep
->data
;
789 if (bb
.eax
.r
.h
== 0) {
791 ep
->function
= function
;
795 #endif /* EISA_SUPPORT */
797 #define PCI_SIGNATURE 0x20494350 /* "PCI " */
800 ReadPCIBusInfo(PCI_bus_info_t
*pp
)
806 if ((bb
.eax
.r
.h
== 0) && (bb
.edx
.rx
== PCI_SIGNATURE
)) {
808 pp
->u_bus
.d
= bb
.eax
.r
.l
;
809 pp
->majorVersion
= bb
.ebx
.r
.h
;
810 pp
->minorVersion
= bb
.ebx
.r
.l
;
811 pp
->maxBusNum
= bb
.ecx
.r
.l
;
819 unsigned int endtime
= (time18() + 18*n
);
820 while (time18() < endtime
);
827 bb
.ecx
.rr
= ms
>> 16;
828 bb
.edx
.rr
= ms
& 0xFFFF;