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