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