]> git.saurik.com Git - apple/xnu.git/blob - osfmk/console/panic_dialog.c
xnu-792.13.8.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_OSREFERENCE_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
10 * License may not be used to create, or enable the creation or
11 * redistribution of, unlawful or unlicensed copies of an Apple operating
12 * system, or to circumvent, violate, or enable the circumvention or
13 * violation of, any terms of an Apple operating system software license
14 * agreement.
15 *
16 * Please obtain a copy of the License at
17 * http://www.opensource.apple.com/apsl/ and read it before using this
18 * file.
19 *
20 * The Original Code and all software distributed under the License are
21 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
22 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
23 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
24 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
25 * Please see the License for the specific language governing rights and
26 * limitations under the License.
27 *
28 * @APPLE_LICENSE_OSREFERENCE_HEADER_END@
29 */
30
31 #include <vc.h>
32 #include <console/video_console.h>
33 #include <libkern/OSByteOrder.h>
34 #include <kdp/kdp_udp.h>
35 #include <kern/debug.h>
36 #include <mach/mach_time.h>
37 #include <sys/errno.h>
38 #include <string.h>
39
40
41 extern struct vc_info vinfo;
42 extern boolean_t panicDialogDesired;
43
44 #include "panic_image.c"
45
46 void panic_ui_initialize(const unsigned char * system_clut);
47 int panic_dialog_set_image( const unsigned char * ptr, unsigned int size );
48 void panic_dialog_get_image( unsigned char ** ptr, unsigned int * size );
49 void draw_panic_dialog( void );
50 void panic_dialog_test( void );
51
52 static int panic_dialog_verify( const struct panicimage * data, unsigned int size );
53 static int pixels_needed_to_blit_digit( int digit );
54 static void blit_digit( int digit );
55 static char * strnstr(const char * s, const char * find, size_t slen);
56 static void dim_screen(void);
57 static void panic_blit_rect(unsigned int x, unsigned int y, unsigned int width, unsigned int height,
58 int transparent, unsigned char * dataPtr );
59
60 static int panic_info_x;
61 static int panic_info_y;
62
63 static const unsigned char * active_clut = NULL; /* This is a copy of the active clut */
64
65 static boolean_t panicDialogDrawn = FALSE;
66
67 static const struct panicimage * panic_dialog = NULL; /* the active panic dialog */
68 static const unsigned char * panic_dialog_data = NULL; /* where the image data starts */
69 static const unsigned char * panic_dialog_clut = NULL; /* where the clut used for the image starts */
70
71 static unsigned char * curr_image_ptr = NULL; /* If NULL, the default panic 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 static char versionbuf[20]; /* ####.###~###\0 */
79
80 #define isdigit(d) ((d) >= '0' && (d) <= '9')
81
82 #define CLUT_ENTRIES 256
83 #define CLUT_SIZE (CLUT_ENTRIES * 3)
84
85
86 /*
87 * This routine sets up the default panic dialog
88 */
89
90 extern unsigned char iso_font[];
91 extern const char version[];
92 extern unsigned int panic_caller;
93
94 void
95 panic_ui_initialize(const unsigned char * system_clut)
96 {
97 char vstr[20];
98
99
100 panic_dialog_set_image( NULL, 0 );
101
102 active_clut = system_clut;
103
104 strcpy(vstr, "custom");
105
106 /* Convert xnu-####.###.obj~### into ####.###~### */
107
108 if (version) {
109 char * versionpos = strnstr(version, "xnu-", 20);
110
111 if (versionpos) {
112 int len, i;
113
114 vstr[0] = '\0';
115
116 for (i=0,len=4;len<20;len++) {
117 if (isdigit(versionpos[len]) || versionpos[len] == '.') { /* extract ####.###. */
118 vstr[i++] = versionpos[len];
119 continue;
120 }
121 break;
122 }
123
124 if ( versionpos[len-1] == '.' ) /* remove trailing period if present */
125 i--;
126
127 for (;len<20;len++) { /* skip to next digit if present */
128 if ( !isdigit(versionpos[len]) )
129 continue;
130 break;
131 }
132
133 if ( versionpos[len-1] == '~' ) { /* extract ~### if present */
134 vstr[i++] = versionpos[len-1];
135 for (;len<20;len++) { /* extract ### */
136 if ( isdigit(versionpos[len]) ) {
137 vstr[i++] = versionpos[len];
138 continue;
139 }
140 break;
141 }
142 }
143
144 vstr[i] = '\0';
145 }
146 }
147
148 strcpy(versionbuf, vstr);
149 }
150
151
152
153 void
154 panic_dialog_test( void )
155 {
156 boolean_t o_panicDialogDrawn = panicDialogDrawn;
157 boolean_t o_panicDialogDesired = panicDialogDesired;
158 unsigned int o_logPanicDataToScreen = logPanicDataToScreen;
159 unsigned int o_panic_caller = panic_caller;
160 unsigned int o_panicDebugging = panicDebugging;
161
162
163 panicDebugging = TRUE;
164 panic_caller = (unsigned int) __builtin_return_address(0);
165 logPanicDataToScreen = FALSE;
166 panicDialogDesired = TRUE;
167 panicDialogDrawn = FALSE;
168
169 draw_panic_dialog();
170
171 panicDebugging = o_panicDebugging;
172 panic_caller = o_panic_caller;
173 logPanicDataToScreen = o_logPanicDataToScreen;
174 panicDialogDesired = o_panicDialogDesired;
175 panicDialogDrawn = o_panicDialogDrawn;
176 }
177
178
179 void
180 draw_panic_dialog( void )
181 {
182 if (!panicDialogDrawn && panicDialogDesired) {
183 if ( !logPanicDataToScreen ) {
184 int pd_x, pd_y;
185 int count, nibble, indx;
186 struct ether_addr kdp_mac_addr;
187 unsigned int panic_dialog_count, ip_addr;
188 char panic_num_chars[13+8+1], mac_addr_chars[17+1], ip_addr_chars[15+1];
189 struct {
190 int pixels;
191 char * chars;
192 } panic_dialog_info[3];
193
194
195 /* dim the screen 50% before putting up panic dialog */
196 dim_screen();
197
198 /* set up to draw background box */
199 /* by locating where the upper left corner is placed */
200
201 pd_x = (vinfo.v_width/2) - panic_dialog->pd_width/2;
202 pd_y = (vinfo.v_height/2) - panic_dialog->pd_height/2;
203
204 /* draw panic dialog at pd_x/pd_y */
205 panic_blit_rect( pd_x, pd_y, panic_dialog->pd_width, panic_dialog->pd_height,
206 0, (unsigned char*) 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 = (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 = (unsigned char *) 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( 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, unsigned int width, unsigned int height,
474 int transparent, unsigned char * dataPtr );
475 static void panic_blit_rect_16( unsigned int x, unsigned int y, unsigned int width, unsigned int height,
476 int transparent, unsigned char * dataPtr );
477 static void panic_blit_rect_32( unsigned int x, unsigned int y, unsigned int width, unsigned int height,
478 int transparent, unsigned char * dataPtr );
479 static int decode_rle( unsigned char * dataPtr, unsigned int * quantity, unsigned int * depth, unsigned char ** value );
480
481
482 /* Utilities to convert 8 bit/gray */
483 static unsigned int make24bitcolor( unsigned int index, const unsigned char * clut );
484 static unsigned char findIndexMatch( unsigned char index );
485 static unsigned char color24togray8( unsigned int color24 );
486 static unsigned char findbestgray( unsigned int color24 );
487 static int isActiveClutOK( void );
488
489 static int
490 pixels_needed_to_blit_digit( int digit )
491 {
492 return FONT_WIDTH;
493 }
494
495
496 static const struct rendered_num *
497 find_rendered_digit( int digit )
498 {
499 //extern unsigned char iso_font[];
500 const struct rendered_num *digitPtr;
501
502 if ( digit < 16 ) {
503 if ( digit < 10 )
504 digit += 0x30;
505 else
506 digit += 0x37;
507 }
508
509 digitPtr = (const struct rendered_num *) &iso_font[digit * 16];
510 return digitPtr;
511 }
512
513
514 static void
515 blit_digit( int digit )
516 {
517 unsigned char * raw_data = (unsigned char *) find_rendered_digit( digit );
518 unsigned width = FONT_WIDTH, height = FONT_HEIGHT;
519 int row;
520
521 for (row=0; row<FONT_HEIGHT; row++) {
522 int j;
523 unsigned char bits;
524
525 bits = raw_data[row];
526 for( j=FONT_WIDTH-1; j>=0; j--) {
527
528 if ( bits & 0x80 )
529 rendered_font[row][j] = OSSwapBigToHostInt16(0x0100 | panic_dialog->pd_info_color[0]);
530 else
531 rendered_font[row][j] = OSSwapBigToHostInt16(0x0100 | panic_dialog->pd_info_color[1]);
532 bits <<= 1;
533 }
534 }
535
536 panic_blit_rect( panic_info_x, panic_info_y , width, height, 255, (unsigned char *) rendered_font);
537 panic_info_x += width;
538 }
539
540
541 static void
542 panic_blit_rect( unsigned int x, unsigned int y,
543 unsigned int width, unsigned int height,
544 int transparent, unsigned char * dataPtr )
545 {
546 if(!vinfo.v_depth)
547 return;
548
549 switch( vinfo.v_depth) {
550 case 8:
551 panic_blit_rect_8( x, y, width, height, transparent, dataPtr);
552 break;
553 case 16:
554 panic_blit_rect_16( x, y, width, height, transparent, dataPtr);
555 break;
556 case 32:
557 panic_blit_rect_32( x, y, width, height, transparent, dataPtr);
558 break;
559 }
560 }
561
562 /*
563 * panic_blit_rect_8 decodes the RLE encoded image data on the fly, looks up the
564 * color by indexing into the clut, or attempts to find the best index.
565 */
566
567 static void
568 panic_blit_rect_8( unsigned int x, unsigned int y,
569 unsigned int width, unsigned int height,
570 int transparent, unsigned char * dataPtr )
571 {
572 volatile unsigned char * dst;
573 unsigned int line, col, i;
574 static int clutOK = -1;
575 unsigned int data, quantity, depth;
576 unsigned char * value;
577
578
579 if ( clutOK == -1 )
580 clutOK = isActiveClutOK();
581
582 dst = (volatile unsigned char *) (vinfo.v_baseaddr +
583 (y * vinfo.v_rowbytes) +
584 x);
585
586 quantity = 0;
587 i = 0;
588
589 for( line = 0; line < height; line++) {
590 for( col = 0; col < width; col++) {
591
592 if (quantity == 0) {
593 dataPtr += decode_rle(dataPtr, &quantity, &depth, &value);
594 i = 0;
595 }
596
597 if ( clutOK )
598 data = value[i++];
599 else
600 data = findIndexMatch( value[i++] );
601
602 *(dst + col) = data;
603
604 if ( i == depth ) {
605 i = 0;
606 quantity--;
607 }
608 }
609
610 dst = (volatile unsigned char *) (((int)dst) + vinfo.v_rowbytes);
611 }
612 }
613
614 /*
615 * panic_blit_rect_16 decodes the RLE encoded image data on the fly, looks up the
616 * color by indexing into the clut, uses the top 5 bits to fill in each of the three
617 * pixel values (RGB) and writes each pixel to the screen.
618 */
619
620 static void
621 panic_blit_rect_16( unsigned int x, unsigned int y,
622 unsigned int width, unsigned int height,
623 int transparent, unsigned char * dataPtr )
624 {
625
626 volatile unsigned short * dst;
627 unsigned int line, col, i;
628 unsigned int quantity, index, data, depth;
629 unsigned char * value;
630
631 dst = (volatile unsigned short *) (vinfo.v_baseaddr +
632 (y * vinfo.v_rowbytes) +
633 (x * 2));
634
635 quantity = 0;
636 i = 0;
637
638 for( line = 0; line < height; line++) {
639 for( col = 0; col < width; col++) {
640
641 if (quantity == 0) {
642 dataPtr += decode_rle(dataPtr, &quantity, &depth, &value);
643 i = 0;
644 }
645
646 index = value[i++] * 3;
647
648 data = ( (unsigned short) (0xf8 & (panic_dialog_clut[index + 0])) << 7)
649 | ( (unsigned short) (0xf8 & (panic_dialog_clut[index + 1])) << 2)
650 | ( (unsigned short) (0xf8 & (panic_dialog_clut[index + 2])) >> 3);
651
652 *(dst + col) = data;
653
654 if ( i == depth ) {
655 i = 0;
656 quantity--;
657 }
658 }
659
660 dst = (volatile unsigned short *) (((int)dst) + vinfo.v_rowbytes);
661 }
662 }
663
664 /*
665 * panic_blit_rect_32 decodes the RLE encoded image data on the fly, and fills
666 * in each of the three pixel values from the clut (RGB) for each pixel and
667 * writes it to the screen.
668 */
669
670 static void
671 panic_blit_rect_32( unsigned int x, unsigned int y,
672 unsigned int width, unsigned int height,
673 int transparent, unsigned char * dataPtr )
674 {
675 volatile unsigned int * dst;
676 unsigned int line, col, i;
677 unsigned int quantity, index, data, depth;
678 unsigned char * value;
679
680
681 dst = (volatile unsigned int *) (vinfo.v_baseaddr +
682 (y * vinfo.v_rowbytes) +
683 (x * 4));
684
685 quantity = 0;
686 i = 0;
687
688 for( line = 0; line < height; line++) {
689 for( col = 0; col < width; col++) {
690
691 if (quantity == 0) {
692 dataPtr += decode_rle(dataPtr, &quantity, &depth, &value);
693 i = 0;
694 }
695
696 index = value[i++] * 3;
697
698 data = ( (unsigned int) panic_dialog_clut[index + 0] << 16)
699 | ( (unsigned int) panic_dialog_clut[index + 1] << 8)
700 | ( (unsigned int) panic_dialog_clut[index + 2]);
701
702 *(dst + col) = data;
703
704 if ( i == depth ) {
705 i = 0;
706 quantity--;
707 }
708 }
709
710 dst = (volatile unsigned int *) (((int)dst) + vinfo.v_rowbytes);
711 }
712 }
713
714 /*
715 decode_rle decodes a single quantity/value run of a "modified-RLE" encoded
716 image. The encoding works as follows:
717
718 The run is described in the first byte. If the MSB is zero, then the next seven bits
719 are the quantity of bytes that follow that make up the run of value bytes. (see case 0)
720
721 If the MSB is set, bits 0-3 are the quantity's least significant 4 bits. If bit 5 is set,
722 then the quantity is further described in the next byte, where an additional 7 bits (4-10)
723 worth of quantity will be found. If the MSB of this byte is set, then an additional
724 7 bits (11-17) worth of quantity will be found in the next byte. This repeats until the MSB of
725 a quantity byte is zero, thus ending the run of quantity bytes.
726
727 Bits 5/6 of the first byte, describe the number of bytes in the value run following the quantity run.
728 These bits describe value runs of 1 to 4 bytes. And the quantity describe the number of value runs.
729 (see cases 1-4)
730
731 encodings are: (q = quantity, v = value, c = quantity continues)
732
733 case 0: [ 0 q6-q0 ] [ v7-v0 ] ... [ v7-v0 ]
734 case 1: [ 1 0 0 c q3-q0 ] [ c q10-q4 ] [ c q17-q11 ] [ q24-q18 ] [ v7-v0 ]
735 case 2: [ 1 0 1 c q3-q0 ] [ c q10-q4 ] [ c q17-q11 ] [ q24-q18 ] [ v7-v0 ] [ v7-v0 ]
736 case 3: [ 1 1 0 c q3-q0 ] [ c q10-q4 ] [ c q17-q11 ] [ q24-q18 ] [ v7-v0 ] [ v7-v0 ] [ v7-v0 ]
737 case 4: [ 1 1 1 c q3-q0 ] [ c q10-q4 ] [ c q17-q11 ] [ q24-q18 ] [ v7-v0 ] [ v7-v0 ] [ v7-v0 ] [ v7-v0 ]
738 */
739
740 static int
741 decode_rle( unsigned char * dataPtr, unsigned int * quantity, unsigned int * depth, unsigned char ** value )
742 {
743 unsigned int mask;
744 int i, runlen, runsize;
745
746 i = 0;
747 mask = dataPtr[i] & 0xF0;
748
749 if ( mask & 0x80 ) {
750 runsize = ((mask & 0x60) >> 5) + 1;
751 runlen = dataPtr[i++] & 0x0F;
752
753 if ( mask & 0x10 ) {
754 int shift = 4;
755
756 do {
757 mask = dataPtr[i] & 0x80;
758 runlen |= ((dataPtr[i++] & 0x7F) << shift);
759 shift+=7;
760 } while (mask);
761 }
762 } else {
763 runlen = 1;
764 runsize = dataPtr[i++];
765 }
766
767 *depth = runsize;
768 *quantity = runlen;
769 *value = &dataPtr[i];
770
771 return i+runsize;
772 }
773
774
775 static void
776 dim_screen(void)
777 {
778 unsigned long *p, *endp, *row;
779 int col, rowline, rowlongs;
780 register unsigned long mask;
781
782 if(!vinfo.v_depth)
783 return;
784
785 if ( vinfo.v_depth == 32 )
786 mask = 0x007F7F7F;
787 else if ( vinfo.v_depth == 16 )
788 mask = 0x3DEF3DEF;
789 else
790 return;
791
792 rowline = vinfo.v_rowscanbytes / 4;
793 rowlongs = vinfo.v_rowbytes / 4;
794
795 p = (unsigned long*) vinfo.v_baseaddr;
796 endp = p + (rowlongs * vinfo.v_height);
797
798 for (row = p ; row < endp ; row += rowlongs) {
799 for (p = &row[0], col = 0; col < rowline; col++) {
800 *p++ = (*p >> 1) & mask;
801 }
802 }
803 }
804
805
806 /* From user mode Libc - this ought to be in a library */
807 static char *
808 strnstr(const char * s, const char * find, size_t slen)
809 {
810 char c, sc;
811 size_t len;
812
813 if ((c = *find++) != '\0') {
814 len = strlen(find);
815 do {
816 do {
817 if ((sc = *s++) == '\0' || slen-- < 1)
818 return (NULL);
819 } while (sc != c);
820 if (len > slen)
821 return (NULL);
822 } while (strncmp(s, find, len) != 0);
823 s--;
824 }
825 return ((char *)s);
826 }
827
828 /*
829 * these routines are for converting a color into grayscale
830 * in 8-bit mode, if the active clut is different than the
831 * clut used to create the panic dialog, then we must convert to gray
832 */
833
834 static unsigned int
835 make24bitcolor( unsigned int index, const unsigned char * clut )
836 {
837 unsigned int color24 = 0;
838 int i = index * 3;
839
840 color24 |= clut[i+0] << 16;
841 color24 |= clut[i+1] << 8;
842 color24 |= clut[i+2];
843
844 return color24;
845 }
846
847
848 static unsigned char
849 findbestgray( unsigned int color24 )
850 {
851 unsigned int c24, rel, bestindex=-1, bestgray = -1;
852 unsigned char gray8, c8;
853 int i;
854 #define abs(v) ((v) > 0)?(v):-(v)
855
856 gray8 = color24togray8( color24 ); /* convert the original color into grayscale */
857
858 for (i=0; i<CLUT_ENTRIES; i++) {
859 c24 = make24bitcolor( i, active_clut );
860 if ( (((c24>>16)&0xff) != ((c24>>8)&0xff)) || ((c24>>8)&0xff) != (c24 & 0xff) )
861 continue; /* only match against grays */
862
863 c8 = c24 & 0xFF; /* isolate the gray */
864
865 /* find the gray with the smallest difference */
866 rel = abs( gray8 - c8 );
867 if ( rel < bestgray ) {
868 bestgray = rel;
869 bestindex = i;
870 }
871 }
872
873 /* Did we fail to find any grays ? */
874 if ( bestindex == -1 ) {
875 /* someday we should look for the best color match */
876 /* but for now just return the gray as the index */
877 /* at least there might be something readble on the display */
878
879 bestindex = gray8;
880 }
881
882 return bestindex;
883 #undef abs
884 }
885
886
887 static unsigned char
888 color24togray8( unsigned int color24 )
889 {
890 int R, G, B;
891 int Gray;
892 unsigned char gray8;
893
894 R = (color24 & 0xFF0000) >> 16 ;
895 G = (color24 & 0xFF00) >> 8 ;
896 B = (color24 & 0xFF);
897
898 Gray = (R*30) + (G*59) + (B*11);
899 gray8 = (unsigned char) ((Gray + 50) / 100);
900 return gray8;
901 }
902
903
904 static unsigned char
905 findIndexMatch( unsigned char index )
906 {
907 static unsigned int last_in_index = -1;
908 static unsigned char last_index;
909 unsigned int sc;
910
911 if ( index == last_in_index )
912 return last_index;
913
914 last_in_index = index;
915 sc = make24bitcolor( index, panic_dialog_clut );
916 last_index = findbestgray( sc ); /* find the nearest matching gray in the active clut */
917
918 return last_index;
919 }
920
921 static int
922 isActiveClutOK( void )
923 {
924 int i;
925 int r = 1; /* assume OK */
926
927 for (i=0; i<CLUT_ENTRIES; i++) {
928 if ( panic_dialog_clut[i] == active_clut[i] ) continue;
929 r = 0;
930 break;
931 }
932
933 return r;
934 }