xref: /xnu-10002.1.13/osfmk/console/video_console.c (revision 1031c584a5e37aff177559b9f69dbd3c8c3fd30a)
1 /*
2  * Copyright (c) 2000-2020 Apple 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  * @OSF_FREE_COPYRIGHT@
30  *
31  */
32 /*
33  * @APPLE_FREE_COPYRIGHT@
34  */
35 /*
36  *	NetBSD: ite.c,v 1.16 1995/07/17 01:24:34 briggs Exp
37  *
38  * Copyright (c) 1988 University of Utah.
39  * Copyright (c) 1990, 1993
40  *	The Regents of the University of California.  All rights reserved.
41  *
42  * This code is derived from software contributed to Berkeley by
43  * the Systems Programming Group of the University of Utah Computer
44  * Science Department.
45  *
46  * Redistribution and use in source and binary forms, with or without
47  * modification, are permitted provided that the following conditions
48  * are met:
49  * 1. Redistributions of source code must retain the above copyright
50  *    notice, this list of conditions and the following disclaimer.
51  * 2. Redistributions in binary form must reproduce the above copyright
52  *    notice, this list of conditions and the following disclaimer in the
53  *    documentation and/or other materials provided with the distribution.
54  * 3. All advertising materials mentioning features or use of this software
55  *    must display the following acknowledgement:
56  *	This product includes software developed by the University of
57  *	California, Berkeley and its contributors.
58  * 4. Neither the name of the University nor the names of its contributors
59  *    may be used to endorse or promote products derived from this software
60  *    without specific prior written permission.
61  *
62  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
63  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
64  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
65  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
66  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
67  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
68  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
69  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
70  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
71  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
72  * SUCH DAMAGE.
73  *
74  * from: Utah $Hdr: ite.c 1.28 92/12/20$
75  *
76  *	@(#)ite.c	8.2 (Berkeley) 1/12/94
77  */
78 
79 /*
80  * ite.c
81  *
82  * The ite module handles the system console; that is, stuff printed
83  * by the kernel and by user programs while "desktop" and X aren't
84  * running.  Some (very small) parts are based on hp300's 4.4 ite.c,
85  * hence the above copyright.
86  *
87  *   -- Brad and Lawrence, June 26th, 1994
88  *
89  */
90 
91 #include <console/video_console.h>
92 #include <console/serial_protos.h>
93 
94 #include <kern/kern_types.h>
95 #include <kern/kalloc.h>
96 #include <kern/debug.h>
97 #include <kern/thread_call.h>
98 
99 #include <vm/pmap.h>
100 #include <vm/vm_kern.h>
101 #include <machine/machine_cpu.h>
102 
103 #include <pexpert/pexpert.h>
104 #include <sys/kdebug.h>
105 
106 #include "iso_font.c"
107 #if defined(XNU_TARGET_OS_OSX)
108 #include "progress_meter_data.c"
109 #endif
110 
111 #include "sys/msgbuf.h"
112 
113 /*
114  * Generic Console (Front-End)
115  * ---------------------------
116  */
117 
118 struct vc_info vinfo;
119 
120 void noroot_icon_test(void);
121 
122 
123 extern int       disableConsoleOutput;
124 static boolean_t gc_enabled     = FALSE;
125 static boolean_t gc_initialized = FALSE;
126 static boolean_t vm_initialized = FALSE;
127 
128 static struct {
129 	void (*initialize)(struct vc_info * info);
130 	void (*enable)(boolean_t enable);
131 	void (*paint_char)(unsigned int xx, unsigned int yy, unsigned char ch,
132 	    int attrs, unsigned char ch_previous,
133 	    int attrs_previous);
134 	void (*clear_screen)(unsigned int xx, unsigned int yy, unsigned int top,
135 	    unsigned int bottom, int which);
136 	void (*scroll_down)(int num, unsigned int top, unsigned int bottom);
137 	void (*scroll_up)(int num, unsigned int top, unsigned int bottom);
138 	void (*hide_cursor)(unsigned int xx, unsigned int yy);
139 	void (*show_cursor)(unsigned int xx, unsigned int yy);
140 	void (*update_color)(int color, boolean_t fore);
141 } gc_ops;
142 
143 static unsigned char *gc_buffer_attributes;
144 static unsigned char *gc_buffer_characters;
145 static unsigned char *gc_buffer_colorcodes;
146 static unsigned char *gc_buffer_tab_stops;
147 static uint32_t gc_buffer_columns;
148 static uint32_t gc_buffer_rows;
149 static uint32_t gc_buffer_size;
150 
151 
152 LCK_GRP_DECLARE(vconsole_lck_grp, "vconsole");
153 static lck_ticket_t vcputc_lock;
154 
155 
156 #define VCPUTC_LOCK_INIT()                              \
157 MACRO_BEGIN                                             \
158 	lck_ticket_init(&vcputc_lock, &vconsole_lck_grp);   \
159 MACRO_END
160 
161 #define VCPUTC_LOCK_LOCK()                              \
162 MACRO_BEGIN                                             \
163 	lck_ticket_lock(&vcputc_lock, &vconsole_lck_grp);   \
164 MACRO_END
165 
166 #define VCPUTC_LOCK_UNLOCK()                            \
167 MACRO_BEGIN                                             \
168 	lck_ticket_unlock(&vcputc_lock);                    \
169 MACRO_END
170 
171 
172 /*
173  # Attribute codes:
174  # 00=none 01=bold 04=underscore 05=blink 07=reverse 08=concealed
175  # Text color codes:
176  # 30=black 31=red 32=green 33=yellow 34=blue 35=magenta 36=cyan 37=white
177  # Background color codes:
178  # 40=black 41=red 42=green 43=yellow 44=blue 45=magenta 46=cyan 47=white
179  */
180 
181 #define ATTR_NONE       0
182 #define ATTR_BOLD       1
183 #define ATTR_UNDER      2
184 #define ATTR_REVERSE    4
185 
186 #define COLOR_BACKGROUND 0
187 #define COLOR_FOREGROUND 7
188 
189 #define COLOR_CODE_GET(code, fore)        (((code) & ((fore) ? 0xF0 : 0x0F))            >> ((fore) ? 4 : 0))
190 #define COLOR_CODE_SET(code, color, fore) (((code) & ((fore) ? 0x0F : 0xF0)) | ((color) << ((fore) ? 4 : 0)))
191 
192 static unsigned char gc_color_code;
193 
194 /* VT100 state: */
195 #define MAXPARS 16
196 static unsigned int gc_x, gc_y, gc_savex, gc_savey;
197 static unsigned int gc_par[MAXPARS], gc_numpars, gc_hanging_cursor, gc_attr, gc_saveattr;
198 
199 /* VT100 scroll region */
200 static unsigned int gc_scrreg_top, gc_scrreg_bottom;
201 
202 enum vt100state_e {
203 	ESnormal,               /* Nothing yet                             */
204 	ESesc,                  /* Got ESC                                 */
205 	ESsquare,               /* Got ESC [				   */
206 	ESgetpars,              /* About to get or getting the parameters  */
207 	ESgotpars,              /* Finished getting the parameters         */
208 	ESfunckey,              /* Function key                            */
209 	EShash,                 /* DEC-specific stuff (screen align, etc.) */
210 	ESsetG0,                /* Specify the G0 character set            */
211 	ESsetG1,                /* Specify the G1 character set            */
212 	ESask,
213 	EScharsize,
214 	ESignore                /* Ignore this sequence                    */
215 } gc_vt100state = ESnormal;
216 
217 
218 enum{
219 	/* secs */
220 	kProgressAcquireDelay   = 0,
221 	kProgressReacquireDelay = (12 * 60 * 60),     /* 12 hrs, ie. disabled unless overridden
222 	                                               * by kVCAcquireImmediate */
223 };
224 
225 static int8_t vc_rotate_matr[4][2][2] = {
226 	{ {  1, 0 },
227 	  {  0, 1 } },
228 	{ {  0, 1 },
229 	  { -1, 0 } },
230 	{ { -1, 0 },
231 	  {  0, -1 } },
232 	{ {  0, -1 },
233 	  {  1, 0 } }
234 };
235 
236 static int gc_wrap_mode = 1, gc_relative_origin = 0;
237 static int gc_charset_select = 0, gc_save_charset_s = 0;
238 static int gc_charset[2] = { 0, 0 };
239 static int gc_charset_save[2] = { 0, 0 };
240 
241 static void gc_clear_line(unsigned int xx, unsigned int yy, int which);
242 static void gc_clear_screen(unsigned int xx, unsigned int yy, int top,
243     unsigned int bottom, int which);
244 static void gc_enable(boolean_t enable);
245 static void gc_hide_cursor(unsigned int xx, unsigned int yy);
246 static void gc_initialize(struct vc_info * info);
247 static boolean_t gc_is_tab_stop(unsigned int column);
248 static void gc_paint_char(unsigned int xx, unsigned int yy, unsigned char ch,
249     int attrs);
250 static void gc_putchar(char ch);
251 static void gc_putc_askcmd(unsigned char ch);
252 static void gc_putc_charsetcmd(int charset, unsigned char ch);
253 static void gc_putc_charsizecmd(unsigned char ch);
254 static void gc_putc_esc(unsigned char ch);
255 static void gc_putc_getpars(unsigned char ch);
256 static void gc_putc_gotpars(unsigned char ch);
257 static void gc_putc_normal(unsigned char ch);
258 static void gc_putc_square(unsigned char ch);
259 static void gc_reset_screen(void);
260 static void gc_reset_tabs(void);
261 static void gc_reset_vt100(void);
262 static void gc_scroll_down(int num, unsigned int top, unsigned int bottom);
263 static void gc_scroll_up(int num, unsigned int top, unsigned int bottom);
264 static void gc_set_tab_stop(unsigned int column, boolean_t enabled);
265 static void gc_show_cursor(unsigned int xx, unsigned int yy);
266 static void gc_update_color(int color, boolean_t fore);
267 
268 static void
gc_clear_line(unsigned int xx,unsigned int yy,int which)269 gc_clear_line(unsigned int xx, unsigned int yy, int which)
270 {
271 	unsigned int start, end, i;
272 
273 	/*
274 	 * This routine runs extremely slowly.  I don't think it's
275 	 * used all that often, except for To end of line.  I'll go
276 	 * back and speed this up when I speed up the whole vc
277 	 * module. --LK
278 	 */
279 
280 	switch (which) {
281 	case 0:         /* To end of line	 */
282 		start = xx;
283 		end = vinfo.v_columns - 1;
284 		break;
285 	case 1:         /* To start of line	 */
286 		start = 0;
287 		end = xx;
288 		break;
289 	case 2:         /* Whole line		 */
290 		start = 0;
291 		end = vinfo.v_columns - 1;
292 		break;
293 	default:
294 		return;
295 	}
296 
297 	for (i = start; i <= end; i++) {
298 		gc_paint_char(i, yy, ' ', ATTR_NONE);
299 	}
300 }
301 
302 static void
gc_clear_screen(unsigned int xx,unsigned int yy,int top,unsigned int bottom,int which)303 gc_clear_screen(unsigned int xx, unsigned int yy, int top, unsigned int bottom,
304     int which)
305 {
306 	if (!gc_buffer_size) {
307 		return;
308 	}
309 
310 	if (xx < gc_buffer_columns && yy < gc_buffer_rows && bottom <= gc_buffer_rows) {
311 		uint32_t start, end;
312 
313 		switch (which) {
314 		case 0:                 /* To end of screen	 */
315 			start = (yy * gc_buffer_columns) + xx;
316 			end = (bottom * gc_buffer_columns) - 1;
317 			break;
318 		case 1:                 /* To start of screen	 */
319 			start = (top * gc_buffer_columns);
320 			end = (yy * gc_buffer_columns) + xx;
321 			break;
322 		case 2:                 /* Whole screen		 */
323 			start = (top * gc_buffer_columns);
324 			end = (bottom * gc_buffer_columns) - 1;
325 			break;
326 		default:
327 			start = 0;
328 			end = 0;
329 			break;
330 		}
331 
332 		memset(gc_buffer_attributes + start, ATTR_NONE, end - start + 1);
333 		memset(gc_buffer_characters + start, ' ', end - start + 1);
334 		memset(gc_buffer_colorcodes + start, gc_color_code, end - start + 1);
335 	}
336 
337 	gc_ops.clear_screen(xx, yy, top, bottom, which);
338 }
339 
340 static void
gc_enable(boolean_t enable)341 gc_enable( boolean_t enable )
342 {
343 	unsigned char *buffer_attributes = NULL;
344 	unsigned char *buffer_characters = NULL;
345 	unsigned char *buffer_colorcodes = NULL;
346 	unsigned char *buffer_tab_stops  = NULL;
347 	uint32_t buffer_columns = 0;
348 	uint32_t buffer_rows = 0;
349 	uint32_t buffer_size = 0;
350 
351 	if (enable == FALSE) {
352 		// only disable console output if it goes to the graphics console
353 		if (console_is_serial() == FALSE) {
354 			disableConsoleOutput = TRUE;
355 		}
356 		gc_enabled           = FALSE;
357 		gc_ops.enable(FALSE);
358 	}
359 
360 	VCPUTC_LOCK_LOCK();
361 
362 	if (gc_buffer_size) {
363 		buffer_attributes = gc_buffer_attributes;
364 		buffer_characters = gc_buffer_characters;
365 		buffer_colorcodes = gc_buffer_colorcodes;
366 		buffer_tab_stops  = gc_buffer_tab_stops;
367 		buffer_columns    = gc_buffer_columns;
368 		buffer_rows       = gc_buffer_rows;
369 		buffer_size       = gc_buffer_size;
370 
371 		gc_buffer_attributes = NULL;
372 		gc_buffer_characters = NULL;
373 		gc_buffer_colorcodes = NULL;
374 		gc_buffer_tab_stops  = NULL;
375 		gc_buffer_columns    = 0;
376 		gc_buffer_rows       = 0;
377 		gc_buffer_size       = 0;
378 
379 		VCPUTC_LOCK_UNLOCK();
380 
381 		kfree_data(buffer_attributes, buffer_size);
382 		kfree_data(buffer_characters, buffer_size);
383 		kfree_data(buffer_colorcodes, buffer_size);
384 		kfree_data(buffer_tab_stops, buffer_columns);
385 	} else {
386 		VCPUTC_LOCK_UNLOCK();
387 	}
388 
389 	if (enable) {
390 		if (vm_initialized) {
391 			buffer_columns = vinfo.v_columns;
392 			buffer_rows    = vinfo.v_rows;
393 			buffer_size    = buffer_columns * buffer_rows;
394 
395 			if (buffer_size) {
396 				buffer_attributes = kalloc_data(buffer_size, Z_WAITOK);
397 				buffer_characters = kalloc_data(buffer_size, Z_WAITOK);
398 				buffer_colorcodes = kalloc_data(buffer_size, Z_WAITOK);
399 				buffer_tab_stops  = kalloc_data(buffer_columns, Z_WAITOK);
400 
401 				if (buffer_attributes == NULL ||
402 				    buffer_characters == NULL ||
403 				    buffer_colorcodes == NULL ||
404 				    buffer_tab_stops == NULL) {
405 					kfree_data(buffer_attributes, buffer_size);
406 					kfree_data(buffer_characters, buffer_size);
407 					kfree_data(buffer_colorcodes, buffer_size);
408 					kfree_data(buffer_tab_stops, buffer_columns);
409 
410 					buffer_attributes = NULL;
411 					buffer_characters = NULL;
412 					buffer_colorcodes = NULL;
413 					buffer_tab_stops  = NULL;
414 					buffer_columns = 0;
415 					buffer_rows    = 0;
416 					buffer_size    = 0;
417 				} else {
418 					memset( buffer_attributes, ATTR_NONE, buffer_size );
419 					memset( buffer_characters, ' ', buffer_size );
420 					memset( buffer_colorcodes, COLOR_CODE_SET( 0, COLOR_FOREGROUND, TRUE ), buffer_size );
421 					memset( buffer_tab_stops, 0, buffer_columns );
422 				}
423 			}
424 		}
425 
426 		VCPUTC_LOCK_LOCK();
427 
428 		gc_buffer_attributes = buffer_attributes;
429 		gc_buffer_characters = buffer_characters;
430 		gc_buffer_colorcodes = buffer_colorcodes;
431 		gc_buffer_tab_stops  = buffer_tab_stops;
432 		gc_buffer_columns    = buffer_columns;
433 		gc_buffer_rows       = buffer_rows;
434 		gc_buffer_size       = buffer_size;
435 
436 		gc_reset_screen();
437 
438 		VCPUTC_LOCK_UNLOCK();
439 
440 		gc_ops.clear_screen(gc_x, gc_y, 0, vinfo.v_rows, 2);
441 		gc_ops.show_cursor(gc_x, gc_y);
442 
443 		gc_ops.enable(TRUE);
444 		gc_enabled           = TRUE;
445 		disableConsoleOutput = FALSE;
446 	}
447 }
448 
449 static void
gc_hide_cursor(unsigned int xx,unsigned int yy)450 gc_hide_cursor(unsigned int xx, unsigned int yy)
451 {
452 	if (xx < gc_buffer_columns && yy < gc_buffer_rows) {
453 		uint32_t index = (yy * gc_buffer_columns) + xx;
454 		unsigned char attribute = gc_buffer_attributes[index];
455 		unsigned char character = gc_buffer_characters[index];
456 		unsigned char colorcode = gc_buffer_colorcodes[index];
457 		unsigned char colorcodesave = gc_color_code;
458 
459 		gc_update_color(COLOR_CODE_GET(colorcode, TRUE ), TRUE );
460 		gc_update_color(COLOR_CODE_GET(colorcode, FALSE), FALSE);
461 
462 		gc_ops.paint_char(xx, yy, character, attribute, 0, 0);
463 
464 		gc_update_color(COLOR_CODE_GET(colorcodesave, TRUE ), TRUE );
465 		gc_update_color(COLOR_CODE_GET(colorcodesave, FALSE), FALSE);
466 	} else {
467 		gc_ops.hide_cursor(xx, yy);
468 	}
469 }
470 
471 static void
gc_initialize(struct vc_info * info)472 gc_initialize(struct vc_info * info)
473 {
474 	if (gc_initialized == FALSE) {
475 		/* Init our lock */
476 		VCPUTC_LOCK_INIT();
477 
478 		gc_initialized = TRUE;
479 	}
480 
481 	gc_ops.initialize(info);
482 
483 	gc_reset_vt100();
484 	gc_x = gc_y = 0;
485 }
486 
487 static void
gc_paint_char(unsigned int xx,unsigned int yy,unsigned char ch,int attrs)488 gc_paint_char(unsigned int xx, unsigned int yy, unsigned char ch, int attrs)
489 {
490 	if (xx < gc_buffer_columns && yy < gc_buffer_rows) {
491 		uint32_t index = (yy * gc_buffer_columns) + xx;
492 
493 		gc_buffer_attributes[index] = attrs;
494 		gc_buffer_characters[index] = ch;
495 		gc_buffer_colorcodes[index] = gc_color_code;
496 	}
497 
498 	gc_ops.paint_char(xx, yy, ch, attrs, 0, 0);
499 }
500 
501 static void
gc_putchar(char ch)502 gc_putchar(char ch)
503 {
504 	if (!ch) {
505 		return; /* ignore null characters */
506 	}
507 	switch (gc_vt100state) {
508 	default:
509 		gc_vt100state = ESnormal;
510 		OS_FALLTHROUGH;
511 	case ESnormal:
512 		gc_putc_normal(ch);
513 		break;
514 	case ESesc:
515 		gc_putc_esc(ch);
516 		break;
517 	case ESsquare:
518 		gc_putc_square(ch);
519 		break;
520 	case ESgetpars:
521 		gc_putc_getpars(ch);
522 		break;
523 	case ESgotpars:
524 		gc_putc_gotpars(ch);
525 		break;
526 	case ESask:
527 		gc_putc_askcmd(ch);
528 		break;
529 	case EScharsize:
530 		gc_putc_charsizecmd(ch);
531 		break;
532 	case ESsetG0:
533 		gc_putc_charsetcmd(0, ch);
534 		break;
535 	case ESsetG1:
536 		gc_putc_charsetcmd(1, ch);
537 		break;
538 	}
539 
540 	if (gc_x >= vinfo.v_columns) {
541 		if (0 == vinfo.v_columns) {
542 			gc_x = 0;
543 		} else {
544 			gc_x = vinfo.v_columns - 1;
545 		}
546 	}
547 	if (gc_y >= vinfo.v_rows) {
548 		if (0 == vinfo.v_rows) {
549 			gc_y = 0;
550 		} else {
551 			gc_y = vinfo.v_rows - 1;
552 		}
553 	}
554 }
555 
556 static void
gc_putc_askcmd(unsigned char ch)557 gc_putc_askcmd(unsigned char ch)
558 {
559 	if (ch >= '0' && ch <= '9') {
560 		gc_par[gc_numpars] = (10 * gc_par[gc_numpars]) + (ch - '0');
561 		return;
562 	}
563 	gc_vt100state = ESnormal;
564 
565 	switch (gc_par[0]) {
566 	case 6:
567 		gc_relative_origin = ch == 'h';
568 		break;
569 	case 7:         /* wrap around mode h=1, l=0*/
570 		gc_wrap_mode = ch == 'h';
571 		break;
572 	default:
573 		break;
574 	}
575 }
576 
577 static void
gc_putc_charsetcmd(int charset,unsigned char ch)578 gc_putc_charsetcmd(int charset, unsigned char ch)
579 {
580 	gc_vt100state = ESnormal;
581 
582 	switch (ch) {
583 	case 'A':
584 	case 'B':
585 	default:
586 		gc_charset[charset] = 0;
587 		break;
588 	case '0':               /* Graphic characters */
589 	case '2':
590 		gc_charset[charset] = 0x21;
591 		break;
592 	}
593 }
594 
595 static void
gc_putc_charsizecmd(unsigned char ch)596 gc_putc_charsizecmd(unsigned char ch)
597 {
598 	gc_vt100state = ESnormal;
599 
600 	switch (ch) {
601 	case '3':
602 	case '4':
603 	case '5':
604 	case '6':
605 		break;
606 	case '8':               /* fill 'E's */
607 	{
608 		unsigned int xx, yy;
609 		for (yy = 0; yy < vinfo.v_rows; yy++) {
610 			for (xx = 0; xx < vinfo.v_columns; xx++) {
611 				gc_paint_char(xx, yy, 'E', ATTR_NONE);
612 			}
613 		}
614 	}
615 	break;
616 	}
617 }
618 
619 static void
gc_putc_esc(unsigned char ch)620 gc_putc_esc(unsigned char ch)
621 {
622 	gc_vt100state = ESnormal;
623 
624 	switch (ch) {
625 	case '[':
626 		gc_vt100state = ESsquare;
627 		break;
628 	case 'c':               /* Reset terminal        */
629 		gc_reset_vt100();
630 		gc_clear_screen(gc_x, gc_y, 0, vinfo.v_rows, 2);
631 		gc_x = gc_y = 0;
632 		break;
633 	case 'D':               /* Line feed		 */
634 	case 'E':
635 		if (gc_y >= gc_scrreg_bottom - 1) {
636 			gc_scroll_up(1, gc_scrreg_top, gc_scrreg_bottom);
637 			gc_y = gc_scrreg_bottom - 1;
638 		} else {
639 			gc_y++;
640 		}
641 		if (ch == 'E') {
642 			gc_x = 0;
643 		}
644 		break;
645 	case 'H':               /* Set tab stop		 */
646 		gc_set_tab_stop(gc_x, TRUE);
647 		break;
648 	case 'M':               /* Cursor up		 */
649 		if (gc_y <= gc_scrreg_top) {
650 			gc_scroll_down(1, gc_scrreg_top, gc_scrreg_bottom);
651 			gc_y = gc_scrreg_top;
652 		} else {
653 			gc_y--;
654 		}
655 		break;
656 	case '>':
657 		gc_reset_vt100();
658 		break;
659 	case '7':               /* Save cursor		 */
660 		gc_savex = gc_x;
661 		gc_savey = gc_y;
662 		gc_saveattr = gc_attr;
663 		gc_save_charset_s = gc_charset_select;
664 		gc_charset_save[0] = gc_charset[0];
665 		gc_charset_save[1] = gc_charset[1];
666 		break;
667 	case '8':               /* Restore cursor	 */
668 		gc_x = gc_savex;
669 		gc_y = gc_savey;
670 		gc_attr = gc_saveattr;
671 		gc_charset_select = gc_save_charset_s;
672 		gc_charset[0] = gc_charset_save[0];
673 		gc_charset[1] = gc_charset_save[1];
674 		break;
675 	case 'Z':               /* return terminal ID */
676 		break;
677 	case '#':               /* change characters height */
678 		gc_vt100state = EScharsize;
679 		break;
680 	case '(':
681 		gc_vt100state = ESsetG0;
682 		break;
683 	case ')':               /* character set sequence */
684 		gc_vt100state = ESsetG1;
685 		break;
686 	case '=':
687 		break;
688 	default:
689 		/* Rest not supported */
690 		break;
691 	}
692 }
693 
694 static void
gc_putc_getpars(unsigned char ch)695 gc_putc_getpars(unsigned char ch)
696 {
697 	if (ch == '?') {
698 		gc_vt100state = ESask;
699 		return;
700 	}
701 	if (ch == '[') {
702 		gc_vt100state = ESnormal;
703 		/* Not supported */
704 		return;
705 	}
706 	if (ch == ';' && gc_numpars < MAXPARS - 1) {
707 		gc_numpars++;
708 	} else if (ch >= '0' && ch <= '9') {
709 		gc_par[gc_numpars] *= 10;
710 		gc_par[gc_numpars] += ch - '0';
711 	} else {
712 		gc_numpars++;
713 		gc_vt100state = ESgotpars;
714 		gc_putc_gotpars(ch);
715 	}
716 }
717 
718 static void
gc_putc_gotpars(unsigned char ch)719 gc_putc_gotpars(unsigned char ch)
720 {
721 	unsigned int i;
722 
723 	if (ch < ' ') {
724 		/* special case for vttest for handling cursor
725 		 *  movement in escape sequences */
726 		gc_putc_normal(ch);
727 		gc_vt100state = ESgotpars;
728 		return;
729 	}
730 	gc_vt100state = ESnormal;
731 	switch (ch) {
732 	case 'A':               /* Up			 */
733 		gc_y -= gc_par[0] ? gc_par[0] : 1;
734 		if (gc_y < gc_scrreg_top) {
735 			gc_y = gc_scrreg_top;
736 		}
737 		break;
738 	case 'B':               /* Down			 */
739 		gc_y += gc_par[0] ? gc_par[0] : 1;
740 		if (gc_y >= gc_scrreg_bottom) {
741 			gc_y = gc_scrreg_bottom - 1;
742 		}
743 		break;
744 	case 'C':               /* Right		 */
745 		gc_x += gc_par[0] ? gc_par[0] : 1;
746 		if (gc_x >= vinfo.v_columns) {
747 			gc_x = vinfo.v_columns - 1;
748 		}
749 		break;
750 	case 'D':               /* Left			 */
751 		if (gc_par[0] > gc_x) {
752 			gc_x = 0;
753 		} else if (gc_par[0]) {
754 			gc_x -= gc_par[0];
755 		} else if (gc_x) {
756 			--gc_x;
757 		}
758 		break;
759 	case 'H':               /* Set cursor position	 */
760 	case 'f':
761 		gc_x = gc_par[1] ? gc_par[1] - 1 : 0;
762 		gc_y = gc_par[0] ? gc_par[0] - 1 : 0;
763 		if (gc_relative_origin) {
764 			gc_y += gc_scrreg_top;
765 		}
766 		gc_hanging_cursor = 0;
767 		break;
768 	case 'X':               /* clear p1 characters */
769 		if (gc_numpars) {
770 			for (i = gc_x; i < gc_x + gc_par[0]; i++) {
771 				gc_paint_char(i, gc_y, ' ', ATTR_NONE);
772 			}
773 		}
774 		break;
775 	case 'J':               /* Clear part of screen	 */
776 		gc_clear_screen(gc_x, gc_y, 0, vinfo.v_rows, gc_par[0]);
777 		break;
778 	case 'K':               /* Clear part of line	 */
779 		gc_clear_line(gc_x, gc_y, gc_par[0]);
780 		break;
781 	case 'g':               /* tab stops	         */
782 		switch (gc_par[0]) {
783 		case 1:
784 		case 2:         /* reset tab stops */
785 			        /* gc_reset_tabs(); */
786 			break;
787 		case 3:         /* Clear every tabs */
788 		{
789 			for (i = 0; i <= vinfo.v_columns; i++) {
790 				gc_set_tab_stop(i, FALSE);
791 			}
792 		}
793 		break;
794 		case 0:
795 			gc_set_tab_stop(gc_x, FALSE);
796 			break;
797 		}
798 		break;
799 	case 'm':               /* Set attribute	 */
800 		for (i = 0; i < gc_numpars; i++) {
801 			switch (gc_par[i]) {
802 			case 0:
803 				gc_attr = ATTR_NONE;
804 				gc_update_color(COLOR_BACKGROUND, FALSE);
805 				gc_update_color(COLOR_FOREGROUND, TRUE );
806 				break;
807 			case 1:
808 				gc_attr |= ATTR_BOLD;
809 				break;
810 			case 4:
811 				gc_attr |= ATTR_UNDER;
812 				break;
813 			case 7:
814 				gc_attr |= ATTR_REVERSE;
815 				break;
816 			case 22:
817 				gc_attr &= ~ATTR_BOLD;
818 				break;
819 			case 24:
820 				gc_attr &= ~ATTR_UNDER;
821 				break;
822 			case 27:
823 				gc_attr &= ~ATTR_REVERSE;
824 				break;
825 			case 5:
826 			case 25:        /* blink/no blink */
827 				break;
828 			default:
829 				if (gc_par[i] >= 30 && gc_par[i] <= 37) {
830 					gc_update_color(gc_par[i] - 30, TRUE);
831 				}
832 				if (gc_par[i] >= 40 && gc_par[i] <= 47) {
833 					gc_update_color(gc_par[i] - 40, FALSE);
834 				}
835 				break;
836 			}
837 		}
838 		break;
839 	case 'r':               /* Set scroll region	 */
840 		gc_x = gc_y = 0;
841 		/* ensure top < bottom, and both within limits */
842 		if ((gc_numpars > 0) && (gc_par[0] < vinfo.v_rows)) {
843 			gc_scrreg_top = gc_par[0] ? gc_par[0] - 1 : 0;
844 		} else {
845 			gc_scrreg_top = 0;
846 		}
847 		if ((gc_numpars > 1) && (gc_par[1] <= vinfo.v_rows) && (gc_par[1] > gc_par[0])) {
848 			gc_scrreg_bottom = gc_par[1];
849 			if (gc_scrreg_bottom > vinfo.v_rows) {
850 				gc_scrreg_bottom = vinfo.v_rows;
851 			}
852 		} else {
853 			gc_scrreg_bottom = vinfo.v_rows;
854 		}
855 		if (gc_relative_origin) {
856 			gc_y = gc_scrreg_top;
857 		}
858 		break;
859 	}
860 }
861 
862 static void
gc_putc_normal(unsigned char ch)863 gc_putc_normal(unsigned char ch)
864 {
865 	switch (ch) {
866 	case '\a':              /* Beep			 */
867 		break;
868 	case 127:               /* Delete		 */
869 	case '\b':              /* Backspace		 */
870 		if (gc_hanging_cursor) {
871 			gc_hanging_cursor = 0;
872 		} else if (gc_x > 0) {
873 			gc_x--;
874 		}
875 		break;
876 	case '\t':              /* Tab			 */
877 		if (gc_buffer_tab_stops) {
878 			while (gc_x < vinfo.v_columns && !gc_is_tab_stop(++gc_x)) {
879 				;
880 			}
881 		}
882 
883 		if (gc_x >= vinfo.v_columns) {
884 			gc_x = vinfo.v_columns - 1;
885 		}
886 		break;
887 	case 0x0b:
888 	case 0x0c:
889 	case '\n':              /* Line feed		 */
890 		if (gc_y >= gc_scrreg_bottom - 1) {
891 			gc_scroll_up(1, gc_scrreg_top, gc_scrreg_bottom);
892 			gc_y = gc_scrreg_bottom - 1;
893 		} else {
894 			gc_y++;
895 		}
896 		break;
897 	case '\r':              /* Carriage return	 */
898 		gc_x = 0;
899 		gc_hanging_cursor = 0;
900 		break;
901 	case 0x0e:  /* Select G1 charset (Control-N) */
902 		gc_charset_select = 1;
903 		break;
904 	case 0x0f:  /* Select G0 charset (Control-O) */
905 		gc_charset_select = 0;
906 		break;
907 	case 0x18:  /* CAN : cancel */
908 	case 0x1A:  /* like cancel */
909 		/* well, i do nothing here, may be later */
910 		break;
911 	case '\033':            /* Escape		 */
912 		gc_vt100state = ESesc;
913 		gc_hanging_cursor = 0;
914 		break;
915 	default:
916 		if (ch >= ' ') {
917 			if (gc_hanging_cursor) {
918 				gc_x = 0;
919 				if (gc_y >= gc_scrreg_bottom - 1) {
920 					gc_scroll_up(1, gc_scrreg_top, gc_scrreg_bottom);
921 					gc_y = gc_scrreg_bottom - 1;
922 				} else {
923 					gc_y++;
924 				}
925 				gc_hanging_cursor = 0;
926 			}
927 			gc_paint_char(gc_x, gc_y, (ch >= 0x60 && ch <= 0x7f) ? ch + gc_charset[gc_charset_select]
928 			    : ch, gc_attr);
929 			if (gc_x == vinfo.v_columns - 1) {
930 				gc_hanging_cursor = gc_wrap_mode;
931 			} else {
932 				gc_x++;
933 			}
934 		}
935 		break;
936 	}
937 }
938 
939 static void
gc_putc_square(unsigned char ch)940 gc_putc_square(unsigned char ch)
941 {
942 	int     i;
943 
944 	for (i = 0; i < MAXPARS; i++) {
945 		gc_par[i] = 0;
946 	}
947 
948 	gc_numpars = 0;
949 	gc_vt100state = ESgetpars;
950 
951 	gc_putc_getpars(ch);
952 }
953 
954 static void
gc_reset_screen(void)955 gc_reset_screen(void)
956 {
957 	gc_reset_vt100();
958 	gc_x = gc_y = 0;
959 }
960 
961 static void
gc_reset_tabs(void)962 gc_reset_tabs(void)
963 {
964 	unsigned int i;
965 
966 	if (!gc_buffer_tab_stops) {
967 		return;
968 	}
969 
970 	for (i = 0; i < vinfo.v_columns; i++) {
971 		gc_buffer_tab_stops[i] = ((i % 8) == 0);
972 	}
973 }
974 
975 static void
gc_set_tab_stop(unsigned int column,boolean_t enabled)976 gc_set_tab_stop(unsigned int column, boolean_t enabled)
977 {
978 	if (gc_buffer_tab_stops && (column < vinfo.v_columns)) {
979 		gc_buffer_tab_stops[column] = enabled;
980 	}
981 }
982 
983 static boolean_t
gc_is_tab_stop(unsigned int column)984 gc_is_tab_stop(unsigned int column)
985 {
986 	if (gc_buffer_tab_stops == NULL) {
987 		return (column % 8) == 0;
988 	}
989 	if (column < vinfo.v_columns) {
990 		return gc_buffer_tab_stops[column];
991 	} else {
992 		return FALSE;
993 	}
994 }
995 
996 static void
gc_reset_vt100(void)997 gc_reset_vt100(void)
998 {
999 	gc_reset_tabs();
1000 	gc_scrreg_top    = 0;
1001 	gc_scrreg_bottom = vinfo.v_rows;
1002 	gc_attr = ATTR_NONE;
1003 	gc_charset[0] = gc_charset[1] = 0;
1004 	gc_charset_select = 0;
1005 	gc_wrap_mode = 1;
1006 	gc_relative_origin = 0;
1007 	gc_update_color(COLOR_BACKGROUND, FALSE);
1008 	gc_update_color(COLOR_FOREGROUND, TRUE);
1009 }
1010 
1011 static void
gc_scroll_down(int num,unsigned int top,unsigned int bottom)1012 gc_scroll_down(int num, unsigned int top, unsigned int bottom)
1013 {
1014 	if (!gc_buffer_size) {
1015 		return;
1016 	}
1017 
1018 	if (bottom <= gc_buffer_rows) {
1019 		unsigned char colorcodesave = gc_color_code;
1020 		uint32_t column, row;
1021 		uint32_t index, jump;
1022 
1023 		jump = num * gc_buffer_columns;
1024 
1025 		for (row = bottom - 1; row >= top + num; row--) {
1026 			index = row * gc_buffer_columns;
1027 
1028 			for (column = 0; column < gc_buffer_columns; index++, column++) {
1029 				if (gc_buffer_attributes[index] != gc_buffer_attributes[index - jump] ||
1030 				    gc_buffer_characters[index] != gc_buffer_characters[index - jump] ||
1031 				    gc_buffer_colorcodes[index] != gc_buffer_colorcodes[index - jump]) {
1032 					if (gc_color_code != gc_buffer_colorcodes[index - jump]) {
1033 						gc_update_color(COLOR_CODE_GET(gc_buffer_colorcodes[index - jump], TRUE ), TRUE );
1034 						gc_update_color(COLOR_CODE_GET(gc_buffer_colorcodes[index - jump], FALSE), FALSE);
1035 					}
1036 
1037 					if (gc_buffer_colorcodes[index] != gc_buffer_colorcodes[index - jump]) {
1038 						gc_ops.paint_char( /* xx             */ column,
1039 						    /* yy             */ row,
1040 						    /* ch             */ gc_buffer_characters[index - jump],
1041 						    /* attrs          */ gc_buffer_attributes[index - jump],
1042 						    /* ch_previous    */ 0,
1043 						    /* attrs_previous */ 0 );
1044 					} else {
1045 						gc_ops.paint_char( /* xx             */ column,
1046 						    /* yy             */ row,
1047 						    /* ch             */ gc_buffer_characters[index - jump],
1048 						    /* attrs          */ gc_buffer_attributes[index - jump],
1049 						    /* ch_previous    */ gc_buffer_characters[index],
1050 						    /* attrs_previous */ gc_buffer_attributes[index] );
1051 					}
1052 
1053 					gc_buffer_attributes[index] = gc_buffer_attributes[index - jump];
1054 					gc_buffer_characters[index] = gc_buffer_characters[index - jump];
1055 					gc_buffer_colorcodes[index] = gc_buffer_colorcodes[index - jump];
1056 				}
1057 			}
1058 		}
1059 
1060 		if (colorcodesave != gc_color_code) {
1061 			gc_update_color(COLOR_CODE_GET(colorcodesave, TRUE ), TRUE );
1062 			gc_update_color(COLOR_CODE_GET(colorcodesave, FALSE), FALSE);
1063 		}
1064 
1065 		/* Now set the freed up lines to the background colour */
1066 
1067 		for (row = top; row < top + num; row++) {
1068 			index = row * gc_buffer_columns;
1069 
1070 			for (column = 0; column < gc_buffer_columns; index++, column++) {
1071 				if (gc_buffer_attributes[index] != ATTR_NONE ||
1072 				    gc_buffer_characters[index] != ' ' ||
1073 				    gc_buffer_colorcodes[index] != gc_color_code) {
1074 					if (gc_buffer_colorcodes[index] != gc_color_code) {
1075 						gc_ops.paint_char( /* xx             */ column,
1076 						    /* yy             */ row,
1077 						    /* ch             */ ' ',
1078 						    /* attrs          */ ATTR_NONE,
1079 						    /* ch_previous    */ 0,
1080 						    /* attrs_previous */ 0 );
1081 					} else {
1082 						gc_ops.paint_char( /* xx             */ column,
1083 						    /* yy             */ row,
1084 						    /* ch             */ ' ',
1085 						    /* attrs          */ ATTR_NONE,
1086 						    /* ch_previous    */ gc_buffer_characters[index],
1087 						    /* attrs_previous */ gc_buffer_attributes[index] );
1088 					}
1089 
1090 					gc_buffer_attributes[index] = ATTR_NONE;
1091 					gc_buffer_characters[index] = ' ';
1092 					gc_buffer_colorcodes[index] = gc_color_code;
1093 				}
1094 			}
1095 		}
1096 	} else {
1097 		gc_ops.scroll_down(num, top, bottom);
1098 
1099 		/* Now set the freed up lines to the background colour */
1100 
1101 		gc_clear_screen(vinfo.v_columns - 1, top + num - 1, top, bottom, 1);
1102 	}
1103 }
1104 
1105 static void
gc_scroll_up(int num,unsigned int top,unsigned int bottom)1106 gc_scroll_up(int num, unsigned int top, unsigned int bottom)
1107 {
1108 	if (!gc_buffer_size) {
1109 		return;
1110 	}
1111 
1112 	if (bottom <= gc_buffer_rows) {
1113 		unsigned char colorcodesave = gc_color_code;
1114 		uint32_t column, row;
1115 		uint32_t index, jump;
1116 
1117 		jump = num * gc_buffer_columns;
1118 
1119 		for (row = top; row < bottom - num; row++) {
1120 			index = row * gc_buffer_columns;
1121 
1122 			for (column = 0; column < gc_buffer_columns; index++, column++) {
1123 				if (gc_buffer_attributes[index] != gc_buffer_attributes[index + jump] ||
1124 				    gc_buffer_characters[index] != gc_buffer_characters[index + jump] ||
1125 				    gc_buffer_colorcodes[index] != gc_buffer_colorcodes[index + jump]) {
1126 					if (gc_color_code != gc_buffer_colorcodes[index + jump]) {
1127 						gc_update_color(COLOR_CODE_GET(gc_buffer_colorcodes[index + jump], TRUE ), TRUE );
1128 						gc_update_color(COLOR_CODE_GET(gc_buffer_colorcodes[index + jump], FALSE), FALSE);
1129 					}
1130 
1131 					if (gc_buffer_colorcodes[index] != gc_buffer_colorcodes[index + jump]) {
1132 						gc_ops.paint_char( /* xx             */ column,
1133 						    /* yy             */ row,
1134 						    /* ch             */ gc_buffer_characters[index + jump],
1135 						    /* attrs          */ gc_buffer_attributes[index + jump],
1136 						    /* ch_previous    */ 0,
1137 						    /* attrs_previous */ 0 );
1138 					} else {
1139 						gc_ops.paint_char( /* xx             */ column,
1140 						    /* yy             */ row,
1141 						    /* ch             */ gc_buffer_characters[index + jump],
1142 						    /* attrs          */ gc_buffer_attributes[index + jump],
1143 						    /* ch_previous    */ gc_buffer_characters[index],
1144 						    /* attrs_previous */ gc_buffer_attributes[index] );
1145 					}
1146 
1147 					gc_buffer_attributes[index] = gc_buffer_attributes[index + jump];
1148 					gc_buffer_characters[index] = gc_buffer_characters[index + jump];
1149 					gc_buffer_colorcodes[index] = gc_buffer_colorcodes[index + jump];
1150 				}
1151 			}
1152 		}
1153 
1154 		if (colorcodesave != gc_color_code) {
1155 			gc_update_color(COLOR_CODE_GET(colorcodesave, TRUE ), TRUE );
1156 			gc_update_color(COLOR_CODE_GET(colorcodesave, FALSE), FALSE);
1157 		}
1158 
1159 		/* Now set the freed up lines to the background colour */
1160 
1161 		for (row = bottom - num; row < bottom; row++) {
1162 			index = row * gc_buffer_columns;
1163 
1164 			for (column = 0; column < gc_buffer_columns; index++, column++) {
1165 				if (gc_buffer_attributes[index] != ATTR_NONE ||
1166 				    gc_buffer_characters[index] != ' ' ||
1167 				    gc_buffer_colorcodes[index] != gc_color_code) {
1168 					if (gc_buffer_colorcodes[index] != gc_color_code) {
1169 						gc_ops.paint_char( /* xx             */ column,
1170 						    /* yy             */ row,
1171 						    /* ch             */ ' ',
1172 						    /* attrs          */ ATTR_NONE,
1173 						    /* ch_previous    */ 0,
1174 						    /* attrs_previous */ 0 );
1175 					} else {
1176 						gc_ops.paint_char( /* xx             */ column,
1177 						    /* yy             */ row,
1178 						    /* ch             */ ' ',
1179 						    /* attrs          */ ATTR_NONE,
1180 						    /* ch_previous    */ gc_buffer_characters[index],
1181 						    /* attrs_previous */ gc_buffer_attributes[index] );
1182 					}
1183 
1184 					gc_buffer_attributes[index] = ATTR_NONE;
1185 					gc_buffer_characters[index] = ' ';
1186 					gc_buffer_colorcodes[index] = gc_color_code;
1187 				}
1188 			}
1189 		}
1190 	} else {
1191 		gc_ops.scroll_up(num, top, bottom);
1192 
1193 		/* Now set the freed up lines to the background colour */
1194 
1195 		gc_clear_screen(0, bottom - num, top, bottom, 0);
1196 	}
1197 }
1198 
1199 static void
gc_show_cursor(unsigned int xx,unsigned int yy)1200 gc_show_cursor(unsigned int xx, unsigned int yy)
1201 {
1202 	if (xx < gc_buffer_columns && yy < gc_buffer_rows) {
1203 		uint32_t index = (yy * gc_buffer_columns) + xx;
1204 		unsigned char attribute = gc_buffer_attributes[index];
1205 		unsigned char character = gc_buffer_characters[index];
1206 		unsigned char colorcode = gc_buffer_colorcodes[index];
1207 		unsigned char colorcodesave = gc_color_code;
1208 
1209 		gc_update_color(COLOR_CODE_GET(colorcode, FALSE), TRUE );
1210 		gc_update_color(COLOR_CODE_GET(colorcode, TRUE ), FALSE);
1211 
1212 		gc_ops.paint_char(xx, yy, character, attribute, 0, 0);
1213 
1214 		gc_update_color(COLOR_CODE_GET(colorcodesave, TRUE ), TRUE );
1215 		gc_update_color(COLOR_CODE_GET(colorcodesave, FALSE), FALSE);
1216 	} else {
1217 		gc_ops.show_cursor(xx, yy);
1218 	}
1219 }
1220 
1221 static void
gc_update_color(int color,boolean_t fore)1222 gc_update_color(int color, boolean_t fore)
1223 {
1224 	assert(gc_ops.update_color);
1225 
1226 	gc_color_code = COLOR_CODE_SET(gc_color_code, color, fore);
1227 	gc_ops.update_color(color, fore);
1228 }
1229 
1230 void
vcputc_options(char c,__unused bool poll)1231 vcputc_options(char c, __unused bool poll)
1232 {
1233 	if (gc_initialized && gc_enabled) {
1234 		VCPUTC_LOCK_LOCK();
1235 		if (gc_enabled) {
1236 			gc_hide_cursor(gc_x, gc_y);
1237 			gc_putchar(c);
1238 			gc_show_cursor(gc_x, gc_y);
1239 		}
1240 #if SCHED_HYGIENE_DEBUG
1241 		abandon_preemption_disable_measurement();
1242 #endif /* SCHED_HYGIENE_DEBUG */
1243 		VCPUTC_LOCK_UNLOCK();
1244 	}
1245 }
1246 
1247 void
vcputc(char c)1248 vcputc(char c)
1249 {
1250 	vcputc_options(c, false);
1251 }
1252 
1253 /*
1254  * Video Console (Back-End)
1255  * ------------------------
1256  */
1257 
1258 /*
1259  * For the color support (Michel Pollet)
1260  */
1261 static unsigned char vc_color_index_table[33] =
1262 {  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1263    1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 2 };
1264 
1265 static uint32_t vc_colors[8][4] = {
1266 	{ 0xFFFFFFFF, 0x00000000, 0x00000000, 0x00000000 },     /* black */
1267 	{ 0x23232323, 0x7C007C00, 0x00FF0000, 0x3FF00000 },     /* red	*/
1268 	{ 0xb9b9b9b9, 0x03e003e0, 0x0000FF00, 0x000FFC00 },     /* green */
1269 	{ 0x05050505, 0x7FE07FE0, 0x00FFFF00, 0x3FFFFC00 },     /* yellow */
1270 	{ 0xd2d2d2d2, 0x001f001f, 0x000000FF, 0x000003FF },     /* blue	 */
1271 //	{ 0x80808080, 0x31933193, 0x00666699, 0x00000000 },	/* blue	 */
1272 	{ 0x18181818, 0x7C1F7C1F, 0x00FF00FF, 0x3FF003FF },     /* magenta */
1273 	{ 0xb4b4b4b4, 0x03FF03FF, 0x0000FFFF, 0x000FFFFF },     /* cyan	*/
1274 	{ 0x00000000, 0x7FFF7FFF, 0x00FFFFFF, 0x3FFFFFFF }      /* white */
1275 };
1276 
1277 static uint32_t vc_color_fore = 0;
1278 static uint32_t vc_color_back = 0;
1279 
1280 /*
1281  * New Rendering code from Michel Pollet
1282  */
1283 
1284 /* Rendered Font Buffer */
1285 static unsigned char *vc_rendered_font = NULL;
1286 
1287 /* Rendered Font Size */
1288 static uint32_t vc_rendered_font_size = 0;
1289 
1290 /* Size of a character in the table (bytes) */
1291 static int vc_rendered_char_size = 0;
1292 
1293 #define REN_MAX_DEPTH   32
1294 static unsigned char vc_rendered_char[ISO_CHAR_HEIGHT * ((REN_MAX_DEPTH / 8) * ISO_CHAR_WIDTH)];
1295 
1296 #if defined(XNU_TARGET_OS_OSX)
1297 #define CONFIG_VC_PROGRESS_METER_SUPPORT        1
1298 #endif /* XNU_TARGET_OS_OSX */
1299 
1300 #if defined(XNU_TARGET_OS_OSX)
1301 static void
1302 internal_set_progressmeter(int new_value);
1303 static void
1304 internal_enable_progressmeter(int new_value);
1305 
1306 enum{
1307 	kProgressMeterOff    = FALSE,
1308 	kProgressMeterUser   = TRUE,
1309 	kProgressMeterKernel = 3,
1310 };
1311 enum{
1312 	kProgressMeterMax    = 1024,
1313 	kProgressMeterEnd    = 512,
1314 };
1315 
1316 #endif  /* defined(XNU_TARGET_OS_OSX) */
1317 
1318 static boolean_t vc_progress_white =
1319 #ifdef CONFIG_VC_PROGRESS_WHITE
1320     TRUE;
1321 #else /* !CONFIG_VC_PROGRESS_WHITE */
1322     FALSE;
1323 #endif /* !CONFIG_VC_PROGRESS_WHITE */
1324 
1325 static int vc_acquire_delay = kProgressAcquireDelay;
1326 
1327 static void
vc_clear_screen(unsigned int xx,unsigned int yy,unsigned int scrreg_top,unsigned int scrreg_bottom,int which)1328 vc_clear_screen(unsigned int xx, unsigned int yy, unsigned int scrreg_top,
1329     unsigned int scrreg_bottom, int which)
1330 {
1331 	uint32_t *p, *endp, *row;
1332 	int      linelongs, col;
1333 	int      rowline, rowlongs;
1334 
1335 	if (!vinfo.v_depth) {
1336 		return;
1337 	}
1338 
1339 	linelongs = vinfo.v_rowbytes * (ISO_CHAR_HEIGHT >> 2);
1340 	rowline = vinfo.v_rowscanbytes >> 2;
1341 	rowlongs = vinfo.v_rowbytes >> 2;
1342 
1343 	p = (uint32_t*) vinfo.v_baseaddr;
1344 	endp = (uint32_t*) vinfo.v_baseaddr;
1345 
1346 	switch (which) {
1347 	case 0:         /* To end of screen	 */
1348 		gc_clear_line(xx, yy, 0);
1349 		if (yy < scrreg_bottom - 1) {
1350 			p += (yy + 1) * linelongs;
1351 			endp += scrreg_bottom * linelongs;
1352 		}
1353 		break;
1354 	case 1:         /* To start of screen	 */
1355 		gc_clear_line(xx, yy, 1);
1356 		if (yy > scrreg_top) {
1357 			p += scrreg_top * linelongs;
1358 			endp += yy * linelongs;
1359 		}
1360 		break;
1361 	case 2:         /* Whole screen		 */
1362 		p += scrreg_top * linelongs;
1363 		if (scrreg_bottom == vinfo.v_rows) {
1364 			endp += rowlongs * vinfo.v_height;
1365 		} else {
1366 			endp += scrreg_bottom * linelongs;
1367 		}
1368 		break;
1369 	}
1370 
1371 	for (row = p; row < endp; row += rowlongs) {
1372 		for (col = 0; col < rowline; col++) {
1373 			*(row + col) = vc_color_back;
1374 		}
1375 	}
1376 }
1377 
1378 static void
vc_render_char(unsigned char ch,unsigned char * renderptr,short newdepth)1379 vc_render_char(unsigned char ch, unsigned char *renderptr, short newdepth)
1380 {
1381 	union {
1382 		unsigned char  *charptr;
1383 		unsigned short *shortptr;
1384 		uint32_t  *longptr;
1385 	} current;      /* current place in rendered font, multiple types. */
1386 	unsigned char *theChar; /* current char in iso_font */
1387 	int line;
1388 
1389 	current.charptr = renderptr;
1390 	theChar = iso_font + (ch * ISO_CHAR_HEIGHT);
1391 
1392 	for (line = 0; line < ISO_CHAR_HEIGHT; line++) {
1393 		unsigned char mask = 1;
1394 		do {
1395 			switch (newdepth) {
1396 			case 8:
1397 				*current.charptr++ = (*theChar & mask) ? 0xFF : 0;
1398 				break;
1399 			case 16:
1400 				*current.shortptr++ = (*theChar & mask) ? 0xFFFF : 0;
1401 				break;
1402 
1403 			case 30:
1404 			case 32:
1405 				*current.longptr++ = (*theChar & mask) ? 0xFFFFFFFF : 0;
1406 				break;
1407 			}
1408 			mask <<= 1;
1409 		} while (mask); /* while the single bit drops to the right */
1410 		theChar++;
1411 	}
1412 }
1413 
1414 static void
vc_paint_char_8(unsigned int xx,unsigned int yy,unsigned char ch,int attrs,__unused unsigned char ch_previous,__unused int attrs_previous)1415 vc_paint_char_8(unsigned int xx, unsigned int yy, unsigned char ch, int attrs,
1416     __unused unsigned char ch_previous, __unused int attrs_previous)
1417 {
1418 	uint32_t *theChar;
1419 	uint32_t *where;
1420 	int i;
1421 
1422 	if (vc_rendered_font) {
1423 		theChar = (uint32_t*)(vc_rendered_font + (ch * vc_rendered_char_size));
1424 	} else {
1425 		vc_render_char(ch, vc_rendered_char, 8);
1426 		theChar = (uint32_t*)(vc_rendered_char);
1427 	}
1428 	where = (uint32_t*)(vinfo.v_baseaddr +
1429 	    (yy * ISO_CHAR_HEIGHT * vinfo.v_rowbytes) +
1430 	    (xx * ISO_CHAR_WIDTH));
1431 
1432 	if (!attrs) {
1433 		for (i = 0; i < ISO_CHAR_HEIGHT; i++) {         /* No attr? FLY !*/
1434 			uint32_t *store = where;
1435 			int x;
1436 			for (x = 0; x < 2; x++) {
1437 				uint32_t val = *theChar++;
1438 				val = (vc_color_back & ~val) | (vc_color_fore & val);
1439 				*store++ = val;
1440 			}
1441 
1442 			where = (uint32_t*)(((unsigned char*)where) + vinfo.v_rowbytes);
1443 		}
1444 	} else {
1445 		for (i = 0; i < ISO_CHAR_HEIGHT; i++) { /* a little slower */
1446 			uint32_t *store = where, lastpixel = 0;
1447 			int x;
1448 			for (x = 0; x < 2; x++) {
1449 				uint32_t val = *theChar++, save = val;
1450 				if (attrs & ATTR_BOLD) { /* bold support */
1451 					if (lastpixel && !(save & 0xFF000000)) {
1452 						val |= 0xff000000;
1453 					}
1454 					if ((save & 0xFFFF0000) == 0xFF000000) {
1455 						val |= 0x00FF0000;
1456 					}
1457 					if ((save & 0x00FFFF00) == 0x00FF0000) {
1458 						val |= 0x0000FF00;
1459 					}
1460 					if ((save & 0x0000FFFF) == 0x0000FF00) {
1461 						val |= 0x000000FF;
1462 					}
1463 				}
1464 				if (attrs & ATTR_REVERSE) {
1465 					val = ~val;
1466 				}
1467 				if (attrs & ATTR_UNDER && i == ISO_CHAR_HEIGHT - 1) {
1468 					val = ~val;
1469 				}
1470 
1471 				val = (vc_color_back & ~val) | (vc_color_fore & val);
1472 				*store++ = val;
1473 				lastpixel = save & 0xff;
1474 			}
1475 
1476 			where = (uint32_t*)(((unsigned char*)where) + vinfo.v_rowbytes);
1477 		}
1478 	}
1479 }
1480 
1481 static void
vc_paint_char_16(unsigned int xx,unsigned int yy,unsigned char ch,int attrs,__unused unsigned char ch_previous,__unused int attrs_previous)1482 vc_paint_char_16(unsigned int xx, unsigned int yy, unsigned char ch, int attrs,
1483     __unused unsigned char ch_previous,
1484     __unused int attrs_previous)
1485 {
1486 	uint32_t *theChar;
1487 	uint32_t *where;
1488 	int i;
1489 
1490 	if (vc_rendered_font) {
1491 		theChar = (uint32_t*)(vc_rendered_font + (ch * vc_rendered_char_size));
1492 	} else {
1493 		vc_render_char(ch, vc_rendered_char, 16);
1494 		theChar = (uint32_t*)(vc_rendered_char);
1495 	}
1496 	where = (uint32_t*)(vinfo.v_baseaddr +
1497 	    (yy * ISO_CHAR_HEIGHT * vinfo.v_rowbytes) +
1498 	    (xx * ISO_CHAR_WIDTH * 2));
1499 
1500 	if (!attrs) {
1501 		for (i = 0; i < ISO_CHAR_HEIGHT; i++) {         /* No attrs ? FLY ! */
1502 			uint32_t *store = where;
1503 			int x;
1504 			for (x = 0; x < 4; x++) {
1505 				uint32_t val = *theChar++;
1506 				val = (vc_color_back & ~val) | (vc_color_fore & val);
1507 				*store++ = val;
1508 			}
1509 
1510 			where = (uint32_t*)(((unsigned char*)where) + vinfo.v_rowbytes);
1511 		}
1512 	} else {
1513 		for (i = 0; i < ISO_CHAR_HEIGHT; i++) { /* a little bit slower */
1514 			uint32_t *store = where, lastpixel = 0;
1515 			int x;
1516 			for (x = 0; x < 4; x++) {
1517 				uint32_t val = *theChar++, save = val;
1518 				if (attrs & ATTR_BOLD) { /* bold support */
1519 					if (save == 0xFFFF0000) {
1520 						val |= 0xFFFF;
1521 					} else if (lastpixel && !(save & 0xFFFF0000)) {
1522 						val |= 0xFFFF0000;
1523 					}
1524 				}
1525 				if (attrs & ATTR_REVERSE) {
1526 					val = ~val;
1527 				}
1528 				if (attrs & ATTR_UNDER && i == ISO_CHAR_HEIGHT - 1) {
1529 					val = ~val;
1530 				}
1531 
1532 				val = (vc_color_back & ~val) | (vc_color_fore & val);
1533 
1534 				*store++ = val;
1535 				lastpixel = save & 0x7fff;
1536 			}
1537 
1538 			where = (uint32_t*)(((unsigned char*)where) + vinfo.v_rowbytes);
1539 		}
1540 	}
1541 }
1542 
1543 static void
vc_paint_char_32(unsigned int xx,unsigned int yy,unsigned char ch,int attrs,unsigned char ch_previous,int attrs_previous)1544 vc_paint_char_32(unsigned int xx, unsigned int yy, unsigned char ch, int attrs,
1545     unsigned char ch_previous, int attrs_previous)
1546 {
1547 	uint32_t *theChar;
1548 	uint32_t *theCharPrevious;
1549 	uint32_t *where;
1550 	int i;
1551 
1552 	if (vc_rendered_font) {
1553 		theChar = (uint32_t*)(vc_rendered_font + (ch * vc_rendered_char_size));
1554 		theCharPrevious = (uint32_t*)(vc_rendered_font + (ch_previous * vc_rendered_char_size));
1555 	} else {
1556 		vc_render_char(ch, vc_rendered_char, 32);
1557 		theChar = (uint32_t*)(vc_rendered_char);
1558 		theCharPrevious = NULL;
1559 	}
1560 	if (!ch_previous) {
1561 		theCharPrevious = NULL;
1562 	}
1563 	if (attrs_previous) {
1564 		theCharPrevious = NULL;
1565 	}
1566 	where = (uint32_t*)(vinfo.v_baseaddr +
1567 	    (yy * ISO_CHAR_HEIGHT * vinfo.v_rowbytes) +
1568 	    (xx * ISO_CHAR_WIDTH * 4));
1569 
1570 	if (!attrs) {
1571 		for (i = 0; i < ISO_CHAR_HEIGHT; i++) {         /* No attrs ? FLY ! */
1572 			uint32_t *store = where;
1573 			int x;
1574 			for (x = 0; x < 8; x++) {
1575 				uint32_t val = *theChar++;
1576 				if (theCharPrevious == NULL || val != *theCharPrevious++) {
1577 					val = (vc_color_back & ~val) | (vc_color_fore & val);
1578 					*store++ = val;
1579 				} else {
1580 					store++;
1581 				}
1582 			}
1583 
1584 			where = (uint32_t *)(((unsigned char*)where) + vinfo.v_rowbytes);
1585 		}
1586 	} else {
1587 		for (i = 0; i < ISO_CHAR_HEIGHT; i++) { /* a little slower */
1588 			uint32_t *store = where, lastpixel = 0;
1589 			int x;
1590 			for (x = 0; x < 8; x++) {
1591 				uint32_t val = *theChar++, save = val;
1592 				if (attrs & ATTR_BOLD) { /* bold support */
1593 					if (lastpixel && !save) {
1594 						val = 0xFFFFFFFF;
1595 					}
1596 				}
1597 				if (attrs & ATTR_REVERSE) {
1598 					val = ~val;
1599 				}
1600 				if (attrs & ATTR_UNDER && i == ISO_CHAR_HEIGHT - 1) {
1601 					val = ~val;
1602 				}
1603 
1604 				val = (vc_color_back & ~val) | (vc_color_fore & val);
1605 				*store++ = val;
1606 				lastpixel = save;
1607 			}
1608 
1609 			where = (uint32_t*)(((unsigned char*)where) + vinfo.v_rowbytes);
1610 		}
1611 	}
1612 }
1613 
1614 static void
vc_paint_char(unsigned int xx,unsigned int yy,unsigned char ch,int attrs,unsigned char ch_previous,int attrs_previous)1615 vc_paint_char(unsigned int xx, unsigned int yy, unsigned char ch, int attrs,
1616     unsigned char ch_previous, int attrs_previous)
1617 {
1618 	if (!vinfo.v_depth) {
1619 		return;
1620 	}
1621 
1622 	switch (vinfo.v_depth) {
1623 	case 8:
1624 		vc_paint_char_8(xx, yy, ch, attrs, ch_previous, attrs_previous);
1625 		break;
1626 	case 16:
1627 		vc_paint_char_16(xx, yy, ch, attrs, ch_previous,
1628 		    attrs_previous);
1629 		break;
1630 	case 30:
1631 	case 32:
1632 		vc_paint_char_32(xx, yy, ch, attrs, ch_previous,
1633 		    attrs_previous);
1634 		break;
1635 	}
1636 }
1637 
1638 static void
vc_render_font(short newdepth)1639 vc_render_font(short newdepth)
1640 {
1641 	static short olddepth = 0;
1642 
1643 	int charindex;  /* index in ISO font */
1644 	unsigned char *rendered_font;
1645 	unsigned int rendered_font_size;
1646 	int rendered_char_size;
1647 
1648 	if (vm_initialized == FALSE) {
1649 		return; /* nothing to do */
1650 	}
1651 	if (olddepth == newdepth && vc_rendered_font) {
1652 		return; /* nothing to do */
1653 	}
1654 
1655 	VCPUTC_LOCK_LOCK();
1656 
1657 	rendered_font      = vc_rendered_font;
1658 	rendered_font_size = vc_rendered_font_size;
1659 	rendered_char_size = vc_rendered_char_size;
1660 
1661 	vc_rendered_font      = NULL;
1662 	vc_rendered_font_size = 0;
1663 	vc_rendered_char_size = 0;
1664 
1665 	VCPUTC_LOCK_UNLOCK();
1666 
1667 	kfree_data(rendered_font, rendered_font_size);
1668 
1669 	if (newdepth) {
1670 		rendered_char_size = ISO_CHAR_HEIGHT * (((newdepth + 7) / 8) * ISO_CHAR_WIDTH);
1671 		rendered_font_size = (ISO_CHAR_MAX - ISO_CHAR_MIN + 1) * rendered_char_size;
1672 		rendered_font = kalloc_data(rendered_font_size, Z_WAITOK);
1673 	}
1674 
1675 	if (rendered_font == NULL) {
1676 		return;
1677 	}
1678 
1679 	for (charindex = ISO_CHAR_MIN; charindex <= ISO_CHAR_MAX; charindex++) {
1680 		vc_render_char(charindex, rendered_font + (charindex * rendered_char_size), newdepth);
1681 	}
1682 
1683 	olddepth = newdepth;
1684 
1685 	VCPUTC_LOCK_LOCK();
1686 
1687 	vc_rendered_font      = rendered_font;
1688 	vc_rendered_font_size = rendered_font_size;
1689 	vc_rendered_char_size = rendered_char_size;
1690 
1691 	VCPUTC_LOCK_UNLOCK();
1692 }
1693 
1694 static void
vc_enable(boolean_t enable)1695 vc_enable(boolean_t enable)
1696 {
1697 	vc_render_font(enable ? vinfo.v_depth : 0);
1698 }
1699 
1700 static void
vc_reverse_cursor(unsigned int xx,unsigned int yy)1701 vc_reverse_cursor(unsigned int xx, unsigned int yy)
1702 {
1703 	uint32_t *where;
1704 	int line, col;
1705 
1706 	if (!vinfo.v_depth) {
1707 		return;
1708 	}
1709 
1710 	where = (uint32_t*)(vinfo.v_baseaddr +
1711 	    (yy * ISO_CHAR_HEIGHT * vinfo.v_rowbytes) +
1712 	    (xx /** ISO_CHAR_WIDTH*/ * vinfo.v_depth));
1713 	for (line = 0; line < ISO_CHAR_HEIGHT; line++) {
1714 		switch (vinfo.v_depth) {
1715 		case 8:
1716 			where[0] = ~where[0];
1717 			where[1] = ~where[1];
1718 			break;
1719 		case 16:
1720 			for (col = 0; col < 4; col++) {
1721 				where[col] = ~where[col];
1722 			}
1723 			break;
1724 		case 32:
1725 			for (col = 0; col < 8; col++) {
1726 				where[col] = ~where[col];
1727 			}
1728 			break;
1729 		}
1730 		where = (uint32_t*)(((unsigned char*)where) + vinfo.v_rowbytes);
1731 	}
1732 }
1733 
1734 static void
vc_scroll_down(int num,unsigned int scrreg_top,unsigned int scrreg_bottom)1735 vc_scroll_down(int num, unsigned int scrreg_top, unsigned int scrreg_bottom)
1736 {
1737 	uint32_t *from, *to, linelongs, i, line, rowline, rowscanline;
1738 
1739 	if (!vinfo.v_depth) {
1740 		return;
1741 	}
1742 
1743 	linelongs = vinfo.v_rowbytes * (ISO_CHAR_HEIGHT >> 2);
1744 	rowline = vinfo.v_rowbytes >> 2;
1745 	rowscanline = vinfo.v_rowscanbytes >> 2;
1746 
1747 	to = (uint32_t *) vinfo.v_baseaddr + (linelongs * scrreg_bottom)
1748 	    - (rowline - rowscanline);
1749 	from = to - (linelongs * num);  /* handle multiple line scroll (Michel Pollet) */
1750 
1751 	i = (scrreg_bottom - scrreg_top) - num;
1752 
1753 	while (i-- > 0) {
1754 		for (line = 0; line < ISO_CHAR_HEIGHT; line++) {
1755 			/*
1756 			 * Only copy what is displayed
1757 			 */
1758 			video_scroll_down(from,
1759 			    (from - (vinfo.v_rowscanbytes >> 2)),
1760 			    to);
1761 
1762 			from -= rowline;
1763 			to -= rowline;
1764 		}
1765 	}
1766 }
1767 
1768 static void
vc_scroll_up(int num,unsigned int scrreg_top,unsigned int scrreg_bottom)1769 vc_scroll_up(int num, unsigned int scrreg_top, unsigned int scrreg_bottom)
1770 {
1771 	uint32_t *from, *to, linelongs, i, line, rowline, rowscanline;
1772 
1773 	if (!vinfo.v_depth) {
1774 		return;
1775 	}
1776 
1777 	linelongs = vinfo.v_rowbytes * (ISO_CHAR_HEIGHT >> 2);
1778 	rowline = vinfo.v_rowbytes >> 2;
1779 	rowscanline = vinfo.v_rowscanbytes >> 2;
1780 
1781 	to = (uint32_t *) vinfo.v_baseaddr + (scrreg_top * linelongs);
1782 	from = to + (linelongs * num);  /* handle multiple line scroll (Michel Pollet) */
1783 
1784 	i = (scrreg_bottom - scrreg_top) - num;
1785 
1786 	while (i-- > 0) {
1787 		for (line = 0; line < ISO_CHAR_HEIGHT; line++) {
1788 			/*
1789 			 * Only copy what is displayed
1790 			 */
1791 			video_scroll_up(from,
1792 			    (from + (vinfo.v_rowscanbytes >> 2)),
1793 			    to);
1794 
1795 			from += rowline;
1796 			to += rowline;
1797 		}
1798 	}
1799 }
1800 
1801 static void
vc_update_color(int color,boolean_t fore)1802 vc_update_color(int color, boolean_t fore)
1803 {
1804 	if (!vinfo.v_depth) {
1805 		return;
1806 	}
1807 	if (fore) {
1808 		vc_color_fore = vc_colors[color][vc_color_index_table[vinfo.v_depth]];
1809 	} else {
1810 		vc_color_back = vc_colors[color][vc_color_index_table[vinfo.v_depth]];
1811 	}
1812 }
1813 
1814 /*
1815  * Video Console (Back-End): Icon Control
1816  * --------------------------------------
1817  */
1818 
1819 static vc_progress_element *    vc_progress;
1820 enum { kMaxProgressData = 3 };
1821 static const unsigned char *    vc_progress_data[kMaxProgressData];
1822 static const unsigned char *    vc_progress_alpha;
1823 static boolean_t                vc_progress_enable;
1824 static const unsigned char *    vc_clut;
1825 static const unsigned char *    vc_clut8;
1826 static unsigned char            vc_revclut8[256];
1827 static uint32_t                 vc_progress_interval;
1828 static uint32_t                 vc_progress_count;
1829 static uint32_t                 vc_progress_angle;
1830 static uint64_t                 vc_progress_deadline;
1831 static thread_call_data_t       vc_progress_call;
1832 static boolean_t                vc_needsave;
1833 static void *                   vc_saveunder;
1834 static vm_size_t                vc_saveunder_len;
1835 static int8_t                   vc_uiscale = 1;
1836 vc_progress_user_options        vc_progress_options;
1837 vc_progress_user_options        vc_user_options;
1838 
1839 decl_simple_lock_data(, vc_progress_lock);
1840 
1841 #if defined(XNU_TARGET_OS_OSX)
1842 static int                      vc_progress_withmeter = 3;
1843 int                             vc_progressmeter_enable;
1844 static int                      vc_progressmeter_drawn;
1845 int                             vc_progressmeter_value;
1846 static uint32_t                 vc_progressmeter_count;
1847 static uint32_t                 vc_progress_meter_start;
1848 static uint32_t                 vc_progress_meter_end;
1849 static uint64_t                 vc_progressmeter_interval;
1850 static uint64_t                 vc_progressmeter_deadline;
1851 static thread_call_data_t       vc_progressmeter_call;
1852 static void *                   vc_progressmeter_backbuffer;
1853 static uint32_t                 vc_progressmeter_diskspeed = 256;
1854 
1855 #endif  /* defined(XNU_TARGET_OS_OSX) */
1856 
1857 enum {
1858 	kSave          = 0x10,
1859 	kDataIndexed   = 0x20,
1860 	kDataAlpha     = 0x40,
1861 	kDataBack      = 0x80,
1862 	kDataRotate    = 0x03,
1863 };
1864 
1865 static void vc_blit_rect(int x, int y, int bx,
1866     int width, int height,
1867     int sourceWidth, int sourceHeight,
1868     int sourceRow, int backRow,
1869     const unsigned char * dataPtr,
1870     void * backBuffer,
1871     unsigned int flags);
1872 static void vc_blit_rect_8(int x, int y, int bx,
1873     int width, int height,
1874     int sourceWidth, int sourceHeight,
1875     int sourceRow, int backRow,
1876     const unsigned char * dataPtr,
1877     unsigned char * backBuffer,
1878     unsigned int flags);
1879 static void vc_blit_rect_16(int x, int y, int bx,
1880     int width, int height,
1881     int sourceWidth, int sourceHeight,
1882     int sourceRow, int backRow,
1883     const unsigned char * dataPtr,
1884     unsigned short * backBuffer,
1885     unsigned int flags);
1886 static void vc_blit_rect_32(int x, int y, int bx,
1887     int width, int height,
1888     int sourceWidth, int sourceHeight,
1889     int sourceRow, int backRow,
1890     const unsigned char * dataPtr,
1891     unsigned int * backBuffer,
1892     unsigned int flags);
1893 static void vc_blit_rect_30(int x, int y, int bx,
1894     int width, int height,
1895     int sourceWidth, int sourceHeight,
1896     int sourceRow, int backRow,
1897     const unsigned char * dataPtr,
1898     unsigned int * backBuffer,
1899     unsigned int flags);
1900 static void vc_progress_task( void * arg0, void * arg );
1901 #if defined(XNU_TARGET_OS_OSX)
1902 static void vc_progressmeter_task( void * arg0, void * arg );
1903 #endif  /* defined(XNU_TARGET_OS_OSX) */
1904 
1905 static void
vc_blit_rect(int x,int y,int bx,int width,int height,int sourceWidth,int sourceHeight,int sourceRow,int backRow,const unsigned char * dataPtr,void * backBuffer,unsigned int flags)1906 vc_blit_rect(int x, int y, int bx,
1907     int width, int height,
1908     int sourceWidth, int sourceHeight,
1909     int sourceRow, int backRow,
1910     const unsigned char * dataPtr,
1911     void * backBuffer,
1912     unsigned int flags)
1913 {
1914 	if (!vinfo.v_depth) {
1915 		return;
1916 	}
1917 	if (((unsigned int)(x + width)) > vinfo.v_width) {
1918 		return;
1919 	}
1920 	if (((unsigned int)(y + height)) > vinfo.v_height) {
1921 		return;
1922 	}
1923 
1924 	switch (vinfo.v_depth) {
1925 	case 8:
1926 		if (vc_clut8 == vc_clut) {
1927 			vc_blit_rect_8( x, y, bx, width, height, sourceWidth, sourceHeight, sourceRow, backRow, dataPtr, (unsigned char *) backBuffer, flags );
1928 		}
1929 		break;
1930 	case 16:
1931 		vc_blit_rect_16( x, y, bx, width, height, sourceWidth, sourceHeight, sourceRow, backRow, dataPtr, (unsigned short *) backBuffer, flags );
1932 		break;
1933 	case 32:
1934 		vc_blit_rect_32( x, y, bx, width, height, sourceWidth, sourceHeight, sourceRow, backRow, dataPtr, (unsigned int *) backBuffer, flags );
1935 		break;
1936 	case 30:
1937 		vc_blit_rect_30( x, y, bx, width, height, sourceWidth, sourceHeight, sourceRow, backRow, dataPtr, (unsigned int *) backBuffer, flags );
1938 		break;
1939 	}
1940 }
1941 
1942 static void
vc_blit_rect_8(int x,int y,__unused int bx,int width,int height,int sourceWidth,int sourceHeight,int sourceRow,__unused int backRow,const unsigned char * dataPtr,__unused unsigned char * backBuffer,__unused unsigned int flags)1943 vc_blit_rect_8(int x, int y, __unused int bx,
1944     int width, int height,
1945     int sourceWidth, int sourceHeight,
1946     int sourceRow, __unused int backRow,
1947     const unsigned char * dataPtr,
1948     __unused unsigned char * backBuffer,
1949     __unused unsigned int flags)
1950 {
1951 	volatile unsigned short * dst;
1952 	int line, col;
1953 	unsigned int data = 0, out = 0;
1954 	int sx, sy, a, b, c, d;
1955 	int scale = 0x10000;
1956 
1957 	a = (sourceRow == 1) ? 0 : vc_rotate_matr[kDataRotate & flags][0][0] * scale;
1958 	b = (sourceRow == 1) ? 0 : vc_rotate_matr[kDataRotate & flags][0][1] * scale;
1959 	c = vc_rotate_matr[kDataRotate & flags][1][0] * scale;
1960 	d = vc_rotate_matr[kDataRotate & flags][1][1] * scale;
1961 
1962 	sx = ((a + b) < 0) ? ((sourceWidth * scale)  - 0x8000) : 0;
1963 	sy = ((c + d) < 0) ? ((sourceHeight * scale) - 0x8000) : 0;
1964 
1965 	if (!sourceRow) {
1966 		data = (unsigned int)(uintptr_t)dataPtr;
1967 	}
1968 
1969 	dst = (volatile unsigned short *) (vinfo.v_baseaddr +
1970 	    (y * vinfo.v_rowbytes) +
1971 	    (x * 4));
1972 
1973 	for (line = 0; line < height; line++) {
1974 		for (col = 0; col < width; col++) {
1975 			if (sourceRow) {
1976 				data = dataPtr[((sx + (col * a) + (line * b)) >> 16)
1977 				    + sourceRow * (((sy + (col * c) + (line * d)) >> 16))];
1978 			}
1979 			if (kDataAlpha & flags) {
1980 				out = vc_revclut8[data];
1981 			} else {
1982 				out = data;
1983 			}
1984 			*(dst + col) = out;
1985 		}
1986 		dst = (volatile unsigned short *) (((volatile char*)dst) + vinfo.v_rowbytes);
1987 	}
1988 }
1989 
1990 /* 16-bit is 1555 (XRGB) on all platforms */
1991 
1992 #define CLUT_MASK_R     0xf8
1993 #define CLUT_MASK_G     0xf8
1994 #define CLUT_MASK_B     0xf8
1995 #define CLUT_SHIFT_R    << 7
1996 #define CLUT_SHIFT_G    << 2
1997 #define CLUT_SHIFT_B    >> 3
1998 #define MASK_R          0x7c00
1999 #define MASK_G          0x03e0
2000 #define MASK_B          0x001f
2001 #define MASK_R_8        0x3fc00
2002 #define MASK_G_8        0x01fe0
2003 #define MASK_B_8        0x000ff
2004 
2005 static void
vc_blit_rect_16(int x,int y,int bx,int width,int height,int sourceWidth,int sourceHeight,int sourceRow,int backRow,const unsigned char * dataPtr,unsigned short * backPtr,unsigned int flags)2006 vc_blit_rect_16( int x, int y, int bx,
2007     int width, int height,
2008     int sourceWidth, int sourceHeight,
2009     int sourceRow, int backRow,
2010     const unsigned char * dataPtr,
2011     unsigned short * backPtr,
2012     unsigned int flags)
2013 {
2014 	volatile unsigned short * dst;
2015 	int line, col;
2016 	unsigned int data = 0, out = 0, back = 0;
2017 	int sx, sy, a, b, c, d;
2018 	int scale = 0x10000;
2019 
2020 	a = (sourceRow == 1) ? 0 : vc_rotate_matr[kDataRotate & flags][0][0] * scale;
2021 	b = (sourceRow == 1) ? 0 : vc_rotate_matr[kDataRotate & flags][0][1] * scale;
2022 	c = vc_rotate_matr[kDataRotate & flags][1][0] * scale;
2023 	d = vc_rotate_matr[kDataRotate & flags][1][1] * scale;
2024 
2025 	sx = ((a + b) < 0) ? ((sourceWidth * scale)  - 0x8000) : 0;
2026 	sy = ((c + d) < 0) ? ((sourceHeight * scale) - 0x8000) : 0;
2027 
2028 	if (!sourceRow) {
2029 		data = (unsigned int)(uintptr_t)dataPtr;
2030 	}
2031 
2032 	if (backPtr) {
2033 		backPtr += bx;
2034 	}
2035 	dst = (volatile unsigned short *) (vinfo.v_baseaddr +
2036 	    (y * vinfo.v_rowbytes) +
2037 	    (x * 2));
2038 
2039 	for (line = 0; line < height; line++) {
2040 		for (col = 0; col < width; col++) {
2041 			if (sourceRow) {
2042 				data = dataPtr[((sx + (col * a) + (line * b)) >> 16)
2043 				    + sourceRow * (((sy + (col * c) + (line * d)) >> 16))];
2044 			}
2045 			if (backPtr) {
2046 				if (kSave & flags) {
2047 					back = *(dst + col);
2048 					*backPtr++ = back;
2049 				} else {
2050 					back = *backPtr++;
2051 				}
2052 			}
2053 			if (kDataIndexed & flags) {
2054 				out = ((CLUT_MASK_R & (vc_clut[data * 3 + 0]))CLUT_SHIFT_R)
2055 				    | ((CLUT_MASK_G & (vc_clut[data * 3 + 1]))CLUT_SHIFT_G)
2056 				    | ((CLUT_MASK_B & (vc_clut[data * 3 + 2]))CLUT_SHIFT_B);
2057 			} else if (kDataAlpha & flags) {
2058 				out = (((((back & MASK_R) * data) + MASK_R_8) >> 8) & MASK_R)
2059 				    | (((((back & MASK_G) * data) + MASK_G_8) >> 8) & MASK_G)
2060 				    | (((((back & MASK_B) * data) + MASK_B_8) >> 8) & MASK_B);
2061 				if (vc_progress_white) {
2062 					out += (((0xff - data) & CLUT_MASK_R)CLUT_SHIFT_R)
2063 					    | (((0xff - data) & CLUT_MASK_G)CLUT_SHIFT_G)
2064 					    | (((0xff - data) & CLUT_MASK_B)CLUT_SHIFT_B);
2065 				}
2066 			} else if (kDataBack & flags) {
2067 				out = back;
2068 			} else {
2069 				out = data;
2070 			}
2071 			*(dst + col) = out;
2072 		}
2073 		dst = (volatile unsigned short *) (((volatile char*)dst) + vinfo.v_rowbytes);
2074 		if (backPtr) {
2075 			backPtr += backRow - width;
2076 		}
2077 	}
2078 }
2079 
2080 
2081 static void
vc_blit_rect_32(int x,int y,int bx,int width,int height,int sourceWidth,int sourceHeight,int sourceRow,int backRow,const unsigned char * dataPtr,unsigned int * backPtr,unsigned int flags)2082 vc_blit_rect_32(int x, int y, int bx,
2083     int width, int height,
2084     int sourceWidth, int sourceHeight,
2085     int sourceRow, int backRow,
2086     const unsigned char * dataPtr,
2087     unsigned int * backPtr,
2088     unsigned int flags)
2089 {
2090 	volatile unsigned int * dst;
2091 	int line, col;
2092 	unsigned int data = 0, out = 0, back = 0;
2093 	int sx, sy, a, b, c, d;
2094 	int scale = 0x10000;
2095 
2096 	a = (sourceRow == 1) ? 0 : vc_rotate_matr[kDataRotate & flags][0][0] * scale;
2097 	b = (sourceRow == 1) ? 0 : vc_rotate_matr[kDataRotate & flags][0][1] * scale;
2098 	c = vc_rotate_matr[kDataRotate & flags][1][0] * scale;
2099 	d = vc_rotate_matr[kDataRotate & flags][1][1] * scale;
2100 
2101 	sx = ((a + b) < 0) ? ((sourceWidth * scale)  - 0x8000) : 0;
2102 	sy = ((c + d) < 0) ? ((sourceHeight * scale) - 0x8000) : 0;
2103 
2104 	if (!sourceRow) {
2105 		data = (unsigned int)(uintptr_t)dataPtr;
2106 	}
2107 
2108 	if (backPtr) {
2109 		backPtr += bx;
2110 	}
2111 	dst = (volatile unsigned int *) (vinfo.v_baseaddr +
2112 	    (y * vinfo.v_rowbytes) +
2113 	    (x * 4));
2114 
2115 	for (line = 0; line < height; line++) {
2116 		for (col = 0; col < width; col++) {
2117 			if (sourceRow) {
2118 				data = dataPtr[((sx + (col * a) + (line * b)) >> 16)
2119 				    + sourceRow * (((sy + (col * c) + (line * d)) >> 16))];
2120 			}
2121 			if (backPtr) {
2122 				if (kSave & flags) {
2123 					back = *(dst + col);
2124 					*backPtr++ = back;
2125 				} else {
2126 					back = *backPtr++;
2127 				}
2128 			}
2129 			if (kDataIndexed & flags) {
2130 				out =     (vc_clut[data * 3 + 0] << 16)
2131 				    | (vc_clut[data * 3 + 1] << 8)
2132 				    | (vc_clut[data * 3 + 2]);
2133 			} else if (kDataAlpha & flags) {
2134 				out = (((((back & 0x00ff00ff) * data) + 0x00ff00ff) >> 8) & 0x00ff00ff)
2135 				    | (((((back & 0x0000ff00) * data) + 0x0000ff00) >> 8) & 0x0000ff00);
2136 				if (vc_progress_white) {
2137 					out += ((0xff - data) << 16)
2138 					    | ((0xff - data) << 8)
2139 					    |  (0xff - data);
2140 				}
2141 			} else if (kDataBack & flags) {
2142 				out = back;
2143 			} else {
2144 				out = data;
2145 			}
2146 			*(dst + col) = out;
2147 		}
2148 		dst = (volatile unsigned int *) (((volatile char*)dst) + vinfo.v_rowbytes);
2149 		if (backPtr) {
2150 			backPtr += backRow - width;
2151 		}
2152 	}
2153 }
2154 
2155 static void
vc_blit_rect_30(int x,int y,int bx,int width,int height,int sourceWidth,int sourceHeight,int sourceRow,int backRow,const unsigned char * dataPtr,unsigned int * backPtr,unsigned int flags)2156 vc_blit_rect_30(int x, int y, int bx,
2157     int width, int height,
2158     int sourceWidth, int sourceHeight,
2159     int sourceRow, int backRow,
2160     const unsigned char * dataPtr,
2161     unsigned int * backPtr,
2162     unsigned int flags)
2163 {
2164 	volatile unsigned int * dst;
2165 	int line, col;
2166 	unsigned int data = 0, out = 0, back = 0;
2167 	unsigned long long exp;
2168 	int sx, sy, a, b, c, d;
2169 	int scale = 0x10000;
2170 
2171 	a = (sourceRow == 1) ? 0 : vc_rotate_matr[kDataRotate & flags][0][0] * scale;
2172 	b = (sourceRow == 1) ? 0 : vc_rotate_matr[kDataRotate & flags][0][1] * scale;
2173 	c = vc_rotate_matr[kDataRotate & flags][1][0] * scale;
2174 	d = vc_rotate_matr[kDataRotate & flags][1][1] * scale;
2175 
2176 	sx = ((a + b) < 0) ? ((sourceWidth * scale)  - 0x8000) : 0;
2177 	sy = ((c + d) < 0) ? ((sourceHeight * scale) - 0x8000) : 0;
2178 
2179 	if (!sourceRow) {
2180 		data = (unsigned int)(uintptr_t)dataPtr;
2181 	}
2182 
2183 	if (backPtr) {
2184 		backPtr += bx;
2185 	}
2186 	dst = (volatile unsigned int *) (vinfo.v_baseaddr +
2187 	    (y * vinfo.v_rowbytes) +
2188 	    (x * 4));
2189 
2190 	for (line = 0; line < height; line++) {
2191 		for (col = 0; col < width; col++) {
2192 			if (sourceRow) {
2193 				data = dataPtr[((sx + (col * a) + (line * b)) >> 16)
2194 				    + sourceRow * (((sy + (col * c) + (line * d)) >> 16))];
2195 			}
2196 			if (backPtr) {
2197 				if (kSave & flags) {
2198 					back = *(dst + col);
2199 					*backPtr++ = back;
2200 				} else {
2201 					back = *backPtr++;
2202 				}
2203 			}
2204 			if (kDataIndexed & flags) {
2205 				out =     (vc_clut[data * 3 + 0] << 22)
2206 				    | (vc_clut[data * 3 + 1] << 12)
2207 				    | (vc_clut[data * 3 + 2] << 2);
2208 			} else if (kDataAlpha & flags) {
2209 				exp = back;
2210 				exp =  (((((exp & 0x3FF003FF) * data) + 0x0FF000FF) >> 8) & 0x3FF003FF)
2211 				    | (((((exp & 0x000FFC00) * data) + 0x0003FC00) >> 8) & 0x000FFC00);
2212 				out = (unsigned int)exp;
2213 				if (vc_progress_white) {
2214 					out += ((0xFF - data) << 22)
2215 					    | ((0xFF - data) << 12)
2216 					    | ((0xFF - data) << 2);
2217 				}
2218 			} else if (kDataBack & flags) {
2219 				out = back;
2220 			} else {
2221 				out = data;
2222 			}
2223 			*(dst + col) = out;
2224 		}
2225 		dst = (volatile unsigned int *) (((volatile char*)dst) + vinfo.v_rowbytes);
2226 		if (backPtr) {
2227 			backPtr += backRow - width;
2228 		}
2229 	}
2230 }
2231 
2232 static void
vc_clean_boot_graphics(void)2233 vc_clean_boot_graphics(void)
2234 {
2235 #if defined(XNU_TARGET_OS_OSX)
2236 	// clean up possible FDE login graphics
2237 	vc_progress_set(FALSE, 0);
2238 	const unsigned char *
2239 	    color = (typeof(color))(uintptr_t)(vc_progress_white ? 0x00000000 : 0xBFBFBFBF);
2240 	vc_blit_rect(0, 0, 0, vinfo.v_width, vinfo.v_height, vinfo.v_width, vinfo.v_height, 0, 0, color, NULL, 0);
2241 #endif
2242 }
2243 
2244 /*
2245  * Routines to render the lzss image format
2246  */
2247 
2248 struct lzss_image_state {
2249 	uint32_t col;
2250 	uint32_t row;
2251 	uint32_t width;
2252 	uint32_t height;
2253 	uint32_t bytes_per_row;
2254 	volatile uint32_t * row_start;
2255 	const uint8_t* clut;
2256 };
2257 typedef struct lzss_image_state lzss_image_state;
2258 
2259 // returns 0 if OK, 1 if error
2260 static inline int
vc_decompress_lzss_next_pixel(int next_data,lzss_image_state * state)2261 vc_decompress_lzss_next_pixel(int next_data, lzss_image_state* state)
2262 {
2263 	uint32_t palette_index = 0;
2264 	uint32_t pixel_value   = 0;
2265 
2266 	palette_index = next_data * 3;
2267 
2268 	pixel_value = ((uint32_t) state->clut[palette_index + 0] << 16)
2269 	    | ((uint32_t) state->clut[palette_index + 1] << 8)
2270 	    | ((uint32_t) state->clut[palette_index + 2]);
2271 
2272 	*(state->row_start + state->col) = pixel_value;
2273 
2274 	if (++state->col >= state->width) {
2275 		state->col = 0;
2276 		if (++state->row >= state->height) {
2277 			return 1;
2278 		}
2279 		state->row_start = (volatile uint32_t *) (((uintptr_t)state->row_start) + state->bytes_per_row);
2280 	}
2281 	return 0;
2282 }
2283 
2284 
2285 /*
2286  * Blit an lzss compressed image to the framebuffer
2287  * Assumes 32 bit screen (which is everything we ship at the moment)
2288  * The function vc_display_lzss_icon was copied from libkern/mkext.c, then modified.
2289  */
2290 
2291 /*
2292  * TODO: Does lzss use too much stack? 4096 plus bytes...
2293  *      Can probably chop it down by 1/2.
2294  */
2295 
2296 /**************************************************************
2297 *   LZSS.C -- A Data Compression Program
2298 ***************************************************************
2299 *    4/6/1989 Haruhiko Okumura
2300 *    Use, distribute, and modify this program freely.
2301 *    Please send me your improved versions.
2302 *        PC-VAN      SCIENCE
2303 *        NIFTY-Serve PAF01022
2304 *        CompuServe  74050,1022
2305 *
2306 **************************************************************/
2307 
2308 #define N         4096  /* size of ring buffer - must be power of 2 */
2309 #define F         18    /* upper limit for match_length */
2310 #define THRESHOLD 2     /* encode string into position and length
2311 	                 *  if match_length is greater than this */
2312 
2313 // returns 0 if OK, 1 if error
2314 // x and y indicate upper left corner of image location on screen
2315 int
vc_display_lzss_icon(uint32_t dst_x,uint32_t dst_y,uint32_t image_width,uint32_t image_height,const uint8_t * compressed_image,uint32_t compressed_size,const uint8_t * clut)2316 vc_display_lzss_icon(uint32_t dst_x, uint32_t dst_y,
2317     uint32_t image_width, uint32_t image_height,
2318     const uint8_t *compressed_image,
2319     uint32_t       compressed_size,
2320     const uint8_t *clut)
2321 {
2322 	uint32_t* image_start;
2323 	uint32_t bytes_per_pixel = 4;
2324 	uint32_t bytes_per_row = vinfo.v_rowbytes;
2325 
2326 	vc_clean_boot_graphics();
2327 
2328 	image_start = (uint32_t *) (vinfo.v_baseaddr + (dst_y * bytes_per_row) + (dst_x * bytes_per_pixel));
2329 
2330 	lzss_image_state state = {0, 0, image_width, image_height, bytes_per_row, image_start, clut};
2331 
2332 	int rval = 0;
2333 
2334 	const uint8_t *src = compressed_image;
2335 	uint32_t srclen = compressed_size;
2336 
2337 	/* ring buffer of size N, with extra F-1 bytes to aid string comparison */
2338 	uint8_t text_buf[N + F - 1];
2339 	const uint8_t *srcend = src + srclen;
2340 	int  i, j, k, r, c;
2341 	unsigned int flags;
2342 
2343 	srcend = src + srclen;
2344 	for (i = 0; i < N - F; i++) {
2345 		text_buf[i] = ' ';
2346 	}
2347 	r = N - F;
2348 	flags = 0;
2349 	for (;;) {
2350 		if (((flags >>= 1) & 0x100) == 0) {
2351 			if (src < srcend) {
2352 				c = *src++;
2353 			} else {
2354 				break;
2355 			}
2356 			flags = c | 0xFF00; /* uses higher byte cleverly */
2357 		} /* to count eight */
2358 		if (flags & 1) {
2359 			if (src < srcend) {
2360 				c = *src++;
2361 			} else {
2362 				break;
2363 			}
2364 			rval = vc_decompress_lzss_next_pixel(c, &state);
2365 			if (rval != 0) {
2366 				return rval;
2367 			}
2368 			text_buf[r++] = c;
2369 			r &= (N - 1);
2370 		} else {
2371 			if (src < srcend) {
2372 				i = *src++;
2373 			} else {
2374 				break;
2375 			}
2376 			if (src < srcend) {
2377 				j = *src++;
2378 			} else {
2379 				break;
2380 			}
2381 			i |= ((j & 0xF0) << 4);
2382 			j  =  (j & 0x0F) + THRESHOLD;
2383 			for (k = 0; k <= j; k++) {
2384 				c = text_buf[(i + k) & (N - 1)];
2385 				rval = vc_decompress_lzss_next_pixel(c, &state);
2386 				if (rval != 0) {
2387 					return rval;
2388 				}
2389 				text_buf[r++] = c;
2390 				r &= (N - 1);
2391 			}
2392 		}
2393 	}
2394 	return 0;
2395 }
2396 
2397 void
noroot_icon_test(void)2398 noroot_icon_test(void)
2399 {
2400 	boolean_t o_vc_progress_enable = vc_progress_enable;
2401 
2402 	vc_progress_enable = 1;
2403 
2404 	PE_display_icon( 0, "noroot");
2405 
2406 	vc_progress_enable = o_vc_progress_enable;
2407 }
2408 
2409 
2410 void
vc_display_icon(vc_progress_element * desc,const unsigned char * data)2411 vc_display_icon( vc_progress_element * desc,
2412     const unsigned char * data )
2413 {
2414 	int                 x, y, width, height;
2415 
2416 	if (vc_progress_enable && vc_clut) {
2417 		vc_clean_boot_graphics();
2418 
2419 		width = desc->width;
2420 		height = desc->height;
2421 		x = desc->dx;
2422 		y = desc->dy;
2423 		if (1 & desc->flags) {
2424 			x += ((vinfo.v_width - width) / 2);
2425 			y += ((vinfo.v_height - height) / 2);
2426 		}
2427 		vc_blit_rect( x, y, 0, width, height, width, height, width, 0, data, NULL, kDataIndexed );
2428 	}
2429 }
2430 
2431 void
vc_progress_initialize(vc_progress_element * desc,const unsigned char * data1x,const unsigned char * data2x,const unsigned char * data3x,const unsigned char * clut)2432 vc_progress_initialize( vc_progress_element * desc,
2433     const unsigned char * data1x,
2434     const unsigned char * data2x,
2435     const unsigned char * data3x,
2436     const unsigned char * clut )
2437 {
2438 	uint64_t    abstime;
2439 
2440 	if ((!clut) || (!desc) || (!data1x)) {
2441 		return;
2442 	}
2443 	vc_clut = clut;
2444 	vc_clut8 = clut;
2445 
2446 	vc_progress = desc;
2447 	vc_progress_data[0] = data1x;
2448 	vc_progress_data[1] = data2x;
2449 	vc_progress_data[2] = data3x;
2450 	if (2 & vc_progress->flags) {
2451 		vc_progress_alpha = data1x
2452 		    + vc_progress->count * vc_progress->width * vc_progress->height;
2453 	} else {
2454 		vc_progress_alpha = NULL;
2455 	}
2456 
2457 	thread_call_setup(&vc_progress_call, vc_progress_task, NULL);
2458 	clock_interval_to_absolutetime_interval(vc_progress->time, 1000 * 1000, &abstime);
2459 	vc_progress_interval = (uint32_t)abstime;
2460 
2461 #if defined(XNU_TARGET_OS_OSX)
2462 	thread_call_setup(&vc_progressmeter_call, vc_progressmeter_task, NULL);
2463 	clock_interval_to_absolutetime_interval(1000 / 8, 1000 * 1000, &abstime);
2464 	vc_progressmeter_interval = (uint32_t)abstime;
2465 #endif  /* defined(XNU_TARGET_OS_OSX) */
2466 }
2467 
2468 void
vc_progress_set(boolean_t enable,uint32_t vc_delay)2469 vc_progress_set(boolean_t enable, uint32_t vc_delay)
2470 {
2471 	void             *saveBuf = NULL;
2472 	vm_size_t        saveLen = 0;
2473 	unsigned int     count;
2474 	unsigned int     index;
2475 	unsigned char    pdata8;
2476 	unsigned short   pdata16;
2477 	unsigned short * buf16;
2478 	unsigned int     pdata32;
2479 	unsigned int *   buf32;
2480 
2481 	if (!vc_progress) {
2482 		return;
2483 	}
2484 
2485 #if defined(CONFIG_VC_PROGRESS_METER_SUPPORT)
2486 
2487 #if defined (__x86_64__)
2488 	if (kBootArgsFlagBlack & ((boot_args *) PE_state.bootArgs)->flags) {
2489 		return;
2490 	}
2491 #endif /* defined (__x86_64__) */
2492 
2493 	if (1 & vc_progress_withmeter) {
2494 		if (enable) {
2495 			internal_enable_progressmeter(kProgressMeterKernel);
2496 		}
2497 
2498 		simple_lock(&vc_progress_lock, LCK_GRP_NULL);
2499 
2500 		if (vc_progress_enable != enable) {
2501 			vc_progress_enable = enable;
2502 			if (enable) {
2503 				vc_progressmeter_count = 0;
2504 				clock_interval_to_deadline(vc_delay,
2505 				    1000 * 1000 * 1000 /*second scale*/,
2506 				    &vc_progressmeter_deadline);
2507 				thread_call_enter_delayed(&vc_progressmeter_call, vc_progressmeter_deadline);
2508 			} else {
2509 				thread_call_cancel(&vc_progressmeter_call);
2510 			}
2511 		}
2512 
2513 		simple_unlock(&vc_progress_lock);
2514 
2515 		if (!enable) {
2516 			internal_enable_progressmeter(kProgressMeterOff);
2517 		}
2518 		return;
2519 	}
2520 
2521 #endif /* defined(CONFIG_VC_PROGRESS_METER_SUPPORT) */
2522 
2523 	if (enable) {
2524 		saveLen = (vc_progress->width * vc_uiscale) * (vc_progress->height * vc_uiscale) * ((vinfo.v_depth + 7) / 8);
2525 		saveBuf = kalloc_data(saveLen, Z_WAITOK);
2526 
2527 		switch (vinfo.v_depth) {
2528 		case 8:
2529 			for (count = 0; count < 256; count++) {
2530 				vc_revclut8[count] = vc_clut[0x01 * 3];
2531 				pdata8 = (vc_clut[0x01 * 3] * count + 0x0ff) >> 8;
2532 				for (index = 0; index < 256; index++) {
2533 					if ((pdata8 == vc_clut[index * 3 + 0]) &&
2534 					    (pdata8 == vc_clut[index * 3 + 1]) &&
2535 					    (pdata8 == vc_clut[index * 3 + 2])) {
2536 						vc_revclut8[count] = index;
2537 						break;
2538 					}
2539 				}
2540 			}
2541 			memset( saveBuf, 0x01, saveLen );
2542 			break;
2543 
2544 		case 16:
2545 			buf16 = (unsigned short *) saveBuf;
2546 			pdata16 = ((vc_clut[0x01 * 3 + 0] & CLUT_MASK_R)CLUT_SHIFT_R)
2547 			    | ((vc_clut[0x01 * 3 + 0] & CLUT_MASK_G)CLUT_SHIFT_G)
2548 			    | ((vc_clut[0x01 * 3 + 0] & CLUT_MASK_B)CLUT_SHIFT_B);
2549 			for (count = 0; count < saveLen / 2; count++) {
2550 				buf16[count] = pdata16;
2551 			}
2552 			break;
2553 
2554 		case 32:
2555 			buf32 = (unsigned int *) saveBuf;
2556 			pdata32 = ((vc_clut[0x01 * 3 + 0] & 0xff) << 16)
2557 			    | ((vc_clut[0x01 * 3 + 1] & 0xff) << 8)
2558 			    | ((vc_clut[0x01 * 3 + 2] & 0xff) << 0);
2559 			for (count = 0; count < saveLen / 4; count++) {
2560 				buf32[count] = pdata32;
2561 			}
2562 			break;
2563 		}
2564 	}
2565 
2566 	simple_lock(&vc_progress_lock, LCK_GRP_NULL);
2567 
2568 	if (vc_progress_enable != enable) {
2569 		vc_progress_enable = enable;
2570 		if (enable) {
2571 			vc_needsave      = TRUE;
2572 			vc_saveunder     = saveBuf;
2573 			vc_saveunder_len = saveLen;
2574 			saveBuf               = NULL;
2575 			saveLen           = 0;
2576 			vc_progress_count = 0;
2577 			vc_progress_angle = 0;
2578 
2579 			clock_interval_to_deadline(vc_delay,
2580 			    1000 * 1000 * 1000 /*second scale*/,
2581 			    &vc_progress_deadline);
2582 			thread_call_enter_delayed(&vc_progress_call, vc_progress_deadline);
2583 		} else {
2584 			if (vc_saveunder) {
2585 				saveBuf      = vc_saveunder;
2586 				saveLen      = vc_saveunder_len;
2587 				vc_saveunder = NULL;
2588 				vc_saveunder_len = 0;
2589 			}
2590 
2591 			thread_call_cancel(&vc_progress_call);
2592 		}
2593 	}
2594 
2595 	simple_unlock(&vc_progress_lock);
2596 
2597 	kfree_data(saveBuf, saveLen);
2598 }
2599 
2600 #if defined(XNU_TARGET_OS_OSX)
2601 
2602 static uint32_t
vc_progressmeter_range(uint32_t pos)2603 vc_progressmeter_range(uint32_t pos)
2604 {
2605 	uint32_t ret;
2606 
2607 	if (pos > kProgressMeterEnd) {
2608 		pos = kProgressMeterEnd;
2609 	}
2610 	ret = vc_progress_meter_start
2611 	    + ((pos * (vc_progress_meter_end - vc_progress_meter_start)) / kProgressMeterEnd);
2612 
2613 	return ret;
2614 }
2615 
2616 static void
vc_progressmeter_task(__unused void * arg0,__unused void * arg)2617 vc_progressmeter_task(__unused void *arg0, __unused void *arg)
2618 {
2619 	uint64_t interval;
2620 
2621 	simple_lock(&vc_progress_lock, LCK_GRP_NULL);
2622 	if (kProgressMeterKernel == vc_progressmeter_enable) {
2623 		uint32_t pos = (vc_progressmeter_count >> 13);
2624 		internal_set_progressmeter(vc_progressmeter_range(pos));
2625 		if (pos < kProgressMeterEnd) {
2626 			static uint16_t incr[8] = { 10000, 10000, 8192, 4096, 2048, 384, 384, 64 };
2627 			vc_progressmeter_count += incr[(pos * 8) / kProgressMeterEnd];
2628 
2629 			interval = vc_progressmeter_interval;
2630 			interval = ((interval * 256) / vc_progressmeter_diskspeed);
2631 
2632 			clock_deadline_for_periodic_event(interval, mach_absolute_time(), &vc_progressmeter_deadline);
2633 			thread_call_enter_delayed(&vc_progressmeter_call, vc_progressmeter_deadline);
2634 		}
2635 	}
2636 	simple_unlock(&vc_progress_lock);
2637 }
2638 
2639 void
vc_progress_setdiskspeed(uint32_t speed)2640 vc_progress_setdiskspeed(uint32_t speed)
2641 {
2642 	vc_progressmeter_diskspeed = speed;
2643 }
2644 
2645 #endif  /* defined(XNU_TARGET_OS_OSX) */
2646 
2647 static void
vc_progress_task(__unused void * arg0,__unused void * arg)2648 vc_progress_task(__unused void *arg0, __unused void *arg)
2649 {
2650 	int       x, y, width, height;
2651 	uint64_t  x_pos, y_pos;
2652 	const unsigned char * data;
2653 
2654 	simple_lock(&vc_progress_lock, LCK_GRP_NULL);
2655 
2656 	if (vc_progress_enable) {
2657 		do {
2658 			vc_progress_count++;
2659 			if (vc_progress_count >= vc_progress->count) {
2660 				vc_progress_count = 0;
2661 				vc_progress_angle++;
2662 			}
2663 
2664 			width  = (vc_progress->width * vc_uiscale);
2665 			height = (vc_progress->height * vc_uiscale);
2666 			data   = vc_progress_data[vc_uiscale - 1];
2667 			if (!data) {
2668 				break;
2669 			}
2670 
2671 			if (kVCUsePosition & vc_progress_options.options) {
2672 				/* Rotation: 0:normal, 1:right 90, 2:left 180, 3:left 90 */
2673 				switch (3 & vinfo.v_rotate) {
2674 				case kDataRotate0:
2675 					x_pos = vc_progress_options.x_pos;
2676 					y_pos = vc_progress_options.y_pos;
2677 					break;
2678 				case kDataRotate180:
2679 					x_pos = 0xFFFFFFFF - vc_progress_options.x_pos;
2680 					y_pos = 0xFFFFFFFF - vc_progress_options.y_pos;
2681 					break;
2682 				case kDataRotate90:
2683 					x_pos = 0xFFFFFFFF - vc_progress_options.y_pos;
2684 					y_pos = vc_progress_options.x_pos;
2685 					break;
2686 				case kDataRotate270:
2687 					x_pos = vc_progress_options.y_pos;
2688 					y_pos = 0xFFFFFFFF - vc_progress_options.x_pos;
2689 					break;
2690 				}
2691 				x = (uint32_t)((x_pos * (uint64_t) vinfo.v_width) / 0xFFFFFFFFULL);
2692 				y = (uint32_t)((y_pos * (uint64_t) vinfo.v_height) / 0xFFFFFFFFULL);
2693 				x -= (width / 2);
2694 				y -= (height / 2);
2695 			} else {
2696 				x = (vc_progress->dx * vc_uiscale);
2697 				y = (vc_progress->dy * vc_uiscale);
2698 				if (1 & vc_progress->flags) {
2699 					x += ((vinfo.v_width - width) / 2);
2700 					y += ((vinfo.v_height - height) / 2);
2701 				}
2702 			}
2703 
2704 			if ((x + width) > (int)vinfo.v_width) {
2705 				break;
2706 			}
2707 			if ((y + height) > (int)vinfo.v_height) {
2708 				break;
2709 			}
2710 
2711 			data += vc_progress_count * width * height;
2712 
2713 			vc_blit_rect( x, y, 0,
2714 			    width, height, width, height, width, width,
2715 			    data, vc_saveunder,
2716 			    kDataAlpha
2717 			    | (vc_progress_angle & kDataRotate)
2718 			    | (vc_needsave ? kSave : 0));
2719 			vc_needsave = FALSE;
2720 
2721 			clock_deadline_for_periodic_event(vc_progress_interval, mach_absolute_time(), &vc_progress_deadline);
2722 			thread_call_enter_delayed(&vc_progress_call, vc_progress_deadline);
2723 		}while (FALSE);
2724 	}
2725 
2726 #if SCHED_HYGIENE_DEBUG
2727 	abandon_preemption_disable_measurement();
2728 #endif /* SCHED_HYGIENE_DEBUG */
2729 
2730 	simple_unlock(&vc_progress_lock);
2731 }
2732 
2733 /*
2734  * Generic Console (Front-End): Master Control
2735  * -------------------------------------------
2736  */
2737 
2738 #if defined (__i386__) || defined (__x86_64__)
2739 #include <pexpert/i386/boot.h>
2740 #endif
2741 
2742 static boolean_t gc_acquired      = FALSE;
2743 static boolean_t gc_graphics_boot = FALSE;
2744 static boolean_t gc_desire_text   = FALSE;
2745 static boolean_t gc_paused_progress;
2746 
2747 static vm_offset_t  lastVideoVirt    = 0;
2748 static vm_size_t    lastVideoMapSize = 0;
2749 static boolean_t    lastVideoMapKmap = FALSE;
2750 
2751 static void
gc_pause(boolean_t pause,boolean_t graphics_now)2752 gc_pause( boolean_t pause, boolean_t graphics_now )
2753 {
2754 	VCPUTC_LOCK_LOCK();
2755 
2756 	disableConsoleOutput = (pause && !console_is_serial());
2757 	gc_enabled           = (!pause && !graphics_now);
2758 
2759 	VCPUTC_LOCK_UNLOCK();
2760 
2761 	simple_lock(&vc_progress_lock, LCK_GRP_NULL);
2762 
2763 	if (pause) {
2764 		gc_paused_progress = vc_progress_enable;
2765 		vc_progress_enable = FALSE;
2766 	} else {
2767 		vc_progress_enable = gc_paused_progress;
2768 	}
2769 
2770 	if (vc_progress_enable) {
2771 #if defined(XNU_TARGET_OS_OSX)
2772 		if (1 & vc_progress_withmeter) {
2773 			thread_call_enter_delayed(&vc_progressmeter_call, vc_progressmeter_deadline);
2774 		} else
2775 #endif /* defined(XNU_TARGET_OS_OSX) */
2776 		thread_call_enter_delayed(&vc_progress_call, vc_progress_deadline);
2777 	}
2778 
2779 	simple_unlock(&vc_progress_lock);
2780 }
2781 
2782 static void
vc_initialize(__unused struct vc_info * vinfo_p)2783 vc_initialize(__unused struct vc_info * vinfo_p)
2784 {
2785 	vinfo.v_rows = vinfo.v_height / ISO_CHAR_HEIGHT;
2786 	vinfo.v_columns = vinfo.v_width / ISO_CHAR_WIDTH;
2787 	vinfo.v_rowscanbytes = ((vinfo.v_depth + 7) / 8) * vinfo.v_width;
2788 	vc_uiscale = vinfo.v_scale;
2789 	if (vc_uiscale > kMaxProgressData) {
2790 		vc_uiscale = kMaxProgressData;
2791 	} else if (!vc_uiscale) {
2792 		vc_uiscale = 1;
2793 	}
2794 }
2795 
2796 void
initialize_screen(PE_Video * boot_vinfo,unsigned int op)2797 initialize_screen(PE_Video * boot_vinfo, unsigned int op)
2798 {
2799 	unsigned int newMapSize = 0;
2800 	vm_offset_t newVideoVirt = 0;
2801 	boolean_t graphics_now;
2802 	uint32_t delay;
2803 
2804 	if (boot_vinfo) {
2805 		struct vc_info new_vinfo = vinfo;
2806 		boolean_t makeMapping = FALSE;
2807 
2808 		/*
2809 		 *	Copy parameters
2810 		 */
2811 		if (kPEBaseAddressChange != op) {
2812 			new_vinfo.v_width    = (unsigned int)boot_vinfo->v_width;
2813 			new_vinfo.v_height   = (unsigned int)boot_vinfo->v_height;
2814 			new_vinfo.v_depth    = (unsigned int)boot_vinfo->v_depth;
2815 			new_vinfo.v_rowbytes = (unsigned int)boot_vinfo->v_rowBytes;
2816 			if (kernel_map == VM_MAP_NULL) {
2817 				// only booter supplies HW rotation
2818 				new_vinfo.v_rotate   = (unsigned int)boot_vinfo->v_rotate;
2819 			}
2820 #if defined(__i386__) || defined(__x86_64__)
2821 			new_vinfo.v_type     = (unsigned int)boot_vinfo->v_display;
2822 #else
2823 			new_vinfo.v_type = 0;
2824 #endif
2825 			unsigned int scale   = (unsigned int)boot_vinfo->v_scale;
2826 			if (scale == kPEScaleFactor1x) {
2827 				new_vinfo.v_scale = kPEScaleFactor1x;
2828 			} else if (scale == kPEScaleFactor2x) {
2829 				new_vinfo.v_scale = kPEScaleFactor2x;
2830 			}
2831 			else { /* Scale factor not set, default to 1x */
2832 				new_vinfo.v_scale = kPEScaleFactor1x;
2833 			}
2834 		}
2835 		new_vinfo.v_name[0]  = 0;
2836 		new_vinfo.v_physaddr = 0;
2837 
2838 		/*
2839 		 *  Check if we are have to map the framebuffer
2840 		 *  If VM is up, we are given a virtual address, unless b0 is set to indicate physical.
2841 		 */
2842 		newVideoVirt = boot_vinfo->v_baseAddr;
2843 		makeMapping = (kernel_map == VM_MAP_NULL) || (0 != (1 & newVideoVirt));
2844 		if (makeMapping) {
2845 			newVideoVirt = 0;
2846 			new_vinfo.v_physaddr = boot_vinfo->v_baseAddr & ~3UL;           /* Get the physical address */
2847 #ifndef __LP64__
2848 			new_vinfo.v_physaddr |= (((uint64_t) boot_vinfo->v_baseAddrHigh) << 32);
2849 #endif
2850 			kprintf("initialize_screen: b=%08llX, w=%08X, h=%08X, r=%08X, d=%08X\n",                  /* (BRINGUP) */
2851 			    new_vinfo.v_physaddr, new_vinfo.v_width, new_vinfo.v_height, new_vinfo.v_rowbytes, new_vinfo.v_type);       /* (BRINGUP) */
2852 		}
2853 
2854 		if (!newVideoVirt && !new_vinfo.v_physaddr) {                                                   /* Check to see if we have a framebuffer */
2855 			kprintf("initialize_screen: No video - forcing serial mode\n");         /* (BRINGUP) */
2856 			new_vinfo.v_depth = 0;                                          /* vc routines are nop */
2857 			(void)switch_to_serial_console();                               /* Switch into serial mode */
2858 			gc_graphics_boot = FALSE;                                       /* Say we are not in graphics mode */
2859 			disableConsoleOutput = FALSE;                                   /* Allow printfs to happen */
2860 			gc_acquired = TRUE;
2861 		} else {
2862 			if (makeMapping) {
2863 #if HAS_UCNORMAL_MEM
2864 				/*
2865 				 * Framebuffers would normally use VM_WIMG_RT, which
2866 				 * io_map doesn't support.  However this buffer is set up
2867 				 * by the bootloader and doesn't require D$ cleaning, so
2868 				 * VM_WIMG_RT and VM_WIMG_WCOMB are functionally
2869 				 * equivalent.
2870 				 */
2871 				unsigned int flags = VM_WIMG_WCOMB;
2872 #else
2873 				unsigned int flags = VM_WIMG_IO;
2874 #endif
2875 				if (boot_vinfo->v_length != 0) {
2876 					newMapSize = (unsigned int) round_page(boot_vinfo->v_length);
2877 				} else {
2878 					newMapSize = (unsigned int) round_page(new_vinfo.v_height * new_vinfo.v_rowbytes);                      /* Remember size */
2879 				}
2880 				newVideoVirt = ml_io_map_unmappable((vm_map_offset_t)new_vinfo.v_physaddr, newMapSize, flags);   /* Allocate address space for framebuffer */
2881 			}
2882 			new_vinfo.v_baseaddr = newVideoVirt + boot_vinfo->v_offset;                     /* Set the new framebuffer address */
2883 		}
2884 
2885 #if defined(__x86_64__)
2886 		// Adjust the video buffer pointer to point to where it is in high virtual (above the hole)
2887 		new_vinfo.v_baseaddr |= (VM_MIN_KERNEL_ADDRESS & ~LOW_4GB_MASK);
2888 #endif
2889 
2890 		/* Update the vinfo structure atomically with respect to the vc_progress task if running */
2891 		if (vc_progress) {
2892 			simple_lock(&vc_progress_lock, LCK_GRP_NULL);
2893 			vinfo = new_vinfo;
2894 			simple_unlock(&vc_progress_lock);
2895 		} else {
2896 			vinfo = new_vinfo;
2897 		}
2898 
2899 		// If we changed the virtual address, remove the old mapping
2900 		if (newVideoVirt != 0) {
2901 			if (lastVideoVirt && lastVideoMapSize) {                                                /* Was the framebuffer mapped before? */
2902 				/* XXX why only !4K? */
2903 				if (!TEST_PAGE_SIZE_4K && lastVideoMapSize) {
2904 					pmap_remove(kernel_pmap, trunc_page_64(lastVideoVirt),
2905 					    round_page_64(lastVideoVirt + lastVideoMapSize));           /* Toss mappings */
2906 				}
2907 				/* Was this not a special pre-VM mapping? */
2908 				if (lastVideoMapKmap) {
2909 					kmem_free(kernel_map, lastVideoVirt, lastVideoMapSize); /* Toss kernel addresses */
2910 				}
2911 			}
2912 			lastVideoMapKmap = (NULL != kernel_map);                /* Remember how mapped */
2913 			lastVideoMapSize = newMapSize;                                  /* Remember the size */
2914 			lastVideoVirt    = newVideoVirt;                                /* Remember the virtual framebuffer address */
2915 		}
2916 
2917 		if (kPEBaseAddressChange != op) {
2918 			// Graphics mode setup by the booter.
2919 
2920 			gc_ops.initialize   = vc_initialize;
2921 			gc_ops.enable       = vc_enable;
2922 			gc_ops.paint_char   = vc_paint_char;
2923 			gc_ops.scroll_down  = vc_scroll_down;
2924 			gc_ops.scroll_up    = vc_scroll_up;
2925 			gc_ops.clear_screen = vc_clear_screen;
2926 			gc_ops.hide_cursor  = vc_reverse_cursor;
2927 			gc_ops.show_cursor  = vc_reverse_cursor;
2928 			gc_ops.update_color = vc_update_color;
2929 			gc_initialize(&vinfo);
2930 		}
2931 	}
2932 
2933 	graphics_now = gc_graphics_boot && !gc_desire_text;
2934 	switch (op) {
2935 	case kPEGraphicsMode:
2936 		gc_graphics_boot = TRUE;
2937 		gc_desire_text = FALSE;
2938 		break;
2939 
2940 	case kPETextMode:
2941 		gc_graphics_boot = FALSE;
2942 		break;
2943 
2944 	case kPEAcquireScreen:
2945 		if (gc_acquired) {
2946 			break;
2947 		}
2948 
2949 		vc_progress_options = vc_user_options;
2950 		bzero(&vc_user_options, sizeof(vc_user_options));
2951 
2952 		if (kVCAcquireImmediate & vc_progress_options.options) {
2953 			delay = 0;
2954 		} else if (kVCDarkReboot & vc_progress_options.options) {
2955 			delay = 120;
2956 		} else {
2957 			delay = vc_acquire_delay;
2958 		}
2959 
2960 		if (kVCDarkBackground & vc_progress_options.options) {
2961 			vc_progress_white = TRUE;
2962 		} else if (kVCLightBackground & vc_progress_options.options) {
2963 			vc_progress_white = FALSE;
2964 		}
2965 
2966 #if !defined(XNU_TARGET_OS_BRIDGE)
2967 		vc_progress_set( graphics_now, delay );
2968 #endif /* !defined(XNU_TARGET_OS_BRIDGE) */
2969 		gc_enable( !graphics_now );
2970 		gc_acquired = TRUE;
2971 		gc_desire_text = FALSE;
2972 		break;
2973 
2974 	case kPEDisableScreen:
2975 		if (gc_acquired) {
2976 			gc_pause( TRUE, graphics_now );
2977 		}
2978 		break;
2979 
2980 	case kPEEnableScreen:
2981 		if (gc_acquired) {
2982 			gc_pause( FALSE, graphics_now );
2983 		}
2984 		break;
2985 
2986 	case kPETextScreen:
2987 		if (console_is_serial()) {
2988 			break;
2989 		}
2990 
2991 		if (gc_acquired == FALSE) {
2992 			gc_desire_text = TRUE;
2993 			break;
2994 		}
2995 		if (gc_graphics_boot == FALSE) {
2996 			break;
2997 		}
2998 
2999 		vc_progress_set( FALSE, 0 );
3000 #if defined(XNU_TARGET_OS_OSX)
3001 		vc_enable_progressmeter( FALSE );
3002 #endif
3003 		gc_enable( TRUE );
3004 		break;
3005 
3006 	case kPEReleaseScreen:
3007 		gc_acquired = FALSE;
3008 		gc_desire_text = FALSE;
3009 		gc_enable( FALSE );
3010 		if (gc_graphics_boot == FALSE) {
3011 			break;
3012 		}
3013 
3014 		vc_progress_set( FALSE, 0 );
3015 		vc_acquire_delay = kProgressReacquireDelay;
3016 		vc_progress_white      = TRUE;
3017 #if defined(XNU_TARGET_OS_OSX)
3018 		vc_enable_progressmeter(FALSE);
3019 		vc_progress_withmeter &= ~1;
3020 #endif
3021 		vc_clut8 = NULL;
3022 		break;
3023 
3024 
3025 #if defined(__x86_64__)
3026 	case kPERefreshBootGraphics:
3027 	{
3028 		boolean_t save;
3029 
3030 		if (kBootArgsFlagBlack & ((boot_args *) PE_state.bootArgs)->flags) {
3031 			break;
3032 		}
3033 
3034 		save = vc_progress_white;
3035 		vc_progress_white = (0 != (kBootArgsFlagBlackBg & ((boot_args *) PE_state.bootArgs)->flags));
3036 
3037 		internal_enable_progressmeter(kProgressMeterKernel);
3038 
3039 		simple_lock(&vc_progress_lock, LCK_GRP_NULL);
3040 
3041 		vc_progressmeter_drawn = 0;
3042 		internal_set_progressmeter(vc_progressmeter_range(vc_progressmeter_count >> 13));
3043 
3044 		simple_unlock(&vc_progress_lock);
3045 
3046 		internal_enable_progressmeter(kProgressMeterOff);
3047 		vc_progress_white = save;
3048 	}
3049 #endif
3050 	}
3051 }
3052 
3053 void vcattach(void); /* XXX gcc 4 warning cleanup */
3054 
3055 void
vcattach(void)3056 vcattach(void)
3057 {
3058 	vm_initialized = TRUE;
3059 
3060 #if defined(CONFIG_VC_PROGRESS_METER_SUPPORT)
3061 	const boot_args * bootargs  = (typeof(bootargs))PE_state.bootArgs;
3062 
3063 	PE_parse_boot_argn("meter", &vc_progress_withmeter, sizeof(vc_progress_withmeter));
3064 
3065 #if defined(__x86_64__)
3066 	vc_progress_white = (0 != ((kBootArgsFlagBlackBg | kBootArgsFlagLoginUI)
3067 	    & bootargs->flags));
3068 	if (kBootArgsFlagInstallUI & bootargs->flags) {
3069 		vc_progress_meter_start = (bootargs->bootProgressMeterStart * kProgressMeterMax) / 65535;
3070 		vc_progress_meter_end   = (bootargs->bootProgressMeterEnd   * kProgressMeterMax) / 65535;
3071 	} else {
3072 		vc_progress_meter_start = 0;
3073 		vc_progress_meter_end   = kProgressMeterEnd;
3074 	}
3075 #else
3076 	vc_progress_meter_start = 0;
3077 	vc_progress_meter_end   = kProgressMeterEnd;
3078 #endif /* defined(__x86_64__ */
3079 #endif /* defined(CONFIG_VC_PROGRESS_METER_SUPPORT) */
3080 	simple_lock_init(&vc_progress_lock, 0);
3081 
3082 	if (gc_graphics_boot == FALSE) {
3083 		long index;
3084 
3085 		if (gc_acquired) {
3086 			initialize_screen(NULL, kPEReleaseScreen);
3087 		}
3088 
3089 		initialize_screen(NULL, kPEAcquireScreen);
3090 
3091 		for (index = 0; index < msgbufp->msg_bufx; index++) {
3092 			if (msgbufp->msg_bufc[index] == '\0') {
3093 				continue;
3094 			}
3095 
3096 			vcputc( msgbufp->msg_bufc[index] );
3097 
3098 			if (msgbufp->msg_bufc[index] == '\n') {
3099 				vcputc( '\r' );
3100 			}
3101 		}
3102 	}
3103 }
3104 
3105 #if defined(XNU_TARGET_OS_OSX)
3106 
3107 // redraw progress meter between pixels start, end, position at pos,
3108 // options (including rotation) passed in flags
3109 static void
vc_draw_progress_meter(unsigned int flags,int start,int end,int pos)3110 vc_draw_progress_meter(unsigned int flags, int start, int end, int pos)
3111 {
3112 	const unsigned char *data;
3113 	int i, width, bx, srcRow, backRow;
3114 	int rectX, rectY, rectW, rectH;
3115 	int endCapPos, endCapStart;
3116 	int barWidth  = kProgressBarWidth * vc_uiscale;
3117 	int barHeight = kProgressBarHeight * vc_uiscale;
3118 	int capWidth  = kProgressBarCapWidth * vc_uiscale;
3119 	// 1 rounded fill, 0 square end
3120 	int style = (0 == (2 & vc_progress_withmeter));
3121 	// 1 white, 0 greyed out
3122 	int onoff;
3123 
3124 	for (i = start; i < end; i += width) {
3125 		onoff       = (i < pos);
3126 		endCapPos   = ((style && onoff) ? pos : barWidth);
3127 		endCapStart = endCapPos - capWidth;
3128 		if (flags & kDataBack) { // restore back bits
3129 			width   = end;// loop done after this iteration
3130 			data    = NULL;
3131 			srcRow  = 0;
3132 		} else if (i < capWidth) { // drawing the left cap
3133 			width   = (end < capWidth) ? (end - i) : (capWidth - i);
3134 			data    = progressmeter_leftcap[vc_uiscale >= 2][onoff];
3135 			data    += i;
3136 			srcRow  = capWidth;
3137 		} else if (i < endCapStart) { // drawing the middle
3138 			width   = (end < endCapStart) ? (end - i) : (endCapStart - i);
3139 			data    = progressmeter_middle[vc_uiscale >= 2][onoff];
3140 			srcRow  = 1;
3141 		} else { // drawing the right cap
3142 			width   = endCapPos - i;
3143 			data    = progressmeter_rightcap[vc_uiscale >= 2][onoff];
3144 			data    += i - endCapStart;
3145 			srcRow  = capWidth;
3146 		}
3147 
3148 		switch (flags & kDataRotate) {
3149 		case kDataRotate90: // left middle, bar goes down
3150 			rectW   = barHeight;
3151 			rectH   = width;
3152 			rectX   = (6 * vinfo.v_width) / 100 + 34 * vc_uiscale - (barHeight / 2);
3153 			rectY   = ((vinfo.v_height - barWidth) / 2) + i;
3154 			bx      = i * barHeight;
3155 			backRow = barHeight;
3156 			break;
3157 		case kDataRotate180: // middle upper, bar goes left
3158 			rectW   = width;
3159 			rectH   = barHeight;
3160 			rectX   = ((vinfo.v_width - barWidth) / 2) + barWidth - width - i;
3161 			rectY   = (6 * vinfo.v_height) / 100 + 34 * vc_uiscale - (barHeight / 2);
3162 			bx      = barWidth - width - i;
3163 			backRow = barWidth;
3164 			break;
3165 		case kDataRotate270: // right middle, bar goes up
3166 			rectW   = barHeight;
3167 			rectH   = width;
3168 			rectX   = (94 * vinfo.v_width) / 100 - 34 * vc_uiscale - (barHeight / 2);
3169 			rectY   = ((vinfo.v_height - barWidth) / 2) + barWidth - width - i;
3170 			bx      = (barWidth - width - i) * barHeight;
3171 			backRow = barHeight;
3172 			break;
3173 		default:
3174 		case kDataRotate0: // middle lower, bar goes right
3175 			rectW   = width;
3176 			rectH   = barHeight;
3177 			rectX   = ((vinfo.v_width - barWidth) / 2) + i;
3178 			rectY   = (94 * vinfo.v_height) / 100 - 34 * vc_uiscale - (barHeight / 2);
3179 			bx      = i;
3180 			backRow = barWidth;
3181 			break;
3182 		}
3183 		vc_blit_rect(rectX, rectY, bx, rectW, rectH, width, barHeight,
3184 		    srcRow, backRow, data, vc_progressmeter_backbuffer, flags);
3185 	}
3186 }
3187 
3188 extern void IORecordProgressBackbuffer(void * buffer, size_t size, uint32_t theme);
3189 
3190 static void
internal_enable_progressmeter(int new_value)3191 internal_enable_progressmeter(int new_value)
3192 {
3193 	void    * new_buffer;
3194 	boolean_t stashBackbuffer;
3195 	int flags = vinfo.v_rotate;
3196 
3197 	stashBackbuffer = FALSE;
3198 	new_buffer = NULL;
3199 	if (new_value) {
3200 		new_buffer = kalloc_data((kProgressBarWidth * vc_uiscale) *
3201 		    (kProgressBarHeight * vc_uiscale) * sizeof(int), Z_WAITOK);
3202 	}
3203 
3204 	simple_lock(&vc_progress_lock, LCK_GRP_NULL);
3205 
3206 	if (kProgressMeterUser == new_value) {
3207 		if (gc_enabled || !gc_acquired || !gc_graphics_boot) {
3208 			new_value = vc_progressmeter_enable;
3209 		}
3210 	}
3211 
3212 	if (new_value != vc_progressmeter_enable) {
3213 		if (new_value) {
3214 			if (kProgressMeterOff == vc_progressmeter_enable) {
3215 				vc_progressmeter_backbuffer = new_buffer;
3216 				vc_draw_progress_meter(kDataAlpha | kSave | flags, 0, (kProgressBarWidth * vc_uiscale), 0);
3217 				new_buffer = NULL;
3218 				vc_progressmeter_drawn = 0;
3219 			}
3220 			vc_progressmeter_enable = new_value;
3221 		} else if (vc_progressmeter_backbuffer) {
3222 			if (kProgressMeterUser == vc_progressmeter_enable) {
3223 				vc_draw_progress_meter(kDataBack | flags, 0, (kProgressBarWidth * vc_uiscale), vc_progressmeter_drawn);
3224 			} else {
3225 				stashBackbuffer = TRUE;
3226 			}
3227 			new_buffer = vc_progressmeter_backbuffer;
3228 			vc_progressmeter_backbuffer = NULL;
3229 			vc_progressmeter_enable = FALSE;
3230 		}
3231 	}
3232 
3233 	simple_unlock(&vc_progress_lock);
3234 
3235 	if (new_buffer) {
3236 		if (stashBackbuffer) {
3237 			IORecordProgressBackbuffer(new_buffer,
3238 			    (kProgressBarWidth * vc_uiscale)
3239 			    * (kProgressBarHeight * vc_uiscale)
3240 			    * sizeof(int),
3241 			    vc_progress_white);
3242 		}
3243 		kfree_data(new_buffer, (kProgressBarWidth * vc_uiscale) *
3244 		    (kProgressBarHeight * vc_uiscale) * sizeof(int));
3245 	}
3246 }
3247 
3248 static void
internal_set_progressmeter(int new_value)3249 internal_set_progressmeter(int new_value)
3250 {
3251 	int x1, x3;
3252 	int capRedraw;
3253 	// 1 rounded fill, 0 square end
3254 	int style = (0 == (2 & vc_progress_withmeter));
3255 	int flags = kDataAlpha | vinfo.v_rotate;
3256 
3257 	if ((new_value < 0) || (new_value > kProgressMeterMax)) {
3258 		return;
3259 	}
3260 
3261 	if (vc_progressmeter_enable) {
3262 		vc_progressmeter_value = new_value;
3263 
3264 		capRedraw = (style ? (kProgressBarCapWidth * vc_uiscale) : 0);
3265 		x3 = (((kProgressBarWidth * vc_uiscale) - 2 * capRedraw) * vc_progressmeter_value) / kProgressMeterMax;
3266 		x3 += (2 * capRedraw);
3267 
3268 		if (x3 > vc_progressmeter_drawn) {
3269 			x1 = capRedraw;
3270 			if (x1 > vc_progressmeter_drawn) {
3271 				x1 = vc_progressmeter_drawn;
3272 			}
3273 			vc_draw_progress_meter(flags, vc_progressmeter_drawn - x1, x3, x3);
3274 		} else {
3275 			vc_draw_progress_meter(flags, x3 - capRedraw, vc_progressmeter_drawn, x3);
3276 		}
3277 		vc_progressmeter_drawn = x3;
3278 	}
3279 }
3280 
3281 void
vc_enable_progressmeter(int new_value)3282 vc_enable_progressmeter(int new_value)
3283 {
3284 	internal_enable_progressmeter(new_value ? kProgressMeterUser : kProgressMeterOff);
3285 }
3286 
3287 void
vc_set_progressmeter(int new_value)3288 vc_set_progressmeter(int new_value)
3289 {
3290 	simple_lock(&vc_progress_lock, LCK_GRP_NULL);
3291 
3292 	if (vc_progressmeter_enable) {
3293 		if (kProgressMeterKernel != vc_progressmeter_enable) {
3294 			internal_set_progressmeter(new_value);
3295 		}
3296 	} else {
3297 		vc_progressmeter_value = new_value;
3298 	}
3299 
3300 	simple_unlock(&vc_progress_lock);
3301 }
3302 
3303 #endif /* defined(XNU_TARGET_OS_OSX) */
3304