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 210 return (B_TRUE); 211 } 212 213 /* set font and pass the data to fb_info */ 214 static void 215 boot_fb_set_font(uint16_t height, uint16_t width) 216 { 217 short h, w; 218 bitmap_data_t *bp; 219 int i; 220 221 h = MIN(height, 4096); 222 w = MIN(width, 4096); 223 224 bp = set_font((short *)&fb_info.terminal.y, 225 (short *)&fb_info.terminal.x, h, w); 226 227 boot_fb_font.vf_bytes = bp->font->vf_bytes; 228 boot_fb_font.vf_width = bp->font->vf_width; 229 boot_fb_font.vf_height = bp->font->vf_height; 230 for (i = 0; i < VFNT_MAPS; i++) { 231 boot_fb_font.vf_map[i] = bp->font->vf_map[i]; 232 boot_fb_font.vf_map_count[i] = bp->font->vf_map_count[i]; 233 } 234 235 fb_info.font_width = boot_fb_font.vf_width; 236 fb_info.font_height = boot_fb_font.vf_height; 237 } 238 239 /* fill framebuffer */ 240 static void 241 boot_fb_fill(uint8_t *dst, uint32_t data, uint32_t len) 242 { 243 uint16_t *dst16; 244 uint32_t *dst32; 245 uint32_t i; 246 247 switch (fb_info.depth) { 248 case 24: 249 case 8: 250 for (i = 0; i < len; i++) 251 dst[i] = (uint8_t)data; 252 break; 253 case 15: 254 case 16: 255 dst16 = (uint16_t *)dst; 256 len /= 2; 257 for (i = 0; i < len; i++) 258 dst16[i] = (uint16_t)data; 259 break; 260 case 32: 261 dst32 = (uint32_t *)dst; 262 len /= 4; 263 for (i = 0; i < len; i++) 264 dst32[i] = data; 265 break; 266 } 267 } 268 269 /* copy data to framebuffer */ 270 static void 271 boot_fb_cpy(uint8_t *dst, uint8_t *src, uint32_t len) 272 { 273 uint16_t *dst16, *src16; 274 uint32_t *dst32, *src32; 275 276 switch (fb_info.depth) { 277 case 24: 278 case 8: 279 default: 280 if (dst <= src) { 281 do { 282 *dst++ = *src++; 283 } while (--len != 0); 284 } else { 285 dst += len; 286 src += len; 287 do { 288 *--dst = *--src; 289 } while (--len != 0); 290 } 291 break; 292 case 15: 293 case 16: 294 dst16 = (uint16_t *)dst; 295 src16 = (uint16_t *)src; 296 len /= 2; 297 if (dst16 <= src16) { 298 do { 299 *dst16++ = *src16++; 300 } while (--len != 0); 301 } else { 302 dst16 += len; 303 src16 += len; 304 do { 305 *--dst16 = *--src16; 306 } while (--len != 0); 307 } 308 break; 309 case 32: 310 dst32 = (uint32_t *)dst; 311 src32 = (uint32_t *)src; 312 len /= 4; 313 if (dst32 <= src32) { 314 do { 315 *dst32++ = *src32++; 316 } while (--len != 0); 317 } else { 318 dst32 += len; 319 src32 += len; 320 do { 321 *--dst32 = *--src32; 322 } while (--len != 0); 323 } 324 break; 325 } 326 } 327 328 /* 329 * Allocate shadow frame buffer, called from fakebop.c when early boot 330 * allocator is ready. 331 */ 332 void 333 boot_fb_shadow_init(bootops_t *bops) 334 { 335 if (boot_console_type(NULL) != CONS_FRAMEBUFFER) 336 return; /* nothing to do */ 337 338 fb_info.shadow_fb = (uint8_t *)bops->bsys_alloc(NULL, NULL, 339 fb_info.fb_size, MMU_PAGESIZE); 340 341 if (fb_info.shadow_fb == NULL) 342 return; 343 344 /* Copy FB to shadow */ 345 boot_fb_cpy(fb_info.shadow_fb, fb_info.fb, fb_info.fb_size); 346 } 347 348 /* 349 * Translate ansi color based on inverses and brightness. 350 */ 351 void 352 boot_get_color(uint32_t *fg, uint32_t *bg) 353 { 354 /* ansi to solaris colors, see also boot_console.c */ 355 if (fb_info.inverse == B_TRUE || 356 fb_info.inverse_screen == B_TRUE) { 357 if (fb_info.fg_color < XLATE_NCOLORS) { 358 /* 359 * white fg -> bright white bg 360 */ 361 if (fb_info.fg_color == pc_white) 362 *bg = brt_xlate[fb_info.fg_color]; 363 else 364 *bg = dim_xlate[fb_info.fg_color]; 365 } else { 366 *bg = fb_info.fg_color; 367 } 368 369 if (fb_info.bg_color < XLATE_NCOLORS) { 370 if (fb_info.bg_color == pc_white) 371 *fg = brt_xlate[fb_info.bg_color]; 372 else 373 *fg = dim_xlate[fb_info.bg_color]; 374 } else { 375 *fg = fb_info.bg_color; 376 } 377 } else { 378 if (fb_info.fg_color < XLATE_NCOLORS) { 379 if (fb_info.fg_color == pc_white) 380 *fg = brt_xlate[fb_info.fg_color]; 381 else 382 *fg = dim_xlate[fb_info.fg_color]; 383 } else { 384 *fg = fb_info.fg_color; 385 } 386 387 if (fb_info.bg_color < XLATE_NCOLORS) { 388 if (fb_info.bg_color == pc_white) 389 *bg = brt_xlate[fb_info.bg_color]; 390 else 391 *bg = dim_xlate[fb_info.bg_color]; 392 } else { 393 *bg = fb_info.bg_color; 394 } 395 } 396 } 397 398 /* 399 * Map indexed color to RGB value. 400 */ 401 uint32_t 402 boot_color_map(uint8_t index) 403 { 404 if (fb_info.fb_type != FB_TYPE_RGB) { 405 if (index < nitems(solaris_color_to_pc_color)) 406 return (solaris_color_to_pc_color[index]); 407 else 408 return (index); 409 } 410 411 return (rgb_color_map(&fb_info.rgb, index)); 412 } 413 414 /* set up out simple console. */ 415 /*ARGSUSED*/ 416 void 417 boot_fb_init(int console) 418 { 419 fb_info_pixel_coord_t window; 420 421 /* frame buffer address is mapped in dboot. */ 422 fb_info.fb = (uint8_t *)(uintptr_t)fb_info.paddr; 423 424 boot_fb_set_font(fb_info.screen.y, fb_info.screen.x); 425 window.x = (fb_info.screen.x - 426 fb_info.terminal.x * boot_fb_font.vf_width) / 2; 427 window.y = (fb_info.screen.y - 428 fb_info.terminal.y * boot_fb_font.vf_height) / 2; 429 fb_info.terminal_origin.x = window.x; 430 fb_info.terminal_origin.y = window.y; 431 432 #if defined(_BOOT) 433 /* 434 * Being called from dboot, we can have cursor terminal 435 * position passed from boot loader. In such case, fix the 436 * cursor screen coords. 437 */ 438 if (fb_info.cursor.pos.x != 0 || fb_info.cursor.pos.y != 0) { 439 fb_info.cursor.origin.x = window.x + 440 fb_info.cursor.pos.x * boot_fb_font.vf_width; 441 fb_info.cursor.origin.y = window.y + 442 fb_info.cursor.pos.y * boot_fb_font.vf_height; 443 } 444 #endif 445 446 /* If the cursor terminal position is 0,0 just reset screen coords */ 447 if (fb_info.cursor.pos.x == 0 && fb_info.cursor.pos.y == 0) { 448 fb_info.cursor.origin.x = window.x; 449 fb_info.cursor.origin.y = window.y; 450 } 451 452 /* 453 * Validate cursor coords with screen/terminal dimensions, 454 * if anything is off, reset to 0,0 455 */ 456 if (fb_info.cursor.pos.x > fb_info.terminal.x || 457 fb_info.cursor.pos.y > fb_info.terminal.y || 458 fb_info.cursor.origin.x > fb_info.screen.x || 459 fb_info.cursor.origin.y > fb_info.screen.y) { 460 461 fb_info.cursor.origin.x = window.x; 462 fb_info.cursor.origin.y = window.y; 463 fb_info.cursor.pos.x = 0; 464 fb_info.cursor.pos.y = 0; 465 } 466 467 #if defined(_BOOT) 468 /* clear the screen if cursor is set to 0,0 */ 469 if (fb_info.cursor.pos.x == 0 && fb_info.cursor.pos.y == 0) { 470 uint32_t fg, bg, toffset; 471 uint16_t y; 472 473 boot_get_color(&fg, &bg); 474 bg = boot_color_map(bg); 475 476 toffset = 0; 477 for (y = 0; y < fb_info.screen.y; y++) { 478 uint8_t *dest = fb_info.fb + toffset; 479 480 boot_fb_fill(dest, bg, fb_info.pitch); 481 toffset += fb_info.pitch; 482 } 483 } 484 #endif 485 } 486 487 /* copy rectangle to framebuffer. */ 488 static void 489 boot_fb_blit(struct vis_consdisplay *rect) 490 { 491 uint32_t offset, size; /* write size per scanline */ 492 uint8_t *fbp, *sfbp = NULL; /* fb + calculated offset */ 493 int i; 494 495 /* make sure we will not write past FB */ 496 if (rect->col >= fb_info.screen.x || 497 rect->row >= fb_info.screen.y || 498 rect->col + rect->width >= fb_info.screen.x || 499 rect->row + rect->height >= fb_info.screen.y) 500 return; 501 502 size = rect->width * fb_info.bpp; 503 offset = rect->col * fb_info.bpp + rect->row * fb_info.pitch; 504 fbp = fb_info.fb + offset; 505 if (fb_info.shadow_fb != NULL) 506 sfbp = fb_info.shadow_fb + offset; 507 508 /* write all scanlines in rectangle */ 509 for (i = 0; i < rect->height; i++) { 510 uint8_t *dest = fbp + i * fb_info.pitch; 511 uint8_t *src = rect->data + i * size; 512 boot_fb_cpy(dest, src, size); 513 if (sfbp != NULL) { 514 dest = sfbp + i * fb_info.pitch; 515 boot_fb_cpy(dest, src, size); 516 } 517 } 518 } 519 520 static void 521 bit_to_pix(uchar_t c) 522 { 523 uint32_t fg, bg; 524 525 boot_get_color(&fg, &bg); 526 fg = boot_color_map(fg); 527 bg = boot_color_map(bg); 528 529 switch (fb_info.depth) { 530 case 8: 531 font_bit_to_pix8(&boot_fb_font, (uint8_t *)glyph, c, fg, bg); 532 break; 533 case 15: 534 case 16: 535 font_bit_to_pix16(&boot_fb_font, (uint16_t *)glyph, c, 536 (uint16_t)fg, (uint16_t)bg); 537 break; 538 case 24: 539 font_bit_to_pix24(&boot_fb_font, (uint8_t *)glyph, c, fg, bg); 540 break; 541 case 32: 542 font_bit_to_pix32(&boot_fb_font, (uint32_t *)glyph, c, fg, bg); 543 break; 544 } 545 } 546 547 static void 548 boot_fb_eraseline_impl(uint16_t x, uint16_t y) 549 { 550 uint32_t toffset, size; 551 uint32_t fg, bg; 552 uint8_t *dst, *sdst; 553 int i; 554 555 boot_get_color(&fg, &bg); 556 bg = boot_color_map(bg); 557 558 size = fb_info.terminal.x * boot_fb_font.vf_width * fb_info.bpp; 559 560 toffset = x * fb_info.bpp + y * fb_info.pitch; 561 dst = fb_info.fb + toffset; 562 sdst = fb_info.shadow_fb + toffset; 563 564 for (i = 0; i < boot_fb_font.vf_height; i++) { 565 uint8_t *dest = dst + i * fb_info.pitch; 566 if (fb_info.fb + fb_info.fb_size >= dest + size) 567 boot_fb_fill(dest, bg, size); 568 if (fb_info.shadow_fb != NULL) { 569 dest = sdst + i * fb_info.pitch; 570 if (fb_info.shadow_fb + fb_info.fb_size >= 571 dest + size) { 572 boot_fb_fill(dest, bg, size); 573 } 574 } 575 } 576 } 577 578 static void 579 boot_fb_eraseline(void) 580 { 581 boot_fb_eraseline_impl(fb_info.cursor.origin.x, 582 fb_info.cursor.origin.y); 583 } 584 585 /* 586 * Copy rectangle from console to console. 587 * If shadow buffer is available, use shadow as source. 588 */ 589 static void 590 boot_fb_conscopy(struct vis_conscopy *c_copy) 591 { 592 uint32_t soffset, toffset; 593 uint32_t width, height, increment; 594 uint8_t *src, *dst, *sdst = NULL; 595 int i; 596 597 soffset = c_copy->s_col * fb_info.bpp + c_copy->s_row * fb_info.pitch; 598 toffset = c_copy->t_col * fb_info.bpp + c_copy->t_row * fb_info.pitch; 599 600 src = fb_info.fb + soffset; 601 dst = fb_info.fb + toffset; 602 603 if (fb_info.shadow_fb != NULL) { 604 src = fb_info.shadow_fb + soffset; 605 sdst = fb_info.shadow_fb + toffset; 606 } 607 608 width = (c_copy->e_col - c_copy->s_col + 1) * fb_info.bpp; 609 height = c_copy->e_row - c_copy->s_row + 1; 610 611 for (i = 0; i < height; i++) { 612 increment = i * fb_info.pitch; 613 614 /* Make sure we fit into FB size. */ 615 if (soffset + increment + width >= fb_info.fb_size || 616 toffset + increment + width >= fb_info.fb_size) 617 break; 618 619 boot_fb_cpy(dst + increment, src + increment, width); 620 621 if (sdst != NULL) 622 boot_fb_cpy(sdst + increment, src + increment, width); 623 } 624 } 625 626 /* Shift the line content by chars. */ 627 static void 628 boot_fb_shiftline(int chars) 629 { 630 struct vis_conscopy c_copy; 631 632 c_copy.s_col = fb_info.cursor.origin.x; 633 c_copy.s_row = fb_info.cursor.origin.y; 634 635 c_copy.e_col = (fb_info.terminal.x - chars) * boot_fb_font.vf_width; 636 c_copy.e_col += fb_info.terminal_origin.x; 637 c_copy.e_row = c_copy.s_row + boot_fb_font.vf_height; 638 639 c_copy.t_col = fb_info.cursor.origin.x + chars * boot_fb_font.vf_width; 640 c_copy.t_row = fb_info.cursor.origin.y; 641 642 boot_fb_conscopy(&c_copy); 643 } 644 645 /* 646 * move the terminal window lines [1..y] to [0..y-1] and clear last line. 647 */ 648 static void 649 boot_fb_scroll(void) 650 { 651 struct vis_conscopy c_copy; 652 653 /* support for scrolling. set up the console copy data and last line */ 654 c_copy.s_row = fb_info.terminal_origin.y + boot_fb_font.vf_height; 655 c_copy.s_col = fb_info.terminal_origin.x; 656 c_copy.e_row = fb_info.screen.y - fb_info.terminal_origin.y; 657 c_copy.e_col = fb_info.screen.x - fb_info.terminal_origin.x; 658 c_copy.t_row = fb_info.terminal_origin.y; 659 c_copy.t_col = fb_info.terminal_origin.x; 660 661 boot_fb_conscopy(&c_copy); 662 663 /* now clean up the last line */ 664 boot_fb_eraseline_impl(fb_info.terminal_origin.x, 665 fb_info.terminal_origin.y + 666 (fb_info.terminal.y - 1) * boot_fb_font.vf_height); 667 } 668 669 /* 670 * Very simple block cursor. Save space below the cursor and restore 671 * when cursor is invisible. 672 */ 673 void 674 boot_fb_cursor(boolean_t visible) 675 { 676 uint32_t offset, size, j; 677 uint32_t *fb32, *sfb32 = NULL; 678 uint32_t fg, bg; 679 uint16_t *fb16, *sfb16 = NULL; 680 uint8_t *fb8, *sfb8 = NULL; 681 int i, pitch; 682 683 if (fb_info.cursor.visible == visible) 684 return; 685 686 boot_get_color(&fg, &bg); 687 fg = boot_color_map(fg); 688 bg = boot_color_map(bg); 689 690 fb_info.cursor.visible = visible; 691 pitch = fb_info.pitch; 692 size = boot_fb_font.vf_width * fb_info.bpp; 693 694 /* 695 * Build cursor image. We are building mirror image of data on 696 * frame buffer by (D xor FG) xor BG. 697 */ 698 offset = fb_info.cursor.origin.x * fb_info.bpp + 699 fb_info.cursor.origin.y * pitch; 700 switch (fb_info.depth) { 701 case 8: 702 for (i = 0; i < boot_fb_font.vf_height; i++) { 703 fb8 = fb_info.fb + offset + i * pitch; 704 if (fb_info.shadow_fb != NULL) 705 sfb8 = fb_info.shadow_fb + offset + i * pitch; 706 for (j = 0; j < size; j += 1) { 707 fb8[j] = (fb8[j] ^ (fg & 0xff)) ^ (bg & 0xff); 708 709 if (sfb8 == NULL) 710 continue; 711 712 sfb8[j] = (sfb8[j] ^ (fg & 0xff)) ^ (bg & 0xff); 713 } 714 } 715 break; 716 case 15: 717 case 16: 718 for (i = 0; i < boot_fb_font.vf_height; i++) { 719 fb16 = (uint16_t *)(fb_info.fb + offset + i * pitch); 720 if (fb_info.shadow_fb != NULL) 721 sfb16 = (uint16_t *) 722 (fb_info.shadow_fb + offset + i * pitch); 723 for (j = 0; j < boot_fb_font.vf_width; j++) { 724 fb16[j] = (fb16[j] ^ (fg & 0xffff)) ^ 725 (bg & 0xffff); 726 727 if (sfb16 == NULL) 728 continue; 729 730 sfb16[j] = (sfb16[j] ^ (fg & 0xffff)) ^ 731 (bg & 0xffff); 732 } 733 } 734 break; 735 case 24: 736 for (i = 0; i < boot_fb_font.vf_height; i++) { 737 fb8 = fb_info.fb + offset + i * pitch; 738 if (fb_info.shadow_fb != NULL) 739 sfb8 = fb_info.shadow_fb + offset + i * pitch; 740 for (j = 0; j < size; j += 3) { 741 fb8[j] = (fb8[j] ^ ((fg >> 16) & 0xff)) ^ 742 ((bg >> 16) & 0xff); 743 fb8[j+1] = (fb8[j+1] ^ ((fg >> 8) & 0xff)) ^ 744 ((bg >> 8) & 0xff); 745 fb8[j+2] = (fb8[j+2] ^ (fg & 0xff)) ^ 746 (bg & 0xff); 747 748 if (sfb8 == NULL) 749 continue; 750 751 sfb8[j] = (sfb8[j] ^ ((fg >> 16) & 0xff)) ^ 752 ((bg >> 16) & 0xff); 753 sfb8[j+1] = (sfb8[j+1] ^ ((fg >> 8) & 0xff)) ^ 754 ((bg >> 8) & 0xff); 755 sfb8[j+2] = (sfb8[j+2] ^ (fg & 0xff)) ^ 756 (bg & 0xff); 757 } 758 } 759 break; 760 case 32: 761 for (i = 0; i < boot_fb_font.vf_height; i++) { 762 fb32 = (uint32_t *)(fb_info.fb + offset + i * pitch); 763 if (fb_info.shadow_fb != NULL) { 764 sfb32 = (uint32_t *) 765 (fb_info.shadow_fb + offset + i * pitch); 766 } 767 for (j = 0; j < boot_fb_font.vf_width; j++) { 768 fb32[j] = (fb32[j] ^ fg) ^ bg; 769 770 if (sfb32 == NULL) 771 continue; 772 773 sfb32[j] = (sfb32[j] ^ fg) ^ bg; 774 } 775 } 776 break; 777 } 778 } 779 780 static void 781 boot_fb_setpos(int row, int col) 782 { 783 if (row < 0) 784 row = 0; 785 if (row >= fb_info.terminal.y) 786 row = fb_info.terminal.y - 1; 787 if (col < 0) 788 col = 0; 789 if (col >= fb_info.terminal.x) 790 col = fb_info.terminal.x - 1; 791 792 fb_info.cursor.pos.x = col; 793 fb_info.cursor.pos.y = row; 794 fb_info.cursor.origin.x = fb_info.terminal_origin.x; 795 fb_info.cursor.origin.x += col * boot_fb_font.vf_width; 796 fb_info.cursor.origin.y = fb_info.terminal_origin.y; 797 fb_info.cursor.origin.y += row * boot_fb_font.vf_height; 798 } 799 800 static void 801 boot_fb_putchar(int c) 802 { 803 struct vis_consdisplay display; 804 int rows, cols; 805 806 rows = fb_info.cursor.pos.y; 807 cols = fb_info.cursor.pos.x; 808 809 if (c == '\n') { 810 if (rows < fb_info.terminal.y - 1) 811 boot_fb_setpos(rows + 1, cols); 812 else 813 boot_fb_scroll(); 814 return; 815 } 816 817 bit_to_pix(c); 818 display.col = fb_info.cursor.origin.x; 819 display.row = fb_info.cursor.origin.y; 820 display.width = boot_fb_font.vf_width; 821 display.height = boot_fb_font.vf_height; 822 display.data = glyph; 823 824 boot_fb_blit(&display); 825 if (cols < fb_info.terminal.x - 1) 826 boot_fb_setpos(rows, cols + 1); 827 else if (rows < fb_info.terminal.y - 1) 828 boot_fb_setpos(rows + 1, 0); 829 else { 830 boot_fb_setpos(rows, 0); 831 boot_fb_scroll(); 832 } 833 } 834