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