]> git.saurik.com Git - apple/xnu.git/blame - osfmk/console/panic_dialog.c
xnu-792.13.8.tar.gz
[apple/xnu.git] / osfmk / console / panic_dialog.c
CommitLineData
55e303ae 1/*
91447636 2 * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
55e303ae 3 *
8ad349bb 4 * @APPLE_LICENSE_OSREFERENCE_HEADER_START@
55e303ae 5 *
8ad349bb
A
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@
55e303ae
A
29 */
30
31#include <vc.h>
55e303ae 32#include <console/video_console.h>
5d5c5d0d 33#include <libkern/OSByteOrder.h>
55e303ae
A
34#include <kdp/kdp_udp.h>
35#include <kern/debug.h>
91447636
A
36#include <mach/mach_time.h>
37#include <sys/errno.h>
38#include <string.h>
55e303ae 39
55e303ae
A
40
41extern struct vc_info vinfo;
42extern boolean_t panicDialogDesired;
43
91447636
A
44#include "panic_image.c"
45
46void panic_ui_initialize(const unsigned char * system_clut);
47int panic_dialog_set_image( const unsigned char * ptr, unsigned int size );
48void panic_dialog_get_image( unsigned char ** ptr, unsigned int * size );
49void draw_panic_dialog( void );
50void panic_dialog_test( void );
51
52static int panic_dialog_verify( const struct panicimage * data, unsigned int size );
53static int pixels_needed_to_blit_digit( int digit );
55e303ae 54static void blit_digit( int digit );
91447636
A
55static char * strnstr(const char * s, const char * find, size_t slen);
56static void dim_screen(void);
57static void panic_blit_rect(unsigned int x, unsigned int y, unsigned int width, unsigned int height,
58 int transparent, unsigned char * dataPtr );
59
60static int panic_info_x;
61static int panic_info_y;
62
63static const unsigned char * active_clut = NULL; /* This is a copy of the active clut */
64
55e303ae
A
65static boolean_t panicDialogDrawn = FALSE;
66
91447636
A
67static const struct panicimage * panic_dialog = NULL; /* the active panic dialog */
68static const unsigned char * panic_dialog_data = NULL; /* where the image data starts */
69static const unsigned char * panic_dialog_clut = NULL; /* where the clut used for the image starts */
55e303ae 70
91447636
A
71static unsigned char * curr_image_ptr = NULL; /* If NULL, the default panic dialog is active */
72static unsigned int curr_image_size = 0;
55e303ae 73
91447636
A
74#define FONT_WIDTH 8
75#define FONT_HEIGHT 16
76static unsigned short rendered_font[FONT_HEIGHT][FONT_WIDTH];
55e303ae 77
91447636 78static char versionbuf[20]; /* ####.###~###\0 */
55e303ae 79
91447636 80#define isdigit(d) ((d) >= '0' && (d) <= '9')
55e303ae 81
91447636
A
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
90extern unsigned char iso_font[];
91extern const char version[];
92extern unsigned int panic_caller;
93
94void
55e303ae
A
95panic_ui_initialize(const unsigned char * system_clut)
96{
91447636
A
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
153void
154panic_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;
55e303ae
A
176}
177
91447636 178
55e303ae
A
179void
180draw_panic_dialog( void )
181{
91447636
A
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
55e303ae
A
194
195 /* dim the screen 50% before putting up panic dialog */
196 dim_screen();
197
198 /* set up to draw background box */
91447636
A
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;
55e303ae 203
91447636
A
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);
55e303ae 207
91447636
A
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 }
55e303ae 245
91447636
A
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();
55e303ae 254
91447636
A
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])) {
55e303ae 258 for (count = 0; count < 6; count++ )
91447636 259 kdp_mac_addr.ether_addr_octet[count] = -1;
55e303ae 260 }
91447636
A
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( ':' );
55e303ae
A
276 }
277 }
91447636
A
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++ ) {
55e303ae
A
296 nibble = (ip_addr & 0xff000000 ) >> 24;
297
91447636
A
298 d3 = (nibble % 10) ; nibble = nibble / 10;
299 d2 = (nibble % 10) ; nibble = nibble / 10;
300 d1 = (nibble % 10) ;
55e303ae 301
91447636
A
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 }
55e303ae
A
317
318 d1= d2 = d3 = 0;
319 ip_addr = ip_addr << 8;
320 }
91447636
A
321
322 ip_addr_chars[0] = indx;
323 panic_dialog_info[panic_dialog_count].chars = ip_addr_chars;
324 panic_dialog_count++;
55e303ae 325 }
91447636
A
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
55e303ae
A
384 panicDialogDrawn = TRUE;
385 panicDialogDesired = FALSE;
91447636
A
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
395int
396panic_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
431void
432panic_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
443static int
444panic_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 }
55e303ae 459
91447636
A
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
472static const struct rendered_num * find_rendered_digit( int digit );
473static void panic_blit_rect_8( unsigned int x, unsigned int y, unsigned int width, unsigned int height,
474 int transparent, unsigned char * dataPtr );
475static void panic_blit_rect_16( unsigned int x, unsigned int y, unsigned int width, unsigned int height,
476 int transparent, unsigned char * dataPtr );
477static void panic_blit_rect_32( unsigned int x, unsigned int y, unsigned int width, unsigned int height,
478 int transparent, unsigned char * dataPtr );
479static int decode_rle( unsigned char * dataPtr, unsigned int * quantity, unsigned int * depth, unsigned char ** value );
480
481
482/* Utilities to convert 8 bit/gray */
483static unsigned int make24bitcolor( unsigned int index, const unsigned char * clut );
484static unsigned char findIndexMatch( unsigned char index );
485static unsigned char color24togray8( unsigned int color24 );
486static unsigned char findbestgray( unsigned int color24 );
487static int isActiveClutOK( void );
488
489static int
490pixels_needed_to_blit_digit( int digit )
491{
492 return FONT_WIDTH;
55e303ae
A
493}
494
91447636
A
495
496static const struct rendered_num *
497find_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
55e303ae
A
514static void
515blit_digit( int digit )
516{
91447636
A
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 )
5d5c5d0d 529 rendered_font[row][j] = OSSwapBigToHostInt16(0x0100 | panic_dialog->pd_info_color[0]);
91447636 530 else
5d5c5d0d 531 rendered_font[row][j] = OSSwapBigToHostInt16(0x0100 | panic_dialog->pd_info_color[1]);
91447636 532 bits <<= 1;
55e303ae 533 }
55e303ae 534 }
91447636
A
535
536 panic_blit_rect( panic_info_x, panic_info_y , width, height, 255, (unsigned char *) rendered_font);
537 panic_info_x += width;
55e303ae
A
538}
539
91447636 540
55e303ae
A
541static void
542panic_blit_rect( unsigned int x, unsigned int y,
91447636
A
543 unsigned int width, unsigned int height,
544 int transparent, unsigned char * dataPtr )
55e303ae
A
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
91447636
A
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 */
55e303ae 566
55e303ae
A
567static void
568panic_blit_rect_8( unsigned int x, unsigned int y,
91447636
A
569 unsigned int width, unsigned int height,
570 int transparent, unsigned char * dataPtr )
55e303ae
A
571{
572 volatile unsigned char * dst;
91447636
A
573 unsigned int line, col, i;
574 static int clutOK = -1;
575 unsigned int data, quantity, depth;
576 unsigned char * value;
55e303ae 577
91447636
A
578
579 if ( clutOK == -1 )
580 clutOK = isActiveClutOK();
581
55e303ae 582 dst = (volatile unsigned char *) (vinfo.v_baseaddr +
91447636
A
583 (y * vinfo.v_rowbytes) +
584 x);
55e303ae
A
585
586 quantity = 0;
91447636 587 i = 0;
55e303ae
A
588
589 for( line = 0; line < height; line++) {
590 for( col = 0; col < width; col++) {
91447636 591
55e303ae 592 if (quantity == 0) {
91447636
A
593 dataPtr += decode_rle(dataPtr, &quantity, &depth, &value);
594 i = 0;
55e303ae
A
595 }
596
91447636
A
597 if ( clutOK )
598 data = value[i++];
599 else
600 data = findIndexMatch( value[i++] );
601
55e303ae 602 *(dst + col) = data;
91447636
A
603
604 if ( i == depth ) {
605 i = 0;
606 quantity--;
607 }
55e303ae
A
608 }
609
610 dst = (volatile unsigned char *) (((int)dst) + vinfo.v_rowbytes);
611 }
612}
613
91447636
A
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
55e303ae
A
620 static void
621 panic_blit_rect_16( unsigned int x, unsigned int y,
91447636
A
622 unsigned int width, unsigned int height,
623 int transparent, unsigned char * dataPtr )
55e303ae 624 {
55e303ae 625
91447636
A
626 volatile unsigned short * dst;
627 unsigned int line, col, i;
628 unsigned int quantity, index, data, depth;
629 unsigned char * value;
55e303ae 630
91447636
A
631 dst = (volatile unsigned short *) (vinfo.v_baseaddr +
632 (y * vinfo.v_rowbytes) +
633 (x * 2));
55e303ae 634
91447636
A
635 quantity = 0;
636 i = 0;
55e303ae 637
91447636
A
638 for( line = 0; line < height; line++) {
639 for( col = 0; col < width; col++) {
55e303ae 640
91447636
A
641 if (quantity == 0) {
642 dataPtr += decode_rle(dataPtr, &quantity, &depth, &value);
643 i = 0;
644 }
55e303ae 645
91447636
A
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);
55e303ae 651
91447636 652 *(dst + col) = data;
55e303ae 653
91447636
A
654 if ( i == depth ) {
655 i = 0;
656 quantity--;
657 }
658 }
55e303ae 659
91447636
A
660 dst = (volatile unsigned short *) (((int)dst) + vinfo.v_rowbytes);
661 }
55e303ae
A
662 }
663
91447636
A
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.
55e303ae 668 */
91447636 669
55e303ae
A
670 static void
671 panic_blit_rect_32( unsigned int x, unsigned int y,
91447636
A
672 unsigned int width, unsigned int height,
673 int transparent, unsigned char * dataPtr )
55e303ae 674 {
91447636
A
675 volatile unsigned int * dst;
676 unsigned int line, col, i;
677 unsigned int quantity, index, data, depth;
678 unsigned char * value;
55e303ae 679
55e303ae
A
680
681 dst = (volatile unsigned int *) (vinfo.v_baseaddr +
91447636
A
682 (y * vinfo.v_rowbytes) +
683 (x * 4));
55e303ae
A
684
685 quantity = 0;
91447636 686 i = 0;
55e303ae
A
687
688 for( line = 0; line < height; line++) {
689 for( col = 0; col < width; col++) {
91447636 690
55e303ae 691 if (quantity == 0) {
91447636
A
692 dataPtr += decode_rle(dataPtr, &quantity, &depth, &value);
693 i = 0;
55e303ae 694 }
91447636
A
695
696 index = value[i++] * 3;
55e303ae 697
91447636
A
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]);
55e303ae
A
701
702 *(dst + col) = data;
91447636
A
703
704 if ( i == depth ) {
705 i = 0;
706 quantity--;
707 }
55e303ae
A
708 }
709
710 dst = (volatile unsigned int *) (((int)dst) + vinfo.v_rowbytes);
711 }
712}
713
714/*
91447636
A
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 ]
55e303ae 738*/
91447636 739
55e303ae 740static int
91447636 741decode_rle( unsigned char * dataPtr, unsigned int * quantity, unsigned int * depth, unsigned char ** value )
55e303ae 742{
91447636
A
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 }
55e303ae 762 } else {
91447636
A
763 runlen = 1;
764 runsize = dataPtr[i++];
55e303ae 765 }
91447636
A
766
767 *depth = runsize;
768 *quantity = runlen;
769 *value = &dataPtr[i];
770
771 return i+runsize;
55e303ae
A
772}
773
91447636 774
55e303ae
A
775static void
776dim_screen(void)
777{
91447636
A
778 unsigned long *p, *endp, *row;
779 int col, rowline, rowlongs;
780 register unsigned long mask;
781
55e303ae
A
782 if(!vinfo.v_depth)
783 return;
784
91447636
A
785 if ( vinfo.v_depth == 32 )
786 mask = 0x007F7F7F;
787 else if ( vinfo.v_depth == 16 )
788 mask = 0x3DEF3DEF;
789 else
790 return;
55e303ae
A
791
792 rowline = vinfo.v_rowscanbytes / 4;
793 rowlongs = vinfo.v_rowbytes / 4;
794
795 p = (unsigned long*) vinfo.v_baseaddr;
91447636 796 endp = p + (rowlongs * vinfo.v_height);
55e303ae
A
797
798 for (row = p ; row < endp ; row += rowlongs) {
91447636
A
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 */
807static char *
808strnstr(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
834static unsigned int
835make24bitcolor( 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
848static unsigned char
849findbestgray( 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)
55e303ae 855
91447636
A
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 }
55e303ae
A
871 }
872
91447636
A
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
55e303ae
A
884}
885
91447636
A
886
887static unsigned char
888color24togray8( unsigned int color24 )
889{
5d5c5d0d
A
890 int R, G, B;
891 int Gray;
91447636
A
892 unsigned char gray8;
893
894 R = (color24 & 0xFF0000) >> 16 ;
895 G = (color24 & 0xFF00) >> 8 ;
896 B = (color24 & 0xFF);
897
5d5c5d0d
A
898 Gray = (R*30) + (G*59) + (B*11);
899 gray8 = (unsigned char) ((Gray + 50) / 100);
91447636
A
900 return gray8;
901}
902
903
904static unsigned char
905findIndexMatch( unsigned char index )
55e303ae 906{
91447636
A
907 static unsigned int last_in_index = -1;
908 static unsigned char last_index;
909 unsigned int sc;
55e303ae 910
91447636
A
911 if ( index == last_in_index )
912 return last_index;
55e303ae 913
91447636
A
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 */
55e303ae 917
91447636
A
918 return last_index;
919}
55e303ae 920
91447636
A
921static int
922isActiveClutOK( void )
923{
924 int i;
925 int r = 1; /* assume OK */
55e303ae 926
91447636
A
927 for (i=0; i<CLUT_ENTRIES; i++) {
928 if ( panic_dialog_clut[i] == active_clut[i] ) continue;
929 r = 0;
930 break;
55e303ae
A
931 }
932
91447636 933 return r;
55e303ae 934}