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