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