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 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 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 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 * 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 * 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 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 * 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 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 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 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 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 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