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 }