1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 /*
28 * Copyright 2017 Toomas Soome <tsoome@me.com>
29 */
30
31 /*
32 * Generic font related data and functions shared by early boot console
33 * in dboot, kernel startup and full kernel.
34 */
35 #include <sys/types.h>
36 #include <sys/systm.h>
37 #include <sys/tem_impl.h>
38 #include <sys/rgb.h>
39 #include <sys/font.h>
40 #include <sys/sysmacros.h>
41
42 /*
43 * To simplify my life, I am "temporarily" collecting the commonly used
44 * color bits here. The bits shared between loader, dboot, early boot, tem.
45 * This data would need some sort of API, but I am in no condition to figure
46 * something out right now.
47 */
48
49 /* ANSI color to sun color translation. */
50 /* BEGIN CSTYLED */
51 /* Bk Rd Gr Br Bl Mg Cy Wh */
52 const uint8_t dim_xlate[XLATE_NCOLORS] = { 1, 5, 3, 7, 2, 6, 4, 8 };
53 const uint8_t brt_xlate[XLATE_NCOLORS] = { 9, 13, 11, 15, 10, 14, 12, 0 };
54
55 const uint8_t solaris_color_to_pc_color[16] = {
56 pc_brt_white, /* 0 - brt_white */
57 pc_black, /* 1 - black */
58 pc_blue, /* 2 - blue */
59 pc_green, /* 3 - green */
60 pc_cyan, /* 4 - cyan */
61 pc_red, /* 5 - red */
62 pc_magenta, /* 6 - magenta */
63 pc_brown, /* 7 - brown */
64 pc_white, /* 8 - white */
65 pc_grey, /* 9 - grey */
66 pc_brt_blue, /* 10 - brt_blue */
67 pc_brt_green, /* 11 - brt_green */
68 pc_brt_cyan, /* 12 - brt_cyan */
69 pc_brt_red, /* 13 - brt_red */
70 pc_brt_magenta, /* 14 - brt_magenta */
71 pc_yellow /* 15 - yellow */
72 };
73
74 const uint8_t pc_color_to_solaris_color[16] = {
75 sun_black, /* 0 - black */
76 sun_blue, /* 1 - blue */
77 sun_green, /* 2 - green */
78 sun_cyan, /* 3 - cyan */
79 sun_red, /* 4 - red */
80 sun_magenta, /* 5 - magenta */
81 sun_brown, /* 6 - brown */
82 sun_white, /* 7 - white */
83 sun_grey, /* 8 - grey */
84 sun_brt_blue, /* 9 - brt_blue */
85 sun_brt_green, /* 10 - brt_green */
86 sun_brt_cyan, /* 11 - brt_cyan */
87 sun_brt_red, /* 12 - brt_red */
88 sun_brt_magenta, /* 13 - brt_magenta */
89 sun_yellow, /* 14 - yellow */
90 sun_brt_white /* 15 - brt_white */
91 };
92
93 /* 4-bit to 24-bit color translation. */
94 const text_cmap_t cmap4_to_24 = {
95 /* 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
96 Wh+ Bk Bl Gr Cy Rd Mg Br Wh Bk+ Bl+ Gr+ Cy+ Rd+ Mg+ Yw */
97 .red = {
98 0xff,0x00,0x00,0x00,0x00,0x80,0x80,0x80,0x80,0x40,0x00,0x00,0x00,0xff,0xff,0xff
99 },
100 .green = {
101 0xff,0x00,0x00,0x80,0x80,0x00,0x00,0x80,0x80,0x40,0x00,0xff,0xff,0x00,0x00,0xff
102 },
103 .blue = {
104 0xff,0x00,0x80,0x00,0x80,0x00,0x80,0x00,0x80,0x40,0xff,0x00,0xff,0x00,0xff,0x00
105 }
106 };
107 /* END CSTYLED */
108
109 /* RGB configuration from boot loader */
110 rgb_t rgb_info = {
111 .red = { .size = 8, .pos = 16 },
112 .green = { .size = 8, .pos = 8 },
113 .blue = { .size = 8, .pos = 0 }
114 };
115
116 /*
117 * Map r, g, b to RGB value.
118 */
119 uint32_t
rgb_to_color(const rgb_t * rgb,uint32_t a,uint32_t r,uint32_t g,uint32_t b)120 rgb_to_color(const rgb_t *rgb, uint32_t a, uint32_t r, uint32_t g, uint32_t b)
121 {
122 uint32_t color;
123 int pos, size;
124
125 color = 0;
126 if (a != 0) {
127 if (rgb->red.pos != 0 &&
128 rgb->green.pos != 0 &&
129 rgb->blue.pos != 0) {
130 pos = 0;
131 size = MIN(rgb->red.pos,
132 MIN(rgb->green.pos, rgb->blue.pos));
133 } else {
134 pos = 24;
135 size = (rgb->red.size + rgb->green.size +
136 rgb->blue.size) / 3;
137 }
138 color = ((a * ((1 << size) - 1)) / 0xff) << pos;
139 }
140
141 pos = rgb->red.pos;
142 size = rgb->red.size;
143 color |= ((r * ((1 << size) - 1)) / 0xff) << pos;
144
145 pos = rgb->green.pos;
146 size = rgb->green.size;
147 color |= (((g * ((1 << size) - 1)) / 0xff) << pos);
148
149 pos = rgb->blue.pos;
150 size = rgb->blue.size;
151 color |= (((b * ((1 << size) - 1)) / 0xff) << pos);
152
153 return (color);
154 }
155
156 uint32_t
rgb_color_map(const rgb_t * rgb,uint8_t index,uint8_t alpha)157 rgb_color_map(const rgb_t *rgb, uint8_t index, uint8_t alpha)
158 {
159 uint32_t color, code, gray, level;
160
161 if (index < 16) {
162 color = rgb_to_color(rgb, alpha, cmap4_to_24.red[index],
163 cmap4_to_24.green[index], cmap4_to_24.blue[index]);
164 return (color);
165 }
166
167 /* 6x6x6 color cube */
168 if (index > 15 && index < 232) {
169 uint32_t red, green, blue;
170
171 for (red = 0; red < 6; red++) {
172 for (green = 0; green < 6; green++) {
173 for (blue = 0; blue < 6; blue++) {
174 code = 16 + (red * 36) +
175 (green * 6) + blue;
176 if (code != index)
177 continue;
178 red = red ? (red * 40 + 55) : 0;
179 green = green ? (green * 40 + 55) : 0;
180 blue = blue ? (blue * 40 + 55) : 0;
181 color = rgb_to_color(rgb, alpha,
182 red, green, blue);
183 return (color);
184 }
185 }
186 }
187 }
188
189 /* colors 232-255 are a grayscale ramp */
190 for (gray = 0; gray < 24; gray++) {
191 level = (gray * 10) + 8;
192 code = 232 + gray;
193 if (code == index)
194 break;
195 }
196 return (rgb_to_color(rgb, alpha, level, level, level));
197 }
198 /*
199 * Fonts are statically linked with this module. At some point an
200 * RFE might be desireable to allow dynamic font loading. The
201 * original intention to facilitate dynamic fonts can be seen
202 * by examining the data structures and set_font(). As much of
203 * the original code is retained but modified to be suited for
204 * traversing a list of static fonts.
205 */
206
207 /*
208 * Must be sorted by font size in descending order
209 */
210 font_list_t fonts = STAILQ_HEAD_INITIALIZER(fonts);
211
212 /*
213 * Reset font flags to FONT_AUTO.
214 */
215 void
reset_font_flags(void)216 reset_font_flags(void)
217 {
218 struct fontlist *fl;
219
220 STAILQ_FOREACH(fl, &fonts, font_next) {
221 fl->font_flags = FONT_AUTO;
222 }
223 }
224
225 __weak_symbol bitmap_data_t *
gfx_get_font(short rows __unused,short cols __unused,short height __unused,short width __unused)226 gfx_get_font(short rows __unused, short cols __unused, short height __unused,
227 short width __unused)
228 {
229 return (NULL);
230 }
231
232 bitmap_data_t *
set_font(short * rows,short * cols,short h,short w)233 set_font(short *rows, short *cols, short h, short w)
234 {
235 bitmap_data_t *font = NULL;
236 struct fontlist *fl;
237 unsigned height = h;
238 unsigned width = w;
239
240 /*
241 * First check for manually loaded font.
242 */
243 STAILQ_FOREACH(fl, &fonts, font_next) {
244 if (fl->font_flags == FONT_MANUAL ||
245 fl->font_flags == FONT_BOOT) {
246 font = fl->font_data;
247 if (font->font == NULL && fl->font_load != NULL &&
248 fl->font_name != NULL) {
249 font = fl->font_load(fl->font_name);
250 }
251 if (font == NULL || font->font == NULL)
252 font = NULL;
253 break;
254 }
255 }
256
257 if (font == NULL)
258 font = gfx_get_font(*rows, *cols, h, w);
259
260 if (font != NULL) {
261 *rows = (height - BORDER_PIXELS) / font->height;
262 *cols = (width - BORDER_PIXELS) / font->width;
263 return (font);
264 }
265
266 /*
267 * Find best font for these dimensions, or use default
268 *
269 * A 1 pixel border is the absolute minimum we could have
270 * as a border around the text window (BORDER_PIXELS = 2),
271 * however a slightly larger border not only looks better
272 * but for the fonts currently statically built into the
273 * emulator causes much better font selection for the
274 * normal range of screen resolutions.
275 */
276 STAILQ_FOREACH(fl, &fonts, font_next) {
277 font = fl->font_data;
278 if ((((*rows * font->height) + BORDER_PIXELS) <= height) &&
279 (((*cols * font->width) + BORDER_PIXELS) <= width)) {
280 if (font->font == NULL ||
281 fl->font_flags == FONT_RELOAD) {
282 if (fl->font_load != NULL &&
283 fl->font_name != NULL) {
284 font = fl->font_load(fl->font_name);
285 }
286 if (font == NULL)
287 continue;
288 }
289 *rows = (height - BORDER_PIXELS) / font->height;
290 *cols = (width - BORDER_PIXELS) / font->width;
291 break;
292 }
293 font = NULL;
294 }
295
296 if (font == NULL) {
297 /*
298 * We have fonts sorted smallest last, try it before
299 * falling back to builtin.
300 */
301 fl = STAILQ_LAST(&fonts, fontlist, font_next);
302 if (fl != NULL && fl->font_load != NULL &&
303 fl->font_name != NULL) {
304 font = fl->font_load(fl->font_name);
305 }
306 if (font == NULL)
307 font = &DEFAULT_FONT_DATA;
308
309 *rows = (height - BORDER_PIXELS) / font->height;
310 *cols = (width - BORDER_PIXELS) / font->width;
311 }
312
313 return (font);
314 }
315
316 /* Binary search for the glyph. Return 0 if not found. */
317 static uint16_t
font_bisearch(const struct font_map * map,uint32_t len,uint32_t src)318 font_bisearch(const struct font_map *map, uint32_t len, uint32_t src)
319 {
320 unsigned min, mid, max;
321
322 min = 0;
323 max = len - 1;
324
325 /* Empty font map. */
326 if (len == 0)
327 return (0);
328 /* Character below minimal entry. */
329 if (src < map[0].font_src)
330 return (0);
331 /* Optimization: ASCII characters occur very often. */
332 if (src <= map[0].font_src + map[0].font_len)
333 return (src - map[0].font_src + map[0].font_dst);
334 /* Character above maximum entry. */
335 if (src > map[max].font_src + map[max].font_len)
336 return (0);
337
338 /* Binary search. */
339 while (max >= min) {
340 mid = (min + max) / 2;
341 if (src < map[mid].font_src)
342 max = mid - 1;
343 else if (src > map[mid].font_src + map[mid].font_len)
344 min = mid + 1;
345 else
346 return (src - map[mid].font_src + map[mid].font_dst);
347 }
348
349 return (0);
350 }
351
352 /*
353 * Return glyph bitmap. If glyph is not found, we will return bitmap
354 * for the first (offset 0) glyph.
355 */
356 const uint8_t *
font_lookup(const struct font * vf,uint32_t c)357 font_lookup(const struct font *vf, uint32_t c)
358 {
359 uint32_t src;
360 uint16_t dst;
361 size_t stride;
362
363 src = TEM_CHAR(c);
364
365 /* Substitute bold with normal if not found. */
366 if (TEM_CHAR_ATTR(c) & TEM_ATTR_BOLD) {
367 dst = font_bisearch(vf->vf_map[VFNT_MAP_BOLD],
368 vf->vf_map_count[VFNT_MAP_BOLD], src);
369 if (dst != 0)
370 goto found;
371 }
372 dst = font_bisearch(vf->vf_map[VFNT_MAP_NORMAL],
373 vf->vf_map_count[VFNT_MAP_NORMAL], src);
374
375 found:
376 stride = howmany(vf->vf_width, 8) * vf->vf_height;
377 return (&vf->vf_bytes[dst * stride]);
378 }
379
380 /*
381 * bit_to_pix4 is for 4-bit frame buffers. It will write one output byte
382 * for each 2 bits of input bitmap. It inverts the input bits before
383 * doing the output translation, for reverse video.
384 *
385 * Assuming foreground is 0001 and background is 0000...
386 * An input data byte of 0x53 will output the bit pattern
387 * 00000001 00000001 00000000 00010001.
388 */
389
390 void
font_bit_to_pix4(struct font * f,uint8_t * dest,uint32_t c,uint32_t fg_color,uint32_t bg_color)391 font_bit_to_pix4(
392 struct font *f,
393 uint8_t *dest,
394 uint32_t c,
395 uint32_t fg_color,
396 uint32_t bg_color)
397 {
398 uint32_t row;
399 int byte;
400 int i;
401 const uint8_t *cp, *ul;
402 uint8_t data;
403 uint8_t nibblett;
404 int bytes_wide;
405
406 if (TEM_CHAR_ATTR(c) & TEM_ATTR_UNDERLINE)
407 ul = font_lookup(f, 0x0332); /* combining low line */
408 else
409 ul = NULL;
410
411 cp = font_lookup(f, c);
412 bytes_wide = (f->vf_width + 7) / 8;
413
414 for (row = 0; row < f->vf_height; row++) {
415 for (byte = 0; byte < bytes_wide; byte++) {
416 if (ul == NULL)
417 data = *cp++;
418 else
419 data = *cp++ | *ul++;
420 for (i = 0; i < 4; i++) {
421 nibblett = (data >> ((3-i) * 2)) & 0x3;
422 switch (nibblett) {
423 case 0x0:
424 *dest++ = bg_color << 4 | bg_color;
425 break;
426 case 0x1:
427 *dest++ = bg_color << 4 | fg_color;
428 break;
429 case 0x2:
430 *dest++ = fg_color << 4 | bg_color;
431 break;
432 case 0x3:
433 *dest++ = fg_color << 4 | fg_color;
434 break;
435 }
436 }
437 }
438 }
439 }
440
441 /*
442 * bit_to_pix8 is for 8-bit frame buffers. It will write one output byte
443 * for each bit of input bitmap. It inverts the input bits before
444 * doing the output translation, for reverse video.
445 *
446 * Assuming foreground is 00000001 and background is 00000000...
447 * An input data byte of 0x53 will output the bit pattern
448 * 0000000 000000001 00000000 00000001 00000000 00000000 00000001 00000001.
449 */
450
451 void
font_bit_to_pix8(struct font * f,uint8_t * dest,uint32_t c,uint32_t fg_color,uint32_t bg_color)452 font_bit_to_pix8(
453 struct font *f,
454 uint8_t *dest,
455 uint32_t c,
456 uint32_t fg_color,
457 uint32_t bg_color)
458 {
459 uint32_t row;
460 int byte;
461 int i;
462 const uint8_t *cp, *ul;
463 uint8_t data;
464 int bytes_wide;
465 uint8_t mask;
466 int bitsleft, nbits;
467
468 if (TEM_CHAR_ATTR(c) & TEM_ATTR_UNDERLINE)
469 ul = font_lookup(f, 0x0332); /* combining low line */
470 else
471 ul = NULL;
472
473 cp = font_lookup(f, c);
474 bytes_wide = (f->vf_width + 7) / 8;
475
476 for (row = 0; row < f->vf_height; row++) {
477 bitsleft = f->vf_width;
478 for (byte = 0; byte < bytes_wide; byte++) {
479 if (ul == NULL)
480 data = *cp++;
481 else
482 data = *cp++ | *ul++;
483 mask = 0x80;
484 nbits = MIN(8, bitsleft);
485 bitsleft -= nbits;
486 for (i = 0; i < nbits; i++) {
487 *dest++ = (data & mask ? fg_color: bg_color);
488 mask = mask >> 1;
489 }
490 }
491 }
492 }
493
494 /*
495 * bit_to_pix16 is for 16-bit frame buffers. It will write two output bytes
496 * for each bit of input bitmap. It inverts the input bits before
497 * doing the output translation, for reverse video.
498 *
499 * Assuming foreground is 11111111 11111111
500 * and background is 00000000 00000000
501 * An input data byte of 0x53 will output the bit pattern
502 *
503 * 00000000 00000000
504 * 11111111 11111111
505 * 00000000 00000000
506 * 11111111 11111111
507 * 00000000 00000000
508 * 00000000 00000000
509 * 11111111 11111111
510 * 11111111 11111111
511 *
512 */
513
514 void
font_bit_to_pix16(struct font * f,uint16_t * dest,uint32_t c,uint32_t fg_color16,uint32_t bg_color16)515 font_bit_to_pix16(
516 struct font *f,
517 uint16_t *dest,
518 uint32_t c,
519 uint32_t fg_color16,
520 uint32_t bg_color16)
521 {
522 uint32_t row;
523 int byte;
524 int i;
525 const uint8_t *cp, *ul;
526 uint16_t data, d;
527 int bytes_wide;
528 int bitsleft, nbits;
529
530 if (TEM_CHAR_ATTR(c) & TEM_ATTR_UNDERLINE)
531 ul = font_lookup(f, 0x0332); /* combining low line */
532 else
533 ul = NULL;
534
535 cp = font_lookup(f, c);
536 bytes_wide = (f->vf_width + 7) / 8;
537
538 for (row = 0; row < f->vf_height; row++) {
539 bitsleft = f->vf_width;
540 for (byte = 0; byte < bytes_wide; byte++) {
541 if (ul == NULL)
542 data = *cp++;
543 else
544 data = *cp++ | *ul++;
545 nbits = MIN(8, bitsleft);
546 bitsleft -= nbits;
547 for (i = 0; i < nbits; i++) {
548 d = ((data << i) & 0x80 ?
549 fg_color16 : bg_color16);
550 *dest++ = d;
551 }
552 }
553 }
554 }
555
556 /*
557 * bit_to_pix24 is for 24-bit frame buffers. It will write three output bytes
558 * for each bit of input bitmap. It inverts the input bits before
559 * doing the output translation, for reverse video.
560 *
561 * Assuming foreground is 11111111 11111111 11111111
562 * and background is 00000000 00000000 00000000
563 * An input data byte of 0x53 will output the bit pattern
564 *
565 * 00000000 00000000 00000000
566 * 11111111 11111111 11111111
567 * 00000000 00000000 00000000
568 * 11111111 11111111 11111111
569 * 00000000 00000000 00000000
570 * 00000000 00000000 00000000
571 * 11111111 11111111 11111111
572 * 11111111 11111111 11111111
573 *
574 */
575
576 void
font_bit_to_pix24(struct font * f,uint8_t * dest,uint32_t c,uint32_t fg_color32,uint32_t bg_color32)577 font_bit_to_pix24(
578 struct font *f,
579 uint8_t *dest,
580 uint32_t c,
581 uint32_t fg_color32,
582 uint32_t bg_color32)
583 {
584 uint32_t row;
585 int byte;
586 int i;
587 const uint8_t *cp, *ul;
588 uint32_t data, d;
589 int bytes_wide;
590 int bitsleft, nbits;
591
592 if (TEM_CHAR_ATTR(c) & TEM_ATTR_UNDERLINE)
593 ul = font_lookup(f, 0x0332); /* combining low line */
594 else
595 ul = NULL;
596
597 cp = font_lookup(f, c);
598 bytes_wide = (f->vf_width + 7) / 8;
599
600 for (row = 0; row < f->vf_height; row++) {
601 bitsleft = f->vf_width;
602 for (byte = 0; byte < bytes_wide; byte++) {
603 if (ul == NULL)
604 data = *cp++;
605 else
606 data = *cp++ | *ul++;
607
608 nbits = MIN(8, bitsleft);
609 bitsleft -= nbits;
610 for (i = 0; i < nbits; i++) {
611 d = ((data << i) & 0x80 ?
612 fg_color32 : bg_color32);
613 *dest++ = d & 0xff;
614 *dest++ = (d >> 8) & 0xff;
615 *dest++ = (d >> 16) & 0xff;
616 }
617 }
618 }
619 }
620
621 /*
622 * bit_to_pix32 is for 32-bit frame buffers. It will write four output bytes
623 * for each bit of input bitmap. It inverts the input bits before
624 * doing the output translation, for reverse video. Note that each
625 * 24-bit RGB value is finally stored in a 32-bit unsigned int, with the
626 * high-order byte set to zero.
627 *
628 * Assuming foreground is 00000000 11111111 11111111 11111111
629 * and background is 00000000 00000000 00000000 00000000
630 * An input data byte of 0x53 will output the bit pattern
631 *
632 * 00000000 00000000 00000000 00000000
633 * 00000000 11111111 11111111 11111111
634 * 00000000 00000000 00000000 00000000
635 * 00000000 11111111 11111111 11111111
636 * 00000000 00000000 00000000 00000000
637 * 00000000 00000000 00000000 00000000
638 * 00000000 11111111 11111111 11111111
639 * 00000000 11111111 11111111 11111111
640 *
641 */
642
643 void
font_bit_to_pix32(struct font * f,uint32_t * dest,uint32_t c,uint32_t fg_color32,uint32_t bg_color32)644 font_bit_to_pix32(
645 struct font *f,
646 uint32_t *dest,
647 uint32_t c,
648 uint32_t fg_color32,
649 uint32_t bg_color32)
650 {
651 uint32_t row;
652 int byte;
653 int i;
654 const uint8_t *cp, *ul;
655 uint32_t data;
656 int bytes_wide;
657 int bitsleft, nbits;
658
659 if (TEM_CHAR_ATTR(c) & TEM_ATTR_UNDERLINE)
660 ul = font_lookup(f, 0x0332); /* combining low line */
661 else
662 ul = NULL;
663
664 cp = font_lookup(f, c);
665 bytes_wide = (f->vf_width + 7) / 8;
666
667 for (row = 0; row < f->vf_height; row++) {
668 bitsleft = f->vf_width;
669 for (byte = 0; byte < bytes_wide; byte++) {
670 if (ul == NULL)
671 data = *cp++;
672 else
673 data = *cp++ | *ul++;
674 nbits = MIN(8, bitsleft);
675 bitsleft -= nbits;
676 for (i = 0; i < nbits; i++) {
677 *dest++ = ((data << i) & 0x80 ?
678 fg_color32 : bg_color32);
679 }
680 }
681 }
682 }
683