]> git.saurik.com Git - apple/xnu.git/blame - osfmk/console/panic_dialog.c
xnu-792.12.6.tar.gz
[apple/xnu.git] / osfmk / console / panic_dialog.c
CommitLineData
55e303ae 1/*
91447636 2 * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
55e303ae 3 *
8ad349bb 4 * @APPLE_LICENSE_OSREFERENCE_HEADER_START@
55e303ae 5 *
8ad349bb
A
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the
10 * License may not be used to create, or enable the creation or
11 * redistribution of, unlawful or unlicensed copies of an Apple operating
12 * system, or to circumvent, violate, or enable the circumvention or
13 * violation of, any terms of an Apple operating system software license
14 * agreement.
15 *
16 * Please obtain a copy of the License at
17 * http://www.opensource.apple.com/apsl/ and read it before using this
18 * file.
19 *
20 * The Original Code and all software distributed under the License are
21 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
22 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
23 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
24 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
25 * Please see the License for the specific language governing rights and
26 * limitations under the License.
27 *
28 * @APPLE_LICENSE_OSREFERENCE_HEADER_END@
55e303ae
A
29 */
30
31#include <vc.h>
55e303ae
A
32#include <console/video_console.h>
33#include <kdp/kdp_udp.h>
34#include <kern/debug.h>
91447636
A
35#include <mach/mach_time.h>
36#include <sys/errno.h>
37#include <string.h>
55e303ae 38
55e303ae
A
39
40extern struct vc_info vinfo;
41extern boolean_t panicDialogDesired;
42
91447636
A
43#include "panic_image.c"
44
45void panic_ui_initialize(const unsigned char * system_clut);
46int panic_dialog_set_image( const unsigned char * ptr, unsigned int size );
47void panic_dialog_get_image( unsigned char ** ptr, unsigned int * size );
48void draw_panic_dialog( void );
49void panic_dialog_test( void );
50
51static int panic_dialog_verify( const struct panicimage * data, unsigned int size );
52static int pixels_needed_to_blit_digit( int digit );
55e303ae 53static void blit_digit( int digit );
91447636
A
54static char * strnstr(const char * s, const char * find, size_t slen);
55static void dim_screen(void);
56static void panic_blit_rect(unsigned int x, unsigned int y, unsigned int width, unsigned int height,
57 int transparent, unsigned char * dataPtr );
58
59static int panic_info_x;
60static int panic_info_y;
61
62static const unsigned char * active_clut = NULL; /* This is a copy of the active clut */
63
55e303ae
A
64static boolean_t panicDialogDrawn = FALSE;
65
91447636
A
66static const struct panicimage * panic_dialog = NULL; /* the active panic dialog */
67static const unsigned char * panic_dialog_data = NULL; /* where the image data starts */
68static const unsigned char * panic_dialog_clut = NULL; /* where the clut used for the image starts */
55e303ae 69
91447636
A
70static unsigned char * curr_image_ptr = NULL; /* If NULL, the default panic dialog is active */
71static unsigned int curr_image_size = 0;
55e303ae 72
91447636
A
73#define FONT_WIDTH 8
74#define FONT_HEIGHT 16
75static unsigned short rendered_font[FONT_HEIGHT][FONT_WIDTH];
55e303ae 76
91447636 77static char versionbuf[20]; /* ####.###~###\0 */
55e303ae 78
91447636 79#define isdigit(d) ((d) >= '0' && (d) <= '9')
55e303ae 80
91447636
A
81#define CLUT_ENTRIES 256
82#define CLUT_SIZE (CLUT_ENTRIES * 3)
83
84
85/*
86 * This routine sets up the default panic dialog
87 */
88
89extern unsigned char iso_font[];
90extern const char version[];
91extern unsigned int panic_caller;
92
93void
55e303ae
A
94panic_ui_initialize(const unsigned char * system_clut)
95{
91447636
A
96 char vstr[20];
97
98
99 panic_dialog_set_image( NULL, 0 );
100
101 active_clut = system_clut;
102
103 strcpy(vstr, "custom");
104
105 /* Convert xnu-####.###.obj~### into ####.###~### */
106
107 if (version) {
108 char * versionpos = strnstr(version, "xnu-", 20);
109
110 if (versionpos) {
111 int len, i;
112
113 vstr[0] = '\0';
114
115 for (i=0,len=4;len<20;len++) {
116 if (isdigit(versionpos[len]) || versionpos[len] == '.') { /* extract ####.###. */
117 vstr[i++] = versionpos[len];
118 continue;
119 }
120 break;
121 }
122
123 if ( versionpos[len-1] == '.' ) /* remove trailing period if present */
124 i--;
125
126 for (;len<20;len++) { /* skip to next digit if present */
127 if ( !isdigit(versionpos[len]) )
128 continue;
129 break;
130 }
131
132 if ( versionpos[len-1] == '~' ) { /* extract ~### if present */
133 vstr[i++] = versionpos[len-1];
134 for (;len<20;len++) { /* extract ### */
135 if ( isdigit(versionpos[len]) ) {
136 vstr[i++] = versionpos[len];
137 continue;
138 }
139 break;
140 }
141 }
142
143 vstr[i] = '\0';
144 }
145 }
146
147 strcpy(versionbuf, vstr);
148}
149
150
151
152void
153panic_dialog_test( void )
154{
155 boolean_t o_panicDialogDrawn = panicDialogDrawn;
156 boolean_t o_panicDialogDesired = panicDialogDesired;
157 unsigned int o_logPanicDataToScreen = logPanicDataToScreen;
158 unsigned int o_panic_caller = panic_caller;
159 unsigned int o_panicDebugging = panicDebugging;
160
161
162 panicDebugging = TRUE;
163 panic_caller = (unsigned int) __builtin_return_address(0);
164 logPanicDataToScreen = FALSE;
165 panicDialogDesired = TRUE;
166 panicDialogDrawn = FALSE;
167
168 draw_panic_dialog();
169
170 panicDebugging = o_panicDebugging;
171 panic_caller = o_panic_caller;
172 logPanicDataToScreen = o_logPanicDataToScreen;
173 panicDialogDesired = o_panicDialogDesired;
174 panicDialogDrawn = o_panicDialogDrawn;
55e303ae
A
175}
176
91447636 177
55e303ae
A
178void
179draw_panic_dialog( void )
180{
91447636
A
181 if (!panicDialogDrawn && panicDialogDesired) {
182 if ( !logPanicDataToScreen ) {
183 int pd_x, pd_y;
184 int count, nibble, indx;
185 struct ether_addr kdp_mac_addr;
186 unsigned int panic_dialog_count, ip_addr;
187 char panic_num_chars[13+8+1], mac_addr_chars[17+1], ip_addr_chars[15+1];
188 struct {
189 int pixels;
190 char * chars;
191 } panic_dialog_info[3];
192
55e303ae
A
193
194 /* dim the screen 50% before putting up panic dialog */
195 dim_screen();
196
197 /* set up to draw background box */
91447636
A
198 /* by locating where the upper left corner is placed */
199
200 pd_x = (vinfo.v_width/2) - panic_dialog->pd_width/2;
201 pd_y = (vinfo.v_height/2) - panic_dialog->pd_height/2;
55e303ae 202
91447636
A
203 /* draw panic dialog at pd_x/pd_y */
204 panic_blit_rect( pd_x, pd_y, panic_dialog->pd_width, panic_dialog->pd_height,
205 0, (unsigned char*) panic_dialog_data);
55e303ae 206
91447636
A
207 panic_dialog_count = 0; /* number of info items to display at the bottom of dialog */
208
209 if (panicDebugging) {
210 int x1, x2;
211
212 /*
213 * PANIC CALLER
214 *
215 * don't display the panic caller if it is 0
216 *
217 */
218
219 if ( panic_caller != 0 ) {
220 /* Calculate the pixels need to generate the panic number */
221 panic_dialog_info[panic_dialog_count].pixels = 0;
222
223 for ( indx=1, count=0; count < 13; count++ ) {
224 if ( versionbuf[count] == '\0' )
225 break;
226
227 panic_num_chars[indx++] = versionbuf[count];
228 panic_dialog_info[panic_dialog_count].pixels += pixels_needed_to_blit_digit( versionbuf[count] );
229 }
230
231 panic_num_chars[indx++] = ':';
232 panic_dialog_info[panic_dialog_count].pixels += pixels_needed_to_blit_digit( ':' );
233
234 for ( count=8; count != 0; count-- ) {
235 nibble = (panic_caller >> ((count-1)<<2)) &0xF;
236 panic_num_chars[indx++] = nibble;
237 panic_dialog_info[panic_dialog_count].pixels += pixels_needed_to_blit_digit( nibble );
238 }
239
240 panic_num_chars[0] = indx;
241 panic_dialog_info[panic_dialog_count].chars = panic_num_chars;
242 panic_dialog_count++;
243 }
55e303ae 244
91447636
A
245 /*
246 * MAC ADDRESS
247 *
248 * if the mac address is not available, then use ff:ff:ff:ff:ff:ff
249 *
250 */
251
252 kdp_mac_addr = kdp_get_mac_addr();
55e303ae 253
91447636
A
254 /* If no mac_addr has been set, then force to -1 */
255 if( ! (kdp_mac_addr.ether_addr_octet[0] || kdp_mac_addr.ether_addr_octet[1] || kdp_mac_addr.ether_addr_octet[2]
256 || kdp_mac_addr.ether_addr_octet[3] || kdp_mac_addr.ether_addr_octet[4] || kdp_mac_addr.ether_addr_octet[5])) {
55e303ae 257 for (count = 0; count < 6; count++ )
91447636 258 kdp_mac_addr.ether_addr_octet[count] = -1;
55e303ae 259 }
91447636
A
260
261 panic_dialog_info[panic_dialog_count].pixels = 0;
262
263 for (indx=1, count=0; count < 6; count++ ) {
264 nibble = (kdp_mac_addr.ether_addr_octet[count] & 0xf0) >> 4;
265 mac_addr_chars[indx++] = nibble;
266 panic_dialog_info[panic_dialog_count].pixels += pixels_needed_to_blit_digit( nibble );
267
268 nibble = kdp_mac_addr.ether_addr_octet[count] & 0xf;
269 mac_addr_chars[indx++] = nibble;
270 panic_dialog_info[panic_dialog_count].pixels += pixels_needed_to_blit_digit( nibble );
271
272 if( count < 5 ) {
273 mac_addr_chars[indx++] = ':';
274 panic_dialog_info[panic_dialog_count].pixels += pixels_needed_to_blit_digit( ':' );
55e303ae
A
275 }
276 }
91447636
A
277
278 mac_addr_chars[0] = indx;
279 panic_dialog_info[panic_dialog_count].chars = mac_addr_chars;
280 panic_dialog_count++;
281
282 /*
283 * IP ADDRESS
284 *
285 * do not display the ip addresses if the machine isn't attachable.
286 * there's no sense in possibly confusing people.
287 */
288
289 if ( (ip_addr = (unsigned int) ntohl(kdp_get_ip_address())) != 0 ) {
290 int d1, d2, d3;
291
292 panic_dialog_info[panic_dialog_count].pixels = 0;
293
294 for ( indx=1, count=0; count < 4; count++ ) {
55e303ae
A
295 nibble = (ip_addr & 0xff000000 ) >> 24;
296
91447636
A
297 d3 = (nibble % 10) ; nibble = nibble / 10;
298 d2 = (nibble % 10) ; nibble = nibble / 10;
299 d1 = (nibble % 10) ;
55e303ae 300
91447636
A
301 if( d1 != 0 ) {
302 ip_addr_chars[indx++] = d1;
303 panic_dialog_info[panic_dialog_count].pixels += pixels_needed_to_blit_digit( d1 );
304 }
305
306 ip_addr_chars[indx++] = d2;
307 panic_dialog_info[panic_dialog_count].pixels += pixels_needed_to_blit_digit( d2 );
308
309 ip_addr_chars[indx++] = d3;
310 panic_dialog_info[panic_dialog_count].pixels += pixels_needed_to_blit_digit( d3 );
311
312 if ( count < 3 ) {
313 ip_addr_chars[indx++] = '.';
314 panic_dialog_info[panic_dialog_count].pixels += pixels_needed_to_blit_digit( '.' );
315 }
55e303ae
A
316
317 d1= d2 = d3 = 0;
318 ip_addr = ip_addr << 8;
319 }
91447636
A
320
321 ip_addr_chars[0] = indx;
322 panic_dialog_info[panic_dialog_count].chars = ip_addr_chars;
323 panic_dialog_count++;
55e303ae 324 }
91447636
A
325
326
327 /* vertical alignment for information to be displayed */
328 panic_info_y = (vinfo.v_height/2) + panic_dialog->pd_height/2 - (panic_dialog->pd_info_height);
329
330 /* blit out all the information we gathered */
331
332 switch ( panic_dialog_count ) {
333 case 1 : /* one item is centered */
334 panic_info_x = (vinfo.v_width/2) - (panic_dialog_info[0].pixels/2);
335 for (indx=1; indx < panic_dialog_info[0].chars[0]; indx++)
336 blit_digit(panic_dialog_info[0].chars[indx]);
337
338 break;
339
340 case 2 : /* left centered and right centered */
341 x1 = ((panic_dialog->pd_width/2) - panic_dialog_info[0].pixels)/2;
342 panic_info_x = ((vinfo.v_width/2) - (panic_dialog->pd_width/2)) + x1;
343
344 for (indx=1; indx < panic_dialog_info[0].chars[0]; indx++)
345 blit_digit(panic_dialog_info[0].chars[indx]);
346
347 x2 = ((panic_dialog->pd_width/2) - panic_dialog_info[1].pixels)/2;
348 panic_info_x = (vinfo.v_width/2) + x2;
349
350 for (indx=1; indx < panic_dialog_info[1].chars[0]; indx++)
351 blit_digit(panic_dialog_info[1].chars[indx]);
352
353 break;
354
355 case 3 : /* left centered, middle and right centered */
356 x1 = ((panic_dialog->pd_width/2) - panic_dialog_info[0].pixels - (panic_dialog_info[1].pixels/2))/2;
357 panic_info_x = ((vinfo.v_width/2) - (panic_dialog->pd_width/2)) + x1;
358
359 for (indx=1; indx < panic_dialog_info[0].chars[0]; indx++)
360 blit_digit(panic_dialog_info[0].chars[indx]);
361
362 panic_info_x = (vinfo.v_width/2) - (panic_dialog_info[1].pixels/2);
363
364 for (indx=1; indx < panic_dialog_info[1].chars[0]; indx++)
365 blit_digit(panic_dialog_info[1].chars[indx]);
366
367 x2 = ((panic_dialog->pd_width/2) - panic_dialog_info[2].pixels - (panic_dialog_info[1].pixels/2))/2;
368 panic_info_x = (vinfo.v_width/2) + x2 + (panic_dialog_info[1].pixels/2);
369
370 for (indx=1; indx < panic_dialog_info[2].chars[0]; indx++)
371 blit_digit(panic_dialog_info[2].chars[indx]);
372
373 break;
374
375 default : /* nothing */
376 break;
377
378 } /* switch */
379 } /* if panic_deugging */
380 } /* if ! logPanicDataToScreen */
381 } /* if ! panicDialogDrawn && ! panicDialogDesired */
382
55e303ae
A
383 panicDialogDrawn = TRUE;
384 panicDialogDesired = FALSE;
91447636
A
385}
386
387
388/*
389 * This routine installs a new panic dialog
390 * If ptr is NULL, then the default "built-in" panic dialog will be installed.
391 * note: It is the caller that must take care of deallocating memory used for the previous panic dialog
392 */
393
394int
395panic_dialog_set_image( const unsigned char * ptr, unsigned int size )
396{
397 int error;
398 unsigned int newsize;
399 const struct panicimage * newimage;
400
401 /* if ptr is NULL, restore panic image to built-in default */
402 if ( ptr == NULL ) {
403 newimage = &panic_dialog_default;
404 newsize = sizeof(struct panicimage) + newimage->pd_dataSize;
405 }
406 else {
407 newimage = (struct panicimage *) ptr;
408 newsize = size;
409 }
410
411 if ( (error = panic_dialog_verify( newimage, newsize )) )
412 return (error);
413
414 panic_dialog = newimage;
415 panic_dialog_data = &panic_dialog->data[0];
416 panic_dialog_clut = &panic_dialog->data[panic_dialog->pd_dataSize-CLUT_SIZE];
417
418 curr_image_ptr = (unsigned char *) ptr;
419 curr_image_size = size;
420
421 return (0);
422}
423
424
425/*
426 * This routines returns the current address of the panic dialog
427 * If the default panic dialog is active, then *ptr will be NULL
428 */
429
430void
431panic_dialog_get_image( unsigned char ** ptr, unsigned int * size )
432{
433 *ptr = curr_image_ptr;
434 *size = curr_image_size;
435}
436
437
438/*
439 * This routine verifies the panic dialog image is valid.
440 */
441
442static int
443panic_dialog_verify( const struct panicimage * newimage, unsigned int size )
444{
445 unsigned int sum, i;
446
447 if ( size < (sizeof(struct panicimage) + newimage->pd_dataSize) )
448 return EINVAL;
449
450 if ( newimage->pd_tag != 'RNMp' )
451 return EINVAL;
452
453 size = newimage->pd_dataSize-CLUT_SIZE;
454 for (sum=0,i=0; i<size; i++) {
455 sum += newimage->data[i];
456 sum <<= sum&1;
457 }
55e303ae 458
91447636
A
459 if ( sum != newimage->pd_sum )
460 return EINVAL;
461
462 return 0;
463}
464
465
466/*
467 * Service Routines for managing the panic dialog
468 */
469
470
471static const struct rendered_num * find_rendered_digit( int digit );
472static void panic_blit_rect_8( unsigned int x, unsigned int y, unsigned int width, unsigned int height,
473 int transparent, unsigned char * dataPtr );
474static void panic_blit_rect_16( unsigned int x, unsigned int y, unsigned int width, unsigned int height,
475 int transparent, unsigned char * dataPtr );
476static void panic_blit_rect_32( unsigned int x, unsigned int y, unsigned int width, unsigned int height,
477 int transparent, unsigned char * dataPtr );
478static int decode_rle( unsigned char * dataPtr, unsigned int * quantity, unsigned int * depth, unsigned char ** value );
479
480
481/* Utilities to convert 8 bit/gray */
482static unsigned int make24bitcolor( unsigned int index, const unsigned char * clut );
483static unsigned char findIndexMatch( unsigned char index );
484static unsigned char color24togray8( unsigned int color24 );
485static unsigned char findbestgray( unsigned int color24 );
486static int isActiveClutOK( void );
487
488static int
489pixels_needed_to_blit_digit( int digit )
490{
491 return FONT_WIDTH;
55e303ae
A
492}
493
91447636
A
494
495static const struct rendered_num *
496find_rendered_digit( int digit )
497{
498 //extern unsigned char iso_font[];
499 const struct rendered_num *digitPtr;
500
501 if ( digit < 16 ) {
502 if ( digit < 10 )
503 digit += 0x30;
504 else
505 digit += 0x37;
506 }
507
508 digitPtr = (const struct rendered_num *) &iso_font[digit * 16];
509 return digitPtr;
510}
511
512
55e303ae
A
513static void
514blit_digit( int digit )
515{
91447636
A
516 unsigned char * raw_data = (unsigned char *) find_rendered_digit( digit );
517 unsigned width = FONT_WIDTH, height = FONT_HEIGHT;
518 int row;
519
520 for (row=0; row<FONT_HEIGHT; row++) {
521 int j;
522 unsigned char bits;
523
524 bits = raw_data[row];
525 for( j=FONT_WIDTH-1; j>=0; j--) {
526
527 if ( bits & 0x80 )
8ad349bb 528 rendered_font[row][j] = 0x0100 | panic_dialog->pd_info_color[0];
91447636 529 else
8ad349bb 530 rendered_font[row][j] = 0x0100 | panic_dialog->pd_info_color[1];
91447636 531 bits <<= 1;
55e303ae 532 }
55e303ae 533 }
91447636
A
534
535 panic_blit_rect( panic_info_x, panic_info_y , width, height, 255, (unsigned char *) rendered_font);
536 panic_info_x += width;
55e303ae
A
537}
538
91447636 539
55e303ae
A
540static void
541panic_blit_rect( unsigned int x, unsigned int y,
91447636
A
542 unsigned int width, unsigned int height,
543 int transparent, unsigned char * dataPtr )
55e303ae
A
544{
545 if(!vinfo.v_depth)
546 return;
547
548 switch( vinfo.v_depth) {
549 case 8:
550 panic_blit_rect_8( x, y, width, height, transparent, dataPtr);
551 break;
552 case 16:
553 panic_blit_rect_16( x, y, width, height, transparent, dataPtr);
554 break;
555 case 32:
556 panic_blit_rect_32( x, y, width, height, transparent, dataPtr);
557 break;
558 }
559}
560
91447636
A
561/*
562 * panic_blit_rect_8 decodes the RLE encoded image data on the fly, looks up the
563 * color by indexing into the clut, or attempts to find the best index.
564 */
55e303ae 565
55e303ae
A
566static void
567panic_blit_rect_8( unsigned int x, unsigned int y,
91447636
A
568 unsigned int width, unsigned int height,
569 int transparent, unsigned char * dataPtr )
55e303ae
A
570{
571 volatile unsigned char * dst;
91447636
A
572 unsigned int line, col, i;
573 static int clutOK = -1;
574 unsigned int data, quantity, depth;
575 unsigned char * value;
55e303ae 576
91447636
A
577
578 if ( clutOK == -1 )
579 clutOK = isActiveClutOK();
580
55e303ae 581 dst = (volatile unsigned char *) (vinfo.v_baseaddr +
91447636
A
582 (y * vinfo.v_rowbytes) +
583 x);
55e303ae
A
584
585 quantity = 0;
91447636 586 i = 0;
55e303ae
A
587
588 for( line = 0; line < height; line++) {
589 for( col = 0; col < width; col++) {
91447636 590
55e303ae 591 if (quantity == 0) {
91447636
A
592 dataPtr += decode_rle(dataPtr, &quantity, &depth, &value);
593 i = 0;
55e303ae
A
594 }
595
91447636
A
596 if ( clutOK )
597 data = value[i++];
598 else
599 data = findIndexMatch( value[i++] );
600
55e303ae 601 *(dst + col) = data;
91447636
A
602
603 if ( i == depth ) {
604 i = 0;
605 quantity--;
606 }
55e303ae
A
607 }
608
609 dst = (volatile unsigned char *) (((int)dst) + vinfo.v_rowbytes);
610 }
611}
612
91447636
A
613/*
614 * panic_blit_rect_16 decodes the RLE encoded image data on the fly, looks up the
615 * color by indexing into the clut, uses the top 5 bits to fill in each of the three
616 * pixel values (RGB) and writes each pixel to the screen.
617 */
618
55e303ae
A
619 static void
620 panic_blit_rect_16( unsigned int x, unsigned int y,
91447636
A
621 unsigned int width, unsigned int height,
622 int transparent, unsigned char * dataPtr )
55e303ae 623 {
55e303ae 624
91447636
A
625 volatile unsigned short * dst;
626 unsigned int line, col, i;
627 unsigned int quantity, index, data, depth;
628 unsigned char * value;
55e303ae 629
91447636
A
630 dst = (volatile unsigned short *) (vinfo.v_baseaddr +
631 (y * vinfo.v_rowbytes) +
632 (x * 2));
55e303ae 633
91447636
A
634 quantity = 0;
635 i = 0;
55e303ae 636
91447636
A
637 for( line = 0; line < height; line++) {
638 for( col = 0; col < width; col++) {
55e303ae 639
91447636
A
640 if (quantity == 0) {
641 dataPtr += decode_rle(dataPtr, &quantity, &depth, &value);
642 i = 0;
643 }
55e303ae 644
91447636
A
645 index = value[i++] * 3;
646
647 data = ( (unsigned short) (0xf8 & (panic_dialog_clut[index + 0])) << 7)
648 | ( (unsigned short) (0xf8 & (panic_dialog_clut[index + 1])) << 2)
649 | ( (unsigned short) (0xf8 & (panic_dialog_clut[index + 2])) >> 3);
55e303ae 650
91447636 651 *(dst + col) = data;
55e303ae 652
91447636
A
653 if ( i == depth ) {
654 i = 0;
655 quantity--;
656 }
657 }
55e303ae 658
91447636
A
659 dst = (volatile unsigned short *) (((int)dst) + vinfo.v_rowbytes);
660 }
55e303ae
A
661 }
662
91447636
A
663/*
664 * panic_blit_rect_32 decodes the RLE encoded image data on the fly, and fills
665 * in each of the three pixel values from the clut (RGB) for each pixel and
666 * writes it to the screen.
55e303ae 667 */
91447636 668
55e303ae
A
669 static void
670 panic_blit_rect_32( unsigned int x, unsigned int y,
91447636
A
671 unsigned int width, unsigned int height,
672 int transparent, unsigned char * dataPtr )
55e303ae 673 {
91447636
A
674 volatile unsigned int * dst;
675 unsigned int line, col, i;
676 unsigned int quantity, index, data, depth;
677 unsigned char * value;
55e303ae 678
55e303ae
A
679
680 dst = (volatile unsigned int *) (vinfo.v_baseaddr +
91447636
A
681 (y * vinfo.v_rowbytes) +
682 (x * 4));
55e303ae
A
683
684 quantity = 0;
91447636 685 i = 0;
55e303ae
A
686
687 for( line = 0; line < height; line++) {
688 for( col = 0; col < width; col++) {
91447636 689
55e303ae 690 if (quantity == 0) {
91447636
A
691 dataPtr += decode_rle(dataPtr, &quantity, &depth, &value);
692 i = 0;
55e303ae 693 }
91447636
A
694
695 index = value[i++] * 3;
55e303ae 696
91447636
A
697 data = ( (unsigned int) panic_dialog_clut[index + 0] << 16)
698 | ( (unsigned int) panic_dialog_clut[index + 1] << 8)
699 | ( (unsigned int) panic_dialog_clut[index + 2]);
55e303ae
A
700
701 *(dst + col) = data;
91447636
A
702
703 if ( i == depth ) {
704 i = 0;
705 quantity--;
706 }
55e303ae
A
707 }
708
709 dst = (volatile unsigned int *) (((int)dst) + vinfo.v_rowbytes);
710 }
711}
712
713/*
91447636
A
714 decode_rle decodes a single quantity/value run of a "modified-RLE" encoded
715 image. The encoding works as follows:
716
717 The run is described in the first byte. If the MSB is zero, then the next seven bits
718 are the quantity of bytes that follow that make up the run of value bytes. (see case 0)
719
720 If the MSB is set, bits 0-3 are the quantity's least significant 4 bits. If bit 5 is set,
721 then the quantity is further described in the next byte, where an additional 7 bits (4-10)
722 worth of quantity will be found. If the MSB of this byte is set, then an additional
723 7 bits (11-17) worth of quantity will be found in the next byte. This repeats until the MSB of
724 a quantity byte is zero, thus ending the run of quantity bytes.
725
726 Bits 5/6 of the first byte, describe the number of bytes in the value run following the quantity run.
727 These bits describe value runs of 1 to 4 bytes. And the quantity describe the number of value runs.
728 (see cases 1-4)
729
730 encodings are: (q = quantity, v = value, c = quantity continues)
731
732 case 0: [ 0 q6-q0 ] [ v7-v0 ] ... [ v7-v0 ]
733 case 1: [ 1 0 0 c q3-q0 ] [ c q10-q4 ] [ c q17-q11 ] [ q24-q18 ] [ v7-v0 ]
734 case 2: [ 1 0 1 c q3-q0 ] [ c q10-q4 ] [ c q17-q11 ] [ q24-q18 ] [ v7-v0 ] [ v7-v0 ]
735 case 3: [ 1 1 0 c q3-q0 ] [ c q10-q4 ] [ c q17-q11 ] [ q24-q18 ] [ v7-v0 ] [ v7-v0 ] [ v7-v0 ]
736 case 4: [ 1 1 1 c q3-q0 ] [ c q10-q4 ] [ c q17-q11 ] [ q24-q18 ] [ v7-v0 ] [ v7-v0 ] [ v7-v0 ] [ v7-v0 ]
55e303ae 737*/
91447636 738
55e303ae 739static int
91447636 740decode_rle( unsigned char * dataPtr, unsigned int * quantity, unsigned int * depth, unsigned char ** value )
55e303ae 741{
91447636
A
742 unsigned int mask;
743 int i, runlen, runsize;
744
745 i = 0;
746 mask = dataPtr[i] & 0xF0;
747
748 if ( mask & 0x80 ) {
749 runsize = ((mask & 0x60) >> 5) + 1;
750 runlen = dataPtr[i++] & 0x0F;
751
752 if ( mask & 0x10 ) {
753 int shift = 4;
754
755 do {
756 mask = dataPtr[i] & 0x80;
757 runlen |= ((dataPtr[i++] & 0x7F) << shift);
758 shift+=7;
759 } while (mask);
760 }
55e303ae 761 } else {
91447636
A
762 runlen = 1;
763 runsize = dataPtr[i++];
55e303ae 764 }
91447636
A
765
766 *depth = runsize;
767 *quantity = runlen;
768 *value = &dataPtr[i];
769
770 return i+runsize;
55e303ae
A
771}
772
91447636 773
55e303ae
A
774static void
775dim_screen(void)
776{
91447636
A
777 unsigned long *p, *endp, *row;
778 int col, rowline, rowlongs;
779 register unsigned long mask;
780
55e303ae
A
781 if(!vinfo.v_depth)
782 return;
783
91447636
A
784 if ( vinfo.v_depth == 32 )
785 mask = 0x007F7F7F;
786 else if ( vinfo.v_depth == 16 )
787 mask = 0x3DEF3DEF;
788 else
789 return;
55e303ae
A
790
791 rowline = vinfo.v_rowscanbytes / 4;
792 rowlongs = vinfo.v_rowbytes / 4;
793
794 p = (unsigned long*) vinfo.v_baseaddr;
91447636 795 endp = p + (rowlongs * vinfo.v_height);
55e303ae
A
796
797 for (row = p ; row < endp ; row += rowlongs) {
91447636
A
798 for (p = &row[0], col = 0; col < rowline; col++) {
799 *p++ = (*p >> 1) & mask;
800 }
801 }
802}
803
804
805/* From user mode Libc - this ought to be in a library */
806static char *
807strnstr(const char * s, const char * find, size_t slen)
808{
809 char c, sc;
810 size_t len;
811
812 if ((c = *find++) != '\0') {
813 len = strlen(find);
814 do {
815 do {
816 if ((sc = *s++) == '\0' || slen-- < 1)
817 return (NULL);
818 } while (sc != c);
819 if (len > slen)
820 return (NULL);
821 } while (strncmp(s, find, len) != 0);
822 s--;
823 }
824 return ((char *)s);
825}
826
827/*
828 * these routines are for converting a color into grayscale
829 * in 8-bit mode, if the active clut is different than the
830 * clut used to create the panic dialog, then we must convert to gray
831 */
832
833static unsigned int
834make24bitcolor( unsigned int index, const unsigned char * clut )
835{
836 unsigned int color24 = 0;
837 int i = index * 3;
838
839 color24 |= clut[i+0] << 16;
840 color24 |= clut[i+1] << 8;
841 color24 |= clut[i+2];
842
843 return color24;
844}
845
846
847static unsigned char
848findbestgray( unsigned int color24 )
849{
850 unsigned int c24, rel, bestindex=-1, bestgray = -1;
851 unsigned char gray8, c8;
852 int i;
853#define abs(v) ((v) > 0)?(v):-(v)
55e303ae 854
91447636
A
855 gray8 = color24togray8( color24 ); /* convert the original color into grayscale */
856
857 for (i=0; i<CLUT_ENTRIES; i++) {
858 c24 = make24bitcolor( i, active_clut );
859 if ( (((c24>>16)&0xff) != ((c24>>8)&0xff)) || ((c24>>8)&0xff) != (c24 & 0xff) )
860 continue; /* only match against grays */
861
862 c8 = c24 & 0xFF; /* isolate the gray */
863
864 /* find the gray with the smallest difference */
865 rel = abs( gray8 - c8 );
866 if ( rel < bestgray ) {
867 bestgray = rel;
868 bestindex = i;
869 }
55e303ae
A
870 }
871
91447636
A
872 /* Did we fail to find any grays ? */
873 if ( bestindex == -1 ) {
874 /* someday we should look for the best color match */
875 /* but for now just return the gray as the index */
876 /* at least there might be something readble on the display */
877
878 bestindex = gray8;
879 }
880
881 return bestindex;
882#undef abs
55e303ae
A
883}
884
91447636
A
885
886static unsigned char
887color24togray8( unsigned int color24 )
888{
8ad349bb
A
889 float R, G, B;
890 float Gray;
91447636
A
891 unsigned char gray8;
892
893 R = (color24 & 0xFF0000) >> 16 ;
894 G = (color24 & 0xFF00) >> 8 ;
895 B = (color24 & 0xFF);
896
8ad349bb
A
897 Gray = (R*.30) + (G*.59) + (B*.11);
898 gray8 = (unsigned char) ( Gray + .5);
91447636
A
899 return gray8;
900}
901
902
903static unsigned char
904findIndexMatch( unsigned char index )
55e303ae 905{
91447636
A
906 static unsigned int last_in_index = -1;
907 static unsigned char last_index;
908 unsigned int sc;
55e303ae 909
91447636
A
910 if ( index == last_in_index )
911 return last_index;
55e303ae 912
91447636
A
913 last_in_index = index;
914 sc = make24bitcolor( index, panic_dialog_clut );
915 last_index = findbestgray( sc ); /* find the nearest matching gray in the active clut */
55e303ae 916
91447636
A
917 return last_index;
918}
55e303ae 919
91447636
A
920static int
921isActiveClutOK( void )
922{
923 int i;
924 int r = 1; /* assume OK */
55e303ae 925
91447636
A
926 for (i=0; i<CLUT_ENTRIES; i++) {
927 if ( panic_dialog_clut[i] == active_clut[i] ) continue;
928 r = 0;
929 break;
55e303ae
A
930 }
931
91447636 932 return r;
55e303ae 933}