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