]> git.saurik.com Git - apple/xnu.git/blobdiff - osfmk/console/video_console.c
xnu-3789.21.4.tar.gz
[apple/xnu.git] / osfmk / console / video_console.c
index 9e00806ff3e28971b46006dabec8734dadcdea20..5295d3c03d10e2ec3c167beb1b632a756eea6ddd 100644 (file)
@@ -1,23 +1,29 @@
 /*
- * Copyright (c) 2000-2004 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2000-2009 Apple Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
  * 
- * The contents of this file constitute Original Code as defined in and
- * are subject to the Apple Public Source License Version 1.1 (the
- * "License").  You may not use this file except in compliance with the
- * License.  Please obtain a copy of the License at
- * http://www.apple.com/publicsource and read it before using this file.
+ * 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.
  * 
- * This Original Code and all software distributed under the License are
- * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * 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 OR NON-INFRINGEMENT.  Please see the
- * License for the specific language governing rights and limitations
- * under the License.
+ * 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_LICENSE_HEADER_END@
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
  */
 /*
  * @OSF_FREE_COPYRIGHT@
  *
  */
 
-#include <vc.h>
-
 #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/lock.h>
 #include <kern/spl.h>
 #include <kern/thread_call.h>
 
 #include <vm/pmap.h>
 #include <vm/vm_kern.h>
+#include <machine/io_map_entries.h>
+#include <machine/machine_cpu.h>
 
 #include <pexpert/pexpert.h>
+#include <sys/kdebug.h>
 
 #include "iso_font.c"
+#include "progress_meter_data.c"
+
+#include "sys/msgbuf.h"
 
 /*
  * Generic Console (Front-End)
  */
 
 struct vc_info vinfo;
-/* if panicDialogDesired is true then we use the panic dialog when its */
-/* allowed otherwise we won't use the panic dialog even if it is allowed */
-boolean_t panicDialogDesired;
 
+void noroot_icon_test(void);
+
+
 extern int       disableConsoleOutput;
 static boolean_t gc_enabled     = FALSE;
 static boolean_t gc_initialized = FALSE;
@@ -119,22 +128,70 @@ static boolean_t vm_initialized = FALSE;
 static struct {
        void (*initialize)(struct vc_info * info);
        void (*enable)(boolean_t enable);
-       void (*paint_char)(int xx, int yy, unsigned char ch, int attrs, unsigned char ch_previous, int attrs_previous);
-       void (*clear_screen)(int xx, int yy, int top, int bottom, int which);
-       void (*scroll_down)(int num, int top, int bottom);
-       void (*scroll_up)(int num, int top, int bottom);
-       void (*hide_cursor)(int xx, int yy);
-       void (*show_cursor)(int xx, int yy);
+       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 = NULL;
-static unsigned char * gc_buffer_characters = NULL;
-static unsigned char * gc_buffer_colorcodes = NULL;
-static unsigned long   gc_buffer_columns    = 0;
-static unsigned long   gc_buffer_rows       = 0;
-static unsigned long   gc_buffer_size       = 0;
-decl_simple_lock_data(,gc_buffer_lock)
+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;
+
+#if defined(__i386__) || defined(__x86_64__)
+decl_simple_lock_data(static, vcputc_lock);
+
+#define VCPUTC_LOCK_INIT()                             \
+MACRO_BEGIN                                            \
+       simple_lock_init(&vcputc_lock, 0);              \
+MACRO_END
+
+#define VCPUTC_LOCK_LOCK()                             \
+MACRO_BEGIN                                            \
+       boolean_t istate = ml_get_interrupts_enabled(); \
+       while (!simple_lock_try(&vcputc_lock))          \
+       {                                               \
+               if (!istate)                            \
+                       handle_pending_TLB_flushes();   \
+               cpu_pause();                            \
+       }                                               \
+MACRO_END
+
+#define VCPUTC_LOCK_UNLOCK()                           \
+MACRO_BEGIN                                            \
+       simple_unlock(&vcputc_lock);                    \
+MACRO_END
+#else
+static hw_lock_data_t vcputc_lock;
+
+#define VCPUTC_LOCK_INIT()                             \
+MACRO_BEGIN                                            \
+       hw_lock_init(&vcputc_lock);                     \
+MACRO_END
+
+#define VCPUTC_LOCK_LOCK()                             \
+MACRO_BEGIN                                            \
+       if (!hw_lock_to(&vcputc_lock, ~0U))\
+       {                                               \
+               panic("VCPUTC_LOCK_LOCK");              \
+       }                                               \
+MACRO_END
+
+#define VCPUTC_LOCK_UNLOCK()                           \
+MACRO_BEGIN                                            \
+       hw_lock_unlock(&vcputc_lock);                   \
+MACRO_END
+#endif
 
 /*
 # Attribute codes: 
@@ -156,18 +213,15 @@ decl_simple_lock_data(,gc_buffer_lock)
 #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 = 0;
+static unsigned char gc_color_code;
 
 /* VT100 state: */
 #define MAXPARS        16
-static int gc_x = 0, gc_y = 0, gc_savex, gc_savey;
-static int gc_par[MAXPARS], gc_numpars, gc_hanging_cursor, gc_attr, gc_saveattr;
+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 tab stops & scroll region */
-static char gc_tab_stops[255];
-static int  gc_scrreg_top, gc_scrreg_bottom;
-
-enum { kProgressAcquireDelay = 5 /* secs */ };
+/* VT100 scroll region */
+static unsigned int gc_scrreg_top, gc_scrreg_bottom;
 
 enum vt100state_e {
        ESnormal,               /* Nothing yet                             */
@@ -184,17 +238,39 @@ enum vt100state_e {
        ESignore                /* Ignore this sequence                    */
 } gc_vt100state = ESnormal;
 
+
+enum 
+{
+    /* secs */
+    kProgressAcquireDelay   = 0,
+    kProgressReacquireDelay = 5,
+};
+
+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(int xx, int yy, int which);
-static void gc_clear_screen(int xx, int yy, int top, int bottom, int which);
+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(int xx, int yy);
+static void gc_hide_cursor(unsigned int xx, unsigned int yy);
 static void gc_initialize(struct vc_info * info);
-static void gc_paint_char(int xx, int yy, unsigned char ch, int attrs);
+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);
@@ -204,20 +280,19 @@ 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_refresh_screen(void);
 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, int top, int bottom);
-static void gc_scroll_up(int num, int top, int bottom);
-static void gc_show_cursor(int xx, int yy);
+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);
-extern int  vcputc(int l, int u, int c);
 
 static void 
-gc_clear_line(int xx, int yy, int which)
+gc_clear_line(unsigned int xx, unsigned int yy, int which)
 {
-       int     start, end, i;
+       unsigned int start, end, i;
 
        /*
         * This routine runs extremely slowly.  I don't think it's
@@ -239,25 +314,24 @@ gc_clear_line(int xx, int yy, int which)
                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(int xx, int yy, int top, int bottom, int which)
+gc_clear_screen(unsigned int xx, unsigned int yy, int top, unsigned int bottom,
+               int which)
 {
-       spl_t    s;
-
-       s = splhigh();
-       simple_lock(&gc_buffer_lock);
+       if (!gc_buffer_size) return;
 
        if ( xx < gc_buffer_columns && yy < gc_buffer_rows && bottom <= gc_buffer_rows )
        {
-               unsigned long start, end;
+               uint32_t start, end;
 
                switch (which) {
                        case 0:         /* To end of screen      */
@@ -272,65 +346,73 @@ gc_clear_screen(int xx, int yy, int top, int bottom, int which)
                                start = (top * gc_buffer_columns);
                                end = (bottom * gc_buffer_columns) - 1;
                                break;
+                       default:
+                               start = 0;
+                               end = 0;
+                               break;
                }
 
-               memset(gc_buffer_attributes + start, 0x00, end - start + 1);
-               memset(gc_buffer_characters + start, 0x00, end - start + 1);
+               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);
        }
 
-       simple_unlock(&gc_buffer_lock);
-       splx(s);
-
        gc_ops.clear_screen(xx, yy, top, bottom, which);
 }
 
 static void
 gc_enable( boolean_t enable )
 {
-       unsigned char * buffer_attributes;
-       unsigned char * buffer_characters;
-       unsigned char * buffer_colorcodes;
-       unsigned long   buffer_columns;
-       unsigned long   buffer_rows;
-       unsigned long   buffer_size;
-
+       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;
        spl_t s;
 
        if ( enable == FALSE )
        {
-               disableConsoleOutput = TRUE;
+               // 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);
        }
 
        s = splhigh( );
-       simple_lock( &gc_buffer_lock );
+       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;
 
-               simple_unlock( &gc_buffer_lock );
+               VCPUTC_LOCK_UNLOCK( );
                splx( s );
 
                kfree( buffer_attributes, buffer_size );
                kfree( buffer_characters, buffer_size );
                kfree( buffer_colorcodes, buffer_size );
+               kfree( buffer_tab_stops,  buffer_columns );
        }
        else
        {
-               simple_unlock( &gc_buffer_lock );
+               VCPUTC_LOCK_UNLOCK( );
                splx( s );
        }
 
@@ -347,42 +429,54 @@ gc_enable( boolean_t enable )
                                buffer_attributes = (unsigned char *) kalloc( buffer_size );
                                buffer_characters = (unsigned char *) kalloc( buffer_size );
                                buffer_colorcodes = (unsigned char *) kalloc( buffer_size );
+                               buffer_tab_stops  = (unsigned char *) kalloc( buffer_columns );
 
                                if ( buffer_attributes == NULL ||
                                     buffer_characters == NULL ||
-                                    buffer_colorcodes == NULL )
+                                    buffer_colorcodes == NULL ||
+                                    buffer_tab_stops  == NULL )
                                {
                                        if ( buffer_attributes ) kfree( buffer_attributes, buffer_size );
                                        if ( buffer_characters ) kfree( buffer_characters, buffer_size );
                                        if ( buffer_colorcodes ) kfree( buffer_colorcodes, buffer_size );
+                                       if ( buffer_tab_stops  ) kfree( 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, 0x00, buffer_size );
-                                       memset( buffer_characters, 0x00, buffer_size );
-                                       memset( buffer_colorcodes, 0x0F, buffer_size );
+                                       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 );
                                }
                        }
                }
 
                s = splhigh( );
-               simple_lock( &gc_buffer_lock );
+               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;
 
-               simple_unlock( &gc_buffer_lock );
+               gc_reset_screen();
+
+               VCPUTC_LOCK_UNLOCK( );
                splx( s );
 
-               gc_reset_screen();
+               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;
@@ -391,24 +485,16 @@ gc_enable( boolean_t enable )
 }
 
 static void
-gc_hide_cursor(int xx, int yy)
+gc_hide_cursor(unsigned int xx, unsigned int yy)
 {
-       spl_t s;
-
-       s = splhigh();
-       simple_lock(&gc_buffer_lock);
-
        if ( xx < gc_buffer_columns && yy < gc_buffer_rows )
        {
-               unsigned long index = (yy * gc_buffer_columns) + xx;
+               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;
 
-               simple_unlock(&gc_buffer_lock);
-               splx(s);
-
                gc_update_color(COLOR_CODE_GET(colorcode, TRUE ), TRUE );
                gc_update_color(COLOR_CODE_GET(colorcode, FALSE), FALSE);
 
@@ -419,9 +505,6 @@ gc_hide_cursor(int xx, int yy)
        }
        else
        {
-               simple_unlock(&gc_buffer_lock);
-               splx(s);
-
                gc_ops.hide_cursor(xx, yy);
        }
 }
@@ -432,7 +515,7 @@ gc_initialize(struct vc_info * info)
        if ( gc_initialized == FALSE )
        {
                /* Init our lock */
-               simple_lock_init(&gc_buffer_lock, 0);
+               VCPUTC_LOCK_INIT();
 
                gc_initialized = TRUE;
        }
@@ -444,25 +527,17 @@ gc_initialize(struct vc_info * info)
 }
 
 static void
-gc_paint_char(int xx, int yy, unsigned char ch, int attrs)
+gc_paint_char(unsigned int xx, unsigned int yy, unsigned char ch, int attrs)
 {
-       spl_t s;
-
-       s = splhigh();
-       simple_lock(&gc_buffer_lock);
-
        if ( xx < gc_buffer_columns && yy < gc_buffer_rows )
        {
-               unsigned long index = (yy * gc_buffer_columns) + xx;
+               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;
        }
 
-       simple_unlock(&gc_buffer_lock);
-       splx(s);
-
        gc_ops.paint_char(xx, yy, ch, attrs, 0, 0);
 }
 
@@ -504,18 +579,17 @@ gc_putchar(char ch)
        }
 
        if (gc_x >= vinfo.v_columns) {
-               gc_x = vinfo.v_columns - 1;
-       }
-       if (gc_x < 0) {
-               gc_x = 0;
+               if (0 == vinfo.v_columns)
+                       gc_x = 0;
+               else
+                       gc_x = vinfo.v_columns - 1;
        }
        if (gc_y >= vinfo.v_rows) {
-               gc_y = vinfo.v_rows - 1;
-       }
-       if (gc_y < 0) {
-               gc_y = 0;
+               if (0 == vinfo.v_rows)
+                       gc_y = 0;
+               else
+                       gc_y = vinfo.v_rows - 1;
        }
-
 }
 
 static void
@@ -572,7 +646,7 @@ gc_putc_charsizecmd(unsigned char ch)
                        break;
                case '8' :      /* fill 'E's */
                        {
-                               int xx, yy;
+                               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);
@@ -607,7 +681,7 @@ gc_putc_esc(unsigned char ch)
                if (ch == 'E') gc_x = 0;
                break;
        case 'H':               /* Set tab stop          */
-               gc_tab_stops[gc_x] = 1;
+               gc_set_tab_stop(gc_x, TRUE);
                break;
        case 'M':               /* Cursor up             */
                if (gc_y <= gc_scrreg_top) {
@@ -684,7 +758,7 @@ gc_putc_getpars(unsigned char ch)
 static void 
 gc_putc_gotpars(unsigned char ch)
 {
-       int     i;
+       unsigned int i;
 
        if (ch < ' ') {
                /* special case for vttest for handling cursor
@@ -711,9 +785,12 @@ gc_putc_gotpars(unsigned char ch)
                        gc_x = vinfo.v_columns-1;
                break;
        case 'D':               /* Left                  */
-               gc_x -= gc_par[0] ? gc_par[0] : 1;
-               if (gc_x < 0)
+               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':
@@ -725,7 +802,6 @@ gc_putc_gotpars(unsigned char ch)
                break;
        case 'X':               /* clear p1 characters */
                if (gc_numpars) {
-                       int i;
                        for (i = gc_x; i < gc_x + gc_par[0]; i++)
                                gc_paint_char(i, gc_y, ' ', ATTR_NONE);
                }
@@ -744,14 +820,12 @@ gc_putc_gotpars(unsigned char ch)
                                break;                          
                        case 3: /* Clear every tabs */
                                {
-                                       int i;
-
                                        for (i = 0; i <= vinfo.v_columns; i++)
-                                               gc_tab_stops[i] = 0;
+                                               gc_set_tab_stop(i, FALSE);
                                }
                                break;
                        case 0:
-                               gc_tab_stops[gc_x] = 0;
+                               gc_set_tab_stop(gc_x, FALSE);
                                break;
                }
                break;
@@ -798,8 +872,6 @@ gc_putc_gotpars(unsigned char ch)
                /* 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;
-                       if (gc_scrreg_top < 0)
-                               gc_scrreg_top = 0;
                } else {
                        gc_scrreg_top = 0;
                }
@@ -833,7 +905,8 @@ gc_putc_normal(unsigned char ch)
                        }
                break;
        case '\t':              /* Tab                   */
-               while (gc_x < vinfo.v_columns && !gc_tab_stops[++gc_x]);
+               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;
@@ -906,64 +979,42 @@ gc_putc_square(unsigned char ch)
 
 }
 
-static void 
-gc_refresh_screen(void)
-{
-       spl_t s;
-
-       s = splhigh();
-       simple_lock(&gc_buffer_lock);
-
-       if ( gc_buffer_size )
-       {
-               unsigned char colorcodesave = gc_color_code;
-               unsigned long column, row;
-               unsigned long index;
-
-               for ( index = 0, row = 0 ; row < gc_buffer_rows ; row++ )
-               {
-                       for ( column = 0 ; column < gc_buffer_columns ; index++, column++ )
-                       {
-                               if ( gc_buffer_colorcodes[index] != gc_color_code )
-                               {
-                                       gc_update_color(COLOR_CODE_GET(gc_buffer_colorcodes[index], TRUE ), TRUE );
-                                       gc_update_color(COLOR_CODE_GET(gc_buffer_colorcodes[index], FALSE), FALSE);
-                               }
-
-                               gc_ops.paint_char(column, row, gc_buffer_characters[index], gc_buffer_attributes[index], 0, 0);
-                       }
-               }
-
-               if ( colorcodesave != gc_color_code )
-               {
-                       gc_update_color(COLOR_CODE_GET(colorcodesave, TRUE ), TRUE );
-                       gc_update_color(COLOR_CODE_GET(colorcodesave, FALSE), FALSE);
-               }
-       }
-        
-       simple_unlock(&gc_buffer_lock);
-       splx(s);
-}
-
 static void
 gc_reset_screen(void)
 {
-       gc_hide_cursor(gc_x, gc_y);
        gc_reset_vt100();
        gc_x = gc_y = 0;
-       gc_clear_screen(gc_x, gc_y, 0, vinfo.v_rows, 2);
-       gc_show_cursor(gc_x, gc_y);
 }
 
 static void
 gc_reset_tabs(void)
 {
-       int i;
+       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);
+       }
+
+}
 
-       for (i = 0; i<= vinfo.v_columns; i++) {
-               gc_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
@@ -982,18 +1033,15 @@ gc_reset_vt100(void)
 }
 
 static void 
-gc_scroll_down(int num, int top, int bottom)
+gc_scroll_down(int num, unsigned int top, unsigned int bottom)
 {
-       spl_t s;
-
-       s = splhigh();
-       simple_lock(&gc_buffer_lock);
+       if (!gc_buffer_size) return;
 
        if ( bottom <= gc_buffer_rows )
        {
                unsigned char colorcodesave = gc_color_code;
-               unsigned long column, row;
-               unsigned long index, jump;
+               uint32_t column, row;
+               uint32_t index, jump;
 
                jump = num * gc_buffer_columns;
 
@@ -1045,35 +1093,64 @@ gc_scroll_down(int num, int top, int bottom)
                        gc_update_color(COLOR_CODE_GET(colorcodesave, FALSE), FALSE);
                }
 
-               simple_unlock(&gc_buffer_lock);
-               splx(s);
+               /* 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
        {
-               simple_unlock(&gc_buffer_lock);
-               splx(s);
-
                gc_ops.scroll_down(num, top, bottom);
-       }
 
-       /* Now set the freed up lines to the background colour */
+               /* Now set the freed up lines to the background colour */
 
-       gc_clear_screen(vinfo.v_columns - 1, top + num - 1, top, bottom, 1);
+               gc_clear_screen(vinfo.v_columns - 1, top + num - 1, top, bottom, 1);
+       }
 }
 
 static void 
-gc_scroll_up(int num, int top, int bottom)
+gc_scroll_up(int num, unsigned int top, unsigned int bottom)
 {
-       spl_t s;
-
-       s = splhigh();
-       simple_lock(&gc_buffer_lock);
+       if (!gc_buffer_size) return;
 
        if ( bottom <= gc_buffer_rows )
        {
                unsigned char colorcodesave = gc_color_code;
-               unsigned long column, row;
-               unsigned long index, jump;
+               uint32_t column, row;
+               uint32_t index, jump;
 
                jump = num * gc_buffer_columns;
 
@@ -1115,7 +1192,6 @@ gc_scroll_up(int num, int top, int bottom)
                                        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];
-
                                }
                        }
                }
@@ -1126,41 +1202,65 @@ gc_scroll_up(int num, int top, int bottom)
                        gc_update_color(COLOR_CODE_GET(colorcodesave, FALSE), FALSE);
                }
 
-               simple_unlock(&gc_buffer_lock);
-               splx(s);
+               /* 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
        {
-               simple_unlock(&gc_buffer_lock);
-               splx(s);
-
                gc_ops.scroll_up(num, top, bottom);
-       }
 
-       /* Now set the freed up lines to the background colour */
+               /* Now set the freed up lines to the background colour */
 
-       gc_clear_screen(0, bottom - num, top, bottom, 0);
+               gc_clear_screen(0, bottom - num, top, bottom, 0);
+       }
 }
 
 static void
-gc_show_cursor(int xx, int yy)
+gc_show_cursor(unsigned int xx, unsigned int yy)
 {
-       spl_t s;
-
-       s = splhigh();
-       simple_lock(&gc_buffer_lock);
-
        if ( xx < gc_buffer_columns && yy < gc_buffer_rows )
        {
-               unsigned long index = (yy * gc_buffer_columns) + xx;
+               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;
 
-               simple_unlock(&gc_buffer_lock);
-               splx(s);
-
                gc_update_color(COLOR_CODE_GET(colorcode, FALSE), TRUE );
                gc_update_color(COLOR_CODE_GET(colorcode, TRUE ), FALSE);
 
@@ -1171,9 +1271,6 @@ gc_show_cursor(int xx, int yy)
        }
        else
        {
-               simple_unlock(&gc_buffer_lock);
-               splx(s);
-
                gc_ops.show_cursor(xx, yy);
        }
 }
@@ -1181,21 +1278,36 @@ gc_show_cursor(int xx, int 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);
 }
 
-int
-vcputc(int l, int u, int c)
+void
+vcputc(__unused int l, __unused int u, int c)
 {
-       if ( gc_enabled || debug_mode )
-        {
-               gc_hide_cursor(gc_x, gc_y);
-               gc_putchar(c);
-               gc_show_cursor(gc_x, gc_y);
-       }
+       if ( gc_initialized && ( gc_enabled || debug_mode ) )
+       {
+               spl_t s;
 
-       return 0;
+               s = splhigh();
+#if    defined(__i386__) || defined(__x86_64__)
+               x86_filter_TLB_coherency_interrupts(TRUE);
+#endif
+               VCPUTC_LOCK_LOCK();
+               if ( gc_enabled || debug_mode )
+               {
+                       gc_hide_cursor(gc_x, gc_y);
+                       gc_putchar(c);
+                       gc_show_cursor(gc_x, gc_y);
+               }
+               VCPUTC_LOCK_UNLOCK();
+#if    defined(__i386__) || defined(__x86_64__)
+               x86_filter_TLB_coherency_interrupts(FALSE);
+#endif
+               splx(s);
+       }
 }
 
 /*
@@ -1208,22 +1320,22 @@ vcputc(int l, int u, int c)
  */
 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, 0, 0, 2 };
-
-static unsigned long vc_colors[8][3] = {
-       { 0xFFFFFFFF, 0x00000000, 0x00000000 }, /* black */
-       { 0x23232323, 0x7C007C00, 0x00FF0000 }, /* red  */
-       { 0xb9b9b9b9, 0x03e003e0, 0x0000FF00 }, /* green */
-       { 0x05050505, 0x7FE07FE0, 0x00FFFF00 }, /* yellow */
-       { 0xd2d2d2d2, 0x001f001f, 0x000000FF},  /* blue  */
-//     { 0x80808080, 0x31933193, 0x00666699 }, /* blue  */
-       { 0x18181818, 0x7C1F7C1F, 0x00FF00FF }, /* magenta */
-       { 0xb4b4b4b4, 0x03FF03FF, 0x0000FFFF }, /* cyan */
-       { 0x00000000, 0x7FFF7FFF, 0x00FFFFFF }  /* white */
+          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 unsigned long vc_color_fore = 0;
-static unsigned long vc_color_back = 0;
+static uint32_t vc_color_fore = 0;
+static uint32_t vc_color_back = 0;
 
 /* 
  * New Rendering code from Michel Pollet
@@ -1233,7 +1345,7 @@ static unsigned long vc_color_back = 0;
 static unsigned char *vc_rendered_font = NULL;
 
 /* Rendered Font Size */
-static unsigned long vc_rendered_font_size = 0;
+static uint32_t vc_rendered_font_size = 0;
 
 /* Size of a character in the table (bytes) */
 static int vc_rendered_char_size = 0;
@@ -1241,24 +1353,38 @@ 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)];
 
-static void vc_clear_screen(int xx, int yy, int scrreg_top, int scrreg_bottom, int which);
-static void vc_enable(boolean_t enable);
-static void vc_initialize(struct vc_info * vinfo_p);
-static void vc_paint_char(int xx, int yy, unsigned char ch, int attrs, unsigned char ch_previous, int attrs_previous);
-static void vc_paint_char_8(int xx, int yy, unsigned char ch, int attrs, unsigned char ch_previous, int attrs_previous); 
-static void vc_paint_char_16(int xx, int yy, unsigned char ch, int attrs, unsigned char ch_previous, int attrs_previous); 
-static void vc_paint_char_32(int xx, int yy, unsigned char ch, int attrs, unsigned char ch_previous, int attrs_previous);
-static void vc_render_char(unsigned char ch, unsigned char *renderptr, short newdepth);
-static void vc_render_font(short newdepth);
-static void vc_reverse_cursor(int xx, int yy);
-static void vc_scroll_down(int num, int scrreg_top, int scrreg_bottom);
-static void vc_scroll_up(int num, int scrreg_top, int scrreg_bottom);
-static void vc_update_color(int color, boolean_t fore);
+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,
+};
+
+
+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(int xx, int yy, int scrreg_top, int scrreg_bottom, int which)
+vc_clear_screen(unsigned int xx, unsigned int yy, unsigned int scrreg_top,
+               unsigned int scrreg_bottom, int which)
 {
-       unsigned long *p, *endp, *row;
+       uint32_t *p, *endp, *row;
        int      linelongs, col;
        int      rowline, rowlongs;
 
@@ -1269,8 +1395,8 @@ vc_clear_screen(int xx, int yy, int scrreg_top, int scrreg_bottom, int which)
        rowline = vinfo.v_rowscanbytes >> 2;
        rowlongs = vinfo.v_rowbytes >> 2;
 
-       p = (unsigned long*) vinfo.v_baseaddr;
-       endp = (unsigned long*) vinfo.v_baseaddr;
+       p = (uint32_t*) vinfo.v_baseaddr;
+       endp = (uint32_t*) vinfo.v_baseaddr;
 
        switch (which) {
        case 0:         /* To end of screen      */
@@ -1304,73 +1430,74 @@ vc_clear_screen(int xx, int yy, int scrreg_top, int scrreg_bottom, int which)
 }
 
 static void
-vc_enable(boolean_t enable)
+vc_render_char(unsigned char ch, unsigned char *renderptr, short newdepth)
 {
-       if ( enable )
-       {
-               vc_render_font(vinfo.v_depth);
-       }
-}
+       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;
 
-static void
-vc_initialize(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 / 8) * vinfo.v_width;
-}
+       current.charptr = renderptr;
+       theChar = iso_font + (ch * ISO_CHAR_HEIGHT);
 
-static void
-vc_paint_char(int xx, int yy, unsigned char ch, int attrs, unsigned char ch_previous, int attrs_previous)
-{
-       if( !vinfo.v_depth)
-               return;
+       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;
 
-       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 32:
-                       vc_paint_char_32(xx, yy, ch, attrs, ch_previous, attrs_previous);
-                       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(int xx, int yy, unsigned char ch, int attrs, unsigned char ch_previous, int attrs_previous) 
+vc_paint_char_8(unsigned int xx, unsigned int yy, unsigned char ch, int attrs,
+               __unused unsigned char ch_previous, __unused int attrs_previous)
 {
-       unsigned long *theChar;
-       unsigned long *where;
+       uint32_t *theChar;
+       uint32_t *where;
        int i;
        
        if (vc_rendered_font) {
-               theChar = (unsigned long*)(vc_rendered_font + (ch * vc_rendered_char_size));
+               theChar = (uint32_t*)(vc_rendered_font + (ch * vc_rendered_char_size));
        } else {
                vc_render_char(ch, vc_rendered_char, 8);
-               theChar = (unsigned long*)(vc_rendered_char);
+               theChar = (uint32_t*)(vc_rendered_char);
        }
-       where = (unsigned long*)(vinfo.v_baseaddr + 
+       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 !*/
-               unsigned long *store = where;
+               uint32_t *store = where;
                int x;
                for (x = 0; x < 2; x++) {
-                       unsigned long val = *theChar++;
+                       uint32_t val = *theChar++;
                        val = (vc_color_back & ~val) | (vc_color_fore & val);
                        *store++ = val;
                }
                
-               where = (unsigned long*)(((unsigned char*)where)+vinfo.v_rowbytes);
+               where = (uint32_t*)(((unsigned char*)where)+vinfo.v_rowbytes);
        } else for (i = 0; i < ISO_CHAR_HEIGHT; i++) {  /* a little slower */
-               unsigned long *store = where, lastpixel = 0;
+               uint32_t *store = where, lastpixel = 0;
                int x;
                for (x = 0 ; x < 2; x++) {
-                       unsigned long val = *theChar++, save = val;
+                       uint32_t val = *theChar++, save = val;
                        if (attrs & ATTR_BOLD) {        /* bold support */
                                if (lastpixel && !(save & 0xFF000000))
                                        val |= 0xff000000;
@@ -1389,43 +1516,45 @@ vc_paint_char_8(int xx, int yy, unsigned char ch, int attrs, unsigned char ch_pr
                        lastpixel = save & 0xff;
                }
                
-               where = (unsigned long*)(((unsigned char*)where)+vinfo.v_rowbytes);             
+               where = (uint32_t*)(((unsigned char*)where)+vinfo.v_rowbytes);          
        }
 
 }
 
 static void
-vc_paint_char_16(int xx, int yy, unsigned char ch, int attrs, unsigned char ch_previous, int attrs_previous) 
+vc_paint_char_16(unsigned int xx, unsigned int yy, unsigned char ch, int attrs,
+                __unused unsigned char ch_previous,
+                __unused int attrs_previous) 
 {
-       unsigned long *theChar;
-       unsigned long *where;
+       uint32_t *theChar;
+       uint32_t *where;
        int i;
        
        if (vc_rendered_font) {
-               theChar = (unsigned long*)(vc_rendered_font + (ch * vc_rendered_char_size));
+               theChar = (uint32_t*)(vc_rendered_font + (ch * vc_rendered_char_size));
        } else {
                vc_render_char(ch, vc_rendered_char, 16);
-               theChar = (unsigned long*)(vc_rendered_char);
+               theChar = (uint32_t*)(vc_rendered_char);
        }
-       where = (unsigned long*)(vinfo.v_baseaddr + 
+       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 ! */
-               unsigned long *store = where;
+               uint32_t *store = where;
                int x;
                for (x = 0; x < 4; x++) {
-                       unsigned long val = *theChar++;
+                       uint32_t val = *theChar++;
                        val = (vc_color_back & ~val) | (vc_color_fore & val);
                        *store++ = val;
                }
                
-               where = (unsigned long*)(((unsigned char*)where)+vinfo.v_rowbytes);
+               where = (uint32_t*)(((unsigned char*)where)+vinfo.v_rowbytes);
        } else for (i = 0; i < ISO_CHAR_HEIGHT; i++) { /* a little bit slower */
-               unsigned long *store = where, lastpixel = 0;
+               uint32_t *store = where, lastpixel = 0;
                int x;
                for (x = 0 ; x < 4; x++) {
-                       unsigned long val = *theChar++, save = val;
+                       uint32_t val = *theChar++, save = val;
                        if (attrs & ATTR_BOLD) {        /* bold support */
                                if (save == 0xFFFF0000) val |= 0xFFFF;
                                else if (lastpixel && !(save & 0xFFFF0000))
@@ -1440,25 +1569,26 @@ vc_paint_char_16(int xx, int yy, unsigned char ch, int attrs, unsigned char ch_p
                        lastpixel = save & 0x7fff;
                }
                
-               where = (unsigned long*)(((unsigned char*)where)+vinfo.v_rowbytes);             
+               where = (uint32_t*)(((unsigned char*)where)+vinfo.v_rowbytes);          
        }
 
 }
 
 static void
-vc_paint_char_32(int xx, int yy, unsigned char ch, int attrs, unsigned char ch_previous, int attrs_previous) 
+vc_paint_char_32(unsigned int xx, unsigned int yy, unsigned char ch, int attrs,
+                unsigned char ch_previous, int attrs_previous) 
 {
-       unsigned long *theChar;
-       unsigned long *theCharPrevious;
-       unsigned long *where;
+       uint32_t *theChar;
+       uint32_t *theCharPrevious;
+       uint32_t *where;
        int i;
        
        if (vc_rendered_font) {
-               theChar = (unsigned long*)(vc_rendered_font + (ch * vc_rendered_char_size));
-               theCharPrevious = (unsigned long*)(vc_rendered_font + (ch_previous * vc_rendered_char_size));
+               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 = (unsigned long*)(vc_rendered_char);
+               theChar = (uint32_t*)(vc_rendered_char);
                theCharPrevious = NULL;
        }
        if (!ch_previous) {
@@ -1467,15 +1597,15 @@ vc_paint_char_32(int xx, int yy, unsigned char ch, int attrs, unsigned char ch_p
        if (attrs_previous) {
                theCharPrevious = NULL;
        }
-       where = (unsigned long*)(vinfo.v_baseaddr + 
+       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 ! */
-               unsigned long *store = where;
+               uint32_t *store = where;
                int x;
                for (x = 0; x < 8; x++) {
-                       unsigned long val = *theChar++;
+                       uint32_t val = *theChar++;
                        if (theCharPrevious == NULL || val != *theCharPrevious++ ) {
                                val = (vc_color_back & ~val) | (vc_color_fore & val);
                                *store++ = val;
@@ -1484,12 +1614,12 @@ vc_paint_char_32(int xx, int yy, unsigned char ch, int attrs, unsigned char ch_p
                        }
                }
                
-               where = (unsigned long*)(((unsigned char*)where)+vinfo.v_rowbytes);
+               where = (uint32_t *)(((unsigned char*)where)+vinfo.v_rowbytes);
        } else for (i = 0; i < ISO_CHAR_HEIGHT; i++) {  /* a little slower */
-               unsigned long *store = where, lastpixel = 0;
+               uint32_t *store = where, lastpixel = 0;
                int x;
                for (x = 0 ; x < 8; x++) {
-                       unsigned long val = *theChar++, save = val;
+                       uint32_t val = *theChar++, save = val;
                        if (attrs & ATTR_BOLD) {        /* bold support */
                                if (lastpixel && !save)
                                        val = 0xFFFFFFFF;
@@ -1502,45 +1632,31 @@ vc_paint_char_32(int xx, int yy, unsigned char ch, int attrs, unsigned char ch_p
                        lastpixel = save;
                }
                
-               where = (unsigned long*)(((unsigned char*)where)+vinfo.v_rowbytes);             
+               where = (uint32_t*)(((unsigned char*)where)+vinfo.v_rowbytes);          
        }
 
 }
 
 static void
-vc_render_char(unsigned char ch, unsigned char *renderptr, short newdepth)
+vc_paint_char(unsigned int xx, unsigned int yy, unsigned char ch, int attrs,
+             unsigned char ch_previous, int attrs_previous)
 {
-       union {
-               unsigned char  *charptr;
-               unsigned short *shortptr;
-               unsigned long  *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);
+       if(!vinfo.v_depth)
+               return;
 
-       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 32: 
-                                       *current.longptr++ = (*theChar & mask) ? 0xFFFFFFFF : 0;
-                                       break;
-                       }
-                       mask <<= 1;
-               } while (mask); /* while the single bit drops to the right */
-               theChar++;
+       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;
        }
 }
 
@@ -1550,6 +1666,10 @@ 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;
+       spl_t s;
 
        if (vm_initialized == FALSE) {
                return; /* nothing to do */
@@ -1557,36 +1677,69 @@ vc_render_font(short newdepth)
        if (olddepth == newdepth && vc_rendered_font) {
                return; /* nothing to do */
        }
-       if (vc_rendered_font) {
-               kfree(vc_rendered_font, vc_rendered_font_size);
-       }
 
-       vc_rendered_char_size = ISO_CHAR_HEIGHT * ((newdepth / 8) * ISO_CHAR_WIDTH);
-       vc_rendered_font_size = (ISO_CHAR_MAX-ISO_CHAR_MIN+1) * vc_rendered_char_size;
-        vc_rendered_font = (unsigned char *) kalloc(vc_rendered_font_size);
+       s = splhigh();
+       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;
 
-       if (vc_rendered_font == NULL) {
-               vc_rendered_font_size = 0;
+       VCPUTC_LOCK_UNLOCK();
+       splx(s);
+
+       if (rendered_font) {
+               kfree(rendered_font, rendered_font_size);
+               rendered_font = NULL;
+       }
+
+       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 = (unsigned char *) kalloc(rendered_font_size);
+       }
+
+       if (rendered_font == NULL) {
                return;
        }
 
        for (charindex = ISO_CHAR_MIN; charindex <= ISO_CHAR_MAX; charindex++) {
-               vc_render_char(charindex, vc_rendered_font + (charindex * vc_rendered_char_size), newdepth);
+               vc_render_char(charindex, rendered_font + (charindex * rendered_char_size), newdepth);
        }
 
        olddepth = newdepth;
+
+       s = splhigh();
+       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();
+       splx(s);
+}
+
+static void
+vc_enable(boolean_t enable)
+{
+       vc_render_font(enable ? vinfo.v_depth : 0);
 }
 
 static void
-vc_reverse_cursor(int xx, int yy)
+vc_reverse_cursor(unsigned int xx, unsigned int yy)
 {
-       unsigned long *where;
+       uint32_t *where;
        int line, col;
 
        if(!vinfo.v_depth)
                return;
 
-       where = (unsigned long*)(vinfo.v_baseaddr + 
+       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++) {
@@ -1604,14 +1757,14 @@ vc_reverse_cursor(int xx, int yy)
                                        where[col] = ~where[col];
                                break;
                }
-               where = (unsigned long*)(((unsigned char*)where)+vinfo.v_rowbytes);             
+               where = (uint32_t*)(((unsigned char*)where)+vinfo.v_rowbytes);
        }
 }
 
 static void 
-vc_scroll_down(int num, int scrreg_top, int scrreg_bottom)
+vc_scroll_down(int num, unsigned int scrreg_top, unsigned int scrreg_bottom)
 {
-       unsigned long *from, *to,  linelongs, i, line, rowline, rowscanline;
+       uint32_t *from, *to,  linelongs, i, line, rowline, rowscanline;
 
        if(!vinfo.v_depth)
                return;
@@ -1620,7 +1773,7 @@ vc_scroll_down(int num, int scrreg_top, int scrreg_bottom)
        rowline = vinfo.v_rowbytes >> 2;
        rowscanline = vinfo.v_rowscanbytes >> 2;
 
-       to = (unsigned long *) vinfo.v_baseaddr + (linelongs * scrreg_bottom)
+       to = (uint32_t *) vinfo.v_baseaddr + (linelongs * scrreg_bottom)
                - (rowline - rowscanline);
        from = to - (linelongs * num);  /* handle multiple line scroll (Michel Pollet) */
 
@@ -1631,9 +1784,9 @@ vc_scroll_down(int num, int scrreg_top, int scrreg_bottom)
                        /*
                         * Only copy what is displayed
                         */
-                       video_scroll_down((unsigned int) from, 
-                                       (unsigned int) (from-(vinfo.v_rowscanbytes >> 2)), 
-                                       (unsigned int) to);
+                       video_scroll_down(from, 
+                                       (from-(vinfo.v_rowscanbytes >> 2)), 
+                                       to);
 
                        from -= rowline;
                        to -= rowline;
@@ -1642,9 +1795,9 @@ vc_scroll_down(int num, int scrreg_top, int scrreg_bottom)
 }
 
 static void 
-vc_scroll_up(int num, int scrreg_top, int scrreg_bottom)
+vc_scroll_up(int num, unsigned int scrreg_top, unsigned int scrreg_bottom)
 {
-       unsigned long *from, *to, linelongs, i, line, rowline, rowscanline;
+       uint32_t *from, *to, linelongs, i, line, rowline, rowscanline;
 
        if(!vinfo.v_depth)
                return;
@@ -1653,7 +1806,7 @@ vc_scroll_up(int num, int scrreg_top, int scrreg_bottom)
        rowline = vinfo.v_rowbytes >> 2;
        rowscanline = vinfo.v_rowscanbytes >> 2;
 
-       to = (unsigned long *) vinfo.v_baseaddr + (scrreg_top * linelongs);
+       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;
@@ -1663,9 +1816,9 @@ vc_scroll_up(int num, int scrreg_top, int scrreg_bottom)
                        /*
                         * Only copy what is displayed
                         */
-                       video_scroll_up((unsigned int) from, 
-                                       (unsigned int) (from+(vinfo.v_rowscanbytes >> 2)), 
-                                       (unsigned int) to);
+                       video_scroll_up(from, 
+                                       (from+(vinfo.v_rowscanbytes >> 2)), 
+                                       to);
 
                        from += rowline;
                        to += rowline;
@@ -1690,238 +1843,526 @@ vc_update_color(int color, boolean_t fore)
  * --------------------------------------
  */
 
-struct vc_progress_element {
-    unsigned int       version;
-    unsigned int       flags;
-    unsigned int       time;
-    unsigned char      count;
-    unsigned char      res[3];
-    int                        width;
-    int                        height;
-    int                        dx;
-    int                        dy;
-    int                        transparent;
-    unsigned int       res2[3];
-    unsigned char      data[0];
-};
-typedef struct vc_progress_element vc_progress_element;
-
 static vc_progress_element *   vc_progress;
-static const unsigned char *    vc_progress_data;
+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)
 
-static void vc_blit_rect(    int x, int y, int width, int height,
-                             const unsigned char * dataPtr, const unsigned char * alphaPtr,
-                             void * backBuffer, boolean_t save, boolean_t static_alpha );
-static void vc_blit_rect_8(  int x, int y, int width, int height,
-                             const unsigned char * dataPtr, const unsigned char * alphaPtr,
-                             unsigned char * backBuffer, boolean_t save, boolean_t static_alpha );
-static void vc_blit_rect_16( int x, int y, int width, int height,
-                             const unsigned char * dataPtr, const unsigned char * alphaPtr,
-                             unsigned short * backBuffer, boolean_t save, boolean_t static_alpha );
-static void vc_blit_rect_32( int x, int y, int width, int height,
-                             const unsigned char * dataPtr, const unsigned char * alphaPtr,
-                             unsigned int * backBuffer, boolean_t save, boolean_t static_alpha );
-extern void vc_display_icon( vc_progress_element * desc, const unsigned char * data );
-extern void vc_progress_initialize( vc_progress_element * desc, const unsigned char * data, const unsigned char * clut );
-static void vc_progress_set( boolean_t enable, uint32_t delay );
-static void vc_progress_task( void * arg0, void * arg );
+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 boolean_t                vc_progressmeter_hold;
+static uint32_t                 vc_progressmeter_diskspeed = 256;
+
+
+enum {
+    kSave          = 0x10,
+    kDataIndexed   = 0x20,
+    kDataAlpha     = 0x40,
+    kDataBack      = 0x80,
+    kDataRotate    = 0x03,
+    kDataRotate0   = 0,
+    kDataRotate90  = 1,
+    kDataRotate180 = 2,
+    kDataRotate270 = 3
+};
 
-static void vc_blit_rect(      int x, int y,
-                                int width, int height,
-                                const unsigned char * dataPtr,
-                                const unsigned char * alphaPtr,
-                                void * backBuffer,
-                                boolean_t save, boolean_t static_alpha )
+static void vc_blit_rect(int x, int y, int bx,
+                            int width, int height,
+                           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 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 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 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 sourceRow, int backRow,
+                           const unsigned char * dataPtr,
+                           unsigned int * backBuffer,
+                           unsigned int flags);
+static void vc_progress_task( void * arg0, void * arg );
+static void vc_progressmeter_task( void * arg0, void * arg );
+
+static void vc_blit_rect(int x, int y, int bx,
+                           int width, int height,
+                           int sourceRow, int backRow,
+                           const unsigned char * dataPtr,
+                           void * backBuffer,
+                           unsigned int flags)
 {
-    if(!vinfo.v_depth)
-        return;
+    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, width, height, dataPtr, alphaPtr, (unsigned char *) backBuffer, save, static_alpha );
+                vc_blit_rect_8( x, y, bx, width, height, sourceRow, backRow, dataPtr, (unsigned char *) backBuffer, flags );
            break;
        case 16:
-           vc_blit_rect_16( x, y, width, height, dataPtr, alphaPtr, (unsigned short *) backBuffer, save, static_alpha );
+           vc_blit_rect_16( x, y, bx, width, height, sourceRow, backRow, dataPtr, (unsigned short *) backBuffer, flags );
            break;
        case 32:
-           vc_blit_rect_32( x, y, width, height, dataPtr, alphaPtr, (unsigned int *) backBuffer, save, static_alpha );
+           vc_blit_rect_32( x, y, bx, width, height, sourceRow, backRow, dataPtr, (unsigned int *) backBuffer, flags );
+           break;
+       case 30:
+           vc_blit_rect_30( x, y, bx, width, height, sourceRow, backRow, dataPtr, (unsigned int *) backBuffer, flags );
            break;
     }
 }
 
-static void vc_blit_rect_8(    int x, int y,
-                                int width, int height, 
-                                const unsigned char * dataPtr,
-                                const unsigned char * alphaPtr,
-                                unsigned char * backPtr,
-                                boolean_t save, boolean_t static_alpha )
+static void
+vc_blit_rect_8(int x, int y, __unused int bx,
+              int width, int height,
+              int sourceRow, __unused int backRow,
+              const unsigned char * dataPtr,
+              __unused unsigned char * backBuffer,
+              __unused unsigned int flags)
 {
-    volatile unsigned char * dst;
+    volatile unsigned short * dst;
     int line, col;
-    unsigned int data;
-
-    dst = (unsigned char *)(vinfo.v_baseaddr +
-                            (y * vinfo.v_rowbytes) +
-                            (x));
-
-    for( line = 0; line < height; line++) {
-        for( col = 0; col < width; col++) {
-            data = 0;
-            if( dataPtr != 0) data = *dataPtr++;
-            else if( alphaPtr != 0) data = vc_revclut8[*alphaPtr++];
-                *(dst + col) = data;
-        }
-        dst = (volatile unsigned char *) (((int)dst) + vinfo.v_rowbytes);
+    unsigned int data = 0, out = 0;
+    int sx, sy, a, b, c, d;
+    int scale = 0x10000;
+
+    a = vc_rotate_matr[kDataRotate & flags][0][0] * scale;
+    b = 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) ? ((width * scale)  - 0x8000) : 0;
+    sy = ((c + d) < 0) ? ((height * scale) - 0x8000) : 0;
+
+    if (!sourceRow) data = (unsigned int)(uintptr_t)dataPtr;
+    else if (1 == sourceRow) a = 0;
+
+    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);
     }
 }
 
-static void vc_blit_rect_16(   int x, int y,
-                                int width, int height,
-                                const unsigned char * dataPtr,
-                                const unsigned char * alphaPtr,
-                                unsigned short *  backPtr,
-                                boolean_t save, boolean_t static_alpha )
+/* For ARM, 16-bit is 565 (RGB); it is 1555 (XRGB) on other 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 sourceRow, int backRow,
+                            const unsigned char * dataPtr,
+                            unsigned short * backPtr,
+                            unsigned int flags)
 {
     volatile unsigned short * dst;
     int line, col;
-    unsigned int data, index, alpha, back;
-
-    dst = (volatile unsigned short *)(vinfo.v_baseaddr +
+    unsigned int data = 0, out = 0, back = 0;
+    int sx, sy, a, b, c, d;
+    int scale = 0x10000;
+
+    a = vc_rotate_matr[kDataRotate & flags][0][0] * scale;
+    b = 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) ? ((width * scale)  - 0x8000) : 0;
+    sy = ((c + d) < 0) ? ((height * scale) - 0x8000) : 0;
+
+    if (!sourceRow) data = (unsigned int)(uintptr_t)dataPtr;
+    else if (1 == sourceRow) a = 0;
+
+    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( dataPtr != 0) {
-               index = *dataPtr++;
-                index *= 3;
+    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;
+    }
+}
 
-            if( alphaPtr && backPtr) {
-
-               alpha = *alphaPtr++;
-                data = 0;
-               if( dataPtr != 0) {
-                    if( vc_clut[index + 0] > alpha)
-                        data |= (((vc_clut[index + 0] - alpha) & 0xf8) << 7);
-                    if( vc_clut[index + 1] > alpha)
-                        data |= (((vc_clut[index + 1] - alpha) & 0xf8) << 2);
-                    if( vc_clut[index + 2] > alpha)
-                        data |= (((vc_clut[index + 2] - alpha) & 0xf8) >> 3);
-               }
 
-                if( save) {
-                    back = *(dst + col);
-                    if ( !static_alpha)
-                        *backPtr++ = back;
-                        back = (((((back & 0x7c00) * alpha) + 0x3fc00) >> 8) & 0x7c00)
-                             | (((((back & 0x03e0) * alpha) + 0x01fe0) >> 8) & 0x03e0)
-                             | (((((back & 0x001f) * alpha) + 0x000ff) >> 8) & 0x001f);
-                    if ( static_alpha)
-                        *backPtr++ = back;
-                } else {
-                    back = *backPtr++;
-                    if ( !static_alpha) {
-                        back = (((((back & 0x7c00) * alpha) + 0x3fc00) >> 8) & 0x7c00)
-                             | (((((back & 0x03e0) * alpha) + 0x01fe0) >> 8) & 0x03e0)
-                             | (((((back & 0x001f) * alpha) + 0x000ff) >> 8) & 0x001f);
-                    }
-                }
-
-                data += back;
-
-            } else
-                if( dataPtr != 0) {
-                   data = ( (0xf8 & (vc_clut[index + 0])) << 7)
-                           | ( (0xf8 & (vc_clut[index + 1])) << 2)
-                           | ( (0xf8 & (vc_clut[index + 2])) >> 3);
-               }
+static void vc_blit_rect_32(int x, int y, int bx, 
+                            int width, int height,
+                           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 = vc_rotate_matr[kDataRotate & flags][0][0] * scale;
+    b = 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) ? ((width * scale)  - 0x8000) : 0;
+    sy = ((c + d) < 0) ? ((height * scale) - 0x8000) : 0;
+
+    if (!sourceRow) data = (unsigned int)(uintptr_t)dataPtr;
+    else if (1 == sourceRow) a = 0;
+        
+    if (backPtr)
+       backPtr += bx;
+    dst = (volatile unsigned int *) (vinfo.v_baseaddr +
+                                    (y * vinfo.v_rowbytes) +
+                                    (x * 4));
 
-            *(dst + col) = data;
-       }
-        dst = (volatile unsigned short *) (((int)dst) + vinfo.v_rowbytes);
+    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_32(   int x, int y,
-                                int width, int height,
-                                const unsigned char * dataPtr,
-                                const unsigned char * alphaPtr,
-                                unsigned int *  backPtr,
-                                boolean_t save, boolean_t static_alpha )
+static void vc_blit_rect_30(int x, int y, int bx, 
+                            int width, int height,
+                           int sourceRow, int backRow,
+                           const unsigned char * dataPtr,
+                           unsigned int * backPtr,
+                           unsigned int flags)
 {
     volatile unsigned int * dst;
     int line, col;
-    unsigned int data, index, alpha, back;
-
+    unsigned int data = 0, out = 0, back = 0;
+    unsigned long long exp;
+    int sx, sy, a, b, c, d;
+    int scale = 0x10000;
+
+    a = vc_rotate_matr[kDataRotate & flags][0][0] * scale;
+    b = 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) ? ((width * scale)  - 0x8000) : 0;
+    sy = ((c + d) < 0) ? ((height * scale) - 0x8000) : 0;
+
+    if (!sourceRow) data = (unsigned int)(uintptr_t)dataPtr;
+    else if (1 == sourceRow) a = 0;
+        
+    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( dataPtr != 0) {
-               index = *dataPtr++;
-                index *= 3;
+    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;
+    }
+}
 
-            if( alphaPtr && backPtr) {
-
-               alpha = *alphaPtr++;
-                data = 0;
-                if( dataPtr != 0) {
-                    if( vc_clut[index + 0] > alpha)
-                        data |= ((vc_clut[index + 0] - alpha) << 16);
-                    if( vc_clut[index + 1] > alpha)
-                        data |= ((vc_clut[index + 1] - alpha) << 8);
-                    if( vc_clut[index + 2] > alpha)
-                        data |= ((vc_clut[index + 2] - alpha));
-               }
+static void vc_clean_boot_graphics(void)
+{
+    // 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, 0, 0, color, NULL, 0);
+}
 
-                if( save) {
-                    back = *(dst + col);
-                    if ( !static_alpha)
-                        *backPtr++ = back;
-                    back = (((((back & 0x00ff00ff) * alpha) + 0x00ff00ff) >> 8) & 0x00ff00ff)
-                         | (((((back & 0x0000ff00) * alpha) + 0x0000ff00) >> 8) & 0x0000ff00);
-                    if ( static_alpha)
-                        *backPtr++ = back;
-                } else {
-                    back = *backPtr++;
-                    if ( !static_alpha) {
-                        back = (((((back & 0x00ff00ff) * alpha) + 0x00ff00ff) >> 8) & 0x00ff00ff)
-                             | (((((back & 0x0000ff00) * alpha) + 0x0000ff00) >> 8) & 0x0000ff00);
-                    }
-               }
+/*
+ * Routines to render the lzss image format
+ */
 
-                data += back;
+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;
 
-            } else
-                if( dataPtr != 0) {
-                    data =    (vc_clut[index + 0] << 16)
-                            | (vc_clut[index + 1] << 8)
-                            | (vc_clut[index + 2]);
-               }
+// 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;
 
-            *(dst + col) = data;
-       }
-        dst = (volatile unsigned int *) (((int)dst) + vinfo.v_rowbytes);
+    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 )
 {
@@ -1929,6 +2370,8 @@ void vc_display_icon( vc_progress_element * desc,
 
     if( vc_progress_enable && vc_clut) {
 
+       vc_clean_boot_graphics();
+
        width = desc->width;
        height = desc->height;
        x = desc->dx;
@@ -1937,43 +2380,49 @@ void vc_display_icon( vc_progress_element * desc,
            x += ((vinfo.v_width - width) / 2);
            y += ((vinfo.v_height - height) / 2);
        }
-       vc_blit_rect( x, y, width, height, data, NULL, NULL, FALSE, TRUE );
+       vc_blit_rect( x, y, 0, width, height, width, 0, data, NULL, kDataIndexed );
     }
 }
 
 void
 vc_progress_initialize( vc_progress_element * desc,
-                       const unsigned char * data,
+                       const unsigned char * data1x,
+                       const unsigned char * data2x,
+                       const unsigned char * data3x,
                        const unsigned char * clut )
 {
-       uint64_t        abstime;
+    uint64_t   abstime;
 
-    if( (!clut) || (!desc) || (!data))
+    if( (!clut) || (!desc) || (!data1x))
        return;
     vc_clut = clut;
     vc_clut8 = clut;
 
     vc_progress = desc;
-    vc_progress_data = data;
+    vc_progress_data[0] = data1x;
+    vc_progress_data[1] = data2x;
+    vc_progress_data[2] = data3x;
     if( 2 & vc_progress->flags)
-        vc_progress_alpha = vc_progress_data
+        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 = abstime;
+    vc_progress_interval = (uint32_t)abstime;
+
+    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;
 
-    simple_lock_init(&vc_progress_lock, 0);
 }
 
-static void
-vc_progress_set( boolean_t enable, uint32_t delay )
+void
+vc_progress_set(boolean_t enable, uint32_t vc_delay)
 {
     spl_t           s;
-    void             *saveBuf = 0;
+    void             *saveBuf = NULL;
     vm_size_t        saveLen = 0;
     unsigned int     count;
     unsigned int     index;
@@ -1983,11 +2432,41 @@ vc_progress_set( boolean_t enable, uint32_t delay )
     unsigned int     pdata32;
     unsigned int *   buf32;
 
-    if( !vc_progress)
+
+    if (kBootArgsFlagBlack & ((boot_args *) PE_state.bootArgs)->flags) return;
+
+    if (1 & vc_progress_withmeter)
+    {
+       if (enable) internal_enable_progressmeter(kProgressMeterKernel);
+
+       s = splhigh();
+       simple_lock(&vc_progress_lock);
+
+       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);
+       splx(s);
+
+       if (!enable) internal_enable_progressmeter(kProgressMeterOff);
        return;
+    }
+
+
+    if(!vc_progress) return;
 
     if( enable) {
-        saveLen = vc_progress->width * vc_progress->height * vinfo.v_depth / 8;
+        saveLen = (vc_progress->width * vc_uiscale) * (vc_progress->height * vc_uiscale) * vinfo.v_depth / 8;
         saveBuf = kalloc( saveLen );
 
        switch( vinfo.v_depth) {
@@ -2009,9 +2488,9 @@ vc_progress_set( boolean_t enable, uint32_t delay )
 
            case 16 :
                buf16 = (unsigned short *) saveBuf;
-               pdata16 = ((vc_clut[0x01 * 3 + 0] & 0xf8) << 7)
-                      | ((vc_clut[0x01 * 3 + 0] & 0xf8) << 2)
-                      | ((vc_clut[0x01 * 3 + 0] & 0xf8) >> 3);
+               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;
@@ -2036,17 +2515,21 @@ vc_progress_set( boolean_t enable, uint32_t delay )
             vc_needsave      = TRUE;
             vc_saveunder     = saveBuf;
             vc_saveunder_len = saveLen;
-            saveBuf         = 0;
-            saveLen         = 0;
-
-            clock_interval_to_deadline(delay, 1000 * 1000 * 1000 /*second scale*/, &vc_progress_deadline);
+            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 = 0;
+                vc_saveunder = NULL;
                 vc_saveunder_len = 0;
             }
 
@@ -2061,40 +2544,126 @@ vc_progress_set( boolean_t enable, uint32_t delay )
         kfree( saveBuf, saveLen );
 }
 
-static void vc_progress_task( void * arg0, void * arg )
+
+static uint32_t vc_progressmeter_range(uint32_t pos)
 {
-    spl_t              s;
-    int                        count = (int) arg;
-    int                        x, y, width, height;
-    const unsigned char * data;
+    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)
+{
+    spl_t    s;
+    uint64_t interval;
 
     s = splhigh();
     simple_lock(&vc_progress_lock);
+    if (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];
 
-    if( vc_progress_enable) {
+           interval = vc_progressmeter_interval;
+           interval = ((interval * 256) / vc_progressmeter_diskspeed);
 
-        count++;
-        if( count >= vc_progress->count)
-            count = 0;
+           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);
+    splx(s);
+}
 
-       width = vc_progress->width;
-       height = vc_progress->height;
-       x = vc_progress->dx;
-       y = vc_progress->dy;
-       data = vc_progress_data;
-       data += count * width * height;
-       if( 1 & vc_progress->flags) {
-           x += ((vinfo.v_width - width) / 2);
-           y += ((vinfo.v_height - height) / 2);
+void vc_progress_setdiskspeed(uint32_t speed)
+{
+    vc_progressmeter_diskspeed = speed;
+}
+
+
+static void
+vc_progress_task(__unused void *arg0, __unused void *arg)
+{
+    spl_t     s;
+    int              x, y, width, height;
+    uint64_t  x_pos, y_pos;
+    const unsigned char * data;
+
+    s = splhigh();
+    simple_lock(&vc_progress_lock);
+
+    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 0:
+                   x_pos = vc_progress_options.x_pos;
+                   y_pos = vc_progress_options.y_pos;
+                   break;
+               case 2:
+                   x_pos = 0xFFFFFFFF - vc_progress_options.x_pos;
+                   y_pos = 0xFFFFFFFF - vc_progress_options.y_pos;
+                   break;
+               case 1:
+                   x_pos = 0xFFFFFFFF - vc_progress_options.y_pos;
+                   y_pos = vc_progress_options.x_pos;
+                   break;
+               case 3:
+                   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);
+           }
        }
-       vc_blit_rect( x, y, width, height,
-                     NULL, data, vc_saveunder,
-                       vc_needsave, (0 == (4 & vc_progress->flags)) );
-        vc_needsave = FALSE;
 
-        clock_deadline_for_periodic_event(vc_progress_interval, mach_absolute_time(), &vc_progress_deadline);
-        thread_call_enter1_delayed(&vc_progress_call, (void *)count, vc_progress_deadline);
+       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, 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);
     simple_unlock(&vc_progress_lock);
     splx(s);
 }
@@ -2104,46 +2673,127 @@ static void vc_progress_task( void * arg0, void * arg )
  * -------------------------------------------
  */
 
-#ifdef __i386__
-#include <console/i386/text_console.h>
-#endif /* __i386__ */
+#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 )
+{
+       spl_t s;
+
+       s = splhigh( );
+       VCPUTC_LOCK_LOCK( );
+
+    disableConsoleOutput = (pause && !console_is_serial());
+    gc_enabled           = (!pause && !graphics_now);
+
+    VCPUTC_LOCK_UNLOCK( );
+
+    simple_lock(&vc_progress_lock);
+
+    if (pause) 
+    {
+        gc_paused_progress = vc_progress_enable;
+       vc_progress_enable = FALSE;
+    }
+    else vc_progress_enable = gc_paused_progress;
+
+    if (vc_progress_enable)
+    {
+       if (1 & vc_progress_withmeter) thread_call_enter_delayed(&vc_progressmeter_call, vc_progressmeter_deadline);
+       else                           
+       thread_call_enter_delayed(&vc_progress_call, vc_progress_deadline);
+    }
+
+    simple_unlock(&vc_progress_lock);
+    splx(s);
+}
 
-static unsigned int lastVideoPhys = 0;
-static unsigned int lastVideoVirt = 0;
-static unsigned int lastVideoSize = 0;
+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(Boot_Video * boot_vinfo, unsigned int op)
+initialize_screen(PE_Video * boot_vinfo, unsigned int op)
 {
-       unsigned int fbsize;
-       unsigned int newVideoVirt;
-       ppnum_t fbppage;
+       unsigned int newMapSize = 0;
+       vm_offset_t newVideoVirt = 0;
+       boolean_t graphics_now;
+       uint32_t delay;
 
        if ( boot_vinfo )
        {
-//             bcopy((const void *)boot_vinfo, (void *)&boot_video_info, sizeof(boot_video_info));
+               struct vc_info new_vinfo = vinfo;
+               boolean_t makeMapping = FALSE;
 
                /* 
-                *      First, check if we are changing the size and/or location of the framebuffer
+                *      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;
 
-               vinfo.v_name[0]  = 0;
-               vinfo.v_width    = boot_vinfo->v_width;
-               vinfo.v_height   = boot_vinfo->v_height;
-               vinfo.v_depth    = boot_vinfo->v_depth;
-               vinfo.v_rowbytes = boot_vinfo->v_rowBytes;
-               vinfo.v_physaddr = boot_vinfo->v_baseAddr;              /* Get the physical address */
-               kprintf("initialize_screen: b=%08X, w=%08X, h=%08X, r=%08X\n",                  /* (BRINGUP) */
-                       vinfo.v_physaddr, vinfo.v_width,  vinfo.v_height,  vinfo.v_rowbytes);   /* (BRINGUP) */
-
-               if (!vinfo.v_physaddr)                                                  /* Check to see if we have a framebuffer */
+               /*
+                *  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) */
-                       vinfo.v_depth = 0;                                              /* vc routines are nop */
+                       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 */
@@ -2151,69 +2801,59 @@ initialize_screen(Boot_Video * boot_vinfo, unsigned int op)
                }
                else
                {
-                   /*
-                   *   Note that for the first time only, boot_vinfo->v_baseAddr is physical.
-                   */
-    
-                   if (kernel_map != VM_MAP_NULL)                                      /* If VM is up, we are given a virtual address */
-                   {
-                           fbppage = pmap_find_phys(kernel_pmap, (addr64_t)boot_vinfo->v_baseAddr);    /* Get the physical address of frame buffer */
-                           if(!fbppage)                                                /* Did we find it? */
-                           {
-                                   panic("initialize_screen: Strange framebuffer - addr = %08X\n", boot_vinfo->v_baseAddr);
-                           }
-                           vinfo.v_physaddr = (fbppage << 12) | (boot_vinfo->v_baseAddr & PAGE_MASK);                  /* Get the physical address */
-                   }
-    
-#ifdef __i386__
-                   vinfo.v_type     = boot_vinfo->v_display;
-#else
-                   vinfo.v_type = 0;
-#endif
-    
-                   fbsize = round_page_32(vinfo.v_height * vinfo.v_rowbytes);                  /* Remember size */
-    
-                   if ((lastVideoPhys != vinfo.v_physaddr) || (fbsize > lastVideoSize))                /* Did framebuffer change location or get bigger? */
+                   if (makeMapping)
                    {
-                           newVideoVirt = io_map_spec((vm_offset_t)vinfo.v_physaddr, fbsize);  /* Allocate address space for framebuffer */
-    
-                           if (lastVideoVirt)                                                  /* Was the framebuffer mapped before? */
-                           {
-                                   pmap_remove(kernel_pmap, trunc_page_64(lastVideoVirt),
-                                               round_page_64(lastVideoVirt + lastVideoSize));  /* Toss mappings */
-
-                                    if(lastVideoVirt <= vm_last_addr)                            /* Was this not a special pre-VM mapping? */
-                                   {
-                                           kmem_free(kernel_map, lastVideoVirt, lastVideoSize);        /* Toss kernel addresses */
-                                   }
-                           }
-    
-                           lastVideoPhys = vinfo.v_physaddr;                                   /* Remember the framebuffer address */
-                           lastVideoSize = fbsize;                                                     /* Remember the size */
-                           lastVideoVirt = newVideoVirt;                                               /* Remember the virtual framebuffer address */
-                   }
+                           unsigned int flags = VM_WIMG_IO;
+                               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 = io_map_spec((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 */
                }
 
-               vinfo.v_baseaddr = lastVideoVirt;                               /* 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
 
-#ifdef __i386__
-               if ( (vinfo.v_type == TEXT_MODE) )
+               /* Update the vinfo structure atomically with respect to the vc_progress task if running */
+               if (vc_progress)
                {
-                       // Text mode setup by the booter.
-
-                       gc_ops.initialize   = tc_initialize;
-                       gc_ops.enable       = tc_enable;
-                       gc_ops.paint_char   = tc_paint_char;
-                       gc_ops.clear_screen = tc_clear_screen;
-                       gc_ops.scroll_down  = tc_scroll_down;
-                       gc_ops.scroll_up    = tc_scroll_up;
-                       gc_ops.hide_cursor  = tc_hide_cursor;
-                       gc_ops.show_cursor  = tc_show_cursor;
-                       gc_ops.update_color = tc_update_color;
+                   simple_lock(&vc_progress_lock);
+                   vinfo = new_vinfo;
+                   simple_unlock(&vc_progress_lock);
                }
                else
-#endif /* __i386__ */
                {
+                   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;
@@ -2225,98 +2865,156 @@ initialize_screen(Boot_Video * boot_vinfo, unsigned int op)
                        gc_ops.hide_cursor  = vc_reverse_cursor;
                        gc_ops.show_cursor  = vc_reverse_cursor;
                        gc_ops.update_color = vc_update_color;
+            gc_initialize(&vinfo);
                }
-
-               gc_initialize(&vinfo);
-
-#ifdef GRATEFULDEBUGGER
-               GratefulDebInit((bootBumbleC *)boot_vinfo);     /* Re-initialize GratefulDeb */
-#endif /* GRATEFULDEBUGGER */
        }
 
+    graphics_now = gc_graphics_boot && !gc_desire_text;
        switch ( op )
        {
                case kPEGraphicsMode:
-                       panicDialogDesired = TRUE;
                        gc_graphics_boot = TRUE;
+                       gc_desire_text = FALSE;
                        break;
 
                case kPETextMode:
-                       panicDialogDesired = FALSE;
+                       disable_debug_output = FALSE;
                        gc_graphics_boot = FALSE;
                        break;
 
                case kPEAcquireScreen:
                        if ( gc_acquired ) break;
 
-                       vc_progress_set( gc_graphics_boot, kProgressAcquireDelay );
-                       gc_enable( !gc_graphics_boot );
+                       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;
+
+                       vc_progress_set( graphics_now, delay );
+                       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:
-                       /* deprecated */
+            if (gc_acquired) 
+            {
+                gc_pause( FALSE, graphics_now );
+            }
                        break;
 
                case kPETextScreen:
-                       panicDialogDesired = FALSE;
-                       if ( gc_acquired      == FALSE ) break;
+                       if ( console_is_serial() ) break;
+
+                       disable_debug_output = FALSE;
+                       if ( gc_acquired == FALSE )
+                       {
+                               gc_desire_text = TRUE;
+                               break;
+                       }
                        if ( gc_graphics_boot == FALSE ) break;
 
                        vc_progress_set( FALSE, 0 );
+                       vc_enable_progressmeter( FALSE );
                        gc_enable( TRUE );
                        break;
 
-               case kPEDisableScreen:
-                       /* deprecated */
-                       /* skip break */
-
                case kPEReleaseScreen:
                        gc_acquired = FALSE;
+                       gc_desire_text = FALSE;
                        gc_enable( FALSE );
-                       vc_progress_set( FALSE, 0 );
+                       if ( gc_graphics_boot == FALSE ) break;
 
+                       vc_progress_set( FALSE, 0 );
+                       vc_acquire_delay = kProgressReacquireDelay;
+                       vc_progress_white      = TRUE;
+                       vc_enable_progressmeter(FALSE);
+                       vc_progress_withmeter &= ~1;
                        vc_clut8 = NULL;
-#ifdef GRATEFULDEBUGGER
-                       GratefulDebInit(0);                                             /* Stop grateful debugger */
-#endif /* GRATEFULDEBUGGER */
                        break;
-       }
-#ifdef GRATEFULDEBUGGER
-       if ( boot_vinfo ) GratefulDebInit((bootBumbleC *)boot_vinfo);   /* Re initialize GratefulDeb */
-#endif /* GRATEFULDEBUGGER */
-}
 
-void
-refresh_screen(void)
-{
-       if ( gc_enabled )
-       {
-               gc_refresh_screen();
-               gc_show_cursor(gc_x, gc_y);
+
+               case kPERefreshBootGraphics:
+               {
+                   spl_t     s;
+                   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);
+
+                   s = splhigh();
+                   simple_lock(&vc_progress_lock);
+
+                   vc_progressmeter_drawn = 0;
+                   internal_set_progressmeter(vc_progressmeter_range(vc_progressmeter_count >> 13));
+
+                   simple_unlock(&vc_progress_lock);
+                   splx(s);
+
+                   internal_enable_progressmeter(kProgressMeterOff);
+                   vc_progress_white = save;
+               }
        }
 }
 
+void vcattach(void); /* XXX gcc 4 warning cleanup */
+
 void
 vcattach(void)
 {
-       extern struct { long msg_magic; long msg_bufx; long msg_bufr; char msg_bufc[]; } * msgbufp;
-
        vm_initialized = TRUE;
 
+        const boot_args * bootargs  = (typeof(bootargs)) PE_state.bootArgs;
+
+       vc_progress_white = (0 != ((kBootArgsFlagBlackBg | kBootArgsFlagLoginUI) 
+                                         & bootargs->flags));
+       PE_parse_boot_argn("meter", &vc_progress_withmeter, sizeof(vc_progress_withmeter));
+
+       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   = kProgressMeterMax;
+       }
+       simple_lock_init(&vc_progress_lock, 0);
+
        if ( gc_graphics_boot == FALSE )
        {
-               unsigned int index;
+               long index;
 
                if ( gc_acquired )
                {
-                       initialize_screen( 0, kPEReleaseScreen );
+                       initialize_screen(NULL, kPEReleaseScreen);
                }
 
-               initialize_screen( 0, kPEAcquireScreen );
+               initialize_screen(NULL, kPEAcquireScreen);
 
                for ( index = 0 ; index < msgbufp->msg_bufx ; index++ )
                {
+                       if (msgbufp->msg_bufc[index] == '\0') {
+                               continue;
+                       }
+
                        vcputc( 0, 0, msgbufp->msg_bufc[index] );
 
                        if ( msgbufp->msg_bufc[index] == '\n' )
@@ -2326,3 +3024,206 @@ vcattach(void)
                }
        }
 }
+
+
+// redraw progress meter between pixels x1, x2, position at x3
+static void
+vc_draw_progress_meter(unsigned int flags, int x1, int x2, int x3)
+{
+    const unsigned char * data;
+    int x, w;
+    int ox, oy;
+    int endCapPos;
+    int onoff;
+    // 1 rounded fill, 0 square end
+    int style = (0 == (2 & vc_progress_withmeter));
+
+    ox = ((vinfo.v_width - (kProgressBarWidth * vc_uiscale)) / 2);
+    oy = vinfo.v_height - (vinfo.v_height / 3) - ((kProgressBarHeight * vc_uiscale) / 2);
+
+    if (kDataBack == flags)
+    {
+       // restore back bits
+       vc_blit_rect(ox + x1, oy, x1,
+                   x2, (kProgressBarHeight * vc_uiscale), 0, (kProgressBarWidth * vc_uiscale),
+                   NULL, vc_progressmeter_backbuffer, flags);
+       return;
+    }
+
+    for (x = x1; x < x2; x += w)
+    {
+       onoff = (x < x3);
+       endCapPos = ((style && onoff) ? x3 : (kProgressBarWidth * vc_uiscale));
+       if (x < (kProgressBarCapWidth * vc_uiscale))
+       {
+           if (x2 < (kProgressBarCapWidth * vc_uiscale))
+               w = x2 - x;
+           else
+               w = (kProgressBarCapWidth * vc_uiscale) - x;
+           data = progressmeter_leftcap[vc_uiscale >= 2][onoff];
+           data += x;
+           vc_blit_rect(ox + x, oy, x, w,
+                           (kProgressBarHeight * vc_uiscale), 
+                           (kProgressBarCapWidth * vc_uiscale), 
+                           (kProgressBarWidth * vc_uiscale),
+                           data, vc_progressmeter_backbuffer, flags);
+       }
+       else if (x < (endCapPos - (kProgressBarCapWidth * vc_uiscale)))
+       {
+           if (x2 < (endCapPos - (kProgressBarCapWidth * vc_uiscale)))
+               w = x2 - x;
+           else
+               w = (endCapPos - (kProgressBarCapWidth * vc_uiscale)) - x;
+           data = progressmeter_middle[vc_uiscale >= 2][onoff];
+           vc_blit_rect(ox + x, oy, x, w,
+                           (kProgressBarHeight * vc_uiscale),
+                           1,
+                           (kProgressBarWidth * vc_uiscale),
+                           data, vc_progressmeter_backbuffer, flags);
+       }
+       else
+       {
+           w = endCapPos - x;
+           data =  progressmeter_rightcap[vc_uiscale >= 2][onoff];
+           data += x - (endCapPos - (kProgressBarCapWidth * vc_uiscale));
+           vc_blit_rect(ox + x, oy, x, w,
+                           (kProgressBarHeight * vc_uiscale), 
+                           (kProgressBarCapWidth * vc_uiscale), 
+                           (kProgressBarWidth * vc_uiscale),
+                           data, vc_progressmeter_backbuffer, flags);
+       }
+    }
+}
+
+extern void IORecordProgressBackbuffer(void * buffer, size_t size, uint32_t theme);
+
+static void
+internal_enable_progressmeter(int new_value)
+{
+    spl_t     s;
+    void    * new_buffer;
+    boolean_t stashBackbuffer;
+
+    stashBackbuffer = FALSE;
+    new_buffer = NULL;
+    if (new_value)
+    {
+       new_buffer = kalloc((kProgressBarWidth * vc_uiscale) 
+                           * (kProgressBarHeight * vc_uiscale) * sizeof(int));
+    }
+
+    s = splhigh();
+    simple_lock(&vc_progress_lock);
+
+    if (kProgressMeterUser == new_value)
+    {
+       if (gc_enabled || !gc_acquired || !gc_graphics_boot
+        || (kProgressMeterKernel == vc_progressmeter_enable)) 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, 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, 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);
+    splx(s);
+
+    if (new_buffer)
+    {
+       if (stashBackbuffer) IORecordProgressBackbuffer(new_buffer, 
+                                                       (kProgressBarWidth * vc_uiscale) 
+                                                       * (kProgressBarHeight * vc_uiscale) 
+                                                       * sizeof(int),
+                                                       vc_progress_white);
+       kfree(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));
+
+    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(kDataAlpha, vc_progressmeter_drawn - x1, x3, x3);
+        }
+       else
+       {
+           vc_draw_progress_meter(kDataAlpha, x3 - capRedraw, vc_progressmeter_drawn, x3);
+       }
+       vc_progressmeter_drawn = x3;
+    }
+}
+
+void
+vc_enable_progressmeter(int new_value)
+{
+    if (kProgressMeterKernel == vc_progressmeter_enable)
+    {
+       vc_progressmeter_hold = new_value;
+    }
+    else
+    {
+       internal_enable_progressmeter(new_value ? kProgressMeterUser : kProgressMeterOff);
+    }
+}
+
+void
+vc_set_progressmeter(int new_value)
+{
+    spl_t s;
+
+    s = splhigh();
+    simple_lock(&vc_progress_lock);
+
+    if (vc_progressmeter_enable && (kProgressMeterKernel != vc_progressmeter_enable))
+    {
+       internal_set_progressmeter((new_value * kProgressMeterMax) / 100);
+    }
+
+    simple_unlock(&vc_progress_lock);
+    splx(s);
+}
+
+
+
+