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