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