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