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 tag = (multiboot_tag_framebuffer_t *)(uintptr_t)xbi_fb->framebuffer; 162 if (tag == NULL) { 163 return (B_FALSE); 164 } 165 166 xbi_init_font(xbi); 167 168 fb_info.paddr = tag->framebuffer_common.framebuffer_addr; 169 fb_info.pitch = tag->framebuffer_common.framebuffer_pitch; 170 fb_info.depth = tag->framebuffer_common.framebuffer_bpp; 171 fb_info.bpp = P2ROUNDUP(fb_info.depth, 8) >> 3; 172 fb_info.screen.x = tag->framebuffer_common.framebuffer_width; 173 fb_info.screen.y = tag->framebuffer_common.framebuffer_height; 174 fb_info.fb_size = fb_info.screen.y * fb_info.pitch; 175 176 bcons_dev->bd_putchar = boot_fb_putchar; 177 bcons_dev->bd_eraseline = boot_fb_eraseline; 178 bcons_dev->bd_cursor = boot_fb_cursor; 179 bcons_dev->bd_setpos = boot_fb_setpos; 180 bcons_dev->bd_shift = boot_fb_shiftline; 181 182 if (fb_info.paddr == 0) 183 fb_info.fb_type = FB_TYPE_UNKNOWN; 184 185 switch (tag->framebuffer_common.framebuffer_type) { 186 case MULTIBOOT_FRAMEBUFFER_TYPE_EGA_TEXT: 187 fb_info.fb_type = FB_TYPE_EGA_TEXT; 188 return (B_FALSE); 189 190 case MULTIBOOT_FRAMEBUFFER_TYPE_INDEXED: 191 if (fb_info.paddr != 0) 192 fb_info.fb_type = FB_TYPE_INDEXED; 193 return (B_TRUE); 194 195 case MULTIBOOT_FRAMEBUFFER_TYPE_RGB: 196 if (fb_info.paddr != 0) 197 fb_info.fb_type = FB_TYPE_RGB; 198 break; 199 200 default: 201 return (B_FALSE); 202 } 203 204 fb_info.rgb.red.size = tag->u.fb2.framebuffer_red_mask_size; 205 fb_info.rgb.red.pos = tag->u.fb2.framebuffer_red_field_position; 206 fb_info.rgb.green.size = tag->u.fb2.framebuffer_green_mask_size; 207 fb_info.rgb.green.pos = tag->u.fb2.framebuffer_green_field_position; 208 fb_info.rgb.blue.size = tag->u.fb2.framebuffer_blue_mask_size; 209 fb_info.rgb.blue.pos = tag->u.fb2.framebuffer_blue_field_position; 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 < 16) 359 *bg = dim_xlate[fb_info.fg_color]; 360 else 361 *bg = fb_info.fg_color; 362 363 if (fb_info.bg_color < 16) 364 *fg = brt_xlate[fb_info.bg_color]; 365 else 366 *fg = fb_info.bg_color; 367 } else { 368 if (fb_info.bg_color < 16) { 369 if (fb_info.bg_color == 7) 370 *bg = brt_xlate[fb_info.bg_color]; 371 else 372 *bg = dim_xlate[fb_info.bg_color]; 373 } else { 374 *bg = fb_info.bg_color; 375 } 376 if (fb_info.fg_color < 16) 377 *fg = dim_xlate[fb_info.fg_color]; 378 else 379 *fg = fb_info.fg_color; 380 } 381 } 382 383 /* 384 * Map indexed color to RGB value. 385 */ 386 uint32_t 387 boot_color_map(uint8_t index) 388 { 389 if (fb_info.fb_type != FB_TYPE_RGB) { 390 if (index < nitems(solaris_color_to_pc_color)) 391 return (solaris_color_to_pc_color[index]); 392 else 393 return (index); 394 } 395 396 return (rgb_color_map(&fb_info.rgb, index)); 397 } 398 399 /* set up out simple console. */ 400 /*ARGSUSED*/ 401 void 402 boot_fb_init(int console) 403 { 404 fb_info_pixel_coord_t window; 405 406 /* frame buffer address is mapped in dboot. */ 407 fb_info.fb = (uint8_t *)(uintptr_t)fb_info.paddr; 408 409 boot_fb_set_font(fb_info.screen.y, fb_info.screen.x); 410 window.x = (fb_info.screen.x - 411 fb_info.terminal.x * boot_fb_font.vf_width) / 2; 412 window.y = (fb_info.screen.y - 413 fb_info.terminal.y * boot_fb_font.vf_height) / 2; 414 fb_info.terminal_origin.x = window.x; 415 fb_info.terminal_origin.y = window.y; 416 417 #if defined(_BOOT) 418 /* 419 * Being called from dboot, we can have cursor terminal 420 * position passed from boot loader. In such case, fix the 421 * cursor screen coords. 422 */ 423 if (fb_info.cursor.pos.x != 0 || fb_info.cursor.pos.y != 0) { 424 fb_info.cursor.origin.x = window.x + 425 fb_info.cursor.pos.x * boot_fb_font.vf_width; 426 fb_info.cursor.origin.y = window.y + 427 fb_info.cursor.pos.y * boot_fb_font.vf_height; 428 } 429 #endif 430 431 /* If the cursor terminal position is 0,0 just reset screen coords */ 432 if (fb_info.cursor.pos.x == 0 && fb_info.cursor.pos.y == 0) { 433 fb_info.cursor.origin.x = window.x; 434 fb_info.cursor.origin.y = window.y; 435 } 436 437 /* 438 * Validate cursor coords with screen/terminal dimensions, 439 * if anything is off, reset to 0,0 440 */ 441 if (fb_info.cursor.pos.x > fb_info.terminal.x || 442 fb_info.cursor.pos.y > fb_info.terminal.y || 443 fb_info.cursor.origin.x > fb_info.screen.x || 444 fb_info.cursor.origin.y > fb_info.screen.y) { 445 446 fb_info.cursor.origin.x = window.x; 447 fb_info.cursor.origin.y = window.y; 448 fb_info.cursor.pos.x = 0; 449 fb_info.cursor.pos.y = 0; 450 } 451 452 #if defined(_BOOT) 453 /* clear the screen if cursor is set to 0,0 */ 454 if (fb_info.cursor.pos.x == 0 && fb_info.cursor.pos.y == 0) { 455 uint32_t fg, bg, toffset; 456 uint16_t y; 457 458 boot_get_color(&fg, &bg); 459 bg = boot_color_map(bg); 460 461 toffset = 0; 462 for (y = 0; y < fb_info.screen.y; y++) { 463 uint8_t *dest = fb_info.fb + toffset; 464 465 boot_fb_fill(dest, bg, fb_info.pitch); 466 toffset += fb_info.pitch; 467 } 468 } 469 #endif 470 } 471 472 /* copy rectangle to framebuffer. */ 473 static void 474 boot_fb_blit(struct vis_consdisplay *rect) 475 { 476 uint32_t offset, size; /* write size per scanline */ 477 uint8_t *fbp, *sfbp = NULL; /* fb + calculated offset */ 478 int i; 479 480 /* make sure we will not write past FB */ 481 if (rect->col >= fb_info.screen.x || 482 rect->row >= fb_info.screen.y || 483 rect->col + rect->width >= fb_info.screen.x || 484 rect->row + rect->height >= fb_info.screen.y) 485 return; 486 487 size = rect->width * fb_info.bpp; 488 offset = rect->col * fb_info.bpp + rect->row * fb_info.pitch; 489 fbp = fb_info.fb + offset; 490 if (fb_info.shadow_fb != NULL) 491 sfbp = fb_info.shadow_fb + offset; 492 493 /* write all scanlines in rectangle */ 494 for (i = 0; i < rect->height; i++) { 495 uint8_t *dest = fbp + i * fb_info.pitch; 496 uint8_t *src = rect->data + i * size; 497 boot_fb_cpy(dest, src, size); 498 if (sfbp != NULL) { 499 dest = sfbp + i * fb_info.pitch; 500 boot_fb_cpy(dest, src, size); 501 } 502 } 503 } 504 505 static void 506 bit_to_pix(uchar_t c) 507 { 508 uint32_t fg, bg; 509 510 boot_get_color(&fg, &bg); 511 fg = boot_color_map(fg); 512 bg = boot_color_map(bg); 513 514 switch (fb_info.depth) { 515 case 8: 516 font_bit_to_pix8(&boot_fb_font, (uint8_t *)glyph, c, fg, bg); 517 break; 518 case 15: 519 case 16: 520 font_bit_to_pix16(&boot_fb_font, (uint16_t *)glyph, c, 521 (uint16_t)fg, (uint16_t)bg); 522 break; 523 case 24: 524 font_bit_to_pix24(&boot_fb_font, (uint8_t *)glyph, c, fg, bg); 525 break; 526 case 32: 527 font_bit_to_pix32(&boot_fb_font, (uint32_t *)glyph, c, fg, bg); 528 break; 529 } 530 } 531 532 static void 533 boot_fb_eraseline_impl(uint16_t x, uint16_t y) 534 { 535 uint32_t toffset, size; 536 uint32_t fg, bg; 537 uint8_t *dst, *sdst; 538 int i; 539 540 boot_get_color(&fg, &bg); 541 bg = boot_color_map(bg); 542 543 size = fb_info.terminal.x * boot_fb_font.vf_width * fb_info.bpp; 544 545 toffset = x * fb_info.bpp + y * fb_info.pitch; 546 dst = fb_info.fb + toffset; 547 sdst = fb_info.shadow_fb + toffset; 548 549 for (i = 0; i < boot_fb_font.vf_height; i++) { 550 uint8_t *dest = dst + i * fb_info.pitch; 551 if (fb_info.fb + fb_info.fb_size >= dest + size) 552 boot_fb_fill(dest, bg, size); 553 if (fb_info.shadow_fb != NULL) { 554 dest = sdst + i * fb_info.pitch; 555 if (fb_info.shadow_fb + fb_info.fb_size >= 556 dest + size) { 557 boot_fb_fill(dest, bg, size); 558 } 559 } 560 } 561 } 562 563 static void 564 boot_fb_eraseline(void) 565 { 566 boot_fb_eraseline_impl(fb_info.cursor.origin.x, 567 fb_info.cursor.origin.y); 568 } 569 570 /* 571 * Copy rectangle from console to console. 572 * If shadow buffer is available, use shadow as source. 573 */ 574 static void 575 boot_fb_conscopy(struct vis_conscopy *c_copy) 576 { 577 uint32_t soffset, toffset; 578 uint32_t width, height, increment; 579 uint8_t *src, *dst, *sdst = NULL; 580 int i; 581 582 soffset = c_copy->s_col * fb_info.bpp + c_copy->s_row * fb_info.pitch; 583 toffset = c_copy->t_col * fb_info.bpp + c_copy->t_row * fb_info.pitch; 584 585 src = fb_info.fb + soffset; 586 dst = fb_info.fb + toffset; 587 588 if (fb_info.shadow_fb != NULL) { 589 src = fb_info.shadow_fb + soffset; 590 sdst = fb_info.shadow_fb + toffset; 591 } 592 593 width = (c_copy->e_col - c_copy->s_col + 1) * fb_info.bpp; 594 height = c_copy->e_row - c_copy->s_row + 1; 595 596 for (i = 0; i < height; i++) { 597 increment = i * fb_info.pitch; 598 599 /* Make sure we fit into FB size. */ 600 if (soffset + increment + width >= fb_info.fb_size || 601 toffset + increment + width >= fb_info.fb_size) 602 break; 603 604 boot_fb_cpy(dst + increment, src + increment, width); 605 606 if (sdst != NULL) 607 boot_fb_cpy(sdst + increment, src + increment, width); 608 } 609 } 610 611 /* Shift the line content by chars. */ 612 static void 613 boot_fb_shiftline(int chars) 614 { 615 struct vis_conscopy c_copy; 616 617 c_copy.s_col = fb_info.cursor.origin.x; 618 c_copy.s_row = fb_info.cursor.origin.y; 619 620 c_copy.e_col = (fb_info.terminal.x - chars) * boot_fb_font.vf_width; 621 c_copy.e_col += fb_info.terminal_origin.x; 622 c_copy.e_row = c_copy.s_row + boot_fb_font.vf_height; 623 624 c_copy.t_col = fb_info.cursor.origin.x + chars * boot_fb_font.vf_width; 625 c_copy.t_row = fb_info.cursor.origin.y; 626 627 boot_fb_conscopy(&c_copy); 628 } 629 630 /* 631 * move the terminal window lines [1..y] to [0..y-1] and clear last line. 632 */ 633 static void 634 boot_fb_scroll(void) 635 { 636 struct vis_conscopy c_copy; 637 638 /* support for scrolling. set up the console copy data and last line */ 639 c_copy.s_row = fb_info.terminal_origin.y + boot_fb_font.vf_height; 640 c_copy.s_col = fb_info.terminal_origin.x; 641 c_copy.e_row = fb_info.screen.y - fb_info.terminal_origin.y; 642 c_copy.e_col = fb_info.screen.x - fb_info.terminal_origin.x; 643 c_copy.t_row = fb_info.terminal_origin.y; 644 c_copy.t_col = fb_info.terminal_origin.x; 645 646 boot_fb_conscopy(&c_copy); 647 648 /* now clean up the last line */ 649 boot_fb_eraseline_impl(fb_info.terminal_origin.x, 650 fb_info.terminal_origin.y + 651 (fb_info.terminal.y - 1) * boot_fb_font.vf_height); 652 } 653 654 /* 655 * Very simple block cursor. Save space below the cursor and restore 656 * when cursor is invisible. 657 */ 658 void 659 boot_fb_cursor(boolean_t visible) 660 { 661 uint32_t offset, size, j; 662 uint32_t *fb32, *sfb32 = NULL; 663 uint32_t fg, bg; 664 uint16_t *fb16, *sfb16 = NULL; 665 uint8_t *fb8, *sfb8 = NULL; 666 int i, pitch; 667 668 if (fb_info.cursor.visible == visible) 669 return; 670 671 boot_get_color(&fg, &bg); 672 fg = boot_color_map(fg); 673 bg = boot_color_map(bg); 674 675 fb_info.cursor.visible = visible; 676 pitch = fb_info.pitch; 677 size = boot_fb_font.vf_width * fb_info.bpp; 678 679 /* 680 * Build cursor image. We are building mirror image of data on 681 * frame buffer by (D xor FG) xor BG. 682 */ 683 offset = fb_info.cursor.origin.x * fb_info.bpp + 684 fb_info.cursor.origin.y * pitch; 685 switch (fb_info.depth) { 686 case 8: 687 for (i = 0; i < boot_fb_font.vf_height; i++) { 688 fb8 = fb_info.fb + offset + i * pitch; 689 if (fb_info.shadow_fb != NULL) 690 sfb8 = fb_info.shadow_fb + offset + i * pitch; 691 for (j = 0; j < size; j += 1) { 692 fb8[j] = (fb8[j] ^ (fg & 0xff)) ^ (bg & 0xff); 693 694 if (sfb8 == NULL) 695 continue; 696 697 sfb8[j] = (sfb8[j] ^ (fg & 0xff)) ^ (bg & 0xff); 698 } 699 } 700 break; 701 case 15: 702 case 16: 703 for (i = 0; i < boot_fb_font.vf_height; i++) { 704 fb16 = (uint16_t *)(fb_info.fb + offset + i * pitch); 705 if (fb_info.shadow_fb != NULL) 706 sfb16 = (uint16_t *) 707 (fb_info.shadow_fb + offset + i * pitch); 708 for (j = 0; j < boot_fb_font.vf_width; j++) { 709 fb16[j] = (fb16[j] ^ (fg & 0xffff)) ^ 710 (bg & 0xffff); 711 712 if (sfb16 == NULL) 713 continue; 714 715 sfb16[j] = (sfb16[j] ^ (fg & 0xffff)) ^ 716 (bg & 0xffff); 717 } 718 } 719 break; 720 case 24: 721 for (i = 0; i < boot_fb_font.vf_height; i++) { 722 fb8 = fb_info.fb + offset + i * pitch; 723 if (fb_info.shadow_fb != NULL) 724 sfb8 = fb_info.shadow_fb + offset + i * pitch; 725 for (j = 0; j < size; j += 3) { 726 fb8[j] = (fb8[j] ^ ((fg >> 16) & 0xff)) ^ 727 ((bg >> 16) & 0xff); 728 fb8[j+1] = (fb8[j+1] ^ ((fg >> 8) & 0xff)) ^ 729 ((bg >> 8) & 0xff); 730 fb8[j+2] = (fb8[j+2] ^ (fg & 0xff)) ^ 731 (bg & 0xff); 732 733 if (sfb8 == NULL) 734 continue; 735 736 sfb8[j] = (sfb8[j] ^ ((fg >> 16) & 0xff)) ^ 737 ((bg >> 16) & 0xff); 738 sfb8[j+1] = (sfb8[j+1] ^ ((fg >> 8) & 0xff)) ^ 739 ((bg >> 8) & 0xff); 740 sfb8[j+2] = (sfb8[j+2] ^ (fg & 0xff)) ^ 741 (bg & 0xff); 742 } 743 } 744 break; 745 case 32: 746 for (i = 0; i < boot_fb_font.vf_height; i++) { 747 fb32 = (uint32_t *)(fb_info.fb + offset + i * pitch); 748 if (fb_info.shadow_fb != NULL) { 749 sfb32 = (uint32_t *) 750 (fb_info.shadow_fb + offset + i * pitch); 751 } 752 for (j = 0; j < boot_fb_font.vf_width; j++) { 753 fb32[j] = (fb32[j] ^ fg) ^ bg; 754 755 if (sfb32 == NULL) 756 continue; 757 758 sfb32[j] = (sfb32[j] ^ fg) ^ bg; 759 } 760 } 761 break; 762 } 763 } 764 765 static void 766 boot_fb_setpos(int row, int col) 767 { 768 if (row < 0) 769 row = 0; 770 if (row >= fb_info.terminal.y) 771 row = fb_info.terminal.y - 1; 772 if (col < 0) 773 col = 0; 774 if (col >= fb_info.terminal.x) 775 col = fb_info.terminal.x - 1; 776 777 fb_info.cursor.pos.x = col; 778 fb_info.cursor.pos.y = row; 779 fb_info.cursor.origin.x = fb_info.terminal_origin.x; 780 fb_info.cursor.origin.x += col * boot_fb_font.vf_width; 781 fb_info.cursor.origin.y = fb_info.terminal_origin.y; 782 fb_info.cursor.origin.y += row * boot_fb_font.vf_height; 783 } 784 785 static void 786 boot_fb_putchar(int c) 787 { 788 struct vis_consdisplay display; 789 int rows, cols; 790 791 rows = fb_info.cursor.pos.y; 792 cols = fb_info.cursor.pos.x; 793 794 if (c == '\n') { 795 if (rows < fb_info.terminal.y - 1) 796 boot_fb_setpos(rows + 1, cols); 797 else 798 boot_fb_scroll(); 799 return; 800 } 801 802 bit_to_pix(c); 803 display.col = fb_info.cursor.origin.x; 804 display.row = fb_info.cursor.origin.y; 805 display.width = boot_fb_font.vf_width; 806 display.height = boot_fb_font.vf_height; 807 display.data = glyph; 808 809 boot_fb_blit(&display); 810 if (cols < fb_info.terminal.x - 1) 811 boot_fb_setpos(rows, cols + 1); 812 else if (rows < fb_info.terminal.y - 1) 813 boot_fb_setpos(rows + 1, 0); 814 else { 815 boot_fb_setpos(rows, 0); 816 boot_fb_scroll(); 817 } 818 } 819