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