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