This is xnu-11215.1.10. See this file in:
/*
* Copyright (c) 2000-2020 Apple Inc. All rights reserved.
*
* @APPLE_OSREFERENCE_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. The rights granted to you under the License
* may not be used to create, or enable the creation or redistribution of,
* unlawful or unlicensed copies of an Apple operating system, or to
* circumvent, violate, or enable the circumvention or violation of, any
* terms of an Apple operating system software license agreement.
*
* Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_OSREFERENCE_LICENSE_HEADER_END@
*/
/*
* @OSF_FREE_COPYRIGHT@
*
*/
/*
* @APPLE_FREE_COPYRIGHT@
*/
/*
* NetBSD: ite.c,v 1.16 1995/07/17 01:24:34 briggs Exp
*
* Copyright (c) 1988 University of Utah.
* Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* the Systems Programming Group of the University of Utah Computer
* Science Department.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* from: Utah $Hdr: ite.c 1.28 92/12/20$
*
* @(#)ite.c 8.2 (Berkeley) 1/12/94
*/
/*
* ite.c
*
* The ite module handles the system console; that is, stuff printed
* by the kernel and by user programs while "desktop" and X aren't
* running. Some (very small) parts are based on hp300's 4.4 ite.c,
* hence the above copyright.
*
* -- Brad and Lawrence, June 26th, 1994
*
*/
#include <console/video_console.h>
#include <console/serial_protos.h>
#include <kern/kern_types.h>
#include <kern/kalloc.h>
#include <kern/debug.h>
#include <kern/thread_call.h>
#include <vm/pmap.h>
#include <vm/vm_kern_xnu.h>
#include <machine/machine_cpu.h>
#include <pexpert/pexpert.h>
#include <sys/kdebug.h>
#include "iso_font.c"
#if defined(XNU_TARGET_OS_OSX)
#include "progress_meter_data.c"
#endif
#include "sys/msgbuf.h"
/*
* Generic Console (Front-End)
* ---------------------------
*/
struct vc_info vinfo;
void noroot_icon_test(void);
extern int disableConsoleOutput;
static boolean_t gc_enabled = FALSE;
static boolean_t gc_initialized = FALSE;
static boolean_t vm_initialized = FALSE;
static struct {
void (*initialize)(struct vc_info * info);
void (*enable)(boolean_t enable);
void (*paint_char)(unsigned int xx, unsigned int yy, unsigned char ch,
int attrs, unsigned char ch_previous,
int attrs_previous);
void (*clear_screen)(unsigned int xx, unsigned int yy, unsigned int top,
unsigned int bottom, int which);
void (*scroll_down)(int num, unsigned int top, unsigned int bottom);
void (*scroll_up)(int num, unsigned int top, unsigned int bottom);
void (*hide_cursor)(unsigned int xx, unsigned int yy);
void (*show_cursor)(unsigned int xx, unsigned int yy);
void (*update_color)(int color, boolean_t fore);
} gc_ops;
static unsigned char *gc_buffer_attributes;
static unsigned char *gc_buffer_characters;
static unsigned char *gc_buffer_colorcodes;
static unsigned char *gc_buffer_tab_stops;
static uint32_t gc_buffer_columns;
static uint32_t gc_buffer_rows;
static uint32_t gc_buffer_size;
LCK_GRP_DECLARE(vconsole_lck_grp, "vconsole");
static lck_ticket_t vcputc_lock;
#define VCPUTC_LOCK_INIT() \
MACRO_BEGIN \
lck_ticket_init(&vcputc_lock, &vconsole_lck_grp); \
MACRO_END
#define VCPUTC_LOCK_LOCK() \
MACRO_BEGIN \
lck_ticket_lock(&vcputc_lock, &vconsole_lck_grp); \
MACRO_END
#define VCPUTC_LOCK_UNLOCK() \
MACRO_BEGIN \
lck_ticket_unlock(&vcputc_lock); \
MACRO_END
/*
# Attribute codes:
# 00=none 01=bold 04=underscore 05=blink 07=reverse 08=concealed
# Text color codes:
# 30=black 31=red 32=green 33=yellow 34=blue 35=magenta 36=cyan 37=white
# Background color codes:
# 40=black 41=red 42=green 43=yellow 44=blue 45=magenta 46=cyan 47=white
*/
#define ATTR_NONE 0
#define ATTR_BOLD 1
#define ATTR_UNDER 2
#define ATTR_REVERSE 4
#define COLOR_BACKGROUND 0
#define COLOR_FOREGROUND 7
#define COLOR_CODE_GET(code, fore) (((code) & ((fore) ? 0xF0 : 0x0F)) >> ((fore) ? 4 : 0))
#define COLOR_CODE_SET(code, color, fore) (((code) & ((fore) ? 0x0F : 0xF0)) | ((color) << ((fore) ? 4 : 0)))
static unsigned char gc_color_code;
/* VT100 state: */
#define MAXPARS 16
static unsigned int gc_x, gc_y, gc_savex, gc_savey;
static unsigned int gc_par[MAXPARS], gc_numpars, gc_hanging_cursor, gc_attr, gc_saveattr;
/* VT100 scroll region */
static unsigned int gc_scrreg_top, gc_scrreg_bottom;
enum vt100state_e {
ESnormal, /* Nothing yet */
ESesc, /* Got ESC */
ESsquare, /* Got ESC [ */
ESgetpars, /* About to get or getting the parameters */
ESgotpars, /* Finished getting the parameters */
ESfunckey, /* Function key */
EShash, /* DEC-specific stuff (screen align, etc.) */
ESsetG0, /* Specify the G0 character set */
ESsetG1, /* Specify the G1 character set */
ESask,
EScharsize,
ESignore /* Ignore this sequence */
} gc_vt100state = ESnormal;
enum{
/* secs */
kProgressAcquireDelay = 0,
kProgressReacquireDelay = (12 * 60 * 60), /* 12 hrs, ie. disabled unless overridden
* by kVCAcquireImmediate */
};
static int8_t vc_rotate_matr[4][2][2] = {
{ { 1, 0 },
{ 0, 1 } },
{ { 0, 1 },
{ -1, 0 } },
{ { -1, 0 },
{ 0, -1 } },
{ { 0, -1 },
{ 1, 0 } }
};
static int gc_wrap_mode = 1, gc_relative_origin = 0;
static int gc_charset_select = 0, gc_save_charset_s = 0;
static int gc_charset[2] = { 0, 0 };
static int gc_charset_save[2] = { 0, 0 };
static void gc_clear_line(unsigned int xx, unsigned int yy, int which);
static void gc_clear_screen(unsigned int xx, unsigned int yy, int top,
unsigned int bottom, int which);
static void gc_enable(boolean_t enable);
static void gc_hide_cursor(unsigned int xx, unsigned int yy);
static void gc_initialize(struct vc_info * info);
static boolean_t gc_is_tab_stop(unsigned int column);
static void gc_paint_char(unsigned int xx, unsigned int yy, unsigned char ch,
int attrs);
static void gc_putchar(char ch);
static void gc_putc_askcmd(unsigned char ch);
static void gc_putc_charsetcmd(int charset, unsigned char ch);
static void gc_putc_charsizecmd(unsigned char ch);
static void gc_putc_esc(unsigned char ch);
static void gc_putc_getpars(unsigned char ch);
static void gc_putc_gotpars(unsigned char ch);
static void gc_putc_normal(unsigned char ch);
static void gc_putc_square(unsigned char ch);
static void gc_reset_screen(void);
static void gc_reset_tabs(void);
static void gc_reset_vt100(void);
static void gc_scroll_down(int num, unsigned int top, unsigned int bottom);
static void gc_scroll_up(int num, unsigned int top, unsigned int bottom);
static void gc_set_tab_stop(unsigned int column, boolean_t enabled);
static void gc_show_cursor(unsigned int xx, unsigned int yy);
static void gc_update_color(int color, boolean_t fore);
static void
gc_clear_line(unsigned int xx, unsigned int yy, int which)
{
unsigned int start, end, i;
/*
* This routine runs extremely slowly. I don't think it's
* used all that often, except for To end of line. I'll go
* back and speed this up when I speed up the whole vc
* module. --LK
*/
switch (which) {
case 0: /* To end of line */
start = xx;
end = vinfo.v_columns - 1;
break;
case 1: /* To start of line */
start = 0;
end = xx;
break;
case 2: /* Whole line */
start = 0;
end = vinfo.v_columns - 1;
break;
default:
return;
}
for (i = start; i <= end; i++) {
gc_paint_char(i, yy, ' ', ATTR_NONE);
}
}
static void
gc_clear_screen(unsigned int xx, unsigned int yy, int top, unsigned int bottom,
int which)
{
if (!gc_buffer_size) {
return;
}
if (xx < gc_buffer_columns && yy < gc_buffer_rows && bottom <= gc_buffer_rows) {
uint32_t start, end;
switch (which) {
case 0: /* To end of screen */
start = (yy * gc_buffer_columns) + xx;
end = (bottom * gc_buffer_columns) - 1;
break;
case 1: /* To start of screen */
start = (top * gc_buffer_columns);
end = (yy * gc_buffer_columns) + xx;
break;
case 2: /* Whole screen */
start = (top * gc_buffer_columns);
end = (bottom * gc_buffer_columns) - 1;
break;
default:
start = 0;
end = 0;
break;
}
memset(gc_buffer_attributes + start, ATTR_NONE, end - start + 1);
memset(gc_buffer_characters + start, ' ', end - start + 1);
memset(gc_buffer_colorcodes + start, gc_color_code, end - start + 1);
}
gc_ops.clear_screen(xx, yy, top, bottom, which);
}
static void
gc_enable( boolean_t enable )
{
unsigned char *buffer_attributes = NULL;
unsigned char *buffer_characters = NULL;
unsigned char *buffer_colorcodes = NULL;
unsigned char *buffer_tab_stops = NULL;
uint32_t buffer_columns = 0;
uint32_t buffer_rows = 0;
uint32_t buffer_size = 0;
if (enable == FALSE) {
// only disable console output if it goes to the graphics console
if (console_is_serial() == FALSE) {
disableConsoleOutput = TRUE;
}
gc_enabled = FALSE;
gc_ops.enable(FALSE);
}
VCPUTC_LOCK_LOCK();
if (gc_buffer_size) {
buffer_attributes = gc_buffer_attributes;
buffer_characters = gc_buffer_characters;
buffer_colorcodes = gc_buffer_colorcodes;
buffer_tab_stops = gc_buffer_tab_stops;
buffer_columns = gc_buffer_columns;
buffer_rows = gc_buffer_rows;
buffer_size = gc_buffer_size;
gc_buffer_attributes = NULL;
gc_buffer_characters = NULL;
gc_buffer_colorcodes = NULL;
gc_buffer_tab_stops = NULL;
gc_buffer_columns = 0;
gc_buffer_rows = 0;
gc_buffer_size = 0;
VCPUTC_LOCK_UNLOCK();
kfree_data(buffer_attributes, buffer_size);
kfree_data(buffer_characters, buffer_size);
kfree_data(buffer_colorcodes, buffer_size);
kfree_data(buffer_tab_stops, buffer_columns);
} else {
VCPUTC_LOCK_UNLOCK();
}
if (enable) {
if (vm_initialized) {
buffer_columns = vinfo.v_columns;
buffer_rows = vinfo.v_rows;
buffer_size = buffer_columns * buffer_rows;
if (buffer_size) {
buffer_attributes = kalloc_data(buffer_size, Z_WAITOK);
buffer_characters = kalloc_data(buffer_size, Z_WAITOK);
buffer_colorcodes = kalloc_data(buffer_size, Z_WAITOK);
buffer_tab_stops = kalloc_data(buffer_columns, Z_WAITOK);
if (buffer_attributes == NULL ||
buffer_characters == NULL ||
buffer_colorcodes == NULL ||
buffer_tab_stops == NULL) {
kfree_data(buffer_attributes, buffer_size);
kfree_data(buffer_characters, buffer_size);
kfree_data(buffer_colorcodes, buffer_size);
kfree_data(buffer_tab_stops, buffer_columns);
buffer_attributes = NULL;
buffer_characters = NULL;
buffer_colorcodes = NULL;
buffer_tab_stops = NULL;
buffer_columns = 0;
buffer_rows = 0;
buffer_size = 0;
} else {
memset( buffer_attributes, ATTR_NONE, buffer_size );
memset( buffer_characters, ' ', buffer_size );
memset( buffer_colorcodes, COLOR_CODE_SET( 0, COLOR_FOREGROUND, TRUE ), buffer_size );
memset( buffer_tab_stops, 0, buffer_columns );
}
}
}
VCPUTC_LOCK_LOCK();
gc_buffer_attributes = buffer_attributes;
gc_buffer_characters = buffer_characters;
gc_buffer_colorcodes = buffer_colorcodes;
gc_buffer_tab_stops = buffer_tab_stops;
gc_buffer_columns = buffer_columns;
gc_buffer_rows = buffer_rows;
gc_buffer_size = buffer_size;
gc_reset_screen();
VCPUTC_LOCK_UNLOCK();
gc_ops.clear_screen(gc_x, gc_y, 0, vinfo.v_rows, 2);
gc_ops.show_cursor(gc_x, gc_y);
gc_ops.enable(TRUE);
gc_enabled = TRUE;
disableConsoleOutput = FALSE;
}
}
static void
gc_hide_cursor(unsigned int xx, unsigned int yy)
{
if (xx < gc_buffer_columns && yy < gc_buffer_rows) {
uint32_t index = (yy * gc_buffer_columns) + xx;
unsigned char attribute = gc_buffer_attributes[index];
unsigned char character = gc_buffer_characters[index];
unsigned char colorcode = gc_buffer_colorcodes[index];
unsigned char colorcodesave = gc_color_code;
gc_update_color(COLOR_CODE_GET(colorcode, TRUE ), TRUE );
gc_update_color(COLOR_CODE_GET(colorcode, FALSE), FALSE);
gc_ops.paint_char(xx, yy, character, attribute, 0, 0);
gc_update_color(COLOR_CODE_GET(colorcodesave, TRUE ), TRUE );
gc_update_color(COLOR_CODE_GET(colorcodesave, FALSE), FALSE);
} else {
gc_ops.hide_cursor(xx, yy);
}
}
static void
gc_initialize(struct vc_info * info)
{
if (gc_initialized == FALSE) {
/* Init our lock */
VCPUTC_LOCK_INIT();
gc_initialized = TRUE;
}
gc_ops.initialize(info);
gc_reset_vt100();
gc_x = gc_y = 0;
}
static void
gc_paint_char(unsigned int xx, unsigned int yy, unsigned char ch, int attrs)
{
if (xx < gc_buffer_columns && yy < gc_buffer_rows) {
uint32_t index = (yy * gc_buffer_columns) + xx;
gc_buffer_attributes[index] = attrs;
gc_buffer_characters[index] = ch;
gc_buffer_colorcodes[index] = gc_color_code;
}
gc_ops.paint_char(xx, yy, ch, attrs, 0, 0);
}
static void
gc_putchar(char ch)
{
if (!ch) {
return; /* ignore null characters */
}
switch (gc_vt100state) {
default:
gc_vt100state = ESnormal;
OS_FALLTHROUGH;
case ESnormal:
gc_putc_normal(ch);
break;
case ESesc:
gc_putc_esc(ch);
break;
case ESsquare:
gc_putc_square(ch);
break;
case ESgetpars:
gc_putc_getpars(ch);
break;
case ESgotpars:
gc_putc_gotpars(ch);
break;
case ESask:
gc_putc_askcmd(ch);
break;
case EScharsize:
gc_putc_charsizecmd(ch);
break;
case ESsetG0:
gc_putc_charsetcmd(0, ch);
break;
case ESsetG1:
gc_putc_charsetcmd(1, ch);
break;
}
if (gc_x >= vinfo.v_columns) {
if (0 == vinfo.v_columns) {
gc_x = 0;
} else {
gc_x = vinfo.v_columns - 1;
}
}
if (gc_y >= vinfo.v_rows) {
if (0 == vinfo.v_rows) {
gc_y = 0;
} else {
gc_y = vinfo.v_rows - 1;
}
}
}
static void
gc_putc_askcmd(unsigned char ch)
{
if (ch >= '0' && ch <= '9') {
gc_par[gc_numpars] = (10 * gc_par[gc_numpars]) + (ch - '0');
return;
}
gc_vt100state = ESnormal;
switch (gc_par[0]) {
case 6:
gc_relative_origin = ch == 'h';
break;
case 7: /* wrap around mode h=1, l=0*/
gc_wrap_mode = ch == 'h';
break;
default:
break;
}
}
static void
gc_putc_charsetcmd(int charset, unsigned char ch)
{
gc_vt100state = ESnormal;
switch (ch) {
case 'A':
case 'B':
default:
gc_charset[charset] = 0;
break;
case '0': /* Graphic characters */
case '2':
gc_charset[charset] = 0x21;
break;
}
}
static void
gc_putc_charsizecmd(unsigned char ch)
{
gc_vt100state = ESnormal;
switch (ch) {
case '3':
case '4':
case '5':
case '6':
break;
case '8': /* fill 'E's */
{
unsigned int xx, yy;
for (yy = 0; yy < vinfo.v_rows; yy++) {
for (xx = 0; xx < vinfo.v_columns; xx++) {
gc_paint_char(xx, yy, 'E', ATTR_NONE);
}
}
}
break;
}
}
static void
gc_putc_esc(unsigned char ch)
{
gc_vt100state = ESnormal;
switch (ch) {
case '[':
gc_vt100state = ESsquare;
break;
case 'c': /* Reset terminal */
gc_reset_vt100();
gc_clear_screen(gc_x, gc_y, 0, vinfo.v_rows, 2);
gc_x = gc_y = 0;
break;
case 'D': /* Line feed */
case 'E':
if (gc_y >= gc_scrreg_bottom - 1) {
gc_scroll_up(1, gc_scrreg_top, gc_scrreg_bottom);
gc_y = gc_scrreg_bottom - 1;
} else {
gc_y++;
}
if (ch == 'E') {
gc_x = 0;
}
break;
case 'H': /* Set tab stop */
gc_set_tab_stop(gc_x, TRUE);
break;
case 'M': /* Cursor up */
if (gc_y <= gc_scrreg_top) {
gc_scroll_down(1, gc_scrreg_top, gc_scrreg_bottom);
gc_y = gc_scrreg_top;
} else {
gc_y--;
}
break;
case '>':
gc_reset_vt100();
break;
case '7': /* Save cursor */
gc_savex = gc_x;
gc_savey = gc_y;
gc_saveattr = gc_attr;
gc_save_charset_s = gc_charset_select;
gc_charset_save[0] = gc_charset[0];
gc_charset_save[1] = gc_charset[1];
break;
case '8': /* Restore cursor */
gc_x = gc_savex;
gc_y = gc_savey;
gc_attr = gc_saveattr;
gc_charset_select = gc_save_charset_s;
gc_charset[0] = gc_charset_save[0];
gc_charset[1] = gc_charset_save[1];
break;
case 'Z': /* return terminal ID */
break;
case '#': /* change characters height */
gc_vt100state = EScharsize;
break;
case '(':
gc_vt100state = ESsetG0;
break;
case ')': /* character set sequence */
gc_vt100state = ESsetG1;
break;
case '=':
break;
default:
/* Rest not supported */
break;
}
}
static void
gc_putc_getpars(unsigned char ch)
{
if (ch == '?') {
gc_vt100state = ESask;
return;
}
if (ch == '[') {
gc_vt100state = ESnormal;
/* Not supported */
return;
}
if (ch == ';' && gc_numpars < MAXPARS - 1) {
gc_numpars++;
} else if (ch >= '0' && ch <= '9') {
gc_par[gc_numpars] *= 10;
gc_par[gc_numpars] += ch - '0';
} else {
gc_numpars++;
gc_vt100state = ESgotpars;
gc_putc_gotpars(ch);
}
}
static void
gc_putc_gotpars(unsigned char ch)
{
unsigned int i;
if (ch < ' ') {
/* special case for vttest for handling cursor
* movement in escape sequences */
gc_putc_normal(ch);
gc_vt100state = ESgotpars;
return;
}
gc_vt100state = ESnormal;
switch (ch) {
case 'A': /* Up */
gc_y -= gc_par[0] ? gc_par[0] : 1;
if (gc_y < gc_scrreg_top) {
gc_y = gc_scrreg_top;
}
break;
case 'B': /* Down */
gc_y += gc_par[0] ? gc_par[0] : 1;
if (gc_y >= gc_scrreg_bottom) {
gc_y = gc_scrreg_bottom - 1;
}
break;
case 'C': /* Right */
gc_x += gc_par[0] ? gc_par[0] : 1;
if (gc_x >= vinfo.v_columns) {
gc_x = vinfo.v_columns - 1;
}
break;
case 'D': /* Left */
if (gc_par[0] > gc_x) {
gc_x = 0;
} else if (gc_par[0]) {
gc_x -= gc_par[0];
} else if (gc_x) {
--gc_x;
}
break;
case 'H': /* Set cursor position */
case 'f':
gc_x = gc_par[1] ? gc_par[1] - 1 : 0;
gc_y = gc_par[0] ? gc_par[0] - 1 : 0;
if (gc_relative_origin) {
gc_y += gc_scrreg_top;
}
gc_hanging_cursor = 0;
break;
case 'X': /* clear p1 characters */
if (gc_numpars) {
for (i = gc_x; i < gc_x + gc_par[0]; i++) {
gc_paint_char(i, gc_y, ' ', ATTR_NONE);
}
}
break;
case 'J': /* Clear part of screen */
gc_clear_screen(gc_x, gc_y, 0, vinfo.v_rows, gc_par[0]);
break;
case 'K': /* Clear part of line */
gc_clear_line(gc_x, gc_y, gc_par[0]);
break;
case 'g': /* tab stops */
switch (gc_par[0]) {
case 1:
case 2: /* reset tab stops */
/* gc_reset_tabs(); */
break;
case 3: /* Clear every tabs */
{
for (i = 0; i <= vinfo.v_columns; i++) {
gc_set_tab_stop(i, FALSE);
}
}
break;
case 0:
gc_set_tab_stop(gc_x, FALSE);
break;
}
break;
case 'm': /* Set attribute */
for (i = 0; i < gc_numpars; i++) {
switch (gc_par[i]) {
case 0:
gc_attr = ATTR_NONE;
gc_update_color(COLOR_BACKGROUND, FALSE);
gc_update_color(COLOR_FOREGROUND, TRUE );
break;
case 1:
gc_attr |= ATTR_BOLD;
break;
case 4:
gc_attr |= ATTR_UNDER;
break;
case 7:
gc_attr |= ATTR_REVERSE;
break;
case 22:
gc_attr &= ~ATTR_BOLD;
break;
case 24:
gc_attr &= ~ATTR_UNDER;
break;
case 27:
gc_attr &= ~ATTR_REVERSE;
break;
case 5:
case 25: /* blink/no blink */
break;
default:
if (gc_par[i] >= 30 && gc_par[i] <= 37) {
gc_update_color(gc_par[i] - 30, TRUE);
}
if (gc_par[i] >= 40 && gc_par[i] <= 47) {
gc_update_color(gc_par[i] - 40, FALSE);
}
break;
}
}
break;
case 'r': /* Set scroll region */
gc_x = gc_y = 0;
/* ensure top < bottom, and both within limits */
if ((gc_numpars > 0) && (gc_par[0] < vinfo.v_rows)) {
gc_scrreg_top = gc_par[0] ? gc_par[0] - 1 : 0;
} else {
gc_scrreg_top = 0;
}
if ((gc_numpars > 1) && (gc_par[1] <= vinfo.v_rows) && (gc_par[1] > gc_par[0])) {
gc_scrreg_bottom = gc_par[1];
if (gc_scrreg_bottom > vinfo.v_rows) {
gc_scrreg_bottom = vinfo.v_rows;
}
} else {
gc_scrreg_bottom = vinfo.v_rows;
}
if (gc_relative_origin) {
gc_y = gc_scrreg_top;
}
break;
}
}
static void
gc_putc_normal(unsigned char ch)
{
switch (ch) {
case '\a': /* Beep */
break;
case 127: /* Delete */
case '\b': /* Backspace */
if (gc_hanging_cursor) {
gc_hanging_cursor = 0;
} else if (gc_x > 0) {
gc_x--;
}
break;
case '\t': /* Tab */
if (gc_buffer_tab_stops) {
while (gc_x < vinfo.v_columns && !gc_is_tab_stop(++gc_x)) {
;
}
}
if (gc_x >= vinfo.v_columns) {
gc_x = vinfo.v_columns - 1;
}
break;
case 0x0b:
case 0x0c:
case '\n': /* Line feed */
if (gc_y >= gc_scrreg_bottom - 1) {
gc_scroll_up(1, gc_scrreg_top, gc_scrreg_bottom);
gc_y = gc_scrreg_bottom - 1;
} else {
gc_y++;
}
break;
case '\r': /* Carriage return */
gc_x = 0;
gc_hanging_cursor = 0;
break;
case 0x0e: /* Select G1 charset (Control-N) */
gc_charset_select = 1;
break;
case 0x0f: /* Select G0 charset (Control-O) */
gc_charset_select = 0;
break;
case 0x18: /* CAN : cancel */
case 0x1A: /* like cancel */
/* well, i do nothing here, may be later */
break;
case '\033': /* Escape */
gc_vt100state = ESesc;
gc_hanging_cursor = 0;
break;
default:
if (ch >= ' ') {
if (gc_hanging_cursor) {
gc_x = 0;
if (gc_y >= gc_scrreg_bottom - 1) {
gc_scroll_up(1, gc_scrreg_top, gc_scrreg_bottom);
gc_y = gc_scrreg_bottom - 1;
} else {
gc_y++;
}
gc_hanging_cursor = 0;
}
gc_paint_char(gc_x, gc_y, (ch >= 0x60 && ch <= 0x7f) ? ch + gc_charset[gc_charset_select]
: ch, gc_attr);
if (gc_x == vinfo.v_columns - 1) {
gc_hanging_cursor = gc_wrap_mode;
} else {
gc_x++;
}
}
break;
}
}
static void
gc_putc_square(unsigned char ch)
{
int i;
for (i = 0; i < MAXPARS; i++) {
gc_par[i] = 0;
}
gc_numpars = 0;
gc_vt100state = ESgetpars;
gc_putc_getpars(ch);
}
static void
gc_reset_screen(void)
{
gc_reset_vt100();
gc_x = gc_y = 0;
}
static void
gc_reset_tabs(void)
{
unsigned int i;
if (!gc_buffer_tab_stops) {
return;
}
for (i = 0; i < vinfo.v_columns; i++) {
gc_buffer_tab_stops[i] = ((i % 8) == 0);
}
}
static void
gc_set_tab_stop(unsigned int column, boolean_t enabled)
{
if (gc_buffer_tab_stops && (column < vinfo.v_columns)) {
gc_buffer_tab_stops[column] = enabled;
}
}
static boolean_t
gc_is_tab_stop(unsigned int column)
{
if (gc_buffer_tab_stops == NULL) {
return (column % 8) == 0;
}
if (column < vinfo.v_columns) {
return gc_buffer_tab_stops[column];
} else {
return FALSE;
}
}
static void
gc_reset_vt100(void)
{
gc_reset_tabs();
gc_scrreg_top = 0;
gc_scrreg_bottom = vinfo.v_rows;
gc_attr = ATTR_NONE;
gc_charset[0] = gc_charset[1] = 0;
gc_charset_select = 0;
gc_wrap_mode = 1;
gc_relative_origin = 0;
gc_update_color(COLOR_BACKGROUND, FALSE);
gc_update_color(COLOR_FOREGROUND, TRUE);
}
static void
gc_scroll_down(int num, unsigned int top, unsigned int bottom)
{
if (!gc_buffer_size) {
return;
}
if (bottom <= gc_buffer_rows) {
unsigned char colorcodesave = gc_color_code;
uint32_t column, row;
uint32_t index, jump;
jump = num * gc_buffer_columns;
for (row = bottom - 1; row >= top + num; row--) {
index = row * gc_buffer_columns;
for (column = 0; column < gc_buffer_columns; index++, column++) {
if (gc_buffer_attributes[index] != gc_buffer_attributes[index - jump] ||
gc_buffer_characters[index] != gc_buffer_characters[index - jump] ||
gc_buffer_colorcodes[index] != gc_buffer_colorcodes[index - jump]) {
if (gc_color_code != gc_buffer_colorcodes[index - jump]) {
gc_update_color(COLOR_CODE_GET(gc_buffer_colorcodes[index - jump], TRUE ), TRUE );
gc_update_color(COLOR_CODE_GET(gc_buffer_colorcodes[index - jump], FALSE), FALSE);
}
if (gc_buffer_colorcodes[index] != gc_buffer_colorcodes[index - jump]) {
gc_ops.paint_char( /* xx */ column,
/* yy */ row,
/* ch */ gc_buffer_characters[index - jump],
/* attrs */ gc_buffer_attributes[index - jump],
/* ch_previous */ 0,
/* attrs_previous */ 0 );
} else {
gc_ops.paint_char( /* xx */ column,
/* yy */ row,
/* ch */ gc_buffer_characters[index - jump],
/* attrs */ gc_buffer_attributes[index - jump],
/* ch_previous */ gc_buffer_characters[index],
/* attrs_previous */ gc_buffer_attributes[index] );
}
gc_buffer_attributes[index] = gc_buffer_attributes[index - jump];
gc_buffer_characters[index] = gc_buffer_characters[index - jump];
gc_buffer_colorcodes[index] = gc_buffer_colorcodes[index - jump];
}
}
}
if (colorcodesave != gc_color_code) {
gc_update_color(COLOR_CODE_GET(colorcodesave, TRUE ), TRUE );
gc_update_color(COLOR_CODE_GET(colorcodesave, FALSE), FALSE);
}
/* Now set the freed up lines to the background colour */
for (row = top; row < top + num; row++) {
index = row * gc_buffer_columns;
for (column = 0; column < gc_buffer_columns; index++, column++) {
if (gc_buffer_attributes[index] != ATTR_NONE ||
gc_buffer_characters[index] != ' ' ||
gc_buffer_colorcodes[index] != gc_color_code) {
if (gc_buffer_colorcodes[index] != gc_color_code) {
gc_ops.paint_char( /* xx */ column,
/* yy */ row,
/* ch */ ' ',
/* attrs */ ATTR_NONE,
/* ch_previous */ 0,
/* attrs_previous */ 0 );
} else {
gc_ops.paint_char( /* xx */ column,
/* yy */ row,
/* ch */ ' ',
/* attrs */ ATTR_NONE,
/* ch_previous */ gc_buffer_characters[index],
/* attrs_previous */ gc_buffer_attributes[index] );
}
gc_buffer_attributes[index] = ATTR_NONE;
gc_buffer_characters[index] = ' ';
gc_buffer_colorcodes[index] = gc_color_code;
}
}
}
} else {
gc_ops.scroll_down(num, top, bottom);
/* Now set the freed up lines to the background colour */
gc_clear_screen(vinfo.v_columns - 1, top + num - 1, top, bottom, 1);
}
}
static void
gc_scroll_up(int num, unsigned int top, unsigned int bottom)
{
if (!gc_buffer_size) {
return;
}
if (bottom <= gc_buffer_rows) {
unsigned char colorcodesave = gc_color_code;
uint32_t column, row;
uint32_t index, jump;
jump = num * gc_buffer_columns;
for (row = top; row < bottom - num; row++) {
index = row * gc_buffer_columns;
for (column = 0; column < gc_buffer_columns; index++, column++) {
if (gc_buffer_attributes[index] != gc_buffer_attributes[index + jump] ||
gc_buffer_characters[index] != gc_buffer_characters[index + jump] ||
gc_buffer_colorcodes[index] != gc_buffer_colorcodes[index + jump]) {
if (gc_color_code != gc_buffer_colorcodes[index + jump]) {
gc_update_color(COLOR_CODE_GET(gc_buffer_colorcodes[index + jump], TRUE ), TRUE );
gc_update_color(COLOR_CODE_GET(gc_buffer_colorcodes[index + jump], FALSE), FALSE);
}
if (gc_buffer_colorcodes[index] != gc_buffer_colorcodes[index + jump]) {
gc_ops.paint_char( /* xx */ column,
/* yy */ row,
/* ch */ gc_buffer_characters[index + jump],
/* attrs */ gc_buffer_attributes[index + jump],
/* ch_previous */ 0,
/* attrs_previous */ 0 );
} else {
gc_ops.paint_char( /* xx */ column,
/* yy */ row,
/* ch */ gc_buffer_characters[index + jump],
/* attrs */ gc_buffer_attributes[index + jump],
/* ch_previous */ gc_buffer_characters[index],
/* attrs_previous */ gc_buffer_attributes[index] );
}
gc_buffer_attributes[index] = gc_buffer_attributes[index + jump];
gc_buffer_characters[index] = gc_buffer_characters[index + jump];
gc_buffer_colorcodes[index] = gc_buffer_colorcodes[index + jump];
}
}
}
if (colorcodesave != gc_color_code) {
gc_update_color(COLOR_CODE_GET(colorcodesave, TRUE ), TRUE );
gc_update_color(COLOR_CODE_GET(colorcodesave, FALSE), FALSE);
}
/* Now set the freed up lines to the background colour */
for (row = bottom - num; row < bottom; row++) {
index = row * gc_buffer_columns;
for (column = 0; column < gc_buffer_columns; index++, column++) {
if (gc_buffer_attributes[index] != ATTR_NONE ||
gc_buffer_characters[index] != ' ' ||
gc_buffer_colorcodes[index] != gc_color_code) {
if (gc_buffer_colorcodes[index] != gc_color_code) {
gc_ops.paint_char( /* xx */ column,
/* yy */ row,
/* ch */ ' ',
/* attrs */ ATTR_NONE,
/* ch_previous */ 0,
/* attrs_previous */ 0 );
} else {
gc_ops.paint_char( /* xx */ column,
/* yy */ row,
/* ch */ ' ',
/* attrs */ ATTR_NONE,
/* ch_previous */ gc_buffer_characters[index],
/* attrs_previous */ gc_buffer_attributes[index] );
}
gc_buffer_attributes[index] = ATTR_NONE;
gc_buffer_characters[index] = ' ';
gc_buffer_colorcodes[index] = gc_color_code;
}
}
}
} else {
gc_ops.scroll_up(num, top, bottom);
/* Now set the freed up lines to the background colour */
gc_clear_screen(0, bottom - num, top, bottom, 0);
}
}
static void
gc_show_cursor(unsigned int xx, unsigned int yy)
{
if (xx < gc_buffer_columns && yy < gc_buffer_rows) {
uint32_t index = (yy * gc_buffer_columns) + xx;
unsigned char attribute = gc_buffer_attributes[index];
unsigned char character = gc_buffer_characters[index];
unsigned char colorcode = gc_buffer_colorcodes[index];
unsigned char colorcodesave = gc_color_code;
gc_update_color(COLOR_CODE_GET(colorcode, FALSE), TRUE );
gc_update_color(COLOR_CODE_GET(colorcode, TRUE ), FALSE);
gc_ops.paint_char(xx, yy, character, attribute, 0, 0);
gc_update_color(COLOR_CODE_GET(colorcodesave, TRUE ), TRUE );
gc_update_color(COLOR_CODE_GET(colorcodesave, FALSE), FALSE);
} else {
gc_ops.show_cursor(xx, yy);
}
}
static void
gc_update_color(int color, boolean_t fore)
{
assert(gc_ops.update_color);
gc_color_code = COLOR_CODE_SET(gc_color_code, color, fore);
gc_ops.update_color(color, fore);
}
void
vcputc_options(char c, __unused bool poll)
{
if (gc_initialized && gc_enabled) {
VCPUTC_LOCK_LOCK();
if (gc_enabled) {
gc_hide_cursor(gc_x, gc_y);
gc_putchar(c);
gc_show_cursor(gc_x, gc_y);
}
#if SCHED_HYGIENE_DEBUG
abandon_preemption_disable_measurement();
#endif /* SCHED_HYGIENE_DEBUG */
VCPUTC_LOCK_UNLOCK();
}
}
void
vcputc(char c)
{
vcputc_options(c, false);
}
/*
* Video Console (Back-End)
* ------------------------
*/
/*
* For the color support (Michel Pollet)
*/
static unsigned char vc_color_index_table[33] =
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 2 };
static uint32_t vc_colors[8][4] = {
{ 0xFFFFFFFF, 0x00000000, 0x00000000, 0x00000000 }, /* black */
{ 0x23232323, 0x7C007C00, 0x00FF0000, 0x3FF00000 }, /* red */
{ 0xb9b9b9b9, 0x03e003e0, 0x0000FF00, 0x000FFC00 }, /* green */
{ 0x05050505, 0x7FE07FE0, 0x00FFFF00, 0x3FFFFC00 }, /* yellow */
{ 0xd2d2d2d2, 0x001f001f, 0x000000FF, 0x000003FF }, /* blue */
// { 0x80808080, 0x31933193, 0x00666699, 0x00000000 }, /* blue */
{ 0x18181818, 0x7C1F7C1F, 0x00FF00FF, 0x3FF003FF }, /* magenta */
{ 0xb4b4b4b4, 0x03FF03FF, 0x0000FFFF, 0x000FFFFF }, /* cyan */
{ 0x00000000, 0x7FFF7FFF, 0x00FFFFFF, 0x3FFFFFFF } /* white */
};
static uint32_t vc_color_fore = 0;
static uint32_t vc_color_back = 0;
/*
* New Rendering code from Michel Pollet
*/
/* Rendered Font Buffer */
static unsigned char *vc_rendered_font = NULL;
/* Rendered Font Size */
static uint32_t vc_rendered_font_size = 0;
/* Size of a character in the table (bytes) */
static int vc_rendered_char_size = 0;
#define REN_MAX_DEPTH 32
static unsigned char vc_rendered_char[ISO_CHAR_HEIGHT * ((REN_MAX_DEPTH / 8) * ISO_CHAR_WIDTH)];
#if defined(XNU_TARGET_OS_OSX)
#define CONFIG_VC_PROGRESS_METER_SUPPORT 1
#endif /* XNU_TARGET_OS_OSX */
#if defined(XNU_TARGET_OS_OSX)
static void
internal_set_progressmeter(int new_value);
static void
internal_enable_progressmeter(int new_value);
enum{
kProgressMeterOff = FALSE,
kProgressMeterUser = TRUE,
kProgressMeterKernel = 3,
};
enum{
kProgressMeterMax = 1024,
kProgressMeterEnd = 512,
};
#endif /* defined(XNU_TARGET_OS_OSX) */
static boolean_t vc_progress_white =
#ifdef CONFIG_VC_PROGRESS_WHITE
TRUE;
#else /* !CONFIG_VC_PROGRESS_WHITE */
FALSE;
#endif /* !CONFIG_VC_PROGRESS_WHITE */
static int vc_acquire_delay = kProgressAcquireDelay;
static void
vc_clear_screen(unsigned int xx, unsigned int yy, unsigned int scrreg_top,
unsigned int scrreg_bottom, int which)
{
uint32_t *p, *endp, *row;
int linelongs, col;
int rowline, rowlongs;
if (!vinfo.v_depth) {
return;
}
linelongs = vinfo.v_rowbytes * (ISO_CHAR_HEIGHT >> 2);
rowline = vinfo.v_rowscanbytes >> 2;
rowlongs = vinfo.v_rowbytes >> 2;
p = (uint32_t*) vinfo.v_baseaddr;
endp = (uint32_t*) vinfo.v_baseaddr;
switch (which) {
case 0: /* To end of screen */
gc_clear_line(xx, yy, 0);
if (yy < scrreg_bottom - 1) {
p += (yy + 1) * linelongs;
endp += scrreg_bottom * linelongs;
}
break;
case 1: /* To start of screen */
gc_clear_line(xx, yy, 1);
if (yy > scrreg_top) {
p += scrreg_top * linelongs;
endp += yy * linelongs;
}
break;
case 2: /* Whole screen */
p += scrreg_top * linelongs;
if (scrreg_bottom == vinfo.v_rows) {
endp += rowlongs * vinfo.v_height;
} else {
endp += scrreg_bottom * linelongs;
}
break;
}
for (row = p; row < endp; row += rowlongs) {
for (col = 0; col < rowline; col++) {
*(row + col) = vc_color_back;
}
}
}
static void
vc_render_char(unsigned char ch, unsigned char *renderptr, short newdepth)
{
union {
unsigned char *charptr;
unsigned short *shortptr;
uint32_t *longptr;
} current; /* current place in rendered font, multiple types. */
unsigned char *theChar; /* current char in iso_font */
int line;
current.charptr = renderptr;
theChar = iso_font + (ch * ISO_CHAR_HEIGHT);
for (line = 0; line < ISO_CHAR_HEIGHT; line++) {
unsigned char mask = 1;
do {
switch (newdepth) {
case 8:
*current.charptr++ = (*theChar & mask) ? 0xFF : 0;
break;
case 16:
*current.shortptr++ = (*theChar & mask) ? 0xFFFF : 0;
break;
case 30:
case 32:
*current.longptr++ = (*theChar & mask) ? 0xFFFFFFFF : 0;
break;
}
mask <<= 1;
} while (mask); /* while the single bit drops to the right */
theChar++;
}
}
static void
vc_paint_char_8(unsigned int xx, unsigned int yy, unsigned char ch, int attrs,
__unused unsigned char ch_previous, __unused int attrs_previous)
{
uint32_t *theChar;
uint32_t *where;
int i;
if (vc_rendered_font) {
theChar = (uint32_t*)(vc_rendered_font + (ch * vc_rendered_char_size));
} else {
vc_render_char(ch, vc_rendered_char, 8);
theChar = (uint32_t*)(vc_rendered_char);
}
where = (uint32_t*)(vinfo.v_baseaddr +
(yy * ISO_CHAR_HEIGHT * vinfo.v_rowbytes) +
(xx * ISO_CHAR_WIDTH));
if (!attrs) {
for (i = 0; i < ISO_CHAR_HEIGHT; i++) { /* No attr? FLY !*/
uint32_t *store = where;
int x;
for (x = 0; x < 2; x++) {
uint32_t val = *theChar++;
val = (vc_color_back & ~val) | (vc_color_fore & val);
*store++ = val;
}
where = (uint32_t*)(((unsigned char*)where) + vinfo.v_rowbytes);
}
} else {
for (i = 0; i < ISO_CHAR_HEIGHT; i++) { /* a little slower */
uint32_t *store = where, lastpixel = 0;
int x;
for (x = 0; x < 2; x++) {
uint32_t val = *theChar++, save = val;
if (attrs & ATTR_BOLD) { /* bold support */
if (lastpixel && !(save & 0xFF000000)) {
val |= 0xff000000;
}
if ((save & 0xFFFF0000) == 0xFF000000) {
val |= 0x00FF0000;
}
if ((save & 0x00FFFF00) == 0x00FF0000) {
val |= 0x0000FF00;
}
if ((save & 0x0000FFFF) == 0x0000FF00) {
val |= 0x000000FF;
}
}
if (attrs & ATTR_REVERSE) {
val = ~val;
}
if (attrs & ATTR_UNDER && i == ISO_CHAR_HEIGHT - 1) {
val = ~val;
}
val = (vc_color_back & ~val) | (vc_color_fore & val);
*store++ = val;
lastpixel = save & 0xff;
}
where = (uint32_t*)(((unsigned char*)where) + vinfo.v_rowbytes);
}
}
}
static void
vc_paint_char_16(unsigned int xx, unsigned int yy, unsigned char ch, int attrs,
__unused unsigned char ch_previous,
__unused int attrs_previous)
{
uint32_t *theChar;
uint32_t *where;
int i;
if (vc_rendered_font) {
theChar = (uint32_t*)(vc_rendered_font + (ch * vc_rendered_char_size));
} else {
vc_render_char(ch, vc_rendered_char, 16);
theChar = (uint32_t*)(vc_rendered_char);
}
where = (uint32_t*)(vinfo.v_baseaddr +
(yy * ISO_CHAR_HEIGHT * vinfo.v_rowbytes) +
(xx * ISO_CHAR_WIDTH * 2));
if (!attrs) {
for (i = 0; i < ISO_CHAR_HEIGHT; i++) { /* No attrs ? FLY ! */
uint32_t *store = where;
int x;
for (x = 0; x < 4; x++) {
uint32_t val = *theChar++;
val = (vc_color_back & ~val) | (vc_color_fore & val);
*store++ = val;
}
where = (uint32_t*)(((unsigned char*)where) + vinfo.v_rowbytes);
}
} else {
for (i = 0; i < ISO_CHAR_HEIGHT; i++) { /* a little bit slower */
uint32_t *store = where, lastpixel = 0;
int x;
for (x = 0; x < 4; x++) {
uint32_t val = *theChar++, save = val;
if (attrs & ATTR_BOLD) { /* bold support */
if (save == 0xFFFF0000) {
val |= 0xFFFF;
} else if (lastpixel && !(save & 0xFFFF0000)) {
val |= 0xFFFF0000;
}
}
if (attrs & ATTR_REVERSE) {
val = ~val;
}
if (attrs & ATTR_UNDER && i == ISO_CHAR_HEIGHT - 1) {
val = ~val;
}
val = (vc_color_back & ~val) | (vc_color_fore & val);
*store++ = val;
lastpixel = save & 0x7fff;
}
where = (uint32_t*)(((unsigned char*)where) + vinfo.v_rowbytes);
}
}
}
static void
vc_paint_char_32(unsigned int xx, unsigned int yy, unsigned char ch, int attrs,
unsigned char ch_previous, int attrs_previous)
{
uint32_t *theChar;
uint32_t *theCharPrevious;
uint32_t *where;
int i;
if (vc_rendered_font) {
theChar = (uint32_t*)(vc_rendered_font + (ch * vc_rendered_char_size));
theCharPrevious = (uint32_t*)(vc_rendered_font + (ch_previous * vc_rendered_char_size));
} else {
vc_render_char(ch, vc_rendered_char, 32);
theChar = (uint32_t*)(vc_rendered_char);
theCharPrevious = NULL;
}
if (!ch_previous) {
theCharPrevious = NULL;
}
if (attrs_previous) {
theCharPrevious = NULL;
}
where = (uint32_t*)(vinfo.v_baseaddr +
(yy * ISO_CHAR_HEIGHT * vinfo.v_rowbytes) +
(xx * ISO_CHAR_WIDTH * 4));
if (!attrs) {
for (i = 0; i < ISO_CHAR_HEIGHT; i++) { /* No attrs ? FLY ! */
uint32_t *store = where;
int x;
for (x = 0; x < 8; x++) {
uint32_t val = *theChar++;
if (theCharPrevious == NULL || val != *theCharPrevious++) {
val = (vc_color_back & ~val) | (vc_color_fore & val);
*store++ = val;
} else {
store++;
}
}
where = (uint32_t *)(((unsigned char*)where) + vinfo.v_rowbytes);
}
} else {
for (i = 0; i < ISO_CHAR_HEIGHT; i++) { /* a little slower */
uint32_t *store = where, lastpixel = 0;
int x;
for (x = 0; x < 8; x++) {
uint32_t val = *theChar++, save = val;
if (attrs & ATTR_BOLD) { /* bold support */
if (lastpixel && !save) {
val = 0xFFFFFFFF;
}
}
if (attrs & ATTR_REVERSE) {
val = ~val;
}
if (attrs & ATTR_UNDER && i == ISO_CHAR_HEIGHT - 1) {
val = ~val;
}
val = (vc_color_back & ~val) | (vc_color_fore & val);
*store++ = val;
lastpixel = save;
}
where = (uint32_t*)(((unsigned char*)where) + vinfo.v_rowbytes);
}
}
}
static void
vc_paint_char(unsigned int xx, unsigned int yy, unsigned char ch, int attrs,
unsigned char ch_previous, int attrs_previous)
{
if (!vinfo.v_depth) {
return;
}
switch (vinfo.v_depth) {
case 8:
vc_paint_char_8(xx, yy, ch, attrs, ch_previous, attrs_previous);
break;
case 16:
vc_paint_char_16(xx, yy, ch, attrs, ch_previous,
attrs_previous);
break;
case 30:
case 32:
vc_paint_char_32(xx, yy, ch, attrs, ch_previous,
attrs_previous);
break;
}
}
static void
vc_render_font(short newdepth)
{
static short olddepth = 0;
int charindex; /* index in ISO font */
unsigned char *rendered_font;
unsigned int rendered_font_size;
int rendered_char_size;
if (vm_initialized == FALSE) {
return; /* nothing to do */
}
if (olddepth == newdepth && vc_rendered_font) {
return; /* nothing to do */
}
VCPUTC_LOCK_LOCK();
rendered_font = vc_rendered_font;
rendered_font_size = vc_rendered_font_size;
rendered_char_size = vc_rendered_char_size;
vc_rendered_font = NULL;
vc_rendered_font_size = 0;
vc_rendered_char_size = 0;
VCPUTC_LOCK_UNLOCK();
kfree_data(rendered_font, rendered_font_size);
if (newdepth) {
rendered_char_size = ISO_CHAR_HEIGHT * (((newdepth + 7) / 8) * ISO_CHAR_WIDTH);
rendered_font_size = (ISO_CHAR_MAX - ISO_CHAR_MIN + 1) * rendered_char_size;
rendered_font = kalloc_data(rendered_font_size, Z_WAITOK);
}
if (rendered_font == NULL) {
return;
}
for (charindex = ISO_CHAR_MIN; charindex <= ISO_CHAR_MAX; charindex++) {
vc_render_char(charindex, rendered_font + (charindex * rendered_char_size), newdepth);
}
olddepth = newdepth;
VCPUTC_LOCK_LOCK();
vc_rendered_font = rendered_font;
vc_rendered_font_size = rendered_font_size;
vc_rendered_char_size = rendered_char_size;
VCPUTC_LOCK_UNLOCK();
}
static void
vc_enable(boolean_t enable)
{
vc_render_font(enable ? vinfo.v_depth : 0);
}
static void
vc_reverse_cursor(unsigned int xx, unsigned int yy)
{
uint32_t *where;
int line, col;
if (!vinfo.v_depth) {
return;
}
where = (uint32_t*)(vinfo.v_baseaddr +
(yy * ISO_CHAR_HEIGHT * vinfo.v_rowbytes) +
(xx /** ISO_CHAR_WIDTH*/ * vinfo.v_depth));
for (line = 0; line < ISO_CHAR_HEIGHT; line++) {
switch (vinfo.v_depth) {
case 8:
where[0] = ~where[0];
where[1] = ~where[1];
break;
case 16:
for (col = 0; col < 4; col++) {
where[col] = ~where[col];
}
break;
case 32:
for (col = 0; col < 8; col++) {
where[col] = ~where[col];
}
break;
}
where = (uint32_t*)(((unsigned char*)where) + vinfo.v_rowbytes);
}
}
static void
vc_scroll_down(int num, unsigned int scrreg_top, unsigned int scrreg_bottom)
{
uint32_t *from, *to, linelongs, i, line, rowline, rowscanline;
if (!vinfo.v_depth) {
return;
}
linelongs = vinfo.v_rowbytes * (ISO_CHAR_HEIGHT >> 2);
rowline = vinfo.v_rowbytes >> 2;
rowscanline = vinfo.v_rowscanbytes >> 2;
to = (uint32_t *) vinfo.v_baseaddr + (linelongs * scrreg_bottom)
- (rowline - rowscanline);
from = to - (linelongs * num); /* handle multiple line scroll (Michel Pollet) */
i = (scrreg_bottom - scrreg_top) - num;
while (i-- > 0) {
for (line = 0; line < ISO_CHAR_HEIGHT; line++) {
/*
* Only copy what is displayed
*/
video_scroll_down(from,
(from - (vinfo.v_rowscanbytes >> 2)),
to);
from -= rowline;
to -= rowline;
}
}
}
static void
vc_scroll_up(int num, unsigned int scrreg_top, unsigned int scrreg_bottom)
{
uint32_t *from, *to, linelongs, i, line, rowline, rowscanline;
if (!vinfo.v_depth) {
return;
}
linelongs = vinfo.v_rowbytes * (ISO_CHAR_HEIGHT >> 2);
rowline = vinfo.v_rowbytes >> 2;
rowscanline = vinfo.v_rowscanbytes >> 2;
to = (uint32_t *) vinfo.v_baseaddr + (scrreg_top * linelongs);
from = to + (linelongs * num); /* handle multiple line scroll (Michel Pollet) */
i = (scrreg_bottom - scrreg_top) - num;
while (i-- > 0) {
for (line = 0; line < ISO_CHAR_HEIGHT; line++) {
/*
* Only copy what is displayed
*/
video_scroll_up(from,
(from + (vinfo.v_rowscanbytes >> 2)),
to);
from += rowline;
to += rowline;
}
}
}
static void
vc_update_color(int color, boolean_t fore)
{
if (!vinfo.v_depth) {
return;
}
if (fore) {
vc_color_fore = vc_colors[color][vc_color_index_table[vinfo.v_depth]];
} else {
vc_color_back = vc_colors[color][vc_color_index_table[vinfo.v_depth]];
}
}
/*
* Video Console (Back-End): Icon Control
* --------------------------------------
*/
static vc_progress_element * vc_progress;
enum { kMaxProgressData = 3 };
static const unsigned char * vc_progress_data[kMaxProgressData];
static const unsigned char * vc_progress_alpha;
static boolean_t vc_progress_enable;
static const unsigned char * vc_clut;
static const unsigned char * vc_clut8;
static unsigned char vc_revclut8[256];
static uint32_t vc_progress_interval;
static uint32_t vc_progress_count;
static uint32_t vc_progress_angle;
static uint64_t vc_progress_deadline;
static thread_call_data_t vc_progress_call;
static boolean_t vc_needsave;
static void * vc_saveunder;
static vm_size_t vc_saveunder_len;
static int8_t vc_uiscale = 1;
vc_progress_user_options vc_progress_options;
vc_progress_user_options vc_user_options;
decl_simple_lock_data(, vc_progress_lock);
#if defined(XNU_TARGET_OS_OSX)
static int vc_progress_withmeter = 3;
int vc_progressmeter_enable;
static int vc_progressmeter_drawn;
int vc_progressmeter_value;
static uint32_t vc_progressmeter_count;
static uint32_t vc_progress_meter_start;
static uint32_t vc_progress_meter_end;
static uint64_t vc_progressmeter_interval;
static uint64_t vc_progressmeter_deadline;
static thread_call_data_t vc_progressmeter_call;
static void * vc_progressmeter_backbuffer;
static uint32_t vc_progressmeter_diskspeed = 256;
#endif /* defined(XNU_TARGET_OS_OSX) */
enum {
kSave = 0x10,
kDataIndexed = 0x20,
kDataAlpha = 0x40,
kDataBack = 0x80,
kDataRotate = 0x03,
};
static void vc_blit_rect(int x, int y, int bx,
int width, int height,
int sourceWidth, int sourceHeight,
int sourceRow, int backRow,
const unsigned char * dataPtr,
void * backBuffer,
unsigned int flags);
static void vc_blit_rect_8(int x, int y, int bx,
int width, int height,
int sourceWidth, int sourceHeight,
int sourceRow, int backRow,
const unsigned char * dataPtr,
unsigned char * backBuffer,
unsigned int flags);
static void vc_blit_rect_16(int x, int y, int bx,
int width, int height,
int sourceWidth, int sourceHeight,
int sourceRow, int backRow,
const unsigned char * dataPtr,
unsigned short * backBuffer,
unsigned int flags);
static void vc_blit_rect_32(int x, int y, int bx,
int width, int height,
int sourceWidth, int sourceHeight,
int sourceRow, int backRow,
const unsigned char * dataPtr,
unsigned int * backBuffer,
unsigned int flags);
static void vc_blit_rect_30(int x, int y, int bx,
int width, int height,
int sourceWidth, int sourceHeight,
int sourceRow, int backRow,
const unsigned char * dataPtr,
unsigned int * backBuffer,
unsigned int flags);
static void vc_progress_task( void * arg0, void * arg );
#if defined(XNU_TARGET_OS_OSX)
static void vc_progressmeter_task( void * arg0, void * arg );
#endif /* defined(XNU_TARGET_OS_OSX) */
static void
vc_blit_rect(int x, int y, int bx,
int width, int height,
int sourceWidth, int sourceHeight,
int sourceRow, int backRow,
const unsigned char * dataPtr,
void * backBuffer,
unsigned int flags)
{
if (!vinfo.v_depth) {
return;
}
if (((unsigned int)(x + width)) > vinfo.v_width) {
return;
}
if (((unsigned int)(y + height)) > vinfo.v_height) {
return;
}
switch (vinfo.v_depth) {
case 8:
if (vc_clut8 == vc_clut) {
vc_blit_rect_8( x, y, bx, width, height, sourceWidth, sourceHeight, sourceRow, backRow, dataPtr, (unsigned char *) backBuffer, flags );
}
break;
case 16:
vc_blit_rect_16( x, y, bx, width, height, sourceWidth, sourceHeight, sourceRow, backRow, dataPtr, (unsigned short *) backBuffer, flags );
break;
case 32:
vc_blit_rect_32( x, y, bx, width, height, sourceWidth, sourceHeight, sourceRow, backRow, dataPtr, (unsigned int *) backBuffer, flags );
break;
case 30:
vc_blit_rect_30( x, y, bx, width, height, sourceWidth, sourceHeight, sourceRow, backRow, dataPtr, (unsigned int *) backBuffer, flags );
break;
}
}
static void
vc_blit_rect_8(int x, int y, __unused int bx,
int width, int height,
int sourceWidth, int sourceHeight,
int sourceRow, __unused int backRow,
const unsigned char * dataPtr,
__unused unsigned char * backBuffer,
__unused unsigned int flags)
{
volatile unsigned short * dst;
int line, col;
unsigned int data = 0, out = 0;
int sx, sy, a, b, c, d;
int scale = 0x10000;
a = (sourceRow == 1) ? 0 : vc_rotate_matr[kDataRotate & flags][0][0] * scale;
b = (sourceRow == 1) ? 0 : vc_rotate_matr[kDataRotate & flags][0][1] * scale;
c = vc_rotate_matr[kDataRotate & flags][1][0] * scale;
d = vc_rotate_matr[kDataRotate & flags][1][1] * scale;
sx = ((a + b) < 0) ? ((sourceWidth * scale) - 0x8000) : 0;
sy = ((c + d) < 0) ? ((sourceHeight * scale) - 0x8000) : 0;
if (!sourceRow) {
data = (unsigned int)(uintptr_t)dataPtr;
}
dst = (volatile unsigned short *) (vinfo.v_baseaddr +
(y * vinfo.v_rowbytes) +
(x * 4));
for (line = 0; line < height; line++) {
for (col = 0; col < width; col++) {
if (sourceRow) {
data = dataPtr[((sx + (col * a) + (line * b)) >> 16)
+ sourceRow * (((sy + (col * c) + (line * d)) >> 16))];
}
if (kDataAlpha & flags) {
out = vc_revclut8[data];
} else {
out = data;
}
*(dst + col) = out;
}
dst = (volatile unsigned short *) (((volatile char*)dst) + vinfo.v_rowbytes);
}
}
/* 16-bit is 1555 (XRGB) on all platforms */
#define CLUT_MASK_R 0xf8
#define CLUT_MASK_G 0xf8
#define CLUT_MASK_B 0xf8
#define CLUT_SHIFT_R << 7
#define CLUT_SHIFT_G << 2
#define CLUT_SHIFT_B >> 3
#define MASK_R 0x7c00
#define MASK_G 0x03e0
#define MASK_B 0x001f
#define MASK_R_8 0x3fc00
#define MASK_G_8 0x01fe0
#define MASK_B_8 0x000ff
static void
vc_blit_rect_16( int x, int y, int bx,
int width, int height,
int sourceWidth, int sourceHeight,
int sourceRow, int backRow,
const unsigned char * dataPtr,
unsigned short * backPtr,
unsigned int flags)
{
volatile unsigned short * dst;
int line, col;
unsigned int data = 0, out = 0, back = 0;
int sx, sy, a, b, c, d;
int scale = 0x10000;
a = (sourceRow == 1) ? 0 : vc_rotate_matr[kDataRotate & flags][0][0] * scale;
b = (sourceRow == 1) ? 0 : vc_rotate_matr[kDataRotate & flags][0][1] * scale;
c = vc_rotate_matr[kDataRotate & flags][1][0] * scale;
d = vc_rotate_matr[kDataRotate & flags][1][1] * scale;
sx = ((a + b) < 0) ? ((sourceWidth * scale) - 0x8000) : 0;
sy = ((c + d) < 0) ? ((sourceHeight * scale) - 0x8000) : 0;
if (!sourceRow) {
data = (unsigned int)(uintptr_t)dataPtr;
}
if (backPtr) {
backPtr += bx;
}
dst = (volatile unsigned short *) (vinfo.v_baseaddr +
(y * vinfo.v_rowbytes) +
(x * 2));
for (line = 0; line < height; line++) {
for (col = 0; col < width; col++) {
if (sourceRow) {
data = dataPtr[((sx + (col * a) + (line * b)) >> 16)
+ sourceRow * (((sy + (col * c) + (line * d)) >> 16))];
}
if (backPtr) {
if (kSave & flags) {
back = *(dst + col);
*backPtr++ = back;
} else {
back = *backPtr++;
}
}
if (kDataIndexed & flags) {
out = ((CLUT_MASK_R & (vc_clut[data * 3 + 0]))CLUT_SHIFT_R)
| ((CLUT_MASK_G & (vc_clut[data * 3 + 1]))CLUT_SHIFT_G)
| ((CLUT_MASK_B & (vc_clut[data * 3 + 2]))CLUT_SHIFT_B);
} else if (kDataAlpha & flags) {
out = (((((back & MASK_R) * data) + MASK_R_8) >> 8) & MASK_R)
| (((((back & MASK_G) * data) + MASK_G_8) >> 8) & MASK_G)
| (((((back & MASK_B) * data) + MASK_B_8) >> 8) & MASK_B);
if (vc_progress_white) {
out += (((0xff - data) & CLUT_MASK_R)CLUT_SHIFT_R)
| (((0xff - data) & CLUT_MASK_G)CLUT_SHIFT_G)
| (((0xff - data) & CLUT_MASK_B)CLUT_SHIFT_B);
}
} else if (kDataBack & flags) {
out = back;
} else {
out = data;
}
*(dst + col) = out;
}
dst = (volatile unsigned short *) (((volatile char*)dst) + vinfo.v_rowbytes);
if (backPtr) {
backPtr += backRow - width;
}
}
}
static void
vc_blit_rect_32(int x, int y, int bx,
int width, int height,
int sourceWidth, int sourceHeight,
int sourceRow, int backRow,
const unsigned char * dataPtr,
unsigned int * backPtr,
unsigned int flags)
{
volatile unsigned int * dst;
int line, col;
unsigned int data = 0, out = 0, back = 0;
int sx, sy, a, b, c, d;
int scale = 0x10000;
a = (sourceRow == 1) ? 0 : vc_rotate_matr[kDataRotate & flags][0][0] * scale;
b = (sourceRow == 1) ? 0 : vc_rotate_matr[kDataRotate & flags][0][1] * scale;
c = vc_rotate_matr[kDataRotate & flags][1][0] * scale;
d = vc_rotate_matr[kDataRotate & flags][1][1] * scale;
sx = ((a + b) < 0) ? ((sourceWidth * scale) - 0x8000) : 0;
sy = ((c + d) < 0) ? ((sourceHeight * scale) - 0x8000) : 0;
if (!sourceRow) {
data = (unsigned int)(uintptr_t)dataPtr;
}
if (backPtr) {
backPtr += bx;
}
dst = (volatile unsigned int *) (vinfo.v_baseaddr +
(y * vinfo.v_rowbytes) +
(x * 4));
for (line = 0; line < height; line++) {
for (col = 0; col < width; col++) {
if (sourceRow) {
data = dataPtr[((sx + (col * a) + (line * b)) >> 16)
+ sourceRow * (((sy + (col * c) + (line * d)) >> 16))];
}
if (backPtr) {
if (kSave & flags) {
back = *(dst + col);
*backPtr++ = back;
} else {
back = *backPtr++;
}
}
if (kDataIndexed & flags) {
out = (vc_clut[data * 3 + 0] << 16)
| (vc_clut[data * 3 + 1] << 8)
| (vc_clut[data * 3 + 2]);
} else if (kDataAlpha & flags) {
out = (((((back & 0x00ff00ff) * data) + 0x00ff00ff) >> 8) & 0x00ff00ff)
| (((((back & 0x0000ff00) * data) + 0x0000ff00) >> 8) & 0x0000ff00);
if (vc_progress_white) {
out += ((0xff - data) << 16)
| ((0xff - data) << 8)
| (0xff - data);
}
} else if (kDataBack & flags) {
out = back;
} else {
out = data;
}
*(dst + col) = out;
}
dst = (volatile unsigned int *) (((volatile char*)dst) + vinfo.v_rowbytes);
if (backPtr) {
backPtr += backRow - width;
}
}
}
static void
vc_blit_rect_30(int x, int y, int bx,
int width, int height,
int sourceWidth, int sourceHeight,
int sourceRow, int backRow,
const unsigned char * dataPtr,
unsigned int * backPtr,
unsigned int flags)
{
volatile unsigned int * dst;
int line, col;
unsigned int data = 0, out = 0, back = 0;
unsigned long long exp;
int sx, sy, a, b, c, d;
int scale = 0x10000;
a = (sourceRow == 1) ? 0 : vc_rotate_matr[kDataRotate & flags][0][0] * scale;
b = (sourceRow == 1) ? 0 : vc_rotate_matr[kDataRotate & flags][0][1] * scale;
c = vc_rotate_matr[kDataRotate & flags][1][0] * scale;
d = vc_rotate_matr[kDataRotate & flags][1][1] * scale;
sx = ((a + b) < 0) ? ((sourceWidth * scale) - 0x8000) : 0;
sy = ((c + d) < 0) ? ((sourceHeight * scale) - 0x8000) : 0;
if (!sourceRow) {
data = (unsigned int)(uintptr_t)dataPtr;
}
if (backPtr) {
backPtr += bx;
}
dst = (volatile unsigned int *) (vinfo.v_baseaddr +
(y * vinfo.v_rowbytes) +
(x * 4));
for (line = 0; line < height; line++) {
for (col = 0; col < width; col++) {
if (sourceRow) {
data = dataPtr[((sx + (col * a) + (line * b)) >> 16)
+ sourceRow * (((sy + (col * c) + (line * d)) >> 16))];
}
if (backPtr) {
if (kSave & flags) {
back = *(dst + col);
*backPtr++ = back;
} else {
back = *backPtr++;
}
}
if (kDataIndexed & flags) {
out = (vc_clut[data * 3 + 0] << 22)
| (vc_clut[data * 3 + 1] << 12)
| (vc_clut[data * 3 + 2] << 2);
} else if (kDataAlpha & flags) {
exp = back;
exp = (((((exp & 0x3FF003FF) * data) + 0x0FF000FF) >> 8) & 0x3FF003FF)
| (((((exp & 0x000FFC00) * data) + 0x0003FC00) >> 8) & 0x000FFC00);
out = (unsigned int)exp;
if (vc_progress_white) {
out += ((0xFF - data) << 22)
| ((0xFF - data) << 12)
| ((0xFF - data) << 2);
}
} else if (kDataBack & flags) {
out = back;
} else {
out = data;
}
*(dst + col) = out;
}
dst = (volatile unsigned int *) (((volatile char*)dst) + vinfo.v_rowbytes);
if (backPtr) {
backPtr += backRow - width;
}
}
}
static void
vc_clean_boot_graphics(void)
{
#if defined(XNU_TARGET_OS_OSX)
// clean up possible FDE login graphics
vc_progress_set(FALSE, 0);
const unsigned char *
color = (typeof(color))(uintptr_t)(vc_progress_white ? 0x00000000 : 0xBFBFBFBF);
vc_blit_rect(0, 0, 0, vinfo.v_width, vinfo.v_height, vinfo.v_width, vinfo.v_height, 0, 0, color, NULL, 0);
#endif
}
/*
* Routines to render the lzss image format
*/
struct lzss_image_state {
uint32_t col;
uint32_t row;
uint32_t width;
uint32_t height;
uint32_t bytes_per_row;
volatile uint32_t * row_start;
const uint8_t* clut;
};
typedef struct lzss_image_state lzss_image_state;
// returns 0 if OK, 1 if error
static inline int
vc_decompress_lzss_next_pixel(int next_data, lzss_image_state* state)
{
uint32_t palette_index = 0;
uint32_t pixel_value = 0;
palette_index = next_data * 3;
pixel_value = ((uint32_t) state->clut[palette_index + 0] << 16)
| ((uint32_t) state->clut[palette_index + 1] << 8)
| ((uint32_t) state->clut[palette_index + 2]);
*(state->row_start + state->col) = pixel_value;
if (++state->col >= state->width) {
state->col = 0;
if (++state->row >= state->height) {
return 1;
}
state->row_start = (volatile uint32_t *) (((uintptr_t)state->row_start) + state->bytes_per_row);
}
return 0;
}
/*
* Blit an lzss compressed image to the framebuffer
* Assumes 32 bit screen (which is everything we ship at the moment)
* The function vc_display_lzss_icon was copied from libkern/mkext.c, then modified.
*/
/*
* TODO: Does lzss use too much stack? 4096 plus bytes...
* Can probably chop it down by 1/2.
*/
/**************************************************************
* LZSS.C -- A Data Compression Program
***************************************************************
* 4/6/1989 Haruhiko Okumura
* Use, distribute, and modify this program freely.
* Please send me your improved versions.
* PC-VAN SCIENCE
* NIFTY-Serve PAF01022
* CompuServe 74050,1022
*
**************************************************************/
#define N 4096 /* size of ring buffer - must be power of 2 */
#define F 18 /* upper limit for match_length */
#define THRESHOLD 2 /* encode string into position and length
* if match_length is greater than this */
// returns 0 if OK, 1 if error
// x and y indicate upper left corner of image location on screen
int
vc_display_lzss_icon(uint32_t dst_x, uint32_t dst_y,
uint32_t image_width, uint32_t image_height,
const uint8_t *compressed_image,
uint32_t compressed_size,
const uint8_t *clut)
{
uint32_t* image_start;
uint32_t bytes_per_pixel = 4;
uint32_t bytes_per_row = vinfo.v_rowbytes;
vc_clean_boot_graphics();
image_start = (uint32_t *) (vinfo.v_baseaddr + (dst_y * bytes_per_row) + (dst_x * bytes_per_pixel));
lzss_image_state state = {0, 0, image_width, image_height, bytes_per_row, image_start, clut};
int rval = 0;
const uint8_t *src = compressed_image;
uint32_t srclen = compressed_size;
/* ring buffer of size N, with extra F-1 bytes to aid string comparison */
uint8_t text_buf[N + F - 1];
const uint8_t *srcend = src + srclen;
int i, j, k, r, c;
unsigned int flags;
srcend = src + srclen;
for (i = 0; i < N - F; i++) {
text_buf[i] = ' ';
}
r = N - F;
flags = 0;
for (;;) {
if (((flags >>= 1) & 0x100) == 0) {
if (src < srcend) {
c = *src++;
} else {
break;
}
flags = c | 0xFF00; /* uses higher byte cleverly */
} /* to count eight */
if (flags & 1) {
if (src < srcend) {
c = *src++;
} else {
break;
}
rval = vc_decompress_lzss_next_pixel(c, &state);
if (rval != 0) {
return rval;
}
text_buf[r++] = c;
r &= (N - 1);
} else {
if (src < srcend) {
i = *src++;
} else {
break;
}
if (src < srcend) {
j = *src++;
} else {
break;
}
i |= ((j & 0xF0) << 4);
j = (j & 0x0F) + THRESHOLD;
for (k = 0; k <= j; k++) {
c = text_buf[(i + k) & (N - 1)];
rval = vc_decompress_lzss_next_pixel(c, &state);
if (rval != 0) {
return rval;
}
text_buf[r++] = c;
r &= (N - 1);
}
}
}
return 0;
}
void
noroot_icon_test(void)
{
boolean_t o_vc_progress_enable = vc_progress_enable;
vc_progress_enable = 1;
PE_display_icon( 0, "noroot");
vc_progress_enable = o_vc_progress_enable;
}
void
vc_display_icon( vc_progress_element * desc,
const unsigned char * data )
{
int x, y, width, height;
if (vc_progress_enable && vc_clut) {
vc_clean_boot_graphics();
width = desc->width;
height = desc->height;
x = desc->dx;
y = desc->dy;
if (1 & desc->flags) {
x += ((vinfo.v_width - width) / 2);
y += ((vinfo.v_height - height) / 2);
}
vc_blit_rect( x, y, 0, width, height, width, height, width, 0, data, NULL, kDataIndexed );
}
}
void
vc_progress_initialize( vc_progress_element * desc,
const unsigned char * data1x,
const unsigned char * data2x,
const unsigned char * data3x,
const unsigned char * clut )
{
uint64_t abstime;
if ((!clut) || (!desc) || (!data1x)) {
return;
}
vc_clut = clut;
vc_clut8 = clut;
vc_progress = desc;
vc_progress_data[0] = data1x;
vc_progress_data[1] = data2x;
vc_progress_data[2] = data3x;
if (2 & vc_progress->flags) {
vc_progress_alpha = data1x
+ vc_progress->count * vc_progress->width * vc_progress->height;
} else {
vc_progress_alpha = NULL;
}
thread_call_setup(&vc_progress_call, vc_progress_task, NULL);
clock_interval_to_absolutetime_interval(vc_progress->time, 1000 * 1000, &abstime);
vc_progress_interval = (uint32_t)abstime;
#if defined(XNU_TARGET_OS_OSX)
thread_call_setup(&vc_progressmeter_call, vc_progressmeter_task, NULL);
clock_interval_to_absolutetime_interval(1000 / 8, 1000 * 1000, &abstime);
vc_progressmeter_interval = (uint32_t)abstime;
#endif /* defined(XNU_TARGET_OS_OSX) */
}
void
vc_progress_set(boolean_t enable, uint32_t vc_delay)
{
void *saveBuf = NULL;
vm_size_t saveLen = 0;
unsigned int count;
unsigned int index;
unsigned char pdata8;
unsigned short pdata16;
unsigned short * buf16;
unsigned int pdata32;
unsigned int * buf32;
if (!vc_progress) {
return;
}
#if defined(CONFIG_VC_PROGRESS_METER_SUPPORT)
#if defined (__x86_64__)
if (kBootArgsFlagBlack & ((boot_args *) PE_state.bootArgs)->flags) {
return;
}
#endif /* defined (__x86_64__) */
if (1 & vc_progress_withmeter) {
if (enable) {
internal_enable_progressmeter(kProgressMeterKernel);
}
simple_lock(&vc_progress_lock, LCK_GRP_NULL);
if (vc_progress_enable != enable) {
vc_progress_enable = enable;
if (enable) {
vc_progressmeter_count = 0;
clock_interval_to_deadline(vc_delay,
1000 * 1000 * 1000 /*second scale*/,
&vc_progressmeter_deadline);
thread_call_enter_delayed(&vc_progressmeter_call, vc_progressmeter_deadline);
} else {
thread_call_cancel(&vc_progressmeter_call);
}
}
simple_unlock(&vc_progress_lock);
if (!enable) {
internal_enable_progressmeter(kProgressMeterOff);
}
return;
}
#endif /* defined(CONFIG_VC_PROGRESS_METER_SUPPORT) */
if (enable) {
saveLen = (vc_progress->width * vc_uiscale) * (vc_progress->height * vc_uiscale) * ((vinfo.v_depth + 7) / 8);
saveBuf = kalloc_data(saveLen, Z_WAITOK);
switch (vinfo.v_depth) {
case 8:
for (count = 0; count < 256; count++) {
vc_revclut8[count] = vc_clut[0x01 * 3];
pdata8 = (vc_clut[0x01 * 3] * count + 0x0ff) >> 8;
for (index = 0; index < 256; index++) {
if ((pdata8 == vc_clut[index * 3 + 0]) &&
(pdata8 == vc_clut[index * 3 + 1]) &&
(pdata8 == vc_clut[index * 3 + 2])) {
vc_revclut8[count] = index;
break;
}
}
}
memset( saveBuf, 0x01, saveLen );
break;
case 16:
buf16 = (unsigned short *) saveBuf;
pdata16 = ((vc_clut[0x01 * 3 + 0] & CLUT_MASK_R)CLUT_SHIFT_R)
| ((vc_clut[0x01 * 3 + 0] & CLUT_MASK_G)CLUT_SHIFT_G)
| ((vc_clut[0x01 * 3 + 0] & CLUT_MASK_B)CLUT_SHIFT_B);
for (count = 0; count < saveLen / 2; count++) {
buf16[count] = pdata16;
}
break;
case 32:
buf32 = (unsigned int *) saveBuf;
pdata32 = ((vc_clut[0x01 * 3 + 0] & 0xff) << 16)
| ((vc_clut[0x01 * 3 + 1] & 0xff) << 8)
| ((vc_clut[0x01 * 3 + 2] & 0xff) << 0);
for (count = 0; count < saveLen / 4; count++) {
buf32[count] = pdata32;
}
break;
}
}
simple_lock(&vc_progress_lock, LCK_GRP_NULL);
if (vc_progress_enable != enable) {
vc_progress_enable = enable;
if (enable) {
vc_needsave = TRUE;
vc_saveunder = saveBuf;
vc_saveunder_len = saveLen;
saveBuf = NULL;
saveLen = 0;
vc_progress_count = 0;
vc_progress_angle = 0;
clock_interval_to_deadline(vc_delay,
1000 * 1000 * 1000 /*second scale*/,
&vc_progress_deadline);
thread_call_enter_delayed(&vc_progress_call, vc_progress_deadline);
} else {
if (vc_saveunder) {
saveBuf = vc_saveunder;
saveLen = vc_saveunder_len;
vc_saveunder = NULL;
vc_saveunder_len = 0;
}
thread_call_cancel(&vc_progress_call);
}
}
simple_unlock(&vc_progress_lock);
kfree_data(saveBuf, saveLen);
}
#if defined(XNU_TARGET_OS_OSX)
static uint32_t
vc_progressmeter_range(uint32_t pos)
{
uint32_t ret;
if (pos > kProgressMeterEnd) {
pos = kProgressMeterEnd;
}
ret = vc_progress_meter_start
+ ((pos * (vc_progress_meter_end - vc_progress_meter_start)) / kProgressMeterEnd);
return ret;
}
static void
vc_progressmeter_task(__unused void *arg0, __unused void *arg)
{
uint64_t interval;
simple_lock(&vc_progress_lock, LCK_GRP_NULL);
if (kProgressMeterKernel == vc_progressmeter_enable) {
uint32_t pos = (vc_progressmeter_count >> 13);
internal_set_progressmeter(vc_progressmeter_range(pos));
if (pos < kProgressMeterEnd) {
static uint16_t incr[8] = { 10000, 10000, 8192, 4096, 2048, 384, 384, 64 };
vc_progressmeter_count += incr[(pos * 8) / kProgressMeterEnd];
interval = vc_progressmeter_interval;
interval = ((interval * 256) / vc_progressmeter_diskspeed);
clock_deadline_for_periodic_event(interval, mach_absolute_time(), &vc_progressmeter_deadline);
thread_call_enter_delayed(&vc_progressmeter_call, vc_progressmeter_deadline);
}
}
simple_unlock(&vc_progress_lock);
}
void
vc_progress_setdiskspeed(uint32_t speed)
{
vc_progressmeter_diskspeed = speed;
}
#endif /* defined(XNU_TARGET_OS_OSX) */
static void
vc_progress_task(__unused void *arg0, __unused void *arg)
{
int x, y, width, height;
uint64_t x_pos, y_pos;
const unsigned char * data;
simple_lock(&vc_progress_lock, LCK_GRP_NULL);
if (vc_progress_enable) {
do {
vc_progress_count++;
if (vc_progress_count >= vc_progress->count) {
vc_progress_count = 0;
vc_progress_angle++;
}
width = (vc_progress->width * vc_uiscale);
height = (vc_progress->height * vc_uiscale);
data = vc_progress_data[vc_uiscale - 1];
if (!data) {
break;
}
if (kVCUsePosition & vc_progress_options.options) {
/* Rotation: 0:normal, 1:right 90, 2:left 180, 3:left 90 */
switch (3 & vinfo.v_rotate) {
case kDataRotate0:
x_pos = vc_progress_options.x_pos;
y_pos = vc_progress_options.y_pos;
break;
case kDataRotate180:
x_pos = 0xFFFFFFFF - vc_progress_options.x_pos;
y_pos = 0xFFFFFFFF - vc_progress_options.y_pos;
break;
case kDataRotate90:
x_pos = 0xFFFFFFFF - vc_progress_options.y_pos;
y_pos = vc_progress_options.x_pos;
break;
case kDataRotate270:
x_pos = vc_progress_options.y_pos;
y_pos = 0xFFFFFFFF - vc_progress_options.x_pos;
break;
}
x = (uint32_t)((x_pos * (uint64_t) vinfo.v_width) / 0xFFFFFFFFULL);
y = (uint32_t)((y_pos * (uint64_t) vinfo.v_height) / 0xFFFFFFFFULL);
x -= (width / 2);
y -= (height / 2);
} else {
x = (vc_progress->dx * vc_uiscale);
y = (vc_progress->dy * vc_uiscale);
if (1 & vc_progress->flags) {
x += ((vinfo.v_width - width) / 2);
y += ((vinfo.v_height - height) / 2);
}
}
if ((x + width) > (int)vinfo.v_width) {
break;
}
if ((y + height) > (int)vinfo.v_height) {
break;
}
data += vc_progress_count * width * height;
vc_blit_rect( x, y, 0,
width, height, width, height, width, width,
data, vc_saveunder,
kDataAlpha
| (vc_progress_angle & kDataRotate)
| (vc_needsave ? kSave : 0));
vc_needsave = FALSE;
clock_deadline_for_periodic_event(vc_progress_interval, mach_absolute_time(), &vc_progress_deadline);
thread_call_enter_delayed(&vc_progress_call, vc_progress_deadline);
}while (FALSE);
}
#if SCHED_HYGIENE_DEBUG
abandon_preemption_disable_measurement();
#endif /* SCHED_HYGIENE_DEBUG */
simple_unlock(&vc_progress_lock);
}
/*
* Generic Console (Front-End): Master Control
* -------------------------------------------
*/
#if defined (__i386__) || defined (__x86_64__)
#include <pexpert/i386/boot.h>
#endif
static boolean_t gc_acquired = FALSE;
static boolean_t gc_graphics_boot = FALSE;
static boolean_t gc_desire_text = FALSE;
static boolean_t gc_paused_progress;
static vm_offset_t lastVideoVirt = 0;
static vm_size_t lastVideoMapSize = 0;
static boolean_t lastVideoMapKmap = FALSE;
static void
gc_pause( boolean_t pause, boolean_t graphics_now )
{
VCPUTC_LOCK_LOCK();
disableConsoleOutput = (pause && !console_is_serial());
gc_enabled = (!pause && !graphics_now);
VCPUTC_LOCK_UNLOCK();
simple_lock(&vc_progress_lock, LCK_GRP_NULL);
if (pause) {
gc_paused_progress = vc_progress_enable;
vc_progress_enable = FALSE;
} else {
vc_progress_enable = gc_paused_progress;
}
if (vc_progress_enable) {
#if defined(XNU_TARGET_OS_OSX)
if (1 & vc_progress_withmeter) {
thread_call_enter_delayed(&vc_progressmeter_call, vc_progressmeter_deadline);
} else
#endif /* defined(XNU_TARGET_OS_OSX) */
thread_call_enter_delayed(&vc_progress_call, vc_progress_deadline);
}
simple_unlock(&vc_progress_lock);
}
static void
vc_initialize(__unused struct vc_info * vinfo_p)
{
vinfo.v_rows = vinfo.v_height / ISO_CHAR_HEIGHT;
vinfo.v_columns = vinfo.v_width / ISO_CHAR_WIDTH;
vinfo.v_rowscanbytes = ((vinfo.v_depth + 7) / 8) * vinfo.v_width;
vc_uiscale = vinfo.v_scale;
if (vc_uiscale > kMaxProgressData) {
vc_uiscale = kMaxProgressData;
} else if (!vc_uiscale) {
vc_uiscale = 1;
}
}
void
initialize_screen(PE_Video * boot_vinfo, unsigned int op)
{
unsigned int newMapSize = 0;
vm_offset_t newVideoVirt = 0;
boolean_t graphics_now;
uint32_t delay;
if (boot_vinfo) {
struct vc_info new_vinfo = vinfo;
boolean_t makeMapping = FALSE;
/*
* Copy parameters
*/
if (kPEBaseAddressChange != op) {
new_vinfo.v_width = (unsigned int)boot_vinfo->v_width;
new_vinfo.v_height = (unsigned int)boot_vinfo->v_height;
new_vinfo.v_depth = (unsigned int)boot_vinfo->v_depth;
new_vinfo.v_rowbytes = (unsigned int)boot_vinfo->v_rowBytes;
if (kernel_map == VM_MAP_NULL) {
// only booter supplies HW rotation
new_vinfo.v_rotate = (unsigned int)boot_vinfo->v_rotate;
}
#if defined(__i386__) || defined(__x86_64__)
new_vinfo.v_type = (unsigned int)boot_vinfo->v_display;
#else
new_vinfo.v_type = 0;
#endif
unsigned int scale = (unsigned int)boot_vinfo->v_scale;
if (scale == kPEScaleFactor1x) {
new_vinfo.v_scale = kPEScaleFactor1x;
} else if (scale == kPEScaleFactor2x) {
new_vinfo.v_scale = kPEScaleFactor2x;
}
else { /* Scale factor not set, default to 1x */
new_vinfo.v_scale = kPEScaleFactor1x;
}
}
new_vinfo.v_name[0] = 0;
new_vinfo.v_physaddr = 0;
/*
* Check if we are have to map the framebuffer
* If VM is up, we are given a virtual address, unless b0 is set to indicate physical.
*/
newVideoVirt = boot_vinfo->v_baseAddr;
makeMapping = (kernel_map == VM_MAP_NULL) || (0 != (1 & newVideoVirt));
if (makeMapping) {
newVideoVirt = 0;
new_vinfo.v_physaddr = boot_vinfo->v_baseAddr & ~3UL; /* Get the physical address */
#ifndef __LP64__
new_vinfo.v_physaddr |= (((uint64_t) boot_vinfo->v_baseAddrHigh) << 32);
#endif
kprintf("initialize_screen: b=%08llX, w=%08X, h=%08X, r=%08X, d=%08X\n", /* (BRINGUP) */
new_vinfo.v_physaddr, new_vinfo.v_width, new_vinfo.v_height, new_vinfo.v_rowbytes, new_vinfo.v_type); /* (BRINGUP) */
}
if (!newVideoVirt && !new_vinfo.v_physaddr) { /* Check to see if we have a framebuffer */
kprintf("initialize_screen: No video - forcing serial mode\n"); /* (BRINGUP) */
new_vinfo.v_depth = 0; /* vc routines are nop */
(void)switch_to_serial_console(); /* Switch into serial mode */
gc_graphics_boot = FALSE; /* Say we are not in graphics mode */
disableConsoleOutput = FALSE; /* Allow printfs to happen */
gc_acquired = TRUE;
} else {
if (makeMapping) {
#if HAS_UCNORMAL_MEM
/*
* Framebuffers would normally use VM_WIMG_RT, which
* io_map doesn't support. However this buffer is set up
* by the bootloader and doesn't require D$ cleaning, so
* VM_WIMG_RT and VM_WIMG_WCOMB are functionally
* equivalent.
*/
unsigned int flags = VM_WIMG_WCOMB;
#else
unsigned int flags = VM_WIMG_IO;
#endif
if (boot_vinfo->v_length != 0) {
newMapSize = (unsigned int) round_page(boot_vinfo->v_length);
} else {
newMapSize = (unsigned int) round_page(new_vinfo.v_height * new_vinfo.v_rowbytes); /* Remember size */
}
newVideoVirt = ml_io_map_unmappable((vm_map_offset_t)new_vinfo.v_physaddr, newMapSize, flags); /* Allocate address space for framebuffer */
}
new_vinfo.v_baseaddr = newVideoVirt + boot_vinfo->v_offset; /* Set the new framebuffer address */
}
#if defined(__x86_64__)
// Adjust the video buffer pointer to point to where it is in high virtual (above the hole)
new_vinfo.v_baseaddr |= (VM_MIN_KERNEL_ADDRESS & ~LOW_4GB_MASK);
#endif
/* Update the vinfo structure atomically with respect to the vc_progress task if running */
if (vc_progress) {
simple_lock(&vc_progress_lock, LCK_GRP_NULL);
vinfo = new_vinfo;
simple_unlock(&vc_progress_lock);
} else {
vinfo = new_vinfo;
}
// If we changed the virtual address, remove the old mapping
if (newVideoVirt != 0) {
if (lastVideoVirt && lastVideoMapSize) { /* Was the framebuffer mapped before? */
/* XXX why only !4K? */
if (!TEST_PAGE_SIZE_4K && lastVideoMapSize) {
pmap_remove(kernel_pmap, trunc_page_64(lastVideoVirt),
round_page_64(lastVideoVirt + lastVideoMapSize)); /* Toss mappings */
}
/* Was this not a special pre-VM mapping? */
if (lastVideoMapKmap) {
kmem_free(kernel_map, lastVideoVirt, lastVideoMapSize); /* Toss kernel addresses */
}
}
lastVideoMapKmap = (NULL != kernel_map); /* Remember how mapped */
lastVideoMapSize = newMapSize; /* Remember the size */
lastVideoVirt = newVideoVirt; /* Remember the virtual framebuffer address */
}
if (kPEBaseAddressChange != op) {
// Graphics mode setup by the booter.
gc_ops.initialize = vc_initialize;
gc_ops.enable = vc_enable;
gc_ops.paint_char = vc_paint_char;
gc_ops.scroll_down = vc_scroll_down;
gc_ops.scroll_up = vc_scroll_up;
gc_ops.clear_screen = vc_clear_screen;
gc_ops.hide_cursor = vc_reverse_cursor;
gc_ops.show_cursor = vc_reverse_cursor;
gc_ops.update_color = vc_update_color;
gc_initialize(&vinfo);
}
}
graphics_now = gc_graphics_boot && !gc_desire_text;
switch (op) {
case kPEGraphicsMode:
gc_graphics_boot = TRUE;
gc_desire_text = FALSE;
break;
case kPETextMode:
gc_graphics_boot = FALSE;
break;
case kPEAcquireScreen:
if (gc_acquired) {
break;
}
vc_progress_options = vc_user_options;
bzero(&vc_user_options, sizeof(vc_user_options));
if (kVCAcquireImmediate & vc_progress_options.options) {
delay = 0;
} else if (kVCDarkReboot & vc_progress_options.options) {
delay = 120;
} else {
delay = vc_acquire_delay;
}
if (kVCDarkBackground & vc_progress_options.options) {
vc_progress_white = TRUE;
} else if (kVCLightBackground & vc_progress_options.options) {
vc_progress_white = FALSE;
}
#if !defined(XNU_TARGET_OS_BRIDGE)
vc_progress_set( graphics_now, delay );
#endif /* !defined(XNU_TARGET_OS_BRIDGE) */
gc_enable( !graphics_now );
gc_acquired = TRUE;
gc_desire_text = FALSE;
break;
case kPEDisableScreen:
if (gc_acquired) {
gc_pause( TRUE, graphics_now );
}
break;
case kPEEnableScreen:
if (gc_acquired) {
gc_pause( FALSE, graphics_now );
}
break;
case kPETextScreen:
if (console_is_serial()) {
break;
}
if (gc_acquired == FALSE) {
gc_desire_text = TRUE;
break;
}
if (gc_graphics_boot == FALSE) {
break;
}
vc_progress_set( FALSE, 0 );
#if defined(XNU_TARGET_OS_OSX)
vc_enable_progressmeter( FALSE );
#endif
gc_enable( TRUE );
break;
case kPEReleaseScreen:
gc_acquired = FALSE;
gc_desire_text = FALSE;
gc_enable( FALSE );
if (gc_graphics_boot == FALSE) {
break;
}
vc_progress_set( FALSE, 0 );
vc_acquire_delay = kProgressReacquireDelay;
vc_progress_white = TRUE;
#if defined(XNU_TARGET_OS_OSX)
vc_enable_progressmeter(FALSE);
vc_progress_withmeter &= ~1;
#endif
vc_clut8 = NULL;
break;
#if defined(__x86_64__)
case kPERefreshBootGraphics:
{
boolean_t save;
if (kBootArgsFlagBlack & ((boot_args *) PE_state.bootArgs)->flags) {
break;
}
save = vc_progress_white;
vc_progress_white = (0 != (kBootArgsFlagBlackBg & ((boot_args *) PE_state.bootArgs)->flags));
internal_enable_progressmeter(kProgressMeterKernel);
simple_lock(&vc_progress_lock, LCK_GRP_NULL);
vc_progressmeter_drawn = 0;
internal_set_progressmeter(vc_progressmeter_range(vc_progressmeter_count >> 13));
simple_unlock(&vc_progress_lock);
internal_enable_progressmeter(kProgressMeterOff);
vc_progress_white = save;
}
#endif
}
}
void vcattach(void); /* XXX gcc 4 warning cleanup */
void
vcattach(void)
{
vm_initialized = TRUE;
#if defined(CONFIG_VC_PROGRESS_METER_SUPPORT)
const boot_args * bootargs = (typeof(bootargs))PE_state.bootArgs;
PE_parse_boot_argn("meter", &vc_progress_withmeter, sizeof(vc_progress_withmeter));
#if defined(__x86_64__)
vc_progress_white = (0 != ((kBootArgsFlagBlackBg | kBootArgsFlagLoginUI)
& bootargs->flags));
if (kBootArgsFlagInstallUI & bootargs->flags) {
vc_progress_meter_start = (bootargs->bootProgressMeterStart * kProgressMeterMax) / 65535;
vc_progress_meter_end = (bootargs->bootProgressMeterEnd * kProgressMeterMax) / 65535;
} else {
vc_progress_meter_start = 0;
vc_progress_meter_end = kProgressMeterEnd;
}
#else
vc_progress_meter_start = 0;
vc_progress_meter_end = kProgressMeterEnd;
#endif /* defined(__x86_64__ */
#endif /* defined(CONFIG_VC_PROGRESS_METER_SUPPORT) */
simple_lock_init(&vc_progress_lock, 0);
if (gc_graphics_boot == FALSE) {
long index;
if (gc_acquired) {
initialize_screen(NULL, kPEReleaseScreen);
}
initialize_screen(NULL, kPEAcquireScreen);
for (index = 0; index < msgbufp->msg_bufx; index++) {
if (msgbufp->msg_bufc[index] == '\0') {
continue;
}
vcputc( msgbufp->msg_bufc[index] );
if (msgbufp->msg_bufc[index] == '\n') {
vcputc( '\r' );
}
}
}
}
#if defined(XNU_TARGET_OS_OSX)
// redraw progress meter between pixels start, end, position at pos,
// options (including rotation) passed in flags
static void
vc_draw_progress_meter(unsigned int flags, int start, int end, int pos)
{
const unsigned char *data;
int i, width, bx, srcRow, backRow;
int rectX, rectY, rectW, rectH;
int endCapPos, endCapStart;
int barWidth = kProgressBarWidth * vc_uiscale;
int barHeight = kProgressBarHeight * vc_uiscale;
int capWidth = kProgressBarCapWidth * vc_uiscale;
// 1 rounded fill, 0 square end
int style = (0 == (2 & vc_progress_withmeter));
// 1 white, 0 greyed out
int onoff;
for (i = start; i < end; i += width) {
onoff = (i < pos);
endCapPos = ((style && onoff) ? pos : barWidth);
endCapStart = endCapPos - capWidth;
if (flags & kDataBack) { // restore back bits
width = end;// loop done after this iteration
data = NULL;
srcRow = 0;
} else if (i < capWidth) { // drawing the left cap
width = (end < capWidth) ? (end - i) : (capWidth - i);
data = progressmeter_leftcap[vc_uiscale >= 2][onoff];
data += i;
srcRow = capWidth;
} else if (i < endCapStart) { // drawing the middle
width = (end < endCapStart) ? (end - i) : (endCapStart - i);
data = progressmeter_middle[vc_uiscale >= 2][onoff];
srcRow = 1;
} else { // drawing the right cap
width = endCapPos - i;
data = progressmeter_rightcap[vc_uiscale >= 2][onoff];
data += i - endCapStart;
srcRow = capWidth;
}
switch (flags & kDataRotate) {
case kDataRotate90: // left middle, bar goes down
rectW = barHeight;
rectH = width;
rectX = (6 * vinfo.v_width) / 100 + 34 * vc_uiscale - (barHeight / 2);
rectY = ((vinfo.v_height - barWidth) / 2) + i;
bx = i * barHeight;
backRow = barHeight;
break;
case kDataRotate180: // middle upper, bar goes left
rectW = width;
rectH = barHeight;
rectX = ((vinfo.v_width - barWidth) / 2) + barWidth - width - i;
rectY = (6 * vinfo.v_height) / 100 + 34 * vc_uiscale - (barHeight / 2);
bx = barWidth - width - i;
backRow = barWidth;
break;
case kDataRotate270: // right middle, bar goes up
rectW = barHeight;
rectH = width;
rectX = (94 * vinfo.v_width) / 100 - 34 * vc_uiscale - (barHeight / 2);
rectY = ((vinfo.v_height - barWidth) / 2) + barWidth - width - i;
bx = (barWidth - width - i) * barHeight;
backRow = barHeight;
break;
default:
case kDataRotate0: // middle lower, bar goes right
rectW = width;
rectH = barHeight;
rectX = ((vinfo.v_width - barWidth) / 2) + i;
rectY = (94 * vinfo.v_height) / 100 - 34 * vc_uiscale - (barHeight / 2);
bx = i;
backRow = barWidth;
break;
}
vc_blit_rect(rectX, rectY, bx, rectW, rectH, width, barHeight,
srcRow, backRow, data, vc_progressmeter_backbuffer, flags);
}
}
extern void IORecordProgressBackbuffer(void * buffer, size_t size, uint32_t theme);
static void
internal_enable_progressmeter(int new_value)
{
void * new_buffer;
boolean_t stashBackbuffer;
int flags = vinfo.v_rotate;
stashBackbuffer = FALSE;
new_buffer = NULL;
if (new_value) {
new_buffer = kalloc_data((kProgressBarWidth * vc_uiscale) *
(kProgressBarHeight * vc_uiscale) * sizeof(int), Z_WAITOK);
}
simple_lock(&vc_progress_lock, LCK_GRP_NULL);
if (kProgressMeterUser == new_value) {
if (gc_enabled || !gc_acquired || !gc_graphics_boot) {
new_value = vc_progressmeter_enable;
}
}
if (new_value != vc_progressmeter_enable) {
if (new_value) {
if (kProgressMeterOff == vc_progressmeter_enable) {
vc_progressmeter_backbuffer = new_buffer;
vc_draw_progress_meter(kDataAlpha | kSave | flags, 0, (kProgressBarWidth * vc_uiscale), 0);
new_buffer = NULL;
vc_progressmeter_drawn = 0;
}
vc_progressmeter_enable = new_value;
} else if (vc_progressmeter_backbuffer) {
if (kProgressMeterUser == vc_progressmeter_enable) {
vc_draw_progress_meter(kDataBack | flags, 0, (kProgressBarWidth * vc_uiscale), vc_progressmeter_drawn);
} else {
stashBackbuffer = TRUE;
}
new_buffer = vc_progressmeter_backbuffer;
vc_progressmeter_backbuffer = NULL;
vc_progressmeter_enable = FALSE;
}
}
simple_unlock(&vc_progress_lock);
if (new_buffer) {
if (stashBackbuffer) {
IORecordProgressBackbuffer(new_buffer,
(kProgressBarWidth * vc_uiscale)
* (kProgressBarHeight * vc_uiscale)
* sizeof(int),
vc_progress_white);
}
kfree_data(new_buffer, (kProgressBarWidth * vc_uiscale) *
(kProgressBarHeight * vc_uiscale) * sizeof(int));
}
}
static void
internal_set_progressmeter(int new_value)
{
int x1, x3;
int capRedraw;
// 1 rounded fill, 0 square end
int style = (0 == (2 & vc_progress_withmeter));
int flags = kDataAlpha | vinfo.v_rotate;
if ((new_value < 0) || (new_value > kProgressMeterMax)) {
return;
}
if (vc_progressmeter_enable) {
vc_progressmeter_value = new_value;
capRedraw = (style ? (kProgressBarCapWidth * vc_uiscale) : 0);
x3 = (((kProgressBarWidth * vc_uiscale) - 2 * capRedraw) * vc_progressmeter_value) / kProgressMeterMax;
x3 += (2 * capRedraw);
if (x3 > vc_progressmeter_drawn) {
x1 = capRedraw;
if (x1 > vc_progressmeter_drawn) {
x1 = vc_progressmeter_drawn;
}
vc_draw_progress_meter(flags, vc_progressmeter_drawn - x1, x3, x3);
} else {
vc_draw_progress_meter(flags, x3 - capRedraw, vc_progressmeter_drawn, x3);
}
vc_progressmeter_drawn = x3;
}
}
void
vc_enable_progressmeter(int new_value)
{
internal_enable_progressmeter(new_value ? kProgressMeterUser : kProgressMeterOff);
}
void
vc_set_progressmeter(int new_value)
{
simple_lock(&vc_progress_lock, LCK_GRP_NULL);
if (vc_progressmeter_enable) {
if (kProgressMeterKernel != vc_progressmeter_enable) {
internal_set_progressmeter(new_value);
}
} else {
vc_progressmeter_value = new_value;
}
simple_unlock(&vc_progress_lock);
}
#endif /* defined(XNU_TARGET_OS_OSX) */