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