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 40 /* 41 * Simplified visual_io data structures from visual_io.h 42 */ 43 44 struct vis_consdisplay { 45 uint16_t row; /* Row to display data at */ 46 uint16_t col; /* Col to display data at */ 47 uint16_t width; /* Width of data */ 48 uint16_t height; /* Height of data */ 49 uint8_t *data; /* Data to display */ 50 }; 51 52 struct vis_conscopy { 53 uint16_t s_row; /* Starting row */ 54 uint16_t s_col; /* Starting col */ 55 uint16_t e_row; /* Ending row */ 56 uint16_t e_col; /* Ending col */ 57 uint16_t t_row; /* Row to move to */ 58 uint16_t t_col; /* Col to move to */ 59 }; 60 61 /* 62 * We have largest font 16x32 with depth 32. This will allocate 2048 63 * bytes from BSS. 64 */ 65 #define MAX_GLYPH (16 * 32 * 4) 66 67 struct fontlist cf_fontlist; 68 static bitmap_data_t cf_data; 69 static struct font cf_font; 70 71 static struct font boot_fb_font; /* set by set_font() */ 72 static uint8_t glyph[MAX_GLYPH]; 73 74 static void boot_fb_putchar(int); 75 static void boot_fb_eraseline(void); 76 static void boot_fb_setpos(int, int); 77 static void boot_fb_shiftline(int); 78 static void boot_fb_eraseline_impl(uint16_t, uint16_t); 79 80 static void 81 xbi_init_font(struct xboot_info *xbi) 82 { 83 uint32_t i, checksum = 0; 84 struct boot_modules *modules; 85 struct font_info *fi; 86 uintptr_t ptr; 87 88 modules = (struct boot_modules *)(uintptr_t)xbi->bi_modules; 89 for (i = 0; i < xbi->bi_module_cnt; i++) { 90 if (modules[i].bm_type == BMT_FONT) 91 break; 92 } 93 if (i == xbi->bi_module_cnt) 94 return; 95 96 ptr = (uintptr_t)modules[i].bm_addr; 97 fi = (struct font_info *)ptr; 98 99 /* 100 * Compute and verify checksum. The total sum of all the fields 101 * must be 0. Note, the return from this point means we will 102 * use default font. 103 */ 104 checksum += fi->fi_width; 105 checksum += fi->fi_height; 106 checksum += fi->fi_bitmap_size; 107 for (i = 0; i < VFNT_MAPS; i++) 108 checksum += fi->fi_map_count[i]; 109 if (checksum + fi->fi_checksum != 0) 110 return; 111 112 cf_data.width = fi->fi_width; 113 cf_data.height = fi->fi_height; 114 cf_data.uncompressed_size = fi->fi_bitmap_size; 115 cf_data.font = &cf_font; 116 117 ptr += sizeof (struct font_info); 118 ptr = P2ROUNDUP(ptr, 8); 119 120 cf_font.vf_width = fi->fi_width; 121 cf_font.vf_height = fi->fi_height; 122 for (i = 0; i < VFNT_MAPS; i++) { 123 if (fi->fi_map_count[i] == 0) 124 continue; 125 cf_font.vf_map_count[i] = fi->fi_map_count[i]; 126 cf_font.vf_map[i] = (struct font_map *)ptr; 127 ptr += (fi->fi_map_count[i] * sizeof (struct font_map)); 128 ptr = P2ROUNDUP(ptr, 8); 129 } 130 cf_font.vf_bytes = (uint8_t *)ptr; 131 cf_fontlist.font_name = NULL; 132 cf_fontlist.font_flags = FONT_BOOT; 133 cf_fontlist.font_data = &cf_data; 134 cf_fontlist.font_load = NULL; 135 STAILQ_INSERT_HEAD(&fonts, &cf_fontlist, font_next); 136 } 137 138 /* 139 * extract data from MB2 framebuffer tag and set up initial frame buffer. 140 */ 141 boolean_t 142 xbi_fb_init(struct xboot_info *xbi, bcons_dev_t *bcons_dev) 143 { 144 multiboot_tag_framebuffer_t *tag; 145 boot_framebuffer_t *xbi_fb; 146 147 xbi_fb = (boot_framebuffer_t *)(uintptr_t)xbi->bi_framebuffer; 148 if (xbi_fb == NULL) 149 return (B_FALSE); 150 151 #if !defined(_BOOT) 152 /* For early kernel, we get cursor position from dboot. */ 153 fb_info.cursor.origin.x = xbi_fb->cursor.origin.x; 154 fb_info.cursor.origin.y = xbi_fb->cursor.origin.y; 155 fb_info.cursor.pos.x = xbi_fb->cursor.pos.x; 156 fb_info.cursor.pos.y = xbi_fb->cursor.pos.y; 157 fb_info.cursor.visible = xbi_fb->cursor.visible; 158 #endif 159 160 tag = (multiboot_tag_framebuffer_t *)(uintptr_t)xbi_fb->framebuffer; 161 if (tag == NULL) { 162 return (B_FALSE); 163 } 164 165 xbi_init_font(xbi); 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 *bg = dim_xlate[fb_info.fg_color]; 358 *fg = brt_xlate[fb_info.bg_color]; 359 } else { 360 if (fb_info.bg_color == 7) 361 *bg = brt_xlate[fb_info.bg_color]; 362 else 363 *bg = dim_xlate[fb_info.bg_color]; 364 *fg = dim_xlate[fb_info.fg_color]; 365 } 366 } 367 368 /* 369 * Map indexed color to RGB value. 370 */ 371 static uint32_t 372 boot_color_map(uint8_t index) 373 { 374 uint8_t c; 375 int pos, size; 376 uint32_t color; 377 378 /* 8bit depth is for indexed colors */ 379 if (fb_info.depth == 8) 380 return (index); 381 382 if (index >= sizeof (cmap4_to_24.red)) 383 index = 0; 384 385 c = cmap4_to_24.red[index]; 386 pos = fb_info.rgb.red.pos; 387 size = fb_info.rgb.red.size; 388 color = ((c >> 8 - size) & ((1 << size) - 1)) << pos; 389 390 c = cmap4_to_24.green[index]; 391 pos = fb_info.rgb.green.pos; 392 size = fb_info.rgb.green.size; 393 color |= ((c >> 8 - size) & ((1 << size) - 1)) << pos; 394 395 c = cmap4_to_24.blue[index]; 396 pos = fb_info.rgb.blue.pos; 397 size = fb_info.rgb.blue.size; 398 color |= ((c >> 8 - size) & ((1 << size) - 1)) << pos; 399 400 return (color); 401 } 402 403 /* set up out simple console. */ 404 /*ARGSUSED*/ 405 void 406 boot_fb_init(int console) 407 { 408 fb_info_pixel_coord_t window; 409 410 /* frame buffer address is mapped in dboot. */ 411 fb_info.fb = (uint8_t *)(uintptr_t)fb_info.paddr; 412 413 boot_fb_set_font(fb_info.screen.y, fb_info.screen.x); 414 window.x = (fb_info.screen.x - 415 fb_info.terminal.x * boot_fb_font.vf_width) / 2; 416 window.y = (fb_info.screen.y - 417 fb_info.terminal.y * boot_fb_font.vf_height) / 2; 418 fb_info.terminal_origin.x = window.x; 419 fb_info.terminal_origin.y = window.y; 420 421 #if defined(_BOOT) 422 /* 423 * Being called from dboot, we can have cursor terminal 424 * position passed from boot loader. In such case, fix the 425 * cursor screen coords. 426 */ 427 if (fb_info.cursor.pos.x != 0 || fb_info.cursor.pos.y != 0) { 428 fb_info.cursor.origin.x = window.x + 429 fb_info.cursor.pos.x * boot_fb_font.vf_width; 430 fb_info.cursor.origin.y = window.y + 431 fb_info.cursor.pos.y * boot_fb_font.vf_height; 432 } 433 #endif 434 435 /* If the cursor terminal position is 0,0 just reset screen coords */ 436 if (fb_info.cursor.pos.x == 0 && fb_info.cursor.pos.y == 0) { 437 fb_info.cursor.origin.x = window.x; 438 fb_info.cursor.origin.y = window.y; 439 } 440 441 /* 442 * Validate cursor coords with screen/terminal dimensions, 443 * if anything is off, reset to 0,0 444 */ 445 if (fb_info.cursor.pos.x > fb_info.terminal.x || 446 fb_info.cursor.pos.y > fb_info.terminal.y || 447 fb_info.cursor.origin.x > fb_info.screen.x || 448 fb_info.cursor.origin.y > fb_info.screen.y) { 449 450 fb_info.cursor.origin.x = window.x; 451 fb_info.cursor.origin.y = window.y; 452 fb_info.cursor.pos.x = 0; 453 fb_info.cursor.pos.y = 0; 454 } 455 456 #if defined(_BOOT) 457 /* clear the screen if cursor is set to 0,0 */ 458 if (fb_info.cursor.pos.x == 0 && fb_info.cursor.pos.y == 0) { 459 uint32_t fg, bg, toffset; 460 uint16_t y; 461 462 boot_get_color(&fg, &bg); 463 bg = boot_color_map(bg); 464 465 toffset = 0; 466 for (y = 0; y < fb_info.screen.y; y++) { 467 uint8_t *dest = fb_info.fb + toffset; 468 469 boot_fb_fill(dest, bg, fb_info.pitch); 470 toffset += fb_info.pitch; 471 } 472 } 473 #endif 474 } 475 476 /* copy rectangle to framebuffer. */ 477 static void 478 boot_fb_blit(struct vis_consdisplay *rect) 479 { 480 uint32_t offset, size; /* write size per scanline */ 481 uint8_t *fbp, *sfbp = NULL; /* fb + calculated offset */ 482 int i; 483 484 /* make sure we will not write past FB */ 485 if (rect->col >= fb_info.screen.x || 486 rect->row >= fb_info.screen.y || 487 rect->col + rect->width >= fb_info.screen.x || 488 rect->row + rect->height >= fb_info.screen.y) 489 return; 490 491 size = rect->width * fb_info.bpp; 492 offset = rect->col * fb_info.bpp + rect->row * fb_info.pitch; 493 fbp = fb_info.fb + offset; 494 if (fb_info.shadow_fb != NULL) 495 sfbp = fb_info.shadow_fb + offset; 496 497 /* write all scanlines in rectangle */ 498 for (i = 0; i < rect->height; i++) { 499 uint8_t *dest = fbp + i * fb_info.pitch; 500 uint8_t *src = rect->data + i * size; 501 boot_fb_cpy(dest, src, size); 502 if (sfbp != NULL) { 503 dest = sfbp + i * fb_info.pitch; 504 boot_fb_cpy(dest, src, size); 505 } 506 } 507 } 508 509 static void 510 bit_to_pix(uchar_t c) 511 { 512 uint32_t fg, bg; 513 514 boot_get_color(&fg, &bg); 515 fg = boot_color_map(fg); 516 bg = boot_color_map(bg); 517 518 switch (fb_info.depth) { 519 case 8: 520 font_bit_to_pix8(&boot_fb_font, (uint8_t *)glyph, c, fg, bg); 521 break; 522 case 15: 523 case 16: 524 font_bit_to_pix16(&boot_fb_font, (uint16_t *)glyph, c, 525 (uint16_t)fg, (uint16_t)bg); 526 break; 527 case 24: 528 font_bit_to_pix24(&boot_fb_font, (uint8_t *)glyph, c, fg, bg); 529 break; 530 case 32: 531 font_bit_to_pix32(&boot_fb_font, (uint32_t *)glyph, c, fg, bg); 532 break; 533 } 534 } 535 536 static void 537 boot_fb_eraseline_impl(uint16_t x, uint16_t y) 538 { 539 uint32_t toffset, size; 540 uint32_t fg, bg; 541 uint8_t *dst, *sdst; 542 int i; 543 544 boot_get_color(&fg, &bg); 545 bg = boot_color_map(bg); 546 547 size = fb_info.terminal.x * boot_fb_font.vf_width * fb_info.bpp; 548 549 toffset = x * fb_info.bpp + y * fb_info.pitch; 550 dst = fb_info.fb + toffset; 551 sdst = fb_info.shadow_fb + toffset; 552 553 for (i = 0; i < boot_fb_font.vf_height; i++) { 554 uint8_t *dest = dst + i * fb_info.pitch; 555 if (fb_info.fb + fb_info.fb_size >= dest + size) 556 boot_fb_fill(dest, bg, size); 557 if (fb_info.shadow_fb != NULL) { 558 dest = sdst + i * fb_info.pitch; 559 if (fb_info.shadow_fb + fb_info.fb_size >= 560 dest + size) { 561 boot_fb_fill(dest, bg, size); 562 } 563 } 564 } 565 } 566 567 static void 568 boot_fb_eraseline(void) 569 { 570 boot_fb_eraseline_impl(fb_info.cursor.origin.x, 571 fb_info.cursor.origin.y); 572 } 573 574 /* 575 * Copy rectangle from console to console. 576 * If shadow buffer is available, use shadow as source. 577 */ 578 static void 579 boot_fb_conscopy(struct vis_conscopy *c_copy) 580 { 581 uint32_t soffset, toffset; 582 uint32_t width, height, increment; 583 uint8_t *src, *dst, *sdst = NULL; 584 int i; 585 586 soffset = c_copy->s_col * fb_info.bpp + c_copy->s_row * fb_info.pitch; 587 toffset = c_copy->t_col * fb_info.bpp + c_copy->t_row * fb_info.pitch; 588 589 src = fb_info.fb + soffset; 590 dst = fb_info.fb + toffset; 591 592 if (fb_info.shadow_fb != NULL) { 593 src = fb_info.shadow_fb + soffset; 594 sdst = fb_info.shadow_fb + toffset; 595 } 596 597 width = (c_copy->e_col - c_copy->s_col + 1) * fb_info.bpp; 598 height = c_copy->e_row - c_copy->s_row + 1; 599 600 for (i = 0; i < height; i++) { 601 increment = i * fb_info.pitch; 602 603 /* Make sure we fit into FB size. */ 604 if (soffset + increment + width >= fb_info.fb_size || 605 toffset + increment + width >= fb_info.fb_size) 606 break; 607 608 boot_fb_cpy(dst + increment, src + increment, width); 609 610 if (sdst != NULL) 611 boot_fb_cpy(sdst + increment, src + increment, width); 612 } 613 } 614 615 /* Shift the line content by chars. */ 616 static void 617 boot_fb_shiftline(int chars) 618 { 619 struct vis_conscopy c_copy; 620 621 c_copy.s_col = fb_info.cursor.origin.x; 622 c_copy.s_row = fb_info.cursor.origin.y; 623 624 c_copy.e_col = (fb_info.terminal.x - chars) * boot_fb_font.vf_width; 625 c_copy.e_col += fb_info.terminal_origin.x; 626 c_copy.e_row = c_copy.s_row + boot_fb_font.vf_height; 627 628 c_copy.t_col = fb_info.cursor.origin.x + chars * boot_fb_font.vf_width; 629 c_copy.t_row = fb_info.cursor.origin.y; 630 631 boot_fb_conscopy(&c_copy); 632 } 633 634 /* 635 * move the terminal window lines [1..y] to [0..y-1] and clear last line. 636 */ 637 static void 638 boot_fb_scroll(void) 639 { 640 struct vis_conscopy c_copy; 641 642 /* support for scrolling. set up the console copy data and last line */ 643 c_copy.s_row = fb_info.terminal_origin.y + boot_fb_font.vf_height; 644 c_copy.s_col = fb_info.terminal_origin.x; 645 c_copy.e_row = fb_info.screen.y - fb_info.terminal_origin.y; 646 c_copy.e_col = fb_info.screen.x - fb_info.terminal_origin.x; 647 c_copy.t_row = fb_info.terminal_origin.y; 648 c_copy.t_col = fb_info.terminal_origin.x; 649 650 boot_fb_conscopy(&c_copy); 651 652 /* now clean up the last line */ 653 boot_fb_eraseline_impl(fb_info.terminal_origin.x, 654 fb_info.terminal_origin.y + 655 (fb_info.terminal.y - 1) * boot_fb_font.vf_height); 656 } 657 658 /* 659 * Very simple block cursor. Save space below the cursor and restore 660 * when cursor is invisible. 661 */ 662 void 663 boot_fb_cursor(boolean_t visible) 664 { 665 uint32_t offset, size, j; 666 uint32_t *fb32, *sfb32 = NULL; 667 uint32_t fg, bg; 668 uint16_t *fb16, *sfb16 = NULL; 669 uint8_t *fb8, *sfb8 = NULL; 670 int i, pitch; 671 672 if (fb_info.cursor.visible == visible) 673 return; 674 675 boot_get_color(&fg, &bg); 676 fg = boot_color_map(fg); 677 bg = boot_color_map(bg); 678 679 fb_info.cursor.visible = visible; 680 pitch = fb_info.pitch; 681 size = boot_fb_font.vf_width * fb_info.bpp; 682 683 /* 684 * Build cursor image. We are building mirror image of data on 685 * frame buffer by (D xor FG) xor BG. 686 */ 687 offset = fb_info.cursor.origin.x * fb_info.bpp + 688 fb_info.cursor.origin.y * pitch; 689 switch (fb_info.depth) { 690 case 8: 691 for (i = 0; i < boot_fb_font.vf_height; i++) { 692 fb8 = fb_info.fb + offset + i * pitch; 693 if (fb_info.shadow_fb != NULL) 694 sfb8 = fb_info.shadow_fb + offset + i * pitch; 695 for (j = 0; j < size; j += 1) { 696 fb8[j] = (fb8[j] ^ (fg & 0xff)) ^ (bg & 0xff); 697 698 if (sfb8 == NULL) 699 continue; 700 701 sfb8[j] = (sfb8[j] ^ (fg & 0xff)) ^ (bg & 0xff); 702 } 703 } 704 break; 705 case 15: 706 case 16: 707 for (i = 0; i < boot_fb_font.vf_height; i++) { 708 fb16 = (uint16_t *)(fb_info.fb + offset + i * pitch); 709 if (fb_info.shadow_fb != NULL) 710 sfb16 = (uint16_t *) 711 (fb_info.shadow_fb + offset + i * pitch); 712 for (j = 0; j < boot_fb_font.vf_width; j++) { 713 fb16[j] = (fb16[j] ^ (fg & 0xffff)) ^ 714 (bg & 0xffff); 715 716 if (sfb16 == NULL) 717 continue; 718 719 sfb16[j] = (sfb16[j] ^ (fg & 0xffff)) ^ 720 (bg & 0xffff); 721 } 722 } 723 break; 724 case 24: 725 for (i = 0; i < boot_fb_font.vf_height; i++) { 726 fb8 = fb_info.fb + offset + i * pitch; 727 if (fb_info.shadow_fb != NULL) 728 sfb8 = fb_info.shadow_fb + offset + i * pitch; 729 for (j = 0; j < size; j += 3) { 730 fb8[j] = (fb8[j] ^ ((fg >> 16) & 0xff)) ^ 731 ((bg >> 16) & 0xff); 732 fb8[j+1] = (fb8[j+1] ^ ((fg >> 8) & 0xff)) ^ 733 ((bg >> 8) & 0xff); 734 fb8[j+2] = (fb8[j+2] ^ (fg & 0xff)) ^ 735 (bg & 0xff); 736 737 if (sfb8 == NULL) 738 continue; 739 740 sfb8[j] = (sfb8[j] ^ ((fg >> 16) & 0xff)) ^ 741 ((bg >> 16) & 0xff); 742 sfb8[j+1] = (sfb8[j+1] ^ ((fg >> 8) & 0xff)) ^ 743 ((bg >> 8) & 0xff); 744 sfb8[j+2] = (sfb8[j+2] ^ (fg & 0xff)) ^ 745 (bg & 0xff); 746 } 747 } 748 break; 749 case 32: 750 for (i = 0; i < boot_fb_font.vf_height; i++) { 751 fb32 = (uint32_t *)(fb_info.fb + offset + i * pitch); 752 if (fb_info.shadow_fb != NULL) { 753 sfb32 = (uint32_t *) 754 (fb_info.shadow_fb + offset + i * pitch); 755 } 756 for (j = 0; j < boot_fb_font.vf_width; j++) { 757 fb32[j] = (fb32[j] ^ fg) ^ bg; 758 759 if (sfb32 == NULL) 760 continue; 761 762 sfb32[j] = (sfb32[j] ^ fg) ^ bg; 763 } 764 } 765 break; 766 } 767 } 768 769 static void 770 boot_fb_setpos(int row, int col) 771 { 772 if (row < 0) 773 row = 0; 774 if (row >= fb_info.terminal.y) 775 row = fb_info.terminal.y - 1; 776 if (col < 0) 777 col = 0; 778 if (col >= fb_info.terminal.x) 779 col = fb_info.terminal.x - 1; 780 781 fb_info.cursor.pos.x = col; 782 fb_info.cursor.pos.y = row; 783 fb_info.cursor.origin.x = fb_info.terminal_origin.x; 784 fb_info.cursor.origin.x += col * boot_fb_font.vf_width; 785 fb_info.cursor.origin.y = fb_info.terminal_origin.y; 786 fb_info.cursor.origin.y += row * boot_fb_font.vf_height; 787 } 788 789 static void 790 boot_fb_putchar(int c) 791 { 792 struct vis_consdisplay display; 793 int rows, cols; 794 795 rows = fb_info.cursor.pos.y; 796 cols = fb_info.cursor.pos.x; 797 798 if (c == '\n') { 799 if (rows < fb_info.terminal.y - 1) 800 boot_fb_setpos(rows + 1, cols); 801 else 802 boot_fb_scroll(); 803 return; 804 } 805 806 bit_to_pix(c); 807 display.col = fb_info.cursor.origin.x; 808 display.row = fb_info.cursor.origin.y; 809 display.width = boot_fb_font.vf_width; 810 display.height = boot_fb_font.vf_height; 811 display.data = glyph; 812 813 boot_fb_blit(&display); 814 if (cols < fb_info.terminal.x - 1) 815 boot_fb_setpos(rows, cols + 1); 816 else if (rows < fb_info.terminal.y - 1) 817 boot_fb_setpos(rows + 1, 0); 818 else { 819 boot_fb_setpos(rows, 0); 820 boot_fb_scroll(); 821 } 822 } 823