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