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