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