]> git.saurik.com Git - apple/xnu.git/blame - osfmk/console/panic_dialog.c
xnu-1228.7.58.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>
55e303ae
A
38
39extern struct vc_info vinfo;
40extern boolean_t panicDialogDesired;
41
91447636
A
42#include "panic_image.c"
43
44void panic_ui_initialize(const unsigned char * system_clut);
45int panic_dialog_set_image( const unsigned char * ptr, unsigned int size );
2d21ac55 46void panic_dialog_get_image(const unsigned char **ptr, unsigned int *size);
91447636
A
47void draw_panic_dialog( void );
48void panic_dialog_test( void );
49
50static int panic_dialog_verify( const struct panicimage * data, unsigned int size );
51static int pixels_needed_to_blit_digit( int digit );
55e303ae 52static void blit_digit( int digit );
2d21ac55 53static const char * strnstr(const char * s, const char * find, size_t slen);
91447636 54static void dim_screen(void);
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
161
162 panicDebugging = TRUE;
2d21ac55 163 panic_caller = (unsigned long)(char *)__builtin_return_address(0);
91447636
A
164 logPanicDataToScreen = FALSE;
165 panicDialogDesired = TRUE;
166 panicDialogDrawn = FALSE;
167
168 draw_panic_dialog();
169
170 panicDebugging = o_panicDebugging;
171 panic_caller = o_panic_caller;
172 logPanicDataToScreen = o_logPanicDataToScreen;
173 panicDialogDesired = o_panicDialogDesired;
174 panicDialogDrawn = o_panicDialogDrawn;
55e303ae
A
175}
176
91447636 177
55e303ae
A
178void
179draw_panic_dialog( void )
180{
91447636
A
181 if (!panicDialogDrawn && panicDialogDesired) {
182 if ( !logPanicDataToScreen ) {
183 int pd_x, pd_y;
184 int count, nibble, indx;
185 struct ether_addr kdp_mac_addr;
186 unsigned int panic_dialog_count, ip_addr;
187 char panic_num_chars[13+8+1], mac_addr_chars[17+1], ip_addr_chars[15+1];
188 struct {
189 int pixels;
190 char * chars;
191 } panic_dialog_info[3];
192
55e303ae
A
193
194 /* dim the screen 50% before putting up panic dialog */
195 dim_screen();
196
197 /* set up to draw background box */
91447636
A
198 /* by locating where the upper left corner is placed */
199
200 pd_x = (vinfo.v_width/2) - panic_dialog->pd_width/2;
201 pd_y = (vinfo.v_height/2) - panic_dialog->pd_height/2;
55e303ae 202
91447636 203 /* draw panic dialog at pd_x/pd_y */
2d21ac55
A
204 panic_blit_rect(pd_x, pd_y, panic_dialog->pd_width,
205 panic_dialog->pd_height, 0,
206 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 {
2d21ac55 408 newimage = (const struct panicimage *)ptr;
91447636
A
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
2d21ac55 419 curr_image_ptr = ptr;
91447636
A
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
2d21ac55 432panic_dialog_get_image(const unsigned char ** ptr, unsigned int * size )
91447636
A
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 );
2d21ac55
A
473static void panic_blit_rect_8(unsigned int x, unsigned int y,
474 unsigned int width, unsigned int height,
475 int transparent, const unsigned char *dataPtr);
476static void panic_blit_rect_16(unsigned int x, unsigned int y,
477 unsigned int width, unsigned int height,
478 int transparent, const unsigned char *dataPtr);
479static void panic_blit_rect_32(unsigned int x, unsigned int y,
480 unsigned int width, unsigned int height,
481 int transparent, const unsigned char *dataPtr);
482static int decode_rle(const unsigned char *dataPtr,
483 unsigned int *quantity, unsigned int *depth,
484 const unsigned char **value);
91447636
A
485
486
487/* Utilities to convert 8 bit/gray */
488static unsigned int make24bitcolor( unsigned int index, const unsigned char * clut );
489static unsigned char findIndexMatch( unsigned char index );
490static unsigned char color24togray8( unsigned int color24 );
491static unsigned char findbestgray( unsigned int color24 );
492static int isActiveClutOK( void );
493
494static int
2d21ac55 495pixels_needed_to_blit_digit(__unused int digit )
91447636
A
496{
497 return FONT_WIDTH;
55e303ae
A
498}
499
91447636
A
500
501static const struct rendered_num *
502find_rendered_digit( int digit )
503{
504 //extern unsigned char iso_font[];
505 const struct rendered_num *digitPtr;
506
507 if ( digit < 16 ) {
508 if ( digit < 10 )
509 digit += 0x30;
510 else
511 digit += 0x37;
512 }
513
514 digitPtr = (const struct rendered_num *) &iso_font[digit * 16];
515 return digitPtr;
516}
517
518
55e303ae
A
519static void
520blit_digit( int digit )
521{
2d21ac55
A
522 const unsigned char *raw_data =
523 (const unsigned char *)find_rendered_digit(digit);
91447636
A
524 unsigned width = FONT_WIDTH, height = FONT_HEIGHT;
525 int row;
526
527 for (row=0; row<FONT_HEIGHT; row++) {
528 int j;
529 unsigned char bits;
530
531 bits = raw_data[row];
532 for( j=FONT_WIDTH-1; j>=0; j--) {
533
534 if ( bits & 0x80 )
0c530ab8 535 rendered_font[row][j] = OSSwapBigToHostInt16(0x0100 | panic_dialog->pd_info_color[0]);
91447636 536 else
0c530ab8 537 rendered_font[row][j] = OSSwapBigToHostInt16(0x0100 | panic_dialog->pd_info_color[1]);
91447636 538 bits <<= 1;
55e303ae 539 }
55e303ae 540 }
91447636
A
541
542 panic_blit_rect( panic_info_x, panic_info_y , width, height, 255, (unsigned char *) rendered_font);
543 panic_info_x += width;
55e303ae
A
544}
545
91447636 546
55e303ae 547static void
2d21ac55
A
548panic_blit_rect(unsigned int x, unsigned int y, unsigned int width,
549 unsigned int height, int transparent,
550 const unsigned char *dataPtr)
55e303ae
A
551{
552 if(!vinfo.v_depth)
553 return;
554
555 switch( vinfo.v_depth) {
556 case 8:
557 panic_blit_rect_8( x, y, width, height, transparent, dataPtr);
558 break;
559 case 16:
560 panic_blit_rect_16( x, y, width, height, transparent, dataPtr);
561 break;
562 case 32:
563 panic_blit_rect_32( x, y, width, height, transparent, dataPtr);
564 break;
565 }
566}
567
91447636
A
568/*
569 * panic_blit_rect_8 decodes the RLE encoded image data on the fly, looks up the
570 * color by indexing into the clut, or attempts to find the best index.
571 */
55e303ae 572
55e303ae 573static void
2d21ac55
A
574panic_blit_rect_8(unsigned int x, unsigned int y, unsigned int width,
575 unsigned int height, __unused int transparent,
576 const unsigned char * dataPtr)
55e303ae
A
577{
578 volatile unsigned char * dst;
91447636
A
579 unsigned int line, col, i;
580 static int clutOK = -1;
581 unsigned int data, quantity, depth;
2d21ac55 582 const unsigned char *value;
55e303ae 583
91447636
A
584
585 if ( clutOK == -1 )
586 clutOK = isActiveClutOK();
587
55e303ae 588 dst = (volatile unsigned char *) (vinfo.v_baseaddr +
91447636
A
589 (y * vinfo.v_rowbytes) +
590 x);
55e303ae
A
591
592 quantity = 0;
91447636 593 i = 0;
55e303ae
A
594
595 for( line = 0; line < height; line++) {
596 for( col = 0; col < width; col++) {
91447636 597
55e303ae 598 if (quantity == 0) {
91447636
A
599 dataPtr += decode_rle(dataPtr, &quantity, &depth, &value);
600 i = 0;
55e303ae
A
601 }
602
91447636
A
603 if ( clutOK )
604 data = value[i++];
605 else
606 data = findIndexMatch( value[i++] );
607
55e303ae 608 *(dst + col) = data;
91447636
A
609
610 if ( i == depth ) {
611 i = 0;
612 quantity--;
613 }
55e303ae
A
614 }
615
616 dst = (volatile unsigned char *) (((int)dst) + vinfo.v_rowbytes);
617 }
618}
619
91447636
A
620/*
621 * panic_blit_rect_16 decodes the RLE encoded image data on the fly, looks up the
622 * color by indexing into the clut, uses the top 5 bits to fill in each of the three
623 * pixel values (RGB) and writes each pixel to the screen.
624 */
625
2d21ac55
A
626static void
627panic_blit_rect_16(unsigned int x, unsigned int y, unsigned int width,
628 unsigned int height, __unused int transparent,
629 const unsigned char *dataPtr)
630{
55e303ae 631
91447636
A
632 volatile unsigned short * dst;
633 unsigned int line, col, i;
634 unsigned int quantity, index, data, depth;
2d21ac55 635 const unsigned char *value;
55e303ae 636
91447636
A
637 dst = (volatile unsigned short *) (vinfo.v_baseaddr +
638 (y * vinfo.v_rowbytes) +
639 (x * 2));
55e303ae 640
91447636
A
641 quantity = 0;
642 i = 0;
55e303ae 643
91447636
A
644 for( line = 0; line < height; line++) {
645 for( col = 0; col < width; col++) {
55e303ae 646
91447636
A
647 if (quantity == 0) {
648 dataPtr += decode_rle(dataPtr, &quantity, &depth, &value);
649 i = 0;
650 }
55e303ae 651
91447636
A
652 index = value[i++] * 3;
653
654 data = ( (unsigned short) (0xf8 & (panic_dialog_clut[index + 0])) << 7)
655 | ( (unsigned short) (0xf8 & (panic_dialog_clut[index + 1])) << 2)
656 | ( (unsigned short) (0xf8 & (panic_dialog_clut[index + 2])) >> 3);
55e303ae 657
91447636 658 *(dst + col) = data;
55e303ae 659
91447636
A
660 if ( i == depth ) {
661 i = 0;
662 quantity--;
663 }
664 }
55e303ae 665
91447636
A
666 dst = (volatile unsigned short *) (((int)dst) + vinfo.v_rowbytes);
667 }
55e303ae
A
668 }
669
91447636
A
670/*
671 * panic_blit_rect_32 decodes the RLE encoded image data on the fly, and fills
672 * in each of the three pixel values from the clut (RGB) for each pixel and
673 * writes it to the screen.
55e303ae 674 */
91447636 675
2d21ac55
A
676static void
677panic_blit_rect_32(unsigned int x, unsigned int y, unsigned int width,
678 unsigned int height, __unused int transparent,
679 const unsigned char *dataPtr)
680{
91447636
A
681 volatile unsigned int * dst;
682 unsigned int line, col, i;
683 unsigned int quantity, index, data, depth;
2d21ac55 684 const unsigned char *value;
55e303ae 685
55e303ae
A
686
687 dst = (volatile unsigned int *) (vinfo.v_baseaddr +
91447636
A
688 (y * vinfo.v_rowbytes) +
689 (x * 4));
55e303ae
A
690
691 quantity = 0;
91447636 692 i = 0;
55e303ae
A
693
694 for( line = 0; line < height; line++) {
695 for( col = 0; col < width; col++) {
91447636 696
55e303ae 697 if (quantity == 0) {
91447636
A
698 dataPtr += decode_rle(dataPtr, &quantity, &depth, &value);
699 i = 0;
55e303ae 700 }
91447636
A
701
702 index = value[i++] * 3;
55e303ae 703
91447636
A
704 data = ( (unsigned int) panic_dialog_clut[index + 0] << 16)
705 | ( (unsigned int) panic_dialog_clut[index + 1] << 8)
706 | ( (unsigned int) panic_dialog_clut[index + 2]);
55e303ae
A
707
708 *(dst + col) = data;
91447636
A
709
710 if ( i == depth ) {
711 i = 0;
712 quantity--;
713 }
55e303ae
A
714 }
715
716 dst = (volatile unsigned int *) (((int)dst) + vinfo.v_rowbytes);
717 }
718}
719
720/*
91447636
A
721 decode_rle decodes a single quantity/value run of a "modified-RLE" encoded
722 image. The encoding works as follows:
723
724 The run is described in the first byte. If the MSB is zero, then the next seven bits
725 are the quantity of bytes that follow that make up the run of value bytes. (see case 0)
726
727 If the MSB is set, bits 0-3 are the quantity's least significant 4 bits. If bit 5 is set,
728 then the quantity is further described in the next byte, where an additional 7 bits (4-10)
729 worth of quantity will be found. If the MSB of this byte is set, then an additional
730 7 bits (11-17) worth of quantity will be found in the next byte. This repeats until the MSB of
731 a quantity byte is zero, thus ending the run of quantity bytes.
732
733 Bits 5/6 of the first byte, describe the number of bytes in the value run following the quantity run.
734 These bits describe value runs of 1 to 4 bytes. And the quantity describe the number of value runs.
735 (see cases 1-4)
736
737 encodings are: (q = quantity, v = value, c = quantity continues)
738
739 case 0: [ 0 q6-q0 ] [ v7-v0 ] ... [ v7-v0 ]
740 case 1: [ 1 0 0 c q3-q0 ] [ c q10-q4 ] [ c q17-q11 ] [ q24-q18 ] [ v7-v0 ]
741 case 2: [ 1 0 1 c q3-q0 ] [ c q10-q4 ] [ c q17-q11 ] [ q24-q18 ] [ v7-v0 ] [ v7-v0 ]
742 case 3: [ 1 1 0 c q3-q0 ] [ c q10-q4 ] [ c q17-q11 ] [ q24-q18 ] [ v7-v0 ] [ v7-v0 ] [ v7-v0 ]
743 case 4: [ 1 1 1 c q3-q0 ] [ c q10-q4 ] [ c q17-q11 ] [ q24-q18 ] [ v7-v0 ] [ v7-v0 ] [ v7-v0 ] [ v7-v0 ]
55e303ae 744*/
91447636 745
55e303ae 746static int
2d21ac55
A
747decode_rle(const unsigned char *dataPtr, unsigned int *quantity,
748 unsigned int *depth, const unsigned char **value )
55e303ae 749{
91447636
A
750 unsigned int mask;
751 int i, runlen, runsize;
752
753 i = 0;
754 mask = dataPtr[i] & 0xF0;
755
756 if ( mask & 0x80 ) {
757 runsize = ((mask & 0x60) >> 5) + 1;
758 runlen = dataPtr[i++] & 0x0F;
759
760 if ( mask & 0x10 ) {
761 int shift = 4;
762
763 do {
764 mask = dataPtr[i] & 0x80;
765 runlen |= ((dataPtr[i++] & 0x7F) << shift);
766 shift+=7;
767 } while (mask);
768 }
55e303ae 769 } else {
91447636
A
770 runlen = 1;
771 runsize = dataPtr[i++];
55e303ae 772 }
91447636
A
773
774 *depth = runsize;
775 *quantity = runlen;
776 *value = &dataPtr[i];
777
778 return i+runsize;
55e303ae
A
779}
780
91447636 781
55e303ae
A
782static void
783dim_screen(void)
784{
91447636
A
785 unsigned long *p, *endp, *row;
786 int col, rowline, rowlongs;
787 register unsigned long mask;
788
55e303ae
A
789 if(!vinfo.v_depth)
790 return;
791
91447636
A
792 if ( vinfo.v_depth == 32 )
793 mask = 0x007F7F7F;
794 else if ( vinfo.v_depth == 16 )
795 mask = 0x3DEF3DEF;
796 else
797 return;
55e303ae
A
798
799 rowline = vinfo.v_rowscanbytes / 4;
800 rowlongs = vinfo.v_rowbytes / 4;
801
802 p = (unsigned long*) vinfo.v_baseaddr;
91447636 803 endp = p + (rowlongs * vinfo.v_height);
55e303ae
A
804
805 for (row = p ; row < endp ; row += rowlongs) {
91447636 806 for (p = &row[0], col = 0; col < rowline; col++) {
2d21ac55
A
807 *p = (*p >> 1) & mask;
808 ++p;
91447636
A
809 }
810 }
811}
812
813
814/* From user mode Libc - this ought to be in a library */
2d21ac55 815static const char *
91447636
A
816strnstr(const char * s, const char * find, size_t slen)
817{
818 char c, sc;
819 size_t len;
820
821 if ((c = *find++) != '\0') {
822 len = strlen(find);
823 do {
824 do {
825 if ((sc = *s++) == '\0' || slen-- < 1)
826 return (NULL);
827 } while (sc != c);
828 if (len > slen)
829 return (NULL);
830 } while (strncmp(s, find, len) != 0);
831 s--;
832 }
2d21ac55 833 return s;
91447636
A
834}
835
836/*
837 * these routines are for converting a color into grayscale
838 * in 8-bit mode, if the active clut is different than the
839 * clut used to create the panic dialog, then we must convert to gray
840 */
841
842static unsigned int
843make24bitcolor( unsigned int index, const unsigned char * clut )
844{
845 unsigned int color24 = 0;
846 int i = index * 3;
847
848 color24 |= clut[i+0] << 16;
849 color24 |= clut[i+1] << 8;
850 color24 |= clut[i+2];
851
852 return color24;
853}
854
855
856static unsigned char
857findbestgray( unsigned int color24 )
858{
859 unsigned int c24, rel, bestindex=-1, bestgray = -1;
860 unsigned char gray8, c8;
861 int i;
862#define abs(v) ((v) > 0)?(v):-(v)
55e303ae 863
91447636
A
864 gray8 = color24togray8( color24 ); /* convert the original color into grayscale */
865
866 for (i=0; i<CLUT_ENTRIES; i++) {
867 c24 = make24bitcolor( i, active_clut );
868 if ( (((c24>>16)&0xff) != ((c24>>8)&0xff)) || ((c24>>8)&0xff) != (c24 & 0xff) )
869 continue; /* only match against grays */
870
871 c8 = c24 & 0xFF; /* isolate the gray */
872
873 /* find the gray with the smallest difference */
874 rel = abs( gray8 - c8 );
875 if ( rel < bestgray ) {
876 bestgray = rel;
877 bestindex = i;
878 }
55e303ae
A
879 }
880
91447636 881 /* Did we fail to find any grays ? */
2d21ac55 882 if (ULONG_MAX == bestindex) {
91447636
A
883 /* someday we should look for the best color match */
884 /* but for now just return the gray as the index */
885 /* at least there might be something readble on the display */
886
887 bestindex = gray8;
888 }
889
890 return bestindex;
891#undef abs
55e303ae
A
892}
893
91447636
A
894
895static unsigned char
896color24togray8( unsigned int color24 )
897{
0c530ab8
A
898 int R, G, B;
899 int Gray;
91447636
A
900 unsigned char gray8;
901
902 R = (color24 & 0xFF0000) >> 16 ;
903 G = (color24 & 0xFF00) >> 8 ;
904 B = (color24 & 0xFF);
905
0c530ab8
A
906 Gray = (R*30) + (G*59) + (B*11);
907 gray8 = (unsigned char) ((Gray + 50) / 100);
91447636 908 return gray8;
2d21ac55 909}
91447636
A
910
911
912static unsigned char
913findIndexMatch( unsigned char index )
55e303ae 914{
91447636
A
915 static unsigned int last_in_index = -1;
916 static unsigned char last_index;
917 unsigned int sc;
55e303ae 918
91447636
A
919 if ( index == last_in_index )
920 return last_index;
55e303ae 921
91447636
A
922 last_in_index = index;
923 sc = make24bitcolor( index, panic_dialog_clut );
924 last_index = findbestgray( sc ); /* find the nearest matching gray in the active clut */
55e303ae 925
91447636
A
926 return last_index;
927}
55e303ae 928
91447636
A
929static int
930isActiveClutOK( void )
931{
932 int i;
933 int r = 1; /* assume OK */
55e303ae 934
91447636
A
935 for (i=0; i<CLUT_ENTRIES; i++) {
936 if ( panic_dialog_clut[i] == active_clut[i] ) continue;
937 r = 0;
938 break;
55e303ae
A
939 }
940
91447636 941 return r;
55e303ae 942}