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 - gery */ 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 /* 4-bit to 24-bit color translation. */ 75 const text_cmap_t cmap4_to_24 = { 76 /* 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 77 Wh+ Bk Bl Gr Cy Rd Mg Br Wh Bk+ Bl+ Gr+ Cy+ Rd+ Mg+ Yw */ 78 .red = { 79 0xff,0x00,0x00,0x00,0x00,0x80,0x80,0x80,0x80,0x40,0x00,0x00,0x00,0xff,0xff,0xff 80 }, 81 .green = { 82 0xff,0x00,0x00,0x80,0x80,0x00,0x00,0x80,0x80,0x40,0x00,0xff,0xff,0x00,0x00,0xff 83 }, 84 .blue = { 85 0xff,0x00,0x80,0x00,0x80,0x00,0x80,0x00,0x80,0x40,0xff,0x00,0xff,0x00,0xff,0x00 86 } 87 }; 88 /* END CSTYLED */ 89 90 static uint32_t 91 rgb_to_color(const rgb_t *rgb, uint8_t r, uint8_t g, uint8_t b) 92 { 93 uint32_t color; 94 int pos, size; 95 96 pos = rgb->red.pos; 97 size = rgb->red.size; 98 color = ((r >> (8 - size)) & ((1 << size) - 1)) << pos; 99 100 pos = rgb->green.pos; 101 size = rgb->green.size; 102 color |= ((g >> (8 - size)) & ((1 << size) - 1)) << pos; 103 104 pos = rgb->blue.pos; 105 size = rgb->blue.size; 106 color |= ((b >> (8 - size)) & ((1 << size) - 1)) << pos; 107 108 return (color); 109 } 110 111 uint32_t 112 rgb_color_map(const rgb_t *rgb, uint8_t index) 113 { 114 uint32_t color, code, gray, level; 115 116 if (index < 16) { 117 color = rgb_to_color(rgb, cmap4_to_24.red[index], 118 cmap4_to_24.green[index], cmap4_to_24.blue[index]); 119 return (color); 120 } 121 122 /* 6x6x6 color cube */ 123 if (index > 15 && index < 232) { 124 uint32_t red, green, blue; 125 126 for (red = 0; red < 6; red++) { 127 for (green = 0; green < 6; green++) { 128 for (blue = 0; blue < 6; blue++) { 129 code = 16 + (red * 36) + 130 (green * 6) + blue; 131 if (code != index) 132 continue; 133 red = red ? (red * 40 + 55) : 0; 134 green = green ? (green * 40 + 55) : 0; 135 blue = blue ? (blue * 40 + 55) : 0; 136 color = rgb_to_color(rgb, red, green, 137 blue); 138 return (color); 139 } 140 } 141 } 142 } 143 144 /* colors 232-255 are a grayscale ramp */ 145 for (gray = 0; gray < 24; gray++) { 146 level = (gray * 10) + 8; 147 code = 232 + gray; 148 if (code == index) 149 break; 150 } 151 return (rgb_to_color(rgb, level, level, level)); 152 } 153 /* 154 * Fonts are statically linked with this module. At some point an 155 * RFE might be desireable to allow dynamic font loading. The 156 * original intention to facilitate dynamic fonts can be seen 157 * by examining the data structures and set_font(). As much of 158 * the original code is retained but modified to be suited for 159 * traversing a list of static fonts. 160 */ 161 162 /* 163 * Must be sorted by font size in descending order 164 */ 165 font_list_t fonts = STAILQ_HEAD_INITIALIZER(fonts); 166 167 /* 168 * Reset font flags to FONT_AUTO. 169 */ 170 void 171 reset_font_flags(void) 172 { 173 struct fontlist *fl; 174 175 STAILQ_FOREACH(fl, &fonts, font_next) { 176 fl->font_flags = FONT_AUTO; 177 } 178 } 179 180 bitmap_data_t * 181 set_font(short *rows, short *cols, short h, short w) 182 { 183 bitmap_data_t *font = NULL; 184 struct fontlist *fl; 185 unsigned height = h; 186 unsigned width = w; 187 188 /* 189 * First check for manually loaded font. 190 */ 191 STAILQ_FOREACH(fl, &fonts, font_next) { 192 if (fl->font_flags == FONT_MANUAL || 193 fl->font_flags == FONT_BOOT) { 194 font = fl->font_data; 195 if (font->font == NULL && fl->font_load != NULL && 196 fl->font_name != NULL) { 197 font = fl->font_load(fl->font_name); 198 } 199 if (font == NULL || font->font == NULL) 200 font = NULL; 201 break; 202 } 203 } 204 205 if (font != NULL) { 206 *rows = (height - BORDER_PIXELS) / font->height; 207 *cols = (width - BORDER_PIXELS) / font->width; 208 return (font); 209 } 210 211 /* 212 * Find best font for these dimensions, or use default 213 * 214 * A 1 pixel border is the absolute minimum we could have 215 * as a border around the text window (BORDER_PIXELS = 2), 216 * however a slightly larger border not only looks better 217 * but for the fonts currently statically built into the 218 * emulator causes much better font selection for the 219 * normal range of screen resolutions. 220 */ 221 STAILQ_FOREACH(fl, &fonts, font_next) { 222 font = fl->font_data; 223 if ((((*rows * font->height) + BORDER_PIXELS) <= height) && 224 (((*cols * font->width) + BORDER_PIXELS) <= width)) { 225 if (font->font == NULL || 226 fl->font_flags == FONT_RELOAD) { 227 if (fl->font_load != NULL && 228 fl->font_name != NULL) { 229 font = fl->font_load(fl->font_name); 230 } 231 if (font == NULL) 232 continue; 233 } 234 *rows = (height - BORDER_PIXELS) / font->height; 235 *cols = (width - BORDER_PIXELS) / font->width; 236 break; 237 } 238 font = NULL; 239 } 240 241 if (font == NULL) { 242 /* 243 * We have fonts sorted smallest last, try it before 244 * falling back to builtin. 245 */ 246 fl = STAILQ_LAST(&fonts, fontlist, font_next); 247 if (fl != NULL && fl->font_load != NULL && 248 fl->font_name != NULL) { 249 font = fl->font_load(fl->font_name); 250 } 251 if (font == NULL) 252 font = &DEFAULT_FONT_DATA; 253 254 *rows = (height - BORDER_PIXELS) / font->height; 255 *cols = (width - BORDER_PIXELS) / font->width; 256 } 257 258 return (font); 259 } 260 261 /* Binary search for the glyph. Return 0 if not found. */ 262 static uint16_t 263 font_bisearch(const struct font_map *map, uint32_t len, uint32_t src) 264 { 265 unsigned min, mid, max; 266 267 min = 0; 268 max = len - 1; 269 270 /* Empty font map. */ 271 if (len == 0) 272 return (0); 273 /* Character below minimal entry. */ 274 if (src < map[0].font_src) 275 return (0); 276 /* Optimization: ASCII characters occur very often. */ 277 if (src <= map[0].font_src + map[0].font_len) 278 return (src - map[0].font_src + map[0].font_dst); 279 /* Character above maximum entry. */ 280 if (src > map[max].font_src + map[max].font_len) 281 return (0); 282 283 /* Binary search. */ 284 while (max >= min) { 285 mid = (min + max) / 2; 286 if (src < map[mid].font_src) 287 max = mid - 1; 288 else if (src > map[mid].font_src + map[mid].font_len) 289 min = mid + 1; 290 else 291 return (src - map[mid].font_src + map[mid].font_dst); 292 } 293 294 return (0); 295 } 296 297 /* 298 * Return glyph bitmap. If glyph is not found, we will return bitmap 299 * for the first (offset 0) glyph. 300 */ 301 const uint8_t * 302 font_lookup(const struct font *vf, uint32_t c) 303 { 304 uint32_t src; 305 uint16_t dst; 306 size_t stride; 307 308 src = TEM_CHAR(c); 309 310 /* Substitute bold with normal if not found. */ 311 if (TEM_CHAR_ATTR(c) & TEM_ATTR_BOLD) { 312 dst = font_bisearch(vf->vf_map[VFNT_MAP_BOLD], 313 vf->vf_map_count[VFNT_MAP_BOLD], src); 314 if (dst != 0) 315 goto found; 316 } 317 dst = font_bisearch(vf->vf_map[VFNT_MAP_NORMAL], 318 vf->vf_map_count[VFNT_MAP_NORMAL], src); 319 320 found: 321 stride = howmany(vf->vf_width, 8) * vf->vf_height; 322 return (&vf->vf_bytes[dst * stride]); 323 } 324 325 /* 326 * bit_to_pix4 is for 4-bit frame buffers. It will write one output byte 327 * for each 2 bits of input bitmap. It inverts the input bits before 328 * doing the output translation, for reverse video. 329 * 330 * Assuming foreground is 0001 and background is 0000... 331 * An input data byte of 0x53 will output the bit pattern 332 * 00000001 00000001 00000000 00010001. 333 */ 334 335 void 336 font_bit_to_pix4( 337 struct font *f, 338 uint8_t *dest, 339 uint32_t c, 340 uint8_t fg_color, 341 uint8_t bg_color) 342 { 343 uint32_t row; 344 int byte; 345 int i; 346 const uint8_t *cp, *ul; 347 uint8_t data; 348 uint8_t nibblett; 349 int bytes_wide; 350 351 if (TEM_CHAR_ATTR(c) & TEM_ATTR_UNDERLINE) 352 ul = font_lookup(f, 0x0332); /* combining low line */ 353 else 354 ul = NULL; 355 356 cp = font_lookup(f, c); 357 bytes_wide = (f->vf_width + 7) / 8; 358 359 for (row = 0; row < f->vf_height; row++) { 360 for (byte = 0; byte < bytes_wide; byte++) { 361 if (ul == NULL) 362 data = *cp++; 363 else 364 data = *cp++ | *ul++; 365 for (i = 0; i < 4; i++) { 366 nibblett = (data >> ((3-i) * 2)) & 0x3; 367 switch (nibblett) { 368 case 0x0: 369 *dest++ = bg_color << 4 | bg_color; 370 break; 371 case 0x1: 372 *dest++ = bg_color << 4 | fg_color; 373 break; 374 case 0x2: 375 *dest++ = fg_color << 4 | bg_color; 376 break; 377 case 0x3: 378 *dest++ = fg_color << 4 | fg_color; 379 break; 380 } 381 } 382 } 383 } 384 } 385 386 /* 387 * bit_to_pix8 is for 8-bit frame buffers. It will write one output byte 388 * for each bit of input bitmap. It inverts the input bits before 389 * doing the output translation, for reverse video. 390 * 391 * Assuming foreground is 00000001 and background is 00000000... 392 * An input data byte of 0x53 will output the bit pattern 393 * 0000000 000000001 00000000 00000001 00000000 00000000 00000001 00000001. 394 */ 395 396 void 397 font_bit_to_pix8( 398 struct font *f, 399 uint8_t *dest, 400 uint32_t c, 401 uint8_t fg_color, 402 uint8_t bg_color) 403 { 404 uint32_t row; 405 int byte; 406 int i; 407 const uint8_t *cp, *ul; 408 uint8_t data; 409 int bytes_wide; 410 uint8_t mask; 411 int bitsleft, nbits; 412 413 if (TEM_CHAR_ATTR(c) & TEM_ATTR_UNDERLINE) 414 ul = font_lookup(f, 0x0332); /* combining low line */ 415 else 416 ul = NULL; 417 418 cp = font_lookup(f, c); 419 bytes_wide = (f->vf_width + 7) / 8; 420 421 for (row = 0; row < f->vf_height; row++) { 422 bitsleft = f->vf_width; 423 for (byte = 0; byte < bytes_wide; byte++) { 424 if (ul == NULL) 425 data = *cp++; 426 else 427 data = *cp++ | *ul++; 428 mask = 0x80; 429 nbits = MIN(8, bitsleft); 430 bitsleft -= nbits; 431 for (i = 0; i < nbits; i++) { 432 *dest++ = (data & mask ? fg_color: bg_color); 433 mask = mask >> 1; 434 } 435 } 436 } 437 } 438 439 /* 440 * bit_to_pix16 is for 16-bit frame buffers. It will write two output bytes 441 * for each bit of input bitmap. It inverts the input bits before 442 * doing the output translation, for reverse video. 443 * 444 * Assuming foreground is 11111111 11111111 445 * and background is 00000000 00000000 446 * An input data byte of 0x53 will output the bit pattern 447 * 448 * 00000000 00000000 449 * 11111111 11111111 450 * 00000000 00000000 451 * 11111111 11111111 452 * 00000000 00000000 453 * 00000000 00000000 454 * 11111111 11111111 455 * 11111111 11111111 456 * 457 */ 458 459 void 460 font_bit_to_pix16( 461 struct font *f, 462 uint16_t *dest, 463 uint32_t c, 464 uint16_t fg_color16, 465 uint16_t bg_color16) 466 { 467 uint32_t row; 468 int byte; 469 int i; 470 const uint8_t *cp, *ul; 471 uint16_t data, d; 472 int bytes_wide; 473 int bitsleft, nbits; 474 475 if (TEM_CHAR_ATTR(c) & TEM_ATTR_UNDERLINE) 476 ul = font_lookup(f, 0x0332); /* combining low line */ 477 else 478 ul = NULL; 479 480 cp = font_lookup(f, c); 481 bytes_wide = (f->vf_width + 7) / 8; 482 483 for (row = 0; row < f->vf_height; row++) { 484 bitsleft = f->vf_width; 485 for (byte = 0; byte < bytes_wide; byte++) { 486 if (ul == NULL) 487 data = *cp++; 488 else 489 data = *cp++ | *ul++; 490 nbits = MIN(8, bitsleft); 491 bitsleft -= nbits; 492 for (i = 0; i < nbits; i++) { 493 d = ((data << i) & 0x80 ? 494 fg_color16 : bg_color16); 495 *dest++ = d; 496 } 497 } 498 } 499 } 500 501 /* 502 * bit_to_pix24 is for 24-bit frame buffers. It will write three output bytes 503 * for each bit of input bitmap. It inverts the input bits before 504 * doing the output translation, for reverse video. 505 * 506 * Assuming foreground is 11111111 11111111 11111111 507 * and background is 00000000 00000000 00000000 508 * An input data byte of 0x53 will output the bit pattern 509 * 510 * 00000000 00000000 00000000 511 * 11111111 11111111 11111111 512 * 00000000 00000000 00000000 513 * 11111111 11111111 11111111 514 * 00000000 00000000 00000000 515 * 00000000 00000000 00000000 516 * 11111111 11111111 11111111 517 * 11111111 11111111 11111111 518 * 519 */ 520 521 void 522 font_bit_to_pix24( 523 struct font *f, 524 uint8_t *dest, 525 uint32_t c, 526 uint32_t fg_color32, 527 uint32_t bg_color32) 528 { 529 uint32_t row; 530 int byte; 531 int i; 532 const uint8_t *cp, *ul; 533 uint32_t data, d; 534 int bytes_wide; 535 int bitsleft, nbits; 536 537 if (TEM_CHAR_ATTR(c) & TEM_ATTR_UNDERLINE) 538 ul = font_lookup(f, 0x0332); /* combining low line */ 539 else 540 ul = NULL; 541 542 cp = font_lookup(f, c); 543 bytes_wide = (f->vf_width + 7) / 8; 544 545 for (row = 0; row < f->vf_height; row++) { 546 bitsleft = f->vf_width; 547 for (byte = 0; byte < bytes_wide; byte++) { 548 if (ul == NULL) 549 data = *cp++; 550 else 551 data = *cp++ | *ul++; 552 553 nbits = MIN(8, bitsleft); 554 bitsleft -= nbits; 555 for (i = 0; i < nbits; i++) { 556 d = ((data << i) & 0x80 ? 557 fg_color32 : bg_color32); 558 *dest++ = d & 0xff; 559 *dest++ = (d >> 8) & 0xff; 560 *dest++ = (d >> 16) & 0xff; 561 } 562 } 563 } 564 } 565 566 /* 567 * bit_to_pix32 is for 32-bit frame buffers. It will write four output bytes 568 * for each bit of input bitmap. It inverts the input bits before 569 * doing the output translation, for reverse video. Note that each 570 * 24-bit RGB value is finally stored in a 32-bit unsigned int, with the 571 * high-order byte set to zero. 572 * 573 * Assuming foreground is 00000000 11111111 11111111 11111111 574 * and background is 00000000 00000000 00000000 00000000 575 * An input data byte of 0x53 will output the bit pattern 576 * 577 * 00000000 00000000 00000000 00000000 578 * 00000000 11111111 11111111 11111111 579 * 00000000 00000000 00000000 00000000 580 * 00000000 11111111 11111111 11111111 581 * 00000000 00000000 00000000 00000000 582 * 00000000 00000000 00000000 00000000 583 * 00000000 11111111 11111111 11111111 584 * 00000000 11111111 11111111 11111111 585 * 586 */ 587 588 void 589 font_bit_to_pix32( 590 struct font *f, 591 uint32_t *dest, 592 uint32_t c, 593 uint32_t fg_color32, 594 uint32_t bg_color32) 595 { 596 uint32_t row; 597 int byte; 598 int i; 599 const uint8_t *cp, *ul; 600 uint32_t data; 601 int bytes_wide; 602 int bitsleft, nbits; 603 604 if (TEM_CHAR_ATTR(c) & TEM_ATTR_UNDERLINE) 605 ul = font_lookup(f, 0x0332); /* combining low line */ 606 else 607 ul = NULL; 608 609 cp = font_lookup(f, c); 610 bytes_wide = (f->vf_width + 7) / 8; 611 612 for (row = 0; row < f->vf_height; row++) { 613 bitsleft = f->vf_width; 614 for (byte = 0; byte < bytes_wide; byte++) { 615 if (ul == NULL) 616 data = *cp++; 617 else 618 data = *cp++ | *ul++; 619 nbits = MIN(8, bitsleft); 620 bitsleft -= nbits; 621 for (i = 0; i < nbits; i++) { 622 *dest++ = ((data << i) & 0x80 ? 623 fg_color32 : bg_color32); 624 } 625 } 626 } 627 } 628