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