1 /* 2 * This file and its contents are supplied under the terms of the 3 * Common Development and Distribution License ("CDDL"), version 1.0. 4 * You may only use this file in accordance with the terms of version 5 * 1.0 of the CDDL. 6 * 7 * A full copy of the text of the CDDL should have accompanied this 8 * source. A copy of the CDDL is also available via the Internet at 9 * http://www.illumos.org/license/CDDL. 10 */ 11 12 /* 13 * Copyright 2016 Toomas Soome <tsoome@me.com> 14 */ 15 16 /* 17 * dboot and early kernel needs simple putchar(int) interface to implement 18 * printf() support. So we implement simple interface on top of 19 * linear frame buffer, since we can not use tem directly, we are 20 * just borrowing bits from it. 21 * 22 * Note, this implementation is assuming UEFI linear frame buffer and 23 * 32-bit depth, which should not be issue as GOP is supposed to provide those. 24 * At the time of writing, this is the only case for frame buffer anyhow. 25 */ 26 27 #include <sys/types.h> 28 #include <sys/systm.h> 29 #include <sys/multiboot2.h> 30 #include <sys/framebuffer.h> 31 #include <sys/bootinfo.h> 32 #include <sys/boot_console.h> 33 #include <sys/bootconf.h> 34 #include "boot_console_impl.h" 35 36 #define P2ROUNDUP(x, align) (-(-(x) & -(align))) 37 #define MIN(a, b) ((a) < (b) ? (a) : (b)) 38 39 /* 40 * Simplified visual_io data structures from visual_io.h 41 */ 42 43 struct vis_consdisplay { 44 uint16_t row; /* Row to display data at */ 45 uint16_t col; /* Col to display data at */ 46 uint16_t width; /* Width of data */ 47 uint16_t height; /* Height of data */ 48 uint8_t *data; /* Data to display */ 49 }; 50 51 struct vis_conscopy { 52 uint16_t s_row; /* Starting row */ 53 uint16_t s_col; /* Starting col */ 54 uint16_t e_row; /* Ending row */ 55 uint16_t e_col; /* Ending col */ 56 uint16_t t_row; /* Row to move to */ 57 uint16_t t_col; /* Col to move to */ 58 }; 59 60 /* we have built in fonts 12x22, 6x10, 7x14 and depth 32. */ 61 #define MAX_GLYPH (12 * 22 * 4) 62 63 static struct font boot_fb_font; /* set by set_font() */ 64 static uint8_t glyph[MAX_GLYPH]; 65 66 /* color translation */ 67 typedef struct { 68 uint8_t red[16]; 69 uint8_t green[16]; 70 uint8_t blue[16]; 71 } text_cmap_t; 72 73 /* BEGIN CSTYLED */ 74 /* Bk Rd Gr Br Bl Mg Cy Wh */ 75 static uint8_t dim_xlate[] = { 1, 5, 3, 7, 2, 6, 4, 8 }; 76 static uint8_t brt_xlate[] = { 9, 13, 11, 15, 10, 14, 12, 0 }; 77 /* END CSTYLED */ 78 79 static text_cmap_t cmap4_to_24 = { 80 /* BEGIN CSTYLED */ 81 /* 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 82 Wh+ Bk Bl Gr Cy Rd Mg Br Wh Bk+ Bl+ Gr+ Cy+ Rd+ Mg+ Yw */ 83 0xff,0x00,0x00,0x00,0x00,0x80,0x80,0x80,0x80,0x40,0x00,0x00,0x00,0xff,0xff,0xff, 84 0xff,0x00,0x00,0x80,0x80,0x00,0x00,0x80,0x80,0x40,0x00,0xff,0xff,0x00,0x00,0xff, 85 0xff,0x00,0x80,0x00,0x80,0x00,0x80,0x00,0x80,0x40,0xff,0x00,0xff,0x00,0xff,0x00 86 /* END CSTYLED */ 87 }; 88 89 static void boot_fb_putchar(int); 90 static void boot_fb_eraseline(void); 91 static void boot_fb_setpos(int, int); 92 static void boot_fb_shiftline(int); 93 static void boot_fb_eraseline_impl(uint16_t, uint16_t); 94 95 /* 96 * extract data from MB2 framebuffer tag and set up initial frame buffer. 97 */ 98 boolean_t 99 xbi_fb_init(struct xboot_info *xbi, bcons_dev_t *bcons_dev) 100 { 101 multiboot_tag_framebuffer_t *tag; 102 boot_framebuffer_t *xbi_fb; 103 104 xbi_fb = (boot_framebuffer_t *)(uintptr_t)xbi->bi_framebuffer; 105 if (xbi_fb == NULL) 106 return (B_FALSE); 107 108 #if !defined(_BOOT) 109 /* For early kernel, we get cursor position from dboot. */ 110 fb_info.cursor.origin.x = xbi_fb->cursor.origin.x; 111 fb_info.cursor.origin.y = xbi_fb->cursor.origin.y; 112 fb_info.cursor.pos.x = xbi_fb->cursor.pos.x; 113 fb_info.cursor.pos.y = xbi_fb->cursor.pos.y; 114 fb_info.cursor.visible = xbi_fb->cursor.visible; 115 #endif 116 117 tag = (multiboot_tag_framebuffer_t *)(uintptr_t)xbi_fb->framebuffer; 118 if (tag == NULL) { 119 return (B_FALSE); 120 } 121 122 fb_info.paddr = tag->framebuffer_common.framebuffer_addr; 123 fb_info.pitch = tag->framebuffer_common.framebuffer_pitch; 124 fb_info.depth = tag->framebuffer_common.framebuffer_bpp; 125 fb_info.bpp = P2ROUNDUP(fb_info.depth, 8) >> 3; 126 fb_info.screen.x = tag->framebuffer_common.framebuffer_width; 127 fb_info.screen.y = tag->framebuffer_common.framebuffer_height; 128 fb_info.fb_size = fb_info.screen.y * fb_info.pitch; 129 130 bcons_dev->bd_putchar = boot_fb_putchar; 131 bcons_dev->bd_eraseline = boot_fb_eraseline; 132 bcons_dev->bd_cursor = boot_fb_cursor; 133 bcons_dev->bd_setpos = boot_fb_setpos; 134 bcons_dev->bd_shift = boot_fb_shiftline; 135 136 if (fb_info.paddr == 0) 137 fb_info.fb_type = FB_TYPE_UNKNOWN; 138 139 switch (tag->framebuffer_common.framebuffer_type) { 140 case MULTIBOOT_FRAMEBUFFER_TYPE_EGA_TEXT: 141 fb_info.fb_type = FB_TYPE_EGA_TEXT; 142 return (B_FALSE); 143 144 case MULTIBOOT_FRAMEBUFFER_TYPE_INDEXED: 145 if (fb_info.paddr != 0) 146 fb_info.fb_type = FB_TYPE_INDEXED; 147 return (B_TRUE); 148 149 case MULTIBOOT_FRAMEBUFFER_TYPE_RGB: 150 if (fb_info.paddr != 0) 151 fb_info.fb_type = FB_TYPE_RGB; 152 break; 153 154 default: 155 return (B_FALSE); 156 } 157 158 fb_info.rgb.red.size = tag->u.fb2.framebuffer_red_mask_size; 159 fb_info.rgb.red.pos = tag->u.fb2.framebuffer_red_field_position; 160 fb_info.rgb.green.size = tag->u.fb2.framebuffer_green_mask_size; 161 fb_info.rgb.green.pos = tag->u.fb2.framebuffer_green_field_position; 162 fb_info.rgb.blue.size = tag->u.fb2.framebuffer_blue_mask_size; 163 fb_info.rgb.blue.pos = tag->u.fb2.framebuffer_blue_field_position; 164 165 return (B_TRUE); 166 } 167 168 /* set font and pass the data to fb_info */ 169 static void 170 boot_fb_set_font(uint16_t height, uint16_t width) 171 { 172 short h, w; 173 174 h = MIN(height, 4096); 175 w = MIN(width, 4096); 176 177 set_font(&boot_fb_font, (short *)&fb_info.terminal.y, 178 (short *)&fb_info.terminal.x, h, w); 179 fb_info.font_width = boot_fb_font.width; 180 fb_info.font_height = boot_fb_font.height; 181 } 182 183 /* fill framebuffer */ 184 static void 185 boot_fb_fill(uint8_t *dst, uint32_t data, uint32_t len) 186 { 187 uint16_t *dst16; 188 uint32_t *dst32; 189 uint32_t i; 190 191 switch (fb_info.depth) { 192 case 24: 193 case 8: 194 for (i = 0; i < len; i++) 195 dst[i] = (uint8_t)data; 196 break; 197 case 15: 198 case 16: 199 dst16 = (uint16_t *)dst; 200 len /= 2; 201 for (i = 0; i < len; i++) 202 dst16[i] = (uint16_t)data; 203 break; 204 case 32: 205 dst32 = (uint32_t *)dst; 206 len /= 4; 207 for (i = 0; i < len; i++) 208 dst32[i] = data; 209 break; 210 } 211 } 212 213 /* copy data to framebuffer */ 214 static void 215 boot_fb_cpy(uint8_t *dst, uint8_t *src, uint32_t len) 216 { 217 uint16_t *dst16, *src16; 218 uint32_t *dst32, *src32; 219 220 switch (fb_info.depth) { 221 case 24: 222 case 8: 223 default: 224 if (dst <= src) { 225 do { 226 *dst++ = *src++; 227 } while (--len != 0); 228 } else { 229 dst += len; 230 src += len; 231 do { 232 *--dst = *--src; 233 } while (--len != 0); 234 } 235 break; 236 case 15: 237 case 16: 238 dst16 = (uint16_t *)dst; 239 src16 = (uint16_t *)src; 240 len /= 2; 241 if (dst16 <= src16) { 242 do { 243 *dst16++ = *src16++; 244 } while (--len != 0); 245 } else { 246 dst16 += len; 247 src16 += len; 248 do { 249 *--dst16 = *--src16; 250 } while (--len != 0); 251 } 252 break; 253 case 32: 254 dst32 = (uint32_t *)dst; 255 src32 = (uint32_t *)src; 256 len /= 4; 257 if (dst32 <= src32) { 258 do { 259 *dst32++ = *src32++; 260 } while (--len != 0); 261 } else { 262 dst32 += len; 263 src32 += len; 264 do { 265 *--dst32 = *--src32; 266 } while (--len != 0); 267 } 268 break; 269 } 270 } 271 272 /* 273 * Allocate shadow frame buffer, called from fakebop.c when early boot 274 * allocator is ready. 275 */ 276 void 277 boot_fb_shadow_init(bootops_t *bops) 278 { 279 if (boot_console_type(NULL) != CONS_FRAMEBUFFER) 280 return; /* nothing to do */ 281 282 fb_info.shadow_fb = (uint8_t *)bops->bsys_alloc(NULL, NULL, 283 fb_info.fb_size, MMU_PAGESIZE); 284 285 if (fb_info.shadow_fb == NULL) 286 return; 287 288 /* Copy FB to shadow */ 289 boot_fb_cpy(fb_info.shadow_fb, fb_info.fb, fb_info.fb_size); 290 } 291 292 /* 293 * Translate ansi color based on inverses and brightness. 294 */ 295 void 296 boot_get_color(uint32_t *fg, uint32_t *bg) 297 { 298 /* ansi to solaris colors, see also boot_console.c */ 299 if (fb_info.inverse == B_TRUE || 300 fb_info.inverse_screen == B_TRUE) { 301 *bg = dim_xlate[fb_info.fg_color]; 302 *fg = brt_xlate[fb_info.bg_color]; 303 } else { 304 if (fb_info.bg_color == 7) 305 *bg = brt_xlate[fb_info.bg_color]; 306 else 307 *bg = dim_xlate[fb_info.bg_color]; 308 *fg = dim_xlate[fb_info.fg_color]; 309 } 310 } 311 312 /* 313 * Map indexed color to RGB value. 314 */ 315 static uint32_t 316 boot_color_map(uint8_t index) 317 { 318 uint8_t c; 319 int pos, size; 320 uint32_t color; 321 322 /* 8bit depth is for indexed colors */ 323 if (fb_info.depth == 8) 324 return (index); 325 326 if (index >= sizeof (cmap4_to_24.red)) 327 index = 0; 328 329 c = cmap4_to_24.red[index]; 330 pos = fb_info.rgb.red.pos; 331 size = fb_info.rgb.red.size; 332 color = ((c >> 8 - size) & ((1 << size) - 1)) << pos; 333 334 c = cmap4_to_24.green[index]; 335 pos = fb_info.rgb.green.pos; 336 size = fb_info.rgb.green.size; 337 color |= ((c >> 8 - size) & ((1 << size) - 1)) << pos; 338 339 c = cmap4_to_24.blue[index]; 340 pos = fb_info.rgb.blue.pos; 341 size = fb_info.rgb.blue.size; 342 color |= ((c >> 8 - size) & ((1 << size) - 1)) << pos; 343 344 return (color); 345 } 346 347 /* set up out simple console. */ 348 /*ARGSUSED*/ 349 void 350 boot_fb_init(int console) 351 { 352 fb_info_pixel_coord_t window; 353 354 /* frame buffer address is mapped in dboot. */ 355 fb_info.fb = (uint8_t *)(uintptr_t)fb_info.paddr; 356 357 boot_fb_set_font(fb_info.screen.y, fb_info.screen.x); 358 window.x = 359 (fb_info.screen.x - fb_info.terminal.x * boot_fb_font.width) / 2; 360 window.y = 361 (fb_info.screen.y - fb_info.terminal.y * boot_fb_font.height) / 2; 362 fb_info.terminal_origin.x = window.x; 363 fb_info.terminal_origin.y = window.y; 364 365 #if defined(_BOOT) 366 /* 367 * Being called from dboot, we can have cursor terminal 368 * position passed from boot loader. In such case, fix the 369 * cursor screen coords. 370 */ 371 if (fb_info.cursor.pos.x != 0 || fb_info.cursor.pos.y != 0) { 372 fb_info.cursor.origin.x = window.x + 373 fb_info.cursor.pos.x * boot_fb_font.width; 374 fb_info.cursor.origin.y = window.y + 375 fb_info.cursor.pos.y * boot_fb_font.height; 376 } 377 #endif 378 379 /* If the cursor terminal position is 0,0 just reset screen coords */ 380 if (fb_info.cursor.pos.x == 0 && fb_info.cursor.pos.y == 0) { 381 fb_info.cursor.origin.x = window.x; 382 fb_info.cursor.origin.y = window.y; 383 } 384 385 /* 386 * Validate cursor coords with screen/terminal dimensions, 387 * if anything is off, reset to 0,0 388 */ 389 if (fb_info.cursor.pos.x > fb_info.terminal.x || 390 fb_info.cursor.pos.y > fb_info.terminal.y || 391 fb_info.cursor.origin.x > fb_info.screen.x || 392 fb_info.cursor.origin.y > fb_info.screen.y) { 393 394 fb_info.cursor.origin.x = window.x; 395 fb_info.cursor.origin.y = window.y; 396 fb_info.cursor.pos.x = 0; 397 fb_info.cursor.pos.y = 0; 398 } 399 400 #if defined(_BOOT) 401 /* clear the screen if cursor is set to 0,0 */ 402 if (fb_info.cursor.pos.x == 0 && fb_info.cursor.pos.y == 0) { 403 uint32_t fg, bg, toffset; 404 uint16_t y; 405 406 boot_get_color(&fg, &bg); 407 bg = boot_color_map(bg); 408 409 toffset = 0; 410 for (y = 0; y < fb_info.screen.y; y++) { 411 uint8_t *dest = fb_info.fb + toffset; 412 413 boot_fb_fill(dest, bg, fb_info.pitch); 414 toffset += fb_info.pitch; 415 } 416 } 417 #endif 418 } 419 420 /* copy rectangle to framebuffer. */ 421 static void 422 boot_fb_blit(struct vis_consdisplay *rect) 423 { 424 uint32_t offset, size; /* write size per scanline */ 425 uint8_t *fbp, *sfbp = NULL; /* fb + calculated offset */ 426 int i; 427 428 /* make sure we will not write past FB */ 429 if (rect->col >= fb_info.screen.x || 430 rect->row >= fb_info.screen.y || 431 rect->col + rect->width >= fb_info.screen.x || 432 rect->row + rect->height >= fb_info.screen.y) 433 return; 434 435 size = rect->width * fb_info.bpp; 436 offset = rect->col * fb_info.bpp + rect->row * fb_info.pitch; 437 fbp = fb_info.fb + offset; 438 if (fb_info.shadow_fb != NULL) 439 sfbp = fb_info.shadow_fb + offset; 440 441 /* write all scanlines in rectangle */ 442 for (i = 0; i < rect->height; i++) { 443 uint8_t *dest = fbp + i * fb_info.pitch; 444 uint8_t *src = rect->data + i * size; 445 boot_fb_cpy(dest, src, size); 446 if (sfbp != NULL) { 447 dest = sfbp + i * fb_info.pitch; 448 boot_fb_cpy(dest, src, size); 449 } 450 } 451 } 452 453 static void 454 bit_to_pix(uchar_t c) 455 { 456 uint32_t fg, bg; 457 458 boot_get_color(&fg, &bg); 459 fg = boot_color_map(fg); 460 bg = boot_color_map(bg); 461 462 switch (fb_info.depth) { 463 case 8: 464 font_bit_to_pix8(&boot_fb_font, (uint8_t *)glyph, c, fg, bg); 465 break; 466 case 15: 467 case 16: 468 font_bit_to_pix16(&boot_fb_font, (uint16_t *)glyph, c, 469 (uint16_t)fg, (uint16_t)bg); 470 break; 471 case 24: 472 font_bit_to_pix24(&boot_fb_font, (uint8_t *)glyph, c, fg, bg); 473 break; 474 case 32: 475 font_bit_to_pix32(&boot_fb_font, (uint32_t *)glyph, c, fg, bg); 476 break; 477 } 478 } 479 480 static void 481 boot_fb_eraseline_impl(uint16_t x, uint16_t y) 482 { 483 uint32_t toffset, size; 484 uint32_t fg, bg; 485 uint8_t *dst, *sdst; 486 int i; 487 488 boot_get_color(&fg, &bg); 489 bg = boot_color_map(bg); 490 491 size = fb_info.terminal.x * boot_fb_font.width * fb_info.bpp; 492 493 toffset = x * fb_info.bpp + y * fb_info.pitch; 494 dst = fb_info.fb + toffset; 495 sdst = fb_info.shadow_fb + toffset; 496 497 for (i = 0; i < boot_fb_font.height; i++) { 498 uint8_t *dest = dst + i * fb_info.pitch; 499 if (fb_info.fb + fb_info.fb_size >= dest + size) 500 boot_fb_fill(dest, bg, size); 501 if (fb_info.shadow_fb != NULL) { 502 dest = sdst + i * fb_info.pitch; 503 if (fb_info.shadow_fb + fb_info.fb_size >= 504 dest + size) { 505 boot_fb_fill(dest, bg, size); 506 } 507 } 508 } 509 } 510 511 static void 512 boot_fb_eraseline(void) 513 { 514 boot_fb_eraseline_impl(fb_info.cursor.origin.x, 515 fb_info.cursor.origin.y); 516 } 517 518 /* 519 * Copy rectangle from console to console. 520 * If shadow buffer is available, use shadow as source. 521 */ 522 static void 523 boot_fb_conscopy(struct vis_conscopy *c_copy) 524 { 525 uint32_t soffset, toffset; 526 uint32_t width, height, increment; 527 uint8_t *src, *dst, *sdst = NULL; 528 int i; 529 530 soffset = c_copy->s_col * fb_info.bpp + c_copy->s_row * fb_info.pitch; 531 toffset = c_copy->t_col * fb_info.bpp + c_copy->t_row * fb_info.pitch; 532 533 src = fb_info.fb + soffset; 534 dst = fb_info.fb + toffset; 535 536 if (fb_info.shadow_fb != NULL) { 537 src = fb_info.shadow_fb + soffset; 538 sdst = fb_info.shadow_fb + toffset; 539 } 540 541 width = (c_copy->e_col - c_copy->s_col + 1) * fb_info.bpp; 542 height = c_copy->e_row - c_copy->s_row + 1; 543 544 for (i = 0; i < height; i++) { 545 increment = i * fb_info.pitch; 546 547 /* Make sure we fit into FB size. */ 548 if (soffset + increment + width >= fb_info.fb_size || 549 toffset + increment + width >= fb_info.fb_size) 550 break; 551 552 boot_fb_cpy(dst + increment, src + increment, width); 553 554 if (sdst != NULL) 555 boot_fb_cpy(sdst + increment, src + increment, width); 556 } 557 } 558 559 /* Shift the line content by chars. */ 560 static void 561 boot_fb_shiftline(int chars) 562 { 563 struct vis_conscopy c_copy; 564 565 c_copy.s_col = fb_info.cursor.origin.x; 566 c_copy.s_row = fb_info.cursor.origin.y; 567 568 c_copy.e_col = (fb_info.terminal.x - chars) * boot_fb_font.width; 569 c_copy.e_col += fb_info.terminal_origin.x; 570 c_copy.e_row = c_copy.s_row + boot_fb_font.height; 571 572 c_copy.t_col = fb_info.cursor.origin.x + chars * boot_fb_font.width; 573 c_copy.t_row = fb_info.cursor.origin.y; 574 575 boot_fb_conscopy(&c_copy); 576 } 577 578 /* 579 * move the terminal window lines [1..y] to [0..y-1] and clear last line. 580 */ 581 static void 582 boot_fb_scroll(void) 583 { 584 struct vis_conscopy c_copy; 585 586 /* support for scrolling. set up the console copy data and last line */ 587 c_copy.s_row = fb_info.terminal_origin.y + boot_fb_font.height; 588 c_copy.s_col = fb_info.terminal_origin.x; 589 c_copy.e_row = fb_info.screen.y - fb_info.terminal_origin.y; 590 c_copy.e_col = fb_info.screen.x - fb_info.terminal_origin.x; 591 c_copy.t_row = fb_info.terminal_origin.y; 592 c_copy.t_col = fb_info.terminal_origin.x; 593 594 boot_fb_conscopy(&c_copy); 595 596 /* now clean up the last line */ 597 boot_fb_eraseline_impl(fb_info.terminal_origin.x, 598 fb_info.terminal_origin.y + 599 (fb_info.terminal.y - 1) * boot_fb_font.height); 600 } 601 602 /* 603 * Very simple block cursor. Save space below the cursor and restore 604 * when cursor is invisible. 605 */ 606 void 607 boot_fb_cursor(boolean_t visible) 608 { 609 uint32_t offset, size; 610 uint32_t *fb32, *sfb32 = NULL; 611 uint32_t fg, bg; 612 uint16_t *fb16, *sfb16 = NULL; 613 uint8_t *fb8, *sfb8 = NULL; 614 int i, pitch; 615 616 if (fb_info.cursor.visible == visible) 617 return; 618 619 boot_get_color(&fg, &bg); 620 fg = boot_color_map(fg); 621 bg = boot_color_map(bg); 622 623 fb_info.cursor.visible = visible; 624 pitch = fb_info.pitch; 625 size = boot_fb_font.width * fb_info.bpp; 626 627 /* 628 * Build cursor image. We are building mirror image of data on 629 * frame buffer by (D xor FG) xor BG. 630 */ 631 offset = fb_info.cursor.origin.x * fb_info.bpp + 632 fb_info.cursor.origin.y * pitch; 633 switch (fb_info.depth) { 634 case 8: 635 for (i = 0; i < boot_fb_font.height; i++) { 636 fb8 = fb_info.fb + offset + i * pitch; 637 if (fb_info.shadow_fb != NULL) 638 sfb8 = fb_info.shadow_fb + offset + i * pitch; 639 for (uint32_t j = 0; j < size; j += 1) { 640 fb8[j] = (fb8[j] ^ (fg & 0xff)) ^ (bg & 0xff); 641 642 if (sfb8 == NULL) 643 continue; 644 645 sfb8[j] = (sfb8[j] ^ (fg & 0xff)) ^ (bg & 0xff); 646 } 647 } 648 break; 649 case 15: 650 case 16: 651 for (i = 0; i < boot_fb_font.height; i++) { 652 fb16 = (uint16_t *)(fb_info.fb + offset + i * pitch); 653 if (fb_info.shadow_fb != NULL) 654 sfb16 = (uint16_t *) 655 (fb_info.shadow_fb + offset + i * pitch); 656 for (int j = 0; j < boot_fb_font.width; j++) { 657 fb16[j] = (fb16[j] ^ (fg & 0xffff)) ^ 658 (bg & 0xffff); 659 660 if (sfb16 == NULL) 661 continue; 662 663 sfb16[j] = (sfb16[j] ^ (fg & 0xffff)) ^ 664 (bg & 0xffff); 665 } 666 } 667 break; 668 case 24: 669 for (i = 0; i < boot_fb_font.height; i++) { 670 fb8 = fb_info.fb + offset + i * pitch; 671 if (fb_info.shadow_fb != NULL) 672 sfb8 = fb_info.shadow_fb + offset + i * pitch; 673 for (uint32_t j = 0; j < size; j += 3) { 674 fb8[j] = (fb8[j] ^ ((fg >> 16) & 0xff)) ^ 675 ((bg >> 16) & 0xff); 676 fb8[j+1] = (fb8[j+1] ^ ((fg >> 8) & 0xff)) ^ 677 ((bg >> 8) & 0xff); 678 fb8[j+2] = (fb8[j+2] ^ (fg & 0xff)) ^ 679 (bg & 0xff); 680 681 if (sfb8 == NULL) 682 continue; 683 684 sfb8[j] = (sfb8[j] ^ ((fg >> 16) & 0xff)) ^ 685 ((bg >> 16) & 0xff); 686 sfb8[j+1] = (sfb8[j+1] ^ ((fg >> 8) & 0xff)) ^ 687 ((bg >> 8) & 0xff); 688 sfb8[j+2] = (sfb8[j+2] ^ (fg & 0xff)) ^ 689 (bg & 0xff); 690 } 691 } 692 break; 693 case 32: 694 for (i = 0; i < boot_fb_font.height; i++) { 695 fb32 = (uint32_t *)(fb_info.fb + offset + i * pitch); 696 if (fb_info.shadow_fb != NULL) { 697 sfb32 = (uint32_t *) 698 (fb_info.shadow_fb + offset + i * pitch); 699 } 700 for (int j = 0; j < boot_fb_font.width; j++) { 701 fb32[j] = (fb32[j] ^ fg) ^ bg; 702 703 if (sfb32 == NULL) 704 continue; 705 706 sfb32[j] = (sfb32[j] ^ fg) ^ bg; 707 } 708 } 709 break; 710 } 711 } 712 713 static void 714 boot_fb_setpos(int row, int col) 715 { 716 if (row < 0) 717 row = 0; 718 if (row >= fb_info.terminal.y) 719 row = fb_info.terminal.y - 1; 720 if (col < 0) 721 col = 0; 722 if (col >= fb_info.terminal.x) 723 col = fb_info.terminal.x - 1; 724 725 fb_info.cursor.pos.x = col; 726 fb_info.cursor.pos.y = row; 727 fb_info.cursor.origin.x = fb_info.terminal_origin.x; 728 fb_info.cursor.origin.x += col * boot_fb_font.width; 729 fb_info.cursor.origin.y = fb_info.terminal_origin.y; 730 fb_info.cursor.origin.y += row * boot_fb_font.height; 731 } 732 733 static void 734 boot_fb_putchar(int c) 735 { 736 struct vis_consdisplay display; 737 int rows, cols; 738 739 rows = fb_info.cursor.pos.y; 740 cols = fb_info.cursor.pos.x; 741 742 if (c == '\n') { 743 if (rows < fb_info.terminal.y - 1) 744 boot_fb_setpos(rows + 1, cols); 745 else 746 boot_fb_scroll(); 747 return; 748 } 749 750 bit_to_pix(c); 751 display.col = fb_info.cursor.origin.x; 752 display.row = fb_info.cursor.origin.y; 753 display.width = boot_fb_font.width; 754 display.height = boot_fb_font.height; 755 display.data = glyph; 756 757 boot_fb_blit(&display); 758 if (cols < fb_info.terminal.x - 1) 759 boot_fb_setpos(rows, cols + 1); 760 else if (rows < fb_info.terminal.y - 1) 761 boot_fb_setpos(rows + 1, 0); 762 else { 763 boot_fb_setpos(rows, 0); 764 boot_fb_scroll(); 765 } 766 } 767