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