]>
Commit | Line | Data |
---|---|---|
55e303ae | 1 | /* |
91447636 | 2 | * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved. |
55e303ae | 3 | * |
8ad349bb | 4 | * @APPLE_LICENSE_OSREFERENCE_HEADER_START@ |
55e303ae | 5 | * |
8ad349bb 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 | |
10 | * License may not be used to create, or enable the creation or | |
11 | * redistribution of, unlawful or unlicensed copies of an Apple operating | |
12 | * system, or to circumvent, violate, or enable the circumvention or | |
13 | * violation of, any terms of an Apple operating system software license | |
14 | * agreement. | |
15 | * | |
16 | * Please obtain a copy of the License at | |
17 | * http://www.opensource.apple.com/apsl/ and read it before using this | |
18 | * file. | |
19 | * | |
20 | * The Original Code and all software distributed under the License are | |
21 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER | |
22 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, | |
23 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
24 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. | |
25 | * Please see the License for the specific language governing rights and | |
26 | * limitations under the License. | |
27 | * | |
28 | * @APPLE_LICENSE_OSREFERENCE_HEADER_END@ | |
55e303ae A |
29 | */ |
30 | ||
31 | #include <vc.h> | |
55e303ae | 32 | #include <console/video_console.h> |
5d5c5d0d | 33 | #include <libkern/OSByteOrder.h> |
55e303ae A |
34 | #include <kdp/kdp_udp.h> |
35 | #include <kern/debug.h> | |
91447636 A |
36 | #include <mach/mach_time.h> |
37 | #include <sys/errno.h> | |
38 | #include <string.h> | |
55e303ae | 39 | |
55e303ae A |
40 | |
41 | extern struct vc_info vinfo; | |
42 | extern boolean_t panicDialogDesired; | |
43 | ||
91447636 A |
44 | #include "panic_image.c" |
45 | ||
46 | void panic_ui_initialize(const unsigned char * system_clut); | |
47 | int panic_dialog_set_image( const unsigned char * ptr, unsigned int size ); | |
48 | void panic_dialog_get_image( unsigned char ** ptr, unsigned int * size ); | |
49 | void draw_panic_dialog( void ); | |
50 | void panic_dialog_test( void ); | |
51 | ||
52 | static int panic_dialog_verify( const struct panicimage * data, unsigned int size ); | |
53 | static int pixels_needed_to_blit_digit( int digit ); | |
55e303ae | 54 | static void blit_digit( int digit ); |
91447636 A |
55 | static char * strnstr(const char * s, const char * find, size_t slen); |
56 | static void dim_screen(void); | |
57 | static void panic_blit_rect(unsigned int x, unsigned int y, unsigned int width, unsigned int height, | |
58 | int transparent, unsigned char * dataPtr ); | |
59 | ||
60 | static int panic_info_x; | |
61 | static int panic_info_y; | |
62 | ||
63 | static const unsigned char * active_clut = NULL; /* This is a copy of the active clut */ | |
64 | ||
55e303ae A |
65 | static boolean_t panicDialogDrawn = FALSE; |
66 | ||
91447636 A |
67 | static const struct panicimage * panic_dialog = NULL; /* the active panic dialog */ |
68 | static const unsigned char * panic_dialog_data = NULL; /* where the image data starts */ | |
69 | static const unsigned char * panic_dialog_clut = NULL; /* where the clut used for the image starts */ | |
55e303ae | 70 | |
91447636 A |
71 | static unsigned char * curr_image_ptr = NULL; /* If NULL, the default panic dialog is active */ |
72 | static unsigned int curr_image_size = 0; | |
55e303ae | 73 | |
91447636 A |
74 | #define FONT_WIDTH 8 |
75 | #define FONT_HEIGHT 16 | |
76 | static unsigned short rendered_font[FONT_HEIGHT][FONT_WIDTH]; | |
55e303ae | 77 | |
91447636 | 78 | static char versionbuf[20]; /* ####.###~###\0 */ |
55e303ae | 79 | |
91447636 | 80 | #define isdigit(d) ((d) >= '0' && (d) <= '9') |
55e303ae | 81 | |
91447636 A |
82 | #define CLUT_ENTRIES 256 |
83 | #define CLUT_SIZE (CLUT_ENTRIES * 3) | |
84 | ||
85 | ||
86 | /* | |
87 | * This routine sets up the default panic dialog | |
88 | */ | |
89 | ||
90 | extern unsigned char iso_font[]; | |
91 | extern const char version[]; | |
92 | extern unsigned int panic_caller; | |
93 | ||
94 | void | |
55e303ae A |
95 | panic_ui_initialize(const unsigned char * system_clut) |
96 | { | |
91447636 A |
97 | char vstr[20]; |
98 | ||
99 | ||
100 | panic_dialog_set_image( NULL, 0 ); | |
101 | ||
102 | active_clut = system_clut; | |
103 | ||
104 | strcpy(vstr, "custom"); | |
105 | ||
106 | /* Convert xnu-####.###.obj~### into ####.###~### */ | |
107 | ||
108 | if (version) { | |
109 | char * versionpos = strnstr(version, "xnu-", 20); | |
110 | ||
111 | if (versionpos) { | |
112 | int len, i; | |
113 | ||
114 | vstr[0] = '\0'; | |
115 | ||
116 | for (i=0,len=4;len<20;len++) { | |
117 | if (isdigit(versionpos[len]) || versionpos[len] == '.') { /* extract ####.###. */ | |
118 | vstr[i++] = versionpos[len]; | |
119 | continue; | |
120 | } | |
121 | break; | |
122 | } | |
123 | ||
124 | if ( versionpos[len-1] == '.' ) /* remove trailing period if present */ | |
125 | i--; | |
126 | ||
127 | for (;len<20;len++) { /* skip to next digit if present */ | |
128 | if ( !isdigit(versionpos[len]) ) | |
129 | continue; | |
130 | break; | |
131 | } | |
132 | ||
133 | if ( versionpos[len-1] == '~' ) { /* extract ~### if present */ | |
134 | vstr[i++] = versionpos[len-1]; | |
135 | for (;len<20;len++) { /* extract ### */ | |
136 | if ( isdigit(versionpos[len]) ) { | |
137 | vstr[i++] = versionpos[len]; | |
138 | continue; | |
139 | } | |
140 | break; | |
141 | } | |
142 | } | |
143 | ||
144 | vstr[i] = '\0'; | |
145 | } | |
146 | } | |
147 | ||
148 | strcpy(versionbuf, vstr); | |
149 | } | |
150 | ||
151 | ||
152 | ||
153 | void | |
154 | panic_dialog_test( void ) | |
155 | { | |
156 | boolean_t o_panicDialogDrawn = panicDialogDrawn; | |
157 | boolean_t o_panicDialogDesired = panicDialogDesired; | |
158 | unsigned int o_logPanicDataToScreen = logPanicDataToScreen; | |
159 | unsigned int o_panic_caller = panic_caller; | |
160 | unsigned int o_panicDebugging = panicDebugging; | |
161 | ||
162 | ||
163 | panicDebugging = TRUE; | |
164 | panic_caller = (unsigned int) __builtin_return_address(0); | |
165 | logPanicDataToScreen = FALSE; | |
166 | panicDialogDesired = TRUE; | |
167 | panicDialogDrawn = FALSE; | |
168 | ||
169 | draw_panic_dialog(); | |
170 | ||
171 | panicDebugging = o_panicDebugging; | |
172 | panic_caller = o_panic_caller; | |
173 | logPanicDataToScreen = o_logPanicDataToScreen; | |
174 | panicDialogDesired = o_panicDialogDesired; | |
175 | panicDialogDrawn = o_panicDialogDrawn; | |
55e303ae A |
176 | } |
177 | ||
91447636 | 178 | |
55e303ae A |
179 | void |
180 | draw_panic_dialog( void ) | |
181 | { | |
91447636 A |
182 | if (!panicDialogDrawn && panicDialogDesired) { |
183 | if ( !logPanicDataToScreen ) { | |
184 | int pd_x, pd_y; | |
185 | int count, nibble, indx; | |
186 | struct ether_addr kdp_mac_addr; | |
187 | unsigned int panic_dialog_count, ip_addr; | |
188 | char panic_num_chars[13+8+1], mac_addr_chars[17+1], ip_addr_chars[15+1]; | |
189 | struct { | |
190 | int pixels; | |
191 | char * chars; | |
192 | } panic_dialog_info[3]; | |
193 | ||
55e303ae A |
194 | |
195 | /* dim the screen 50% before putting up panic dialog */ | |
196 | dim_screen(); | |
197 | ||
198 | /* set up to draw background box */ | |
91447636 A |
199 | /* by locating where the upper left corner is placed */ |
200 | ||
201 | pd_x = (vinfo.v_width/2) - panic_dialog->pd_width/2; | |
202 | pd_y = (vinfo.v_height/2) - panic_dialog->pd_height/2; | |
55e303ae | 203 | |
91447636 A |
204 | /* draw panic dialog at pd_x/pd_y */ |
205 | panic_blit_rect( pd_x, pd_y, panic_dialog->pd_width, panic_dialog->pd_height, | |
206 | 0, (unsigned char*) 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 | ||
395 | int | |
396 | panic_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 { | |
408 | newimage = (struct panicimage *) ptr; | |
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 | ||
419 | curr_image_ptr = (unsigned char *) ptr; | |
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 | ||
431 | void | |
432 | panic_dialog_get_image( unsigned char ** ptr, unsigned int * size ) | |
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 | ||
443 | static int | |
444 | panic_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 | ||
472 | static const struct rendered_num * find_rendered_digit( int digit ); | |
473 | static void panic_blit_rect_8( unsigned int x, unsigned int y, unsigned int width, unsigned int height, | |
474 | int transparent, unsigned char * dataPtr ); | |
475 | static void panic_blit_rect_16( unsigned int x, unsigned int y, unsigned int width, unsigned int height, | |
476 | int transparent, unsigned char * dataPtr ); | |
477 | static void panic_blit_rect_32( unsigned int x, unsigned int y, unsigned int width, unsigned int height, | |
478 | int transparent, unsigned char * dataPtr ); | |
479 | static int decode_rle( unsigned char * dataPtr, unsigned int * quantity, unsigned int * depth, unsigned char ** value ); | |
480 | ||
481 | ||
482 | /* Utilities to convert 8 bit/gray */ | |
483 | static unsigned int make24bitcolor( unsigned int index, const unsigned char * clut ); | |
484 | static unsigned char findIndexMatch( unsigned char index ); | |
485 | static unsigned char color24togray8( unsigned int color24 ); | |
486 | static unsigned char findbestgray( unsigned int color24 ); | |
487 | static int isActiveClutOK( void ); | |
488 | ||
489 | static int | |
490 | pixels_needed_to_blit_digit( int digit ) | |
491 | { | |
492 | return FONT_WIDTH; | |
55e303ae A |
493 | } |
494 | ||
91447636 A |
495 | |
496 | static const struct rendered_num * | |
497 | find_rendered_digit( int digit ) | |
498 | { | |
499 | //extern unsigned char iso_font[]; | |
500 | const struct rendered_num *digitPtr; | |
501 | ||
502 | if ( digit < 16 ) { | |
503 | if ( digit < 10 ) | |
504 | digit += 0x30; | |
505 | else | |
506 | digit += 0x37; | |
507 | } | |
508 | ||
509 | digitPtr = (const struct rendered_num *) &iso_font[digit * 16]; | |
510 | return digitPtr; | |
511 | } | |
512 | ||
513 | ||
55e303ae A |
514 | static void |
515 | blit_digit( int digit ) | |
516 | { | |
91447636 A |
517 | unsigned char * raw_data = (unsigned char *) find_rendered_digit( digit ); |
518 | unsigned width = FONT_WIDTH, height = FONT_HEIGHT; | |
519 | int row; | |
520 | ||
521 | for (row=0; row<FONT_HEIGHT; row++) { | |
522 | int j; | |
523 | unsigned char bits; | |
524 | ||
525 | bits = raw_data[row]; | |
526 | for( j=FONT_WIDTH-1; j>=0; j--) { | |
527 | ||
528 | if ( bits & 0x80 ) | |
5d5c5d0d | 529 | rendered_font[row][j] = OSSwapBigToHostInt16(0x0100 | panic_dialog->pd_info_color[0]); |
91447636 | 530 | else |
5d5c5d0d | 531 | rendered_font[row][j] = OSSwapBigToHostInt16(0x0100 | panic_dialog->pd_info_color[1]); |
91447636 | 532 | bits <<= 1; |
55e303ae | 533 | } |
55e303ae | 534 | } |
91447636 A |
535 | |
536 | panic_blit_rect( panic_info_x, panic_info_y , width, height, 255, (unsigned char *) rendered_font); | |
537 | panic_info_x += width; | |
55e303ae A |
538 | } |
539 | ||
91447636 | 540 | |
55e303ae A |
541 | static void |
542 | panic_blit_rect( unsigned int x, unsigned int y, | |
91447636 A |
543 | unsigned int width, unsigned int height, |
544 | int transparent, unsigned char * dataPtr ) | |
55e303ae A |
545 | { |
546 | if(!vinfo.v_depth) | |
547 | return; | |
548 | ||
549 | switch( vinfo.v_depth) { | |
550 | case 8: | |
551 | panic_blit_rect_8( x, y, width, height, transparent, dataPtr); | |
552 | break; | |
553 | case 16: | |
554 | panic_blit_rect_16( x, y, width, height, transparent, dataPtr); | |
555 | break; | |
556 | case 32: | |
557 | panic_blit_rect_32( x, y, width, height, transparent, dataPtr); | |
558 | break; | |
559 | } | |
560 | } | |
561 | ||
91447636 A |
562 | /* |
563 | * panic_blit_rect_8 decodes the RLE encoded image data on the fly, looks up the | |
564 | * color by indexing into the clut, or attempts to find the best index. | |
565 | */ | |
55e303ae | 566 | |
55e303ae A |
567 | static void |
568 | panic_blit_rect_8( unsigned int x, unsigned int y, | |
91447636 A |
569 | unsigned int width, unsigned int height, |
570 | int transparent, unsigned char * dataPtr ) | |
55e303ae A |
571 | { |
572 | volatile unsigned char * dst; | |
91447636 A |
573 | unsigned int line, col, i; |
574 | static int clutOK = -1; | |
575 | unsigned int data, quantity, depth; | |
576 | unsigned char * value; | |
55e303ae | 577 | |
91447636 A |
578 | |
579 | if ( clutOK == -1 ) | |
580 | clutOK = isActiveClutOK(); | |
581 | ||
55e303ae | 582 | dst = (volatile unsigned char *) (vinfo.v_baseaddr + |
91447636 A |
583 | (y * vinfo.v_rowbytes) + |
584 | x); | |
55e303ae A |
585 | |
586 | quantity = 0; | |
91447636 | 587 | i = 0; |
55e303ae A |
588 | |
589 | for( line = 0; line < height; line++) { | |
590 | for( col = 0; col < width; col++) { | |
91447636 | 591 | |
55e303ae | 592 | if (quantity == 0) { |
91447636 A |
593 | dataPtr += decode_rle(dataPtr, &quantity, &depth, &value); |
594 | i = 0; | |
55e303ae A |
595 | } |
596 | ||
91447636 A |
597 | if ( clutOK ) |
598 | data = value[i++]; | |
599 | else | |
600 | data = findIndexMatch( value[i++] ); | |
601 | ||
55e303ae | 602 | *(dst + col) = data; |
91447636 A |
603 | |
604 | if ( i == depth ) { | |
605 | i = 0; | |
606 | quantity--; | |
607 | } | |
55e303ae A |
608 | } |
609 | ||
610 | dst = (volatile unsigned char *) (((int)dst) + vinfo.v_rowbytes); | |
611 | } | |
612 | } | |
613 | ||
91447636 A |
614 | /* |
615 | * panic_blit_rect_16 decodes the RLE encoded image data on the fly, looks up the | |
616 | * color by indexing into the clut, uses the top 5 bits to fill in each of the three | |
617 | * pixel values (RGB) and writes each pixel to the screen. | |
618 | */ | |
619 | ||
55e303ae A |
620 | static void |
621 | panic_blit_rect_16( unsigned int x, unsigned int y, | |
91447636 A |
622 | unsigned int width, unsigned int height, |
623 | int transparent, unsigned char * dataPtr ) | |
55e303ae | 624 | { |
55e303ae | 625 | |
91447636 A |
626 | volatile unsigned short * dst; |
627 | unsigned int line, col, i; | |
628 | unsigned int quantity, index, data, depth; | |
629 | unsigned char * value; | |
55e303ae | 630 | |
91447636 A |
631 | dst = (volatile unsigned short *) (vinfo.v_baseaddr + |
632 | (y * vinfo.v_rowbytes) + | |
633 | (x * 2)); | |
55e303ae | 634 | |
91447636 A |
635 | quantity = 0; |
636 | i = 0; | |
55e303ae | 637 | |
91447636 A |
638 | for( line = 0; line < height; line++) { |
639 | for( col = 0; col < width; col++) { | |
55e303ae | 640 | |
91447636 A |
641 | if (quantity == 0) { |
642 | dataPtr += decode_rle(dataPtr, &quantity, &depth, &value); | |
643 | i = 0; | |
644 | } | |
55e303ae | 645 | |
91447636 A |
646 | index = value[i++] * 3; |
647 | ||
648 | data = ( (unsigned short) (0xf8 & (panic_dialog_clut[index + 0])) << 7) | |
649 | | ( (unsigned short) (0xf8 & (panic_dialog_clut[index + 1])) << 2) | |
650 | | ( (unsigned short) (0xf8 & (panic_dialog_clut[index + 2])) >> 3); | |
55e303ae | 651 | |
91447636 | 652 | *(dst + col) = data; |
55e303ae | 653 | |
91447636 A |
654 | if ( i == depth ) { |
655 | i = 0; | |
656 | quantity--; | |
657 | } | |
658 | } | |
55e303ae | 659 | |
91447636 A |
660 | dst = (volatile unsigned short *) (((int)dst) + vinfo.v_rowbytes); |
661 | } | |
55e303ae A |
662 | } |
663 | ||
91447636 A |
664 | /* |
665 | * panic_blit_rect_32 decodes the RLE encoded image data on the fly, and fills | |
666 | * in each of the three pixel values from the clut (RGB) for each pixel and | |
667 | * writes it to the screen. | |
55e303ae | 668 | */ |
91447636 | 669 | |
55e303ae A |
670 | static void |
671 | panic_blit_rect_32( unsigned int x, unsigned int y, | |
91447636 A |
672 | unsigned int width, unsigned int height, |
673 | int transparent, unsigned char * dataPtr ) | |
55e303ae | 674 | { |
91447636 A |
675 | volatile unsigned int * dst; |
676 | unsigned int line, col, i; | |
677 | unsigned int quantity, index, data, depth; | |
678 | unsigned char * value; | |
55e303ae | 679 | |
55e303ae A |
680 | |
681 | dst = (volatile unsigned int *) (vinfo.v_baseaddr + | |
91447636 A |
682 | (y * vinfo.v_rowbytes) + |
683 | (x * 4)); | |
55e303ae A |
684 | |
685 | quantity = 0; | |
91447636 | 686 | i = 0; |
55e303ae A |
687 | |
688 | for( line = 0; line < height; line++) { | |
689 | for( col = 0; col < width; col++) { | |
91447636 | 690 | |
55e303ae | 691 | if (quantity == 0) { |
91447636 A |
692 | dataPtr += decode_rle(dataPtr, &quantity, &depth, &value); |
693 | i = 0; | |
55e303ae | 694 | } |
91447636 A |
695 | |
696 | index = value[i++] * 3; | |
55e303ae | 697 | |
91447636 A |
698 | data = ( (unsigned int) panic_dialog_clut[index + 0] << 16) |
699 | | ( (unsigned int) panic_dialog_clut[index + 1] << 8) | |
700 | | ( (unsigned int) panic_dialog_clut[index + 2]); | |
55e303ae A |
701 | |
702 | *(dst + col) = data; | |
91447636 A |
703 | |
704 | if ( i == depth ) { | |
705 | i = 0; | |
706 | quantity--; | |
707 | } | |
55e303ae A |
708 | } |
709 | ||
710 | dst = (volatile unsigned int *) (((int)dst) + vinfo.v_rowbytes); | |
711 | } | |
712 | } | |
713 | ||
714 | /* | |
91447636 A |
715 | decode_rle decodes a single quantity/value run of a "modified-RLE" encoded |
716 | image. The encoding works as follows: | |
717 | ||
718 | The run is described in the first byte. If the MSB is zero, then the next seven bits | |
719 | are the quantity of bytes that follow that make up the run of value bytes. (see case 0) | |
720 | ||
721 | If the MSB is set, bits 0-3 are the quantity's least significant 4 bits. If bit 5 is set, | |
722 | then the quantity is further described in the next byte, where an additional 7 bits (4-10) | |
723 | worth of quantity will be found. If the MSB of this byte is set, then an additional | |
724 | 7 bits (11-17) worth of quantity will be found in the next byte. This repeats until the MSB of | |
725 | a quantity byte is zero, thus ending the run of quantity bytes. | |
726 | ||
727 | Bits 5/6 of the first byte, describe the number of bytes in the value run following the quantity run. | |
728 | These bits describe value runs of 1 to 4 bytes. And the quantity describe the number of value runs. | |
729 | (see cases 1-4) | |
730 | ||
731 | encodings are: (q = quantity, v = value, c = quantity continues) | |
732 | ||
733 | case 0: [ 0 q6-q0 ] [ v7-v0 ] ... [ v7-v0 ] | |
734 | case 1: [ 1 0 0 c q3-q0 ] [ c q10-q4 ] [ c q17-q11 ] [ q24-q18 ] [ v7-v0 ] | |
735 | case 2: [ 1 0 1 c q3-q0 ] [ c q10-q4 ] [ c q17-q11 ] [ q24-q18 ] [ v7-v0 ] [ v7-v0 ] | |
736 | case 3: [ 1 1 0 c q3-q0 ] [ c q10-q4 ] [ c q17-q11 ] [ q24-q18 ] [ v7-v0 ] [ v7-v0 ] [ v7-v0 ] | |
737 | 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 | 738 | */ |
91447636 | 739 | |
55e303ae | 740 | static int |
91447636 | 741 | decode_rle( unsigned char * dataPtr, unsigned int * quantity, unsigned int * depth, unsigned char ** value ) |
55e303ae | 742 | { |
91447636 A |
743 | unsigned int mask; |
744 | int i, runlen, runsize; | |
745 | ||
746 | i = 0; | |
747 | mask = dataPtr[i] & 0xF0; | |
748 | ||
749 | if ( mask & 0x80 ) { | |
750 | runsize = ((mask & 0x60) >> 5) + 1; | |
751 | runlen = dataPtr[i++] & 0x0F; | |
752 | ||
753 | if ( mask & 0x10 ) { | |
754 | int shift = 4; | |
755 | ||
756 | do { | |
757 | mask = dataPtr[i] & 0x80; | |
758 | runlen |= ((dataPtr[i++] & 0x7F) << shift); | |
759 | shift+=7; | |
760 | } while (mask); | |
761 | } | |
55e303ae | 762 | } else { |
91447636 A |
763 | runlen = 1; |
764 | runsize = dataPtr[i++]; | |
55e303ae | 765 | } |
91447636 A |
766 | |
767 | *depth = runsize; | |
768 | *quantity = runlen; | |
769 | *value = &dataPtr[i]; | |
770 | ||
771 | return i+runsize; | |
55e303ae A |
772 | } |
773 | ||
91447636 | 774 | |
55e303ae A |
775 | static void |
776 | dim_screen(void) | |
777 | { | |
91447636 A |
778 | unsigned long *p, *endp, *row; |
779 | int col, rowline, rowlongs; | |
780 | register unsigned long mask; | |
781 | ||
55e303ae A |
782 | if(!vinfo.v_depth) |
783 | return; | |
784 | ||
91447636 A |
785 | if ( vinfo.v_depth == 32 ) |
786 | mask = 0x007F7F7F; | |
787 | else if ( vinfo.v_depth == 16 ) | |
788 | mask = 0x3DEF3DEF; | |
789 | else | |
790 | return; | |
55e303ae A |
791 | |
792 | rowline = vinfo.v_rowscanbytes / 4; | |
793 | rowlongs = vinfo.v_rowbytes / 4; | |
794 | ||
795 | p = (unsigned long*) vinfo.v_baseaddr; | |
91447636 | 796 | endp = p + (rowlongs * vinfo.v_height); |
55e303ae A |
797 | |
798 | for (row = p ; row < endp ; row += rowlongs) { | |
91447636 A |
799 | for (p = &row[0], col = 0; col < rowline; col++) { |
800 | *p++ = (*p >> 1) & mask; | |
801 | } | |
802 | } | |
803 | } | |
804 | ||
805 | ||
806 | /* From user mode Libc - this ought to be in a library */ | |
807 | static char * | |
808 | strnstr(const char * s, const char * find, size_t slen) | |
809 | { | |
810 | char c, sc; | |
811 | size_t len; | |
812 | ||
813 | if ((c = *find++) != '\0') { | |
814 | len = strlen(find); | |
815 | do { | |
816 | do { | |
817 | if ((sc = *s++) == '\0' || slen-- < 1) | |
818 | return (NULL); | |
819 | } while (sc != c); | |
820 | if (len > slen) | |
821 | return (NULL); | |
822 | } while (strncmp(s, find, len) != 0); | |
823 | s--; | |
824 | } | |
825 | return ((char *)s); | |
826 | } | |
827 | ||
828 | /* | |
829 | * these routines are for converting a color into grayscale | |
830 | * in 8-bit mode, if the active clut is different than the | |
831 | * clut used to create the panic dialog, then we must convert to gray | |
832 | */ | |
833 | ||
834 | static unsigned int | |
835 | make24bitcolor( unsigned int index, const unsigned char * clut ) | |
836 | { | |
837 | unsigned int color24 = 0; | |
838 | int i = index * 3; | |
839 | ||
840 | color24 |= clut[i+0] << 16; | |
841 | color24 |= clut[i+1] << 8; | |
842 | color24 |= clut[i+2]; | |
843 | ||
844 | return color24; | |
845 | } | |
846 | ||
847 | ||
848 | static unsigned char | |
849 | findbestgray( unsigned int color24 ) | |
850 | { | |
851 | unsigned int c24, rel, bestindex=-1, bestgray = -1; | |
852 | unsigned char gray8, c8; | |
853 | int i; | |
854 | #define abs(v) ((v) > 0)?(v):-(v) | |
55e303ae | 855 | |
91447636 A |
856 | gray8 = color24togray8( color24 ); /* convert the original color into grayscale */ |
857 | ||
858 | for (i=0; i<CLUT_ENTRIES; i++) { | |
859 | c24 = make24bitcolor( i, active_clut ); | |
860 | if ( (((c24>>16)&0xff) != ((c24>>8)&0xff)) || ((c24>>8)&0xff) != (c24 & 0xff) ) | |
861 | continue; /* only match against grays */ | |
862 | ||
863 | c8 = c24 & 0xFF; /* isolate the gray */ | |
864 | ||
865 | /* find the gray with the smallest difference */ | |
866 | rel = abs( gray8 - c8 ); | |
867 | if ( rel < bestgray ) { | |
868 | bestgray = rel; | |
869 | bestindex = i; | |
870 | } | |
55e303ae A |
871 | } |
872 | ||
91447636 A |
873 | /* Did we fail to find any grays ? */ |
874 | if ( bestindex == -1 ) { | |
875 | /* someday we should look for the best color match */ | |
876 | /* but for now just return the gray as the index */ | |
877 | /* at least there might be something readble on the display */ | |
878 | ||
879 | bestindex = gray8; | |
880 | } | |
881 | ||
882 | return bestindex; | |
883 | #undef abs | |
55e303ae A |
884 | } |
885 | ||
91447636 A |
886 | |
887 | static unsigned char | |
888 | color24togray8( unsigned int color24 ) | |
889 | { | |
5d5c5d0d A |
890 | int R, G, B; |
891 | int Gray; | |
91447636 A |
892 | unsigned char gray8; |
893 | ||
894 | R = (color24 & 0xFF0000) >> 16 ; | |
895 | G = (color24 & 0xFF00) >> 8 ; | |
896 | B = (color24 & 0xFF); | |
897 | ||
5d5c5d0d A |
898 | Gray = (R*30) + (G*59) + (B*11); |
899 | gray8 = (unsigned char) ((Gray + 50) / 100); | |
91447636 A |
900 | return gray8; |
901 | } | |
902 | ||
903 | ||
904 | static unsigned char | |
905 | findIndexMatch( unsigned char index ) | |
55e303ae | 906 | { |
91447636 A |
907 | static unsigned int last_in_index = -1; |
908 | static unsigned char last_index; | |
909 | unsigned int sc; | |
55e303ae | 910 | |
91447636 A |
911 | if ( index == last_in_index ) |
912 | return last_index; | |
55e303ae | 913 | |
91447636 A |
914 | last_in_index = index; |
915 | sc = make24bitcolor( index, panic_dialog_clut ); | |
916 | last_index = findbestgray( sc ); /* find the nearest matching gray in the active clut */ | |
55e303ae | 917 | |
91447636 A |
918 | return last_index; |
919 | } | |
55e303ae | 920 | |
91447636 A |
921 | static int |
922 | isActiveClutOK( void ) | |
923 | { | |
924 | int i; | |
925 | int r = 1; /* assume OK */ | |
55e303ae | 926 | |
91447636 A |
927 | for (i=0; i<CLUT_ENTRIES; i++) { |
928 | if ( panic_dialog_clut[i] == active_clut[i] ) continue; | |
929 | r = 0; | |
930 | break; | |
55e303ae A |
931 | } |
932 | ||
91447636 | 933 | return r; |
55e303ae | 934 | } |