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