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, Inc.
26 * All rights reserved.
31 #include "appleClut8.h"
32 #include "appleboot.h"
33 #include "bootstruct.h"
38 static int currentIndicator
= 0;
40 static unsigned long lookUpCLUTIndex( unsigned char index
,
41 unsigned char depth
);
43 void drawColorRectangle( unsigned short x
,
46 unsigned short height
,
47 unsigned char colorIndex
);
49 void drawDataRectangle( unsigned short x
,
52 unsigned short height
,
53 unsigned char * data
);
55 static void setBorderColor( unsigned char colorIndex
);
58 convertImage( unsigned short width
,
59 unsigned short height
,
60 const unsigned char *imageData
,
61 unsigned char **newImageData
);
63 #define VIDEO(x) (bootArgs->Video.v_ ## x)
65 #define MIN(x, y) ((x) < (y) ? (x) : (y))
67 //==========================================================================
76 // Fetch VBE Controller Info.
78 bzero( &vbeInfo
, sizeof(vbeInfo
) );
79 err
= getVBEInfo( &vbeInfo
);
80 if ( err
!= errSuccess
)
83 // Check presence of VESA signature.
85 if ( strncmp( (char *)vbeInfo
.VESASignature
, "VESA", 4 ) )
88 // Announce controller properties.
90 small
= (vbeInfo
.TotalMemory
< 16);
92 printf("VESA v%d.%d %d%s (%s)\n",
93 vbeInfo
.VESAVersion
>> 8,
94 vbeInfo
.VESAVersion
& 0xf,
95 small
? (vbeInfo
.TotalMemory
* 64) : (vbeInfo
.TotalMemory
/ 16),
97 VBEDecodeFP(const char *, vbeInfo
.OEMStringPtr
) );
100 //==========================================================================
106 VBEInfoBlock vbeInfo
;
107 unsigned short * modePtr
;
108 VBEModeInfoBlock modeInfo
;
112 err
= getVBEInfo( &vbeInfo
);
113 if ( err
!= errSuccess
)
118 // Activate and clear page 1
119 setActiveDisplayPage(1);
120 clearScreenRows(0, 24);
121 setCursorPosition( 0, 0, 1 );
124 printf("Video modes supported:\n", VBEDecodeFP(const char *, vbeInfo
.OEMStringPtr
));
126 // Loop through the mode list, and find the matching mode.
128 for ( modePtr
= VBEDecodeFP( unsigned short *, vbeInfo
.VideoModePtr
);
129 *modePtr
!= modeEndOfList
; modePtr
++ )
131 // Get mode information.
133 bzero( &modeInfo
, sizeof(modeInfo
) );
134 err
= getVBEModeInfo( *modePtr
, &modeInfo
);
135 if ( err
!= errSuccess
)
140 printf("Mode %x: %dx%dx%d mm:%d attr:%x\n",
141 *modePtr
, modeInfo
.XResolution
, modeInfo
.YResolution
,
142 modeInfo
.BitsPerPixel
, modeInfo
.MemoryModel
,
143 modeInfo
.ModeAttributes
);
146 printf("(Press a key to continue...)");
149 clearScreenRows(0, 24);
150 setCursorPosition( 0, 0, 1 );
154 printf("(Press a key to continue...)");
157 setActiveDisplayPage(0);
161 //==========================================================================
162 // getVESAModeWithProperties
164 // Return the VESA mode that matches the properties specified.
165 // If a mode is not found, then return the "best" available mode.
167 static unsigned short
168 getVESAModeWithProperties( unsigned short width
,
169 unsigned short height
,
170 unsigned char bitsPerPixel
,
171 unsigned short attributesSet
,
172 unsigned short attributesClear
,
173 VBEModeInfoBlock
* outModeInfo
,
174 unsigned short * vesaVersion
)
176 VBEInfoBlock vbeInfo
;
177 unsigned short * modePtr
;
178 VBEModeInfoBlock modeInfo
;
179 unsigned char modeBitsPerPixel
;
180 unsigned short matchedMode
= modeEndOfList
;
183 // Clear output mode info.
185 bzero( outModeInfo
, sizeof(*outModeInfo
) );
187 // Get VBE controller info containing the list of supported modes.
189 bzero( &vbeInfo
, sizeof(vbeInfo
) );
190 err
= getVBEInfo( &vbeInfo
);
191 if ( err
!= errSuccess
)
193 return modeEndOfList
;
196 // Report the VESA major/minor version number.
198 if (vesaVersion
) *vesaVersion
= vbeInfo
.VESAVersion
;
200 // Loop through the mode list, and find the matching mode.
202 for ( modePtr
= VBEDecodeFP( unsigned short *, vbeInfo
.VideoModePtr
);
203 *modePtr
!= modeEndOfList
; modePtr
++ )
205 // Get mode information.
207 bzero( &modeInfo
, sizeof(modeInfo
) );
208 err
= getVBEModeInfo( *modePtr
, &modeInfo
);
209 if ( err
!= errSuccess
)
215 printf("Mode %x: %dx%dx%d mm:%d attr:%x\n",
216 *modePtr
, modeInfo
.XResolution
, modeInfo
.YResolution
,
217 modeInfo
.BitsPerPixel
, modeInfo
.MemoryModel
,
218 modeInfo
.ModeAttributes
);
221 // Filter out unwanted modes based on mode attributes.
223 if ( ( ( modeInfo
.ModeAttributes
& attributesSet
) != attributesSet
)
224 || ( ( modeInfo
.ModeAttributes
& attributesClear
) != 0 ) )
229 // Pixel depth in bits.
231 modeBitsPerPixel
= modeInfo
.BitsPerPixel
;
233 if ( ( modeBitsPerPixel
== 4 ) && ( modeInfo
.MemoryModel
== 0 ) )
235 // Text mode, 16 colors.
237 else if ( ( modeBitsPerPixel
== 8 ) && ( modeInfo
.MemoryModel
== 4 ) )
239 // Packed pixel, 256 colors.
241 else if ( ( ( modeBitsPerPixel
== 16 ) || ( modeBitsPerPixel
== 15 ) )
242 && ( modeInfo
.MemoryModel
== 6 )
243 && ( modeInfo
.RedMaskSize
== 5 )
244 && ( modeInfo
.GreenMaskSize
== 5 )
245 && ( modeInfo
.BlueMaskSize
== 5 ) )
247 // Direct color, 16 bpp (1:5:5:5).
248 modeInfo
.BitsPerPixel
= modeBitsPerPixel
= 16;
250 else if ( ( modeBitsPerPixel
== 32 )
251 && ( modeInfo
.MemoryModel
== 6 )
252 && ( modeInfo
.RedMaskSize
== 8 )
253 && ( modeInfo
.GreenMaskSize
== 8 )
254 && ( modeInfo
.BlueMaskSize
== 8 ) )
256 // Direct color, 32 bpp (8:8:8:8).
260 continue; // Not a supported mode.
263 // Modes larger than the specified dimensions are skipped.
265 if ( ( modeInfo
.XResolution
> width
) ||
266 ( modeInfo
.YResolution
> height
) )
271 // Perfect match, we're done looking.
273 if ( ( modeInfo
.XResolution
== width
) &&
274 ( modeInfo
.YResolution
== height
) &&
275 ( modeBitsPerPixel
== bitsPerPixel
) )
277 matchedMode
= *modePtr
;
278 bcopy( &modeInfo
, outModeInfo
, sizeof(modeInfo
) );
282 // Save the next "best" mode in case a perfect match is not found.
284 if ( modeInfo
.XResolution
== outModeInfo
->XResolution
&&
285 modeInfo
.YResolution
== outModeInfo
->YResolution
&&
286 modeBitsPerPixel
<= outModeInfo
->BitsPerPixel
)
288 continue; // Saved mode has more depth.
290 if ( modeInfo
.XResolution
< outModeInfo
->XResolution
||
291 modeInfo
.YResolution
< outModeInfo
->YResolution
||
292 modeBitsPerPixel
< outModeInfo
->BitsPerPixel
)
294 continue; // Saved mode has more resolution.
297 matchedMode
= *modePtr
;
298 bcopy( &modeInfo
, outModeInfo
, sizeof(modeInfo
) );
304 //==========================================================================
307 static void setupPalette( VBEPalette
* p
, const unsigned char * g
)
310 unsigned char * source
= (unsigned char *) g
;
312 for (i
= 0; i
< 256; i
++)
315 (*p
)[i
] |= ((unsigned long)((*source
++) >> 2)) << 16; // Red
316 (*p
)[i
] |= ((unsigned long)((*source
++) >> 2)) << 8; // Green
317 (*p
)[i
] |= ((unsigned long)((*source
++) >> 2)); // Blue
321 //==========================================================================
322 // Simple decompressor for boot images encoded in RLE format.
324 char * decodeRLE( const void * rleData
, int rleBlocks
, int outBytes
)
331 } * bp
= (struct RLEBlock
*) rleData
;
333 out
= cp
= (char *) malloc( outBytes
);
334 if ( out
== NULL
) return NULL
;
336 while ( rleBlocks
-- )
338 memset( cp
, bp
->value
, bp
->count
);
346 //==========================================================================
347 // setVESAGraphicsMode
350 setVESAGraphicsMode( unsigned short width
,
351 unsigned short height
,
352 unsigned char bitsPerPixel
,
353 unsigned short refreshRate
)
355 VBEModeInfoBlock minfo
;
357 unsigned short vesaVersion
;
358 int err
= errFuncNotSupported
;
361 mode
= getVESAModeWithProperties( width
, height
, bitsPerPixel
,
363 maModeIsSupportedBit
|
365 maLinearFrameBufferAvailBit
,
367 &minfo
, &vesaVersion
);
368 if ( mode
== modeEndOfList
)
373 if ( (vesaVersion
>> 8) >= 3 && refreshRate
>= 60 &&
374 (gBootMode
& kBootModeSafe
) == 0 )
376 VBECRTCInfoBlock timing
;
378 // Generate CRTC timing for given refresh rate.
380 generateCRTCTiming( minfo
.XResolution
, minfo
.YResolution
,
381 refreshRate
, kCRTCParamRefreshRate
,
384 // Find the actual pixel clock supported by the hardware.
386 getVBEPixelClock( mode
, &timing
.PixelClock
);
388 // Re-compute CRTC timing based on actual pixel clock.
390 generateCRTCTiming( minfo
.XResolution
, minfo
.YResolution
,
391 timing
.PixelClock
, kCRTCParamPixelClock
,
394 // Set the video mode and use specified CRTC timing.
396 err
= setVBEMode( mode
| kLinearFrameBufferBit
|
397 kCustomRefreshRateBit
, &timing
);
401 // Set the mode with default refresh rate.
403 err
= setVBEMode( mode
| kLinearFrameBufferBit
, NULL
);
405 if ( err
!= errSuccess
)
410 // Set 8-bit color palette.
412 if ( minfo
.BitsPerPixel
== 8 )
415 setupPalette( &palette
, appleClut8
);
416 if ((err
= setVBEPalette(palette
)) != errSuccess
)
422 // Is this required for buggy Video BIOS implementations?
425 if ( minfo
.BytesPerScanline
== 0 )
426 minfo
.BytesPerScanline
= ( minfo
.XResolution
*
427 minfo
.BitsPerPixel
) >> 3;
429 // Update KernBootStruct using info provided by the selected
432 bootArgs
->Video
.v_display
= GRAPHICS_MODE
;
433 bootArgs
->Video
.v_width
= minfo
.XResolution
;
434 bootArgs
->Video
.v_height
= minfo
.YResolution
;
435 bootArgs
->Video
.v_depth
= minfo
.BitsPerPixel
;
436 bootArgs
->Video
.v_rowBytes
= minfo
.BytesPerScanline
;
437 bootArgs
->Video
.v_baseAddr
= VBEMakeUInt32(minfo
.PhysBasePtr
);
446 convertImage( unsigned short width
,
447 unsigned short height
,
448 const unsigned char *imageData
,
449 unsigned char **newImageData
)
452 unsigned char *img
= 0;
453 unsigned short *img16
;
454 unsigned long *img32
;
456 switch ( VIDEO(depth
) ) {
458 img16
= malloc(width
* height
* 2);
460 for (cnt
= 0; cnt
< (width
* height
); cnt
++)
461 img16
[cnt
] = lookUpCLUTIndex(imageData
[cnt
], 16);
462 img
= (unsigned char *)img16
;
466 img32
= malloc(width
* height
* 4);
468 for (cnt
= 0; cnt
< (width
* height
); cnt
++)
469 img32
[cnt
] = lookUpCLUTIndex(imageData
[cnt
], 32);
470 img
= (unsigned char *)img32
;
474 img
= malloc(width
* height
);
475 bcopy(imageData
, img
, width
* height
);
482 //==========================================================================
486 drawBootGraphics( void )
488 unsigned char * imageData
= 0;
490 char * appleBootPict
;
493 // Fill the background to 75% grey (same as BootX).
495 drawColorRectangle( 0, 0, VIDEO(width
), VIDEO(height
),
496 0x01 /* color index */ );
498 setBorderColor( 0x01 /* color index */ );
500 appleBootPict
= decodeRLE( gAppleBootPictRLE
, kAppleBootRLEBlocks
,
501 kAppleBootWidth
* kAppleBootHeight
);
503 // Prepare the data for the happy mac.
507 convertImage(kAppleBootWidth
, kAppleBootHeight
,
508 (unsigned char *)appleBootPict
, &imageData
);
510 x
= ( VIDEO(width
) - kAppleBootWidth
) / 2;
511 y
= ( VIDEO(height
) - kAppleBootHeight
) / 2 + kAppleBootOffset
;
513 // Draw the happy mac in the center of the display.
517 drawDataRectangle( x
, y
, kAppleBootWidth
, kAppleBootHeight
,
521 free( appleBootPict
);
527 //==========================================================================
530 static unsigned long lookUpCLUTIndex( unsigned char index
,
531 unsigned char depth
)
533 long result
, red
, green
, blue
;
535 red
= appleClut8
[index
* 3 + 0];
536 green
= appleClut8
[index
* 3 + 1];
537 blue
= appleClut8
[index
* 3 + 2];
541 result
= ((red
& 0xF8) << 7) |
542 ((green
& 0xF8) << 2) |
543 ((blue
& 0xF8) >> 3);
544 result
|= (result
<< 16);
548 result
= (red
<< 16) | (green
<< 8) | blue
;
552 result
= index
| (index
<< 8);
553 result
|= (result
<< 16);
560 //==========================================================================
561 // drawColorRectangle
563 static void * stosl(void * dst
, long val
, long len
)
565 asm volatile ( "rep; stosl"
566 : "=c" (len
), "=D" (dst
)
567 : "0" (len
), "1" (dst
), "a" (val
)
573 void drawColorRectangle( unsigned short x
,
575 unsigned short width
,
576 unsigned short height
,
577 unsigned char colorIndex
)
580 long color
= lookUpCLUTIndex( colorIndex
, VIDEO(depth
) );
583 pixelBytes
= VIDEO(depth
) / 8;
584 vram
= (char *) VIDEO(baseAddr
) +
585 VIDEO(rowBytes
) * y
+ pixelBytes
* x
;
587 width
= MIN(width
, VIDEO(width
) - x
);
588 height
= MIN(height
, VIDEO(height
) - y
);
592 int rem
= ( pixelBytes
* width
) % 4;
593 if ( rem
) bcopy( &color
, vram
, rem
);
594 stosl( vram
+ rem
, color
, pixelBytes
* width
/ 4 );
595 vram
+= VIDEO(rowBytes
);
599 //==========================================================================
602 void drawDataRectangle( unsigned short x
,
604 unsigned short width
,
605 unsigned short height
,
606 unsigned char * data
)
608 unsigned short drawWidth
;
609 long pixelBytes
= VIDEO(depth
) / 8;
610 unsigned char * vram
= (unsigned char *) VIDEO(baseAddr
) +
611 VIDEO(rowBytes
) * y
+ pixelBytes
* x
;
613 drawWidth
= MIN(width
, VIDEO(width
) - x
);
614 height
= MIN(height
, VIDEO(height
) - y
);
616 bcopy( data
, vram
, drawWidth
* pixelBytes
);
617 vram
+= VIDEO(rowBytes
);
618 data
+= width
* pixelBytes
;
623 //==========================================================================
627 setBorderColor( unsigned char colorIndex
)
629 long color
= lookUpCLUTIndex( colorIndex
, 32 );
630 VBEInfoBlock vbeInfo
;
633 // Get VBE controller info.
635 bzero( &vbeInfo
, sizeof(vbeInfo
) );
636 err
= getVBEInfo( &vbeInfo
);
637 if ( err
!= errSuccess
)
645 //==========================================================================
649 setVESATextMode( unsigned short cols
,
651 unsigned char bitsPerPixel
)
653 VBEModeInfoBlock minfo
;
654 unsigned short mode
= modeEndOfList
;
656 if ( (cols
!= 80) || (rows
!= 25) ) // not 80x25 mode
658 mode
= getVESAModeWithProperties( cols
, rows
, bitsPerPixel
,
660 maModeIsSupportedBit
,
665 if ( ( mode
== modeEndOfList
) || ( setVBEMode(mode
, NULL
) != errSuccess
) )
667 video_mode( 2 ); // VGA BIOS, 80x25 text mode.
668 minfo
.XResolution
= 80;
669 minfo
.YResolution
= 25;
672 // Update KernBootStruct using info provided by the selected
675 bootArgs
->Video
.v_display
= VGA_TEXT_MODE
;
676 bootArgs
->Video
.v_baseAddr
= 0xb8000;
677 bootArgs
->Video
.v_width
= minfo
.XResolution
;
678 bootArgs
->Video
.v_height
= minfo
.YResolution
;
679 bootArgs
->Video
.v_depth
= 8;
680 bootArgs
->Video
.v_rowBytes
= 0x8000;
682 return errSuccess
; // always return success
685 //==========================================================================
686 // getNumberArrayFromProperty
689 getNumberArrayFromProperty( const char * propKey
,
690 unsigned long numbers
[],
691 unsigned long maxArrayCount
)
694 unsigned long count
= 0;
696 #define _isdigit(c) ((c) >= '0' && (c) <= '9')
698 propStr
= newStringForKey( (char *) propKey
);
701 char * delimiter
= propStr
;
704 while ( count
< maxArrayCount
&& *p
!= '\0' )
706 unsigned long val
= strtoul( p
, &delimiter
, 10 );
707 if ( p
!= delimiter
)
709 numbers
[count
++] = val
;
712 while ( ( *p
!= '\0' ) && !_isdigit(*p
) )
722 //==========================================================================
725 // Set the video mode to VGA_TEXT_MODE or GRAPHICS_MODE.
728 setVideoMode( int mode
)
730 unsigned long params
[4];
732 int err
= errSuccess
;
734 if ( mode
== GRAPHICS_MODE
)
737 count
= getNumberArrayFromProperty( kGraphicsModeKey
, params
, 4 );
740 params
[0] = 1024; // Default graphics mode is 1024x768x32.
745 // Map from pixel format to bits per pixel.
747 if ( params
[2] == 256 ) params
[2] = 8;
748 if ( params
[2] == 555 ) params
[2] = 16;
749 if ( params
[2] == 888 ) params
[2] = 32;
751 err
= setVESAGraphicsMode( params
[0], params
[1], params
[2], params
[3] );
752 if ( err
== errSuccess
)
755 // Tell the kernel to use text mode on a linear frame buffer display
756 bootArgs
->Video
.v_display
= FB_TEXT_MODE
;
758 bootArgs
->Video
.v_display
= GRAPHICS_MODE
;
764 if ( (mode
== VGA_TEXT_MODE
) || (err
!= errSuccess
) )
766 count
= getNumberArrayFromProperty( kTextModeKey
, params
, 2 );
769 params
[0] = 80; // Default text mode is 80x25.
773 setVESATextMode( params
[0], params
[1], 4 );
774 bootArgs
->Video
.v_display
= VGA_TEXT_MODE
;
777 currentIndicator
= 0;
780 //==========================================================================
781 // Return the current video mode, VGA_TEXT_MODE or GRAPHICS_MODE.
783 int getVideoMode(void)
785 return bootArgs
->Video
.v_display
;
788 //==========================================================================
789 // Display and clear the activity indicator.
791 static char indicator
[] = {'-', '\\', '|', '/', '-', '\\', '|', '/', '\0'};
792 #define kNumIndicators (sizeof(indicator) - 1)
794 // To prevent a ridiculously fast-spinning indicator,
795 // ensure a minimum of 1/9 sec between animation frames.
799 spinActivityIndicator( void )
801 static unsigned long lastTickTime
= 0;
802 unsigned long currentTickTime
= time18();
803 static char string
[3] = {'\0', '\b', '\0'};
805 if (currentTickTime
< lastTickTime
+ MIN_TICKS
)
808 lastTickTime
= currentTickTime
;
810 if ( getVideoMode() == VGA_TEXT_MODE
)
812 if (currentIndicator
>= kNumIndicators
) currentIndicator
= 0;
813 string
[0] = indicator
[currentIndicator
++];
819 clearActivityIndicator( void )
821 if ( getVideoMode() == VGA_TEXT_MODE
)