xref: /illumos-gate/usr/src/uts/i86pc/boot/boot_fb.c (revision b70e9485)
18e6d016fSToomas Soome /*
28e6d016fSToomas Soome  * This file and its contents are supplied under the terms of the
38e6d016fSToomas Soome  * Common Development and Distribution License ("CDDL"), version 1.0.
48e6d016fSToomas Soome  * You may only use this file in accordance with the terms of version
58e6d016fSToomas Soome  * 1.0 of the CDDL.
68e6d016fSToomas Soome  *
78e6d016fSToomas Soome  * A full copy of the text of the CDDL should have accompanied this
88e6d016fSToomas Soome  * source.  A copy of the CDDL is also available via the Internet at
98e6d016fSToomas Soome  * http://www.illumos.org/license/CDDL.
108e6d016fSToomas Soome  */
118e6d016fSToomas Soome 
128e6d016fSToomas Soome /*
138e6d016fSToomas Soome  * Copyright 2016 Toomas Soome <tsoome@me.com>
148e6d016fSToomas Soome  */
158e6d016fSToomas Soome 
168e6d016fSToomas Soome /*
178e6d016fSToomas Soome  * dboot and early kernel needs simple putchar(int) interface to implement
188e6d016fSToomas Soome  * printf() support. So we implement simple interface on top of
198e6d016fSToomas Soome  * linear frame buffer, since we can not use tem directly, we are
208e6d016fSToomas Soome  * just borrowing bits from it.
218e6d016fSToomas Soome  *
228e6d016fSToomas Soome  * Note, this implementation is assuming UEFI linear frame buffer and
238e6d016fSToomas Soome  * 32-bit depth, which should not be issue as GOP is supposed to provide those.
248e6d016fSToomas Soome  * At the time of writing, this is the only case for frame buffer anyhow.
258e6d016fSToomas Soome  */
268e6d016fSToomas Soome 
278e6d016fSToomas Soome #include <sys/types.h>
288e6d016fSToomas Soome #include <sys/systm.h>
298e6d016fSToomas Soome #include <sys/multiboot2.h>
308e6d016fSToomas Soome #include <sys/framebuffer.h>
318e6d016fSToomas Soome #include <sys/bootinfo.h>
328e6d016fSToomas Soome #include <sys/boot_console.h>
338e6d016fSToomas Soome #include <sys/bootconf.h>
34cbc8e155SToomas Soome #include <sys/rgb.h>
3529a77b73SToomas Soome #include "boot_console_impl.h"
368e6d016fSToomas Soome 
378e6d016fSToomas Soome #define	P2ROUNDUP(x, align)	(-(-(x) & -(align)))
388e6d016fSToomas Soome #define	MIN(a, b)		((a) < (b) ? (a) : (b))
39a4e6b9b6SToomas Soome #define	nitems(x)		(sizeof ((x)) / sizeof ((x)[0]))
408e6d016fSToomas Soome 
418e6d016fSToomas Soome /*
428e6d016fSToomas Soome  * Simplified visual_io data structures from visual_io.h
438e6d016fSToomas Soome  */
448e6d016fSToomas Soome 
458e6d016fSToomas Soome struct vis_consdisplay {
468e6d016fSToomas Soome 	uint16_t row;		/* Row to display data at */
478e6d016fSToomas Soome 	uint16_t col;		/* Col to display data at */
488e6d016fSToomas Soome 	uint16_t width;		/* Width of data */
498e6d016fSToomas Soome 	uint16_t height;	/* Height of data */
508e6d016fSToomas Soome 	uint8_t  *data;		/* Data to display */
518e6d016fSToomas Soome };
528e6d016fSToomas Soome 
538e6d016fSToomas Soome struct vis_conscopy {
548e6d016fSToomas Soome 	uint16_t s_row;		/* Starting row */
558e6d016fSToomas Soome 	uint16_t s_col;		/* Starting col */
568e6d016fSToomas Soome 	uint16_t e_row;		/* Ending row */
578e6d016fSToomas Soome 	uint16_t e_col;		/* Ending col */
588e6d016fSToomas Soome 	uint16_t t_row;		/* Row to move to */
598e6d016fSToomas Soome 	uint16_t t_col;		/* Col to move to */
608e6d016fSToomas Soome };
618e6d016fSToomas Soome 
62cbc8e155SToomas Soome /*
63cbc8e155SToomas Soome  * We have largest font 16x32 with depth 32. This will allocate 2048
64cbc8e155SToomas Soome  * bytes from BSS.
65cbc8e155SToomas Soome  */
66cbc8e155SToomas Soome #define	MAX_GLYPH	(16 * 32 * 4)
67cbc8e155SToomas Soome 
68cbc8e155SToomas Soome struct fontlist		cf_fontlist;
69cbc8e155SToomas Soome static bitmap_data_t	cf_data;
70cbc8e155SToomas Soome static struct font	cf_font;
718e6d016fSToomas Soome 
728e6d016fSToomas Soome static struct font	boot_fb_font; /* set by set_font() */
738e6d016fSToomas Soome static uint8_t		glyph[MAX_GLYPH];
748e6d016fSToomas Soome 
7529a77b73SToomas Soome static void boot_fb_putchar(int);
7629a77b73SToomas Soome static void boot_fb_eraseline(void);
7729a77b73SToomas Soome static void boot_fb_setpos(int, int);
7829a77b73SToomas Soome static void boot_fb_shiftline(int);
7929a77b73SToomas Soome static void boot_fb_eraseline_impl(uint16_t, uint16_t);
8029a77b73SToomas Soome 
81cbc8e155SToomas Soome static void
82cbc8e155SToomas Soome xbi_init_font(struct xboot_info *xbi)
83cbc8e155SToomas Soome {
84cbc8e155SToomas Soome 	uint32_t i, checksum = 0;
85cbc8e155SToomas Soome 	struct boot_modules *modules;
86cbc8e155SToomas Soome 	struct font_info *fi;
87cbc8e155SToomas Soome 	uintptr_t ptr;
88cbc8e155SToomas Soome 
89cbc8e155SToomas Soome 	modules = (struct boot_modules *)(uintptr_t)xbi->bi_modules;
90cbc8e155SToomas Soome 	for (i = 0; i < xbi->bi_module_cnt; i++) {
91cbc8e155SToomas Soome 		if (modules[i].bm_type == BMT_FONT)
92cbc8e155SToomas Soome 			break;
93cbc8e155SToomas Soome 	}
94cbc8e155SToomas Soome 	if (i == xbi->bi_module_cnt)
95cbc8e155SToomas Soome 		return;
96cbc8e155SToomas Soome 
97cbc8e155SToomas Soome 	ptr = (uintptr_t)modules[i].bm_addr;
98cbc8e155SToomas Soome 	fi = (struct font_info *)ptr;
99cbc8e155SToomas Soome 
100cbc8e155SToomas Soome 	/*
101cbc8e155SToomas Soome 	 * Compute and verify checksum. The total sum of all the fields
102cbc8e155SToomas Soome 	 * must be 0. Note, the return from this point means we will
103cbc8e155SToomas Soome 	 * use default font.
104cbc8e155SToomas Soome 	 */
105cbc8e155SToomas Soome 	checksum += fi->fi_width;
106cbc8e155SToomas Soome 	checksum += fi->fi_height;
107cbc8e155SToomas Soome 	checksum += fi->fi_bitmap_size;
108cbc8e155SToomas Soome 	for (i = 0; i < VFNT_MAPS; i++)
109cbc8e155SToomas Soome 		checksum += fi->fi_map_count[i];
110cbc8e155SToomas Soome 	if (checksum + fi->fi_checksum != 0)
111cbc8e155SToomas Soome 		return;
112cbc8e155SToomas Soome 
113cbc8e155SToomas Soome 	cf_data.width = fi->fi_width;
114cbc8e155SToomas Soome 	cf_data.height = fi->fi_height;
115cbc8e155SToomas Soome 	cf_data.uncompressed_size = fi->fi_bitmap_size;
116cbc8e155SToomas Soome 	cf_data.font = &cf_font;
117cbc8e155SToomas Soome 
118cbc8e155SToomas Soome 	ptr += sizeof (struct font_info);
119cbc8e155SToomas Soome 	ptr = P2ROUNDUP(ptr, 8);
120cbc8e155SToomas Soome 
121cbc8e155SToomas Soome 	cf_font.vf_width = fi->fi_width;
122cbc8e155SToomas Soome 	cf_font.vf_height = fi->fi_height;
123cbc8e155SToomas Soome 	for (i = 0; i < VFNT_MAPS; i++) {
124cbc8e155SToomas Soome 		if (fi->fi_map_count[i] == 0)
125cbc8e155SToomas Soome 			continue;
126cbc8e155SToomas Soome 		cf_font.vf_map_count[i] = fi->fi_map_count[i];
127cbc8e155SToomas Soome 		cf_font.vf_map[i] = (struct font_map *)ptr;
128cbc8e155SToomas Soome 		ptr += (fi->fi_map_count[i] * sizeof (struct font_map));
129cbc8e155SToomas Soome 		ptr = P2ROUNDUP(ptr, 8);
130cbc8e155SToomas Soome 	}
131cbc8e155SToomas Soome 	cf_font.vf_bytes = (uint8_t *)ptr;
132cbc8e155SToomas Soome 	cf_fontlist.font_name = NULL;
133cbc8e155SToomas Soome 	cf_fontlist.font_flags = FONT_BOOT;
134cbc8e155SToomas Soome 	cf_fontlist.font_data = &cf_data;
135cbc8e155SToomas Soome 	cf_fontlist.font_load = NULL;
136cbc8e155SToomas Soome 	STAILQ_INSERT_HEAD(&fonts, &cf_fontlist, font_next);
137cbc8e155SToomas Soome }
138cbc8e155SToomas Soome 
1398e6d016fSToomas Soome /*
1408e6d016fSToomas Soome  * extract data from MB2 framebuffer tag and set up initial frame buffer.
1418e6d016fSToomas Soome  */
1428e6d016fSToomas Soome boolean_t
14329a77b73SToomas Soome xbi_fb_init(struct xboot_info *xbi, bcons_dev_t *bcons_dev)
1448e6d016fSToomas Soome {
1458e6d016fSToomas Soome 	multiboot_tag_framebuffer_t *tag;
1468e6d016fSToomas Soome 	boot_framebuffer_t *xbi_fb;
1478e6d016fSToomas Soome 
1488e6d016fSToomas Soome 	xbi_fb = (boot_framebuffer_t *)(uintptr_t)xbi->bi_framebuffer;
1498e6d016fSToomas Soome 	if (xbi_fb == NULL)
1508e6d016fSToomas Soome 		return (B_FALSE);
1518e6d016fSToomas Soome 
1528e6d016fSToomas Soome #if !defined(_BOOT)
1538e6d016fSToomas Soome 	/* For early kernel, we get cursor position from dboot. */
1548e6d016fSToomas Soome 	fb_info.cursor.origin.x = xbi_fb->cursor.origin.x;
1558e6d016fSToomas Soome 	fb_info.cursor.origin.y = xbi_fb->cursor.origin.y;
1568e6d016fSToomas Soome 	fb_info.cursor.pos.x = xbi_fb->cursor.pos.x;
1578e6d016fSToomas Soome 	fb_info.cursor.pos.y = xbi_fb->cursor.pos.y;
1588e6d016fSToomas Soome 	fb_info.cursor.visible = xbi_fb->cursor.visible;
1598e6d016fSToomas Soome #endif
1608e6d016fSToomas Soome 
161*b70e9485SToomas Soome 	xbi_init_font(xbi);
1628e6d016fSToomas Soome 	tag = (multiboot_tag_framebuffer_t *)(uintptr_t)xbi_fb->framebuffer;
1638e6d016fSToomas Soome 	if (tag == NULL) {
1648e6d016fSToomas Soome 		return (B_FALSE);
1658e6d016fSToomas Soome 	}
1668e6d016fSToomas Soome 
1678e6d016fSToomas Soome 	fb_info.paddr = tag->framebuffer_common.framebuffer_addr;
1688e6d016fSToomas Soome 	fb_info.pitch = tag->framebuffer_common.framebuffer_pitch;
1698e6d016fSToomas Soome 	fb_info.depth = tag->framebuffer_common.framebuffer_bpp;
1708e6d016fSToomas Soome 	fb_info.bpp = P2ROUNDUP(fb_info.depth, 8) >> 3;
1718e6d016fSToomas Soome 	fb_info.screen.x = tag->framebuffer_common.framebuffer_width;
1728e6d016fSToomas Soome 	fb_info.screen.y = tag->framebuffer_common.framebuffer_height;
1738e6d016fSToomas Soome 	fb_info.fb_size = fb_info.screen.y * fb_info.pitch;
1748e6d016fSToomas Soome 
17529a77b73SToomas Soome 	bcons_dev->bd_putchar = boot_fb_putchar;
17629a77b73SToomas Soome 	bcons_dev->bd_eraseline = boot_fb_eraseline;
17729a77b73SToomas Soome 	bcons_dev->bd_cursor = boot_fb_cursor;
17829a77b73SToomas Soome 	bcons_dev->bd_setpos = boot_fb_setpos;
17929a77b73SToomas Soome 	bcons_dev->bd_shift = boot_fb_shiftline;
18029a77b73SToomas Soome 
1818e6d016fSToomas Soome 	if (fb_info.paddr == 0)
1828e6d016fSToomas Soome 		fb_info.fb_type = FB_TYPE_UNKNOWN;
1838e6d016fSToomas Soome 
1848e6d016fSToomas Soome 	switch (tag->framebuffer_common.framebuffer_type) {
1858e6d016fSToomas Soome 	case MULTIBOOT_FRAMEBUFFER_TYPE_EGA_TEXT:
1868e6d016fSToomas Soome 		fb_info.fb_type = FB_TYPE_EGA_TEXT;
1878e6d016fSToomas Soome 		return (B_FALSE);
1888e6d016fSToomas Soome 
1898e6d016fSToomas Soome 	case MULTIBOOT_FRAMEBUFFER_TYPE_INDEXED:
1908e6d016fSToomas Soome 		if (fb_info.paddr != 0)
1918e6d016fSToomas Soome 			fb_info.fb_type = FB_TYPE_INDEXED;
1928e6d016fSToomas Soome 		return (B_TRUE);
1938e6d016fSToomas Soome 
1948e6d016fSToomas Soome 	case MULTIBOOT_FRAMEBUFFER_TYPE_RGB:
1958e6d016fSToomas Soome 		if (fb_info.paddr != 0)
1968e6d016fSToomas Soome 			fb_info.fb_type = FB_TYPE_RGB;
1978e6d016fSToomas Soome 		break;
1988e6d016fSToomas Soome 
1998e6d016fSToomas Soome 	default:
2008e6d016fSToomas Soome 		return (B_FALSE);
2018e6d016fSToomas Soome 	}
2028e6d016fSToomas Soome 
2038e6d016fSToomas Soome 	fb_info.rgb.red.size = tag->u.fb2.framebuffer_red_mask_size;
2048e6d016fSToomas Soome 	fb_info.rgb.red.pos = tag->u.fb2.framebuffer_red_field_position;
2058e6d016fSToomas Soome 	fb_info.rgb.green.size = tag->u.fb2.framebuffer_green_mask_size;
2068e6d016fSToomas Soome 	fb_info.rgb.green.pos = tag->u.fb2.framebuffer_green_field_position;
2078e6d016fSToomas Soome 	fb_info.rgb.blue.size = tag->u.fb2.framebuffer_blue_mask_size;
2088e6d016fSToomas Soome 	fb_info.rgb.blue.pos = tag->u.fb2.framebuffer_blue_field_position;
2098e6d016fSToomas Soome 
2108e6d016fSToomas Soome 	return (B_TRUE);
2118e6d016fSToomas Soome }
2128e6d016fSToomas Soome 
2138e6d016fSToomas Soome /* set font and pass the data to fb_info */
2148e6d016fSToomas Soome static void
2158e6d016fSToomas Soome boot_fb_set_font(uint16_t height, uint16_t width)
2168e6d016fSToomas Soome {
2178e6d016fSToomas Soome 	short h, w;
218cbc8e155SToomas Soome 	bitmap_data_t *bp;
219cbc8e155SToomas Soome 	int i;
2208e6d016fSToomas Soome 
2218e6d016fSToomas Soome 	h = MIN(height, 4096);
2228e6d016fSToomas Soome 	w = MIN(width, 4096);
2238e6d016fSToomas Soome 
224cbc8e155SToomas Soome 	bp = set_font((short *)&fb_info.terminal.y,
2258e6d016fSToomas Soome 	    (short *)&fb_info.terminal.x, h, w);
226cbc8e155SToomas Soome 
227cbc8e155SToomas Soome 	boot_fb_font.vf_bytes = bp->font->vf_bytes;
228cbc8e155SToomas Soome 	boot_fb_font.vf_width = bp->font->vf_width;
229cbc8e155SToomas Soome 	boot_fb_font.vf_height = bp->font->vf_height;
230cbc8e155SToomas Soome 	for (i = 0; i < VFNT_MAPS; i++) {
231cbc8e155SToomas Soome 		boot_fb_font.vf_map[i] = bp->font->vf_map[i];
232cbc8e155SToomas Soome 		boot_fb_font.vf_map_count[i] = bp->font->vf_map_count[i];
233cbc8e155SToomas Soome 	}
234cbc8e155SToomas Soome 
235cbc8e155SToomas Soome 	fb_info.font_width = boot_fb_font.vf_width;
236cbc8e155SToomas Soome 	fb_info.font_height = boot_fb_font.vf_height;
2378e6d016fSToomas Soome }
2388e6d016fSToomas Soome 
2398e6d016fSToomas Soome /* fill framebuffer */
2408e6d016fSToomas Soome static void
2418e6d016fSToomas Soome boot_fb_fill(uint8_t *dst, uint32_t data, uint32_t len)
2428e6d016fSToomas Soome {
2438e6d016fSToomas Soome 	uint16_t *dst16;
2448e6d016fSToomas Soome 	uint32_t *dst32;
2458e6d016fSToomas Soome 	uint32_t i;
2468e6d016fSToomas Soome 
2478e6d016fSToomas Soome 	switch (fb_info.depth) {
2488e6d016fSToomas Soome 	case 24:
2498e6d016fSToomas Soome 	case 8:
2508e6d016fSToomas Soome 		for (i = 0; i < len; i++)
2518e6d016fSToomas Soome 			dst[i] = (uint8_t)data;
2528e6d016fSToomas Soome 		break;
2538e6d016fSToomas Soome 	case 15:
2548e6d016fSToomas Soome 	case 16:
2558e6d016fSToomas Soome 		dst16 = (uint16_t *)dst;
2568e6d016fSToomas Soome 		len /= 2;
25729a77b73SToomas Soome 		for (i = 0; i < len; i++)
2588e6d016fSToomas Soome 			dst16[i] = (uint16_t)data;
2598e6d016fSToomas Soome 		break;
2608e6d016fSToomas Soome 	case 32:
2618e6d016fSToomas Soome 		dst32 = (uint32_t *)dst;
2628e6d016fSToomas Soome 		len /= 4;
26329a77b73SToomas Soome 		for (i = 0; i < len; i++)
2648e6d016fSToomas Soome 			dst32[i] = data;
2658e6d016fSToomas Soome 		break;
2668e6d016fSToomas Soome 	}
2678e6d016fSToomas Soome }
2688e6d016fSToomas Soome 
2698e6d016fSToomas Soome /* copy data to framebuffer */
2708e6d016fSToomas Soome static void
2718e6d016fSToomas Soome boot_fb_cpy(uint8_t *dst, uint8_t *src, uint32_t len)
2728e6d016fSToomas Soome {
2738e6d016fSToomas Soome 	uint16_t *dst16, *src16;
2748e6d016fSToomas Soome 	uint32_t *dst32, *src32;
2758e6d016fSToomas Soome 
2768e6d016fSToomas Soome 	switch (fb_info.depth) {
2778e6d016fSToomas Soome 	case 24:
2788e6d016fSToomas Soome 	case 8:
27929a77b73SToomas Soome 	default:
28029a77b73SToomas Soome 		if (dst <= src) {
28129a77b73SToomas Soome 			do {
28229a77b73SToomas Soome 				*dst++ = *src++;
28329a77b73SToomas Soome 			} while (--len != 0);
28429a77b73SToomas Soome 		} else {
28529a77b73SToomas Soome 			dst += len;
28629a77b73SToomas Soome 			src += len;
28729a77b73SToomas Soome 			do {
28829a77b73SToomas Soome 				*--dst = *--src;
28929a77b73SToomas Soome 			} while (--len != 0);
29029a77b73SToomas Soome 		}
2918e6d016fSToomas Soome 		break;
2928e6d016fSToomas Soome 	case 15:
2938e6d016fSToomas Soome 	case 16:
2948e6d016fSToomas Soome 		dst16 = (uint16_t *)dst;
2958e6d016fSToomas Soome 		src16 = (uint16_t *)src;
29629a77b73SToomas Soome 		len /= 2;
29729a77b73SToomas Soome 		if (dst16 <= src16) {
29829a77b73SToomas Soome 			do {
29929a77b73SToomas Soome 				*dst16++ = *src16++;
30029a77b73SToomas Soome 			} while (--len != 0);
30129a77b73SToomas Soome 		} else {
30229a77b73SToomas Soome 			dst16 += len;
30329a77b73SToomas Soome 			src16 += len;
30429a77b73SToomas Soome 			do {
30529a77b73SToomas Soome 				*--dst16 = *--src16;
30629a77b73SToomas Soome 			} while (--len != 0);
3078e6d016fSToomas Soome 		}
3088e6d016fSToomas Soome 		break;
3098e6d016fSToomas Soome 	case 32:
3108e6d016fSToomas Soome 		dst32 = (uint32_t *)dst;
3118e6d016fSToomas Soome 		src32 = (uint32_t *)src;
31229a77b73SToomas Soome 		len /= 4;
31329a77b73SToomas Soome 		if (dst32 <= src32) {
31429a77b73SToomas Soome 			do {
31529a77b73SToomas Soome 				*dst32++ = *src32++;
31629a77b73SToomas Soome 			} while (--len != 0);
31729a77b73SToomas Soome 		} else {
31829a77b73SToomas Soome 			dst32 += len;
31929a77b73SToomas Soome 			src32 += len;
32029a77b73SToomas Soome 			do {
32129a77b73SToomas Soome 				*--dst32 = *--src32;
32229a77b73SToomas Soome 			} while (--len != 0);
3238e6d016fSToomas Soome 		}
3248e6d016fSToomas Soome 		break;
3258e6d016fSToomas Soome 	}
3268e6d016fSToomas Soome }
3278e6d016fSToomas Soome 
3288e6d016fSToomas Soome /*
3298e6d016fSToomas Soome  * Allocate shadow frame buffer, called from fakebop.c when early boot
3308e6d016fSToomas Soome  * allocator is ready.
3318e6d016fSToomas Soome  */
3328e6d016fSToomas Soome void
3338e6d016fSToomas Soome boot_fb_shadow_init(bootops_t *bops)
3348e6d016fSToomas Soome {
3358e6d016fSToomas Soome 	if (boot_console_type(NULL) != CONS_FRAMEBUFFER)
3368e6d016fSToomas Soome 		return;			/* nothing to do */
3378e6d016fSToomas Soome 
3388e6d016fSToomas Soome 	fb_info.shadow_fb = (uint8_t *)bops->bsys_alloc(NULL, NULL,
3398e6d016fSToomas Soome 	    fb_info.fb_size, MMU_PAGESIZE);
3408e6d016fSToomas Soome 
3418e6d016fSToomas Soome 	if (fb_info.shadow_fb == NULL)
3428e6d016fSToomas Soome 		return;
3438e6d016fSToomas Soome 
3448e6d016fSToomas Soome 	/* Copy FB to shadow */
3458e6d016fSToomas Soome 	boot_fb_cpy(fb_info.shadow_fb, fb_info.fb, fb_info.fb_size);
3468e6d016fSToomas Soome }
3478e6d016fSToomas Soome 
3488e6d016fSToomas Soome /*
3498e6d016fSToomas Soome  * Translate ansi color based on inverses and brightness.
3508e6d016fSToomas Soome  */
35129a77b73SToomas Soome void
3528e6d016fSToomas Soome boot_get_color(uint32_t *fg, uint32_t *bg)
3538e6d016fSToomas Soome {
3548e6d016fSToomas Soome 	/* ansi to solaris colors, see also boot_console.c */
3558e6d016fSToomas Soome 	if (fb_info.inverse == B_TRUE ||
3568e6d016fSToomas Soome 	    fb_info.inverse_screen == B_TRUE) {
357a4e6b9b6SToomas Soome 		if (fb_info.fg_color < 16)
358a4e6b9b6SToomas Soome 			*bg = dim_xlate[fb_info.fg_color];
359a4e6b9b6SToomas Soome 		else
360a4e6b9b6SToomas Soome 			*bg = fb_info.fg_color;
361a4e6b9b6SToomas Soome 
362a4e6b9b6SToomas Soome 		if (fb_info.bg_color < 16)
363a4e6b9b6SToomas Soome 			*fg = brt_xlate[fb_info.bg_color];
364a4e6b9b6SToomas Soome 		else
365a4e6b9b6SToomas Soome 			*fg = fb_info.bg_color;
3668e6d016fSToomas Soome 	} else {
367a4e6b9b6SToomas Soome 		if (fb_info.bg_color < 16) {
368a4e6b9b6SToomas Soome 			if (fb_info.bg_color == 7)
369a4e6b9b6SToomas Soome 				*bg = brt_xlate[fb_info.bg_color];
370a4e6b9b6SToomas Soome 			else
371a4e6b9b6SToomas Soome 				*bg = dim_xlate[fb_info.bg_color];
372a4e6b9b6SToomas Soome 		} else {
373a4e6b9b6SToomas Soome 			*bg = fb_info.bg_color;
374a4e6b9b6SToomas Soome 		}
375a4e6b9b6SToomas Soome 		if (fb_info.fg_color < 16)
376a4e6b9b6SToomas Soome 			*fg = dim_xlate[fb_info.fg_color];
3778e6d016fSToomas Soome 		else
378a4e6b9b6SToomas Soome 			*fg = fb_info.fg_color;
3798e6d016fSToomas Soome 	}
3808e6d016fSToomas Soome }
3818e6d016fSToomas Soome 
3828e6d016fSToomas Soome /*
3838e6d016fSToomas Soome  * Map indexed color to RGB value.
3848e6d016fSToomas Soome  */
385a4e6b9b6SToomas Soome uint32_t
3868e6d016fSToomas Soome boot_color_map(uint8_t index)
3878e6d016fSToomas Soome {
388a4e6b9b6SToomas Soome 	if (fb_info.fb_type != FB_TYPE_RGB) {
389a4e6b9b6SToomas Soome 		if (index < nitems(solaris_color_to_pc_color))
390a4e6b9b6SToomas Soome 			return (solaris_color_to_pc_color[index]);
391a4e6b9b6SToomas Soome 		else
392a4e6b9b6SToomas Soome 			return (index);
393a4e6b9b6SToomas Soome 	}
3948e6d016fSToomas Soome 
395a4e6b9b6SToomas Soome 	return (rgb_color_map(&fb_info.rgb, index));
3968e6d016fSToomas Soome }
3978e6d016fSToomas Soome 
3988e6d016fSToomas Soome /* set up out simple console. */
3998e6d016fSToomas Soome /*ARGSUSED*/
4008e6d016fSToomas Soome void
4018e6d016fSToomas Soome boot_fb_init(int console)
4028e6d016fSToomas Soome {
4038e6d016fSToomas Soome 	fb_info_pixel_coord_t window;
4048e6d016fSToomas Soome 
4058e6d016fSToomas Soome 	/* frame buffer address is mapped in dboot. */
4068e6d016fSToomas Soome 	fb_info.fb = (uint8_t *)(uintptr_t)fb_info.paddr;
4078e6d016fSToomas Soome 
4088e6d016fSToomas Soome 	boot_fb_set_font(fb_info.screen.y, fb_info.screen.x);
409cbc8e155SToomas Soome 	window.x = (fb_info.screen.x -
410cbc8e155SToomas Soome 	    fb_info.terminal.x * boot_fb_font.vf_width) / 2;
411cbc8e155SToomas Soome 	window.y = (fb_info.screen.y -
412cbc8e155SToomas Soome 	    fb_info.terminal.y * boot_fb_font.vf_height) / 2;
4138e6d016fSToomas Soome 	fb_info.terminal_origin.x = window.x;
4148e6d016fSToomas Soome 	fb_info.terminal_origin.y = window.y;
4158e6d016fSToomas Soome 
4168e6d016fSToomas Soome #if defined(_BOOT)
4178e6d016fSToomas Soome 	/*
4188e6d016fSToomas Soome 	 * Being called from dboot, we can have cursor terminal
4198e6d016fSToomas Soome 	 * position passed from boot loader. In such case, fix the
4208e6d016fSToomas Soome 	 * cursor screen coords.
4218e6d016fSToomas Soome 	 */
4228e6d016fSToomas Soome 	if (fb_info.cursor.pos.x != 0 || fb_info.cursor.pos.y != 0) {
4238e6d016fSToomas Soome 		fb_info.cursor.origin.x = window.x +
424cbc8e155SToomas Soome 		    fb_info.cursor.pos.x * boot_fb_font.vf_width;
4258e6d016fSToomas Soome 		fb_info.cursor.origin.y = window.y +
426cbc8e155SToomas Soome 		    fb_info.cursor.pos.y * boot_fb_font.vf_height;
4278e6d016fSToomas Soome 	}
4288e6d016fSToomas Soome #endif
4298e6d016fSToomas Soome 
4308e6d016fSToomas Soome 	/* If the cursor terminal position is 0,0 just reset screen coords */
4318e6d016fSToomas Soome 	if (fb_info.cursor.pos.x == 0 && fb_info.cursor.pos.y == 0) {
4328e6d016fSToomas Soome 		fb_info.cursor.origin.x = window.x;
4338e6d016fSToomas Soome 		fb_info.cursor.origin.y = window.y;
4348e6d016fSToomas Soome 	}
4358e6d016fSToomas Soome 
4368e6d016fSToomas Soome 	/*
4378e6d016fSToomas Soome 	 * Validate cursor coords with screen/terminal dimensions,
4388e6d016fSToomas Soome 	 * if anything is off, reset to 0,0
4398e6d016fSToomas Soome 	 */
4408e6d016fSToomas Soome 	if (fb_info.cursor.pos.x > fb_info.terminal.x ||
4418e6d016fSToomas Soome 	    fb_info.cursor.pos.y > fb_info.terminal.y ||
4428e6d016fSToomas Soome 	    fb_info.cursor.origin.x > fb_info.screen.x ||
4438e6d016fSToomas Soome 	    fb_info.cursor.origin.y > fb_info.screen.y) {
4448e6d016fSToomas Soome 
4458e6d016fSToomas Soome 		fb_info.cursor.origin.x = window.x;
4468e6d016fSToomas Soome 		fb_info.cursor.origin.y = window.y;
4478e6d016fSToomas Soome 		fb_info.cursor.pos.x = 0;
4488e6d016fSToomas Soome 		fb_info.cursor.pos.y = 0;
4498e6d016fSToomas Soome 	}
4508e6d016fSToomas Soome 
4518e6d016fSToomas Soome #if defined(_BOOT)
4528e6d016fSToomas Soome 	/* clear the screen if cursor is set to 0,0 */
45329a77b73SToomas Soome 	if (fb_info.cursor.pos.x == 0 && fb_info.cursor.pos.y == 0) {
45429a77b73SToomas Soome 		uint32_t fg, bg, toffset;
45529a77b73SToomas Soome 		uint16_t y;
4568e6d016fSToomas Soome 
4578e6d016fSToomas Soome 		boot_get_color(&fg, &bg);
4588e6d016fSToomas Soome 		bg = boot_color_map(bg);
4598e6d016fSToomas Soome 
46029a77b73SToomas Soome 		toffset = 0;
46129a77b73SToomas Soome 		for (y = 0; y < fb_info.screen.y; y++) {
46229a77b73SToomas Soome 			uint8_t *dest = fb_info.fb + toffset;
46329a77b73SToomas Soome 
4648e6d016fSToomas Soome 			boot_fb_fill(dest, bg, fb_info.pitch);
46529a77b73SToomas Soome 			toffset += fb_info.pitch;
4668e6d016fSToomas Soome 		}
4678e6d016fSToomas Soome 	}
4688e6d016fSToomas Soome #endif
4698e6d016fSToomas Soome }
4708e6d016fSToomas Soome 
4718e6d016fSToomas Soome /* copy rectangle to framebuffer. */
4728e6d016fSToomas Soome static void
4738e6d016fSToomas Soome boot_fb_blit(struct vis_consdisplay *rect)
4748e6d016fSToomas Soome {
47529a77b73SToomas Soome 	uint32_t offset, size;		/* write size per scanline */
47629a77b73SToomas Soome 	uint8_t *fbp, *sfbp = NULL;	/* fb + calculated offset */
4778e6d016fSToomas Soome 	int i;
4788e6d016fSToomas Soome 
4798e6d016fSToomas Soome 	/* make sure we will not write past FB */
4808e6d016fSToomas Soome 	if (rect->col >= fb_info.screen.x ||
4818e6d016fSToomas Soome 	    rect->row >= fb_info.screen.y ||
4828e6d016fSToomas Soome 	    rect->col + rect->width >= fb_info.screen.x ||
4838e6d016fSToomas Soome 	    rect->row + rect->height >= fb_info.screen.y)
4848e6d016fSToomas Soome 		return;
4858e6d016fSToomas Soome 
4868e6d016fSToomas Soome 	size = rect->width * fb_info.bpp;
48729a77b73SToomas Soome 	offset = rect->col * fb_info.bpp + rect->row * fb_info.pitch;
48829a77b73SToomas Soome 	fbp = fb_info.fb + offset;
48929a77b73SToomas Soome 	if (fb_info.shadow_fb != NULL)
49029a77b73SToomas Soome 		sfbp = fb_info.shadow_fb + offset;
4918e6d016fSToomas Soome 
4928e6d016fSToomas Soome 	/* write all scanlines in rectangle */
4938e6d016fSToomas Soome 	for (i = 0; i < rect->height; i++) {
4948e6d016fSToomas Soome 		uint8_t *dest = fbp + i * fb_info.pitch;
4958e6d016fSToomas Soome 		uint8_t *src = rect->data + i * size;
4968e6d016fSToomas Soome 		boot_fb_cpy(dest, src, size);
4978e6d016fSToomas Soome 		if (sfbp != NULL) {
4988e6d016fSToomas Soome 			dest = sfbp + i * fb_info.pitch;
4998e6d016fSToomas Soome 			boot_fb_cpy(dest, src, size);
5008e6d016fSToomas Soome 		}
5018e6d016fSToomas Soome 	}
5028e6d016fSToomas Soome }
5038e6d016fSToomas Soome 
5048e6d016fSToomas Soome static void
5058e6d016fSToomas Soome bit_to_pix(uchar_t c)
5068e6d016fSToomas Soome {
5078e6d016fSToomas Soome 	uint32_t fg, bg;
5088e6d016fSToomas Soome 
5098e6d016fSToomas Soome 	boot_get_color(&fg, &bg);
5108e6d016fSToomas Soome 	fg = boot_color_map(fg);
5118e6d016fSToomas Soome 	bg = boot_color_map(bg);
5128e6d016fSToomas Soome 
5138e6d016fSToomas Soome 	switch (fb_info.depth) {
5148e6d016fSToomas Soome 	case 8:
5158e6d016fSToomas Soome 		font_bit_to_pix8(&boot_fb_font, (uint8_t *)glyph, c, fg, bg);
5168e6d016fSToomas Soome 		break;
5178e6d016fSToomas Soome 	case 15:
5188e6d016fSToomas Soome 	case 16:
5198e6d016fSToomas Soome 		font_bit_to_pix16(&boot_fb_font, (uint16_t *)glyph, c,
5208e6d016fSToomas Soome 		    (uint16_t)fg, (uint16_t)bg);
5218e6d016fSToomas Soome 		break;
5228e6d016fSToomas Soome 	case 24:
5238e6d016fSToomas Soome 		font_bit_to_pix24(&boot_fb_font, (uint8_t *)glyph, c, fg, bg);
5248e6d016fSToomas Soome 		break;
5258e6d016fSToomas Soome 	case 32:
5268e6d016fSToomas Soome 		font_bit_to_pix32(&boot_fb_font, (uint32_t *)glyph, c, fg, bg);
5278e6d016fSToomas Soome 		break;
5288e6d016fSToomas Soome 	}
5298e6d016fSToomas Soome }
5308e6d016fSToomas Soome 
5318e6d016fSToomas Soome static void
53229a77b73SToomas Soome boot_fb_eraseline_impl(uint16_t x, uint16_t y)
5338e6d016fSToomas Soome {
53429a77b73SToomas Soome 	uint32_t toffset, size;
5358e6d016fSToomas Soome 	uint32_t fg, bg;
53629a77b73SToomas Soome 	uint8_t *dst, *sdst;
5378e6d016fSToomas Soome 	int i;
5388e6d016fSToomas Soome 
5398e6d016fSToomas Soome 	boot_get_color(&fg, &bg);
5408e6d016fSToomas Soome 	bg = boot_color_map(bg);
5418e6d016fSToomas Soome 
542cbc8e155SToomas Soome 	size = fb_info.terminal.x * boot_fb_font.vf_width * fb_info.bpp;
54329a77b73SToomas Soome 
54429a77b73SToomas Soome 	toffset = x * fb_info.bpp + y * fb_info.pitch;
54529a77b73SToomas Soome 	dst = fb_info.fb + toffset;
546a6f5e66aSToomas Soome 	sdst = fb_info.shadow_fb + toffset;
54729a77b73SToomas Soome 
548cbc8e155SToomas Soome 	for (i = 0; i < boot_fb_font.vf_height; i++) {
54929a77b73SToomas Soome 		uint8_t *dest = dst + i * fb_info.pitch;
55029a77b73SToomas Soome 		if (fb_info.fb + fb_info.fb_size >= dest + size)
55129a77b73SToomas Soome 			boot_fb_fill(dest, bg, size);
55229a77b73SToomas Soome 		if (fb_info.shadow_fb != NULL) {
55329a77b73SToomas Soome 			dest = sdst + i * fb_info.pitch;
55429a77b73SToomas Soome 			if (fb_info.shadow_fb + fb_info.fb_size >=
55529a77b73SToomas Soome 			    dest + size) {
55629a77b73SToomas Soome 				boot_fb_fill(dest, bg, size);
55729a77b73SToomas Soome 			}
55829a77b73SToomas Soome 		}
55929a77b73SToomas Soome 	}
56029a77b73SToomas Soome }
56129a77b73SToomas Soome 
56229a77b73SToomas Soome static void
56329a77b73SToomas Soome boot_fb_eraseline(void)
56429a77b73SToomas Soome {
56529a77b73SToomas Soome 	boot_fb_eraseline_impl(fb_info.cursor.origin.x,
56629a77b73SToomas Soome 	    fb_info.cursor.origin.y);
56729a77b73SToomas Soome }
56829a77b73SToomas Soome 
56929a77b73SToomas Soome /*
57029a77b73SToomas Soome  * Copy rectangle from console to console.
57129a77b73SToomas Soome  * If shadow buffer is available, use shadow as source.
57229a77b73SToomas Soome  */
57329a77b73SToomas Soome static void
57429a77b73SToomas Soome boot_fb_conscopy(struct vis_conscopy *c_copy)
57529a77b73SToomas Soome {
57629a77b73SToomas Soome 	uint32_t soffset, toffset;
57729a77b73SToomas Soome 	uint32_t width, height, increment;
57829a77b73SToomas Soome 	uint8_t *src, *dst, *sdst = NULL;
57929a77b73SToomas Soome 	int i;
58029a77b73SToomas Soome 
58129a77b73SToomas Soome 	soffset = c_copy->s_col * fb_info.bpp + c_copy->s_row * fb_info.pitch;
58229a77b73SToomas Soome 	toffset = c_copy->t_col * fb_info.bpp + c_copy->t_row * fb_info.pitch;
58329a77b73SToomas Soome 
58429a77b73SToomas Soome 	src = fb_info.fb + soffset;
58529a77b73SToomas Soome 	dst = fb_info.fb + toffset;
5868e6d016fSToomas Soome 
5878e6d016fSToomas Soome 	if (fb_info.shadow_fb != NULL) {
5888e6d016fSToomas Soome 		src = fb_info.shadow_fb + soffset;
5898e6d016fSToomas Soome 		sdst = fb_info.shadow_fb + toffset;
5908e6d016fSToomas Soome 	}
5918e6d016fSToomas Soome 
59229a77b73SToomas Soome 	width = (c_copy->e_col - c_copy->s_col + 1) * fb_info.bpp;
59329a77b73SToomas Soome 	height = c_copy->e_row - c_copy->s_row + 1;
59429a77b73SToomas Soome 
5958e6d016fSToomas Soome 	for (i = 0; i < height; i++) {
59629a77b73SToomas Soome 		increment = i * fb_info.pitch;
59729a77b73SToomas Soome 
59829a77b73SToomas Soome 		/* Make sure we fit into FB size. */
59929a77b73SToomas Soome 		if (soffset + increment + width >= fb_info.fb_size ||
60029a77b73SToomas Soome 		    toffset + increment + width >= fb_info.fb_size)
60129a77b73SToomas Soome 			break;
60229a77b73SToomas Soome 
6038e6d016fSToomas Soome 		boot_fb_cpy(dst + increment, src + increment, width);
60429a77b73SToomas Soome 
6058e6d016fSToomas Soome 		if (sdst != NULL)
6068e6d016fSToomas Soome 			boot_fb_cpy(sdst + increment, src + increment, width);
6078e6d016fSToomas Soome 	}
60829a77b73SToomas Soome }
6098e6d016fSToomas Soome 
61029a77b73SToomas Soome /* Shift the line content by chars. */
61129a77b73SToomas Soome static void
61229a77b73SToomas Soome boot_fb_shiftline(int chars)
61329a77b73SToomas Soome {
61429a77b73SToomas Soome 	struct vis_conscopy c_copy;
6158e6d016fSToomas Soome 
61629a77b73SToomas Soome 	c_copy.s_col = fb_info.cursor.origin.x;
61729a77b73SToomas Soome 	c_copy.s_row = fb_info.cursor.origin.y;
61829a77b73SToomas Soome 
619cbc8e155SToomas Soome 	c_copy.e_col = (fb_info.terminal.x - chars) * boot_fb_font.vf_width;
62029a77b73SToomas Soome 	c_copy.e_col += fb_info.terminal_origin.x;
621cbc8e155SToomas Soome 	c_copy.e_row = c_copy.s_row + boot_fb_font.vf_height;
62229a77b73SToomas Soome 
623cbc8e155SToomas Soome 	c_copy.t_col = fb_info.cursor.origin.x + chars * boot_fb_font.vf_width;
62429a77b73SToomas Soome 	c_copy.t_row = fb_info.cursor.origin.y;
62529a77b73SToomas Soome 
62629a77b73SToomas Soome 	boot_fb_conscopy(&c_copy);
62729a77b73SToomas Soome }
62829a77b73SToomas Soome 
62929a77b73SToomas Soome /*
63029a77b73SToomas Soome  * move the terminal window lines [1..y] to [0..y-1] and clear last line.
63129a77b73SToomas Soome  */
63229a77b73SToomas Soome static void
63329a77b73SToomas Soome boot_fb_scroll(void)
63429a77b73SToomas Soome {
63529a77b73SToomas Soome 	struct vis_conscopy c_copy;
63629a77b73SToomas Soome 
63729a77b73SToomas Soome 	/* support for scrolling. set up the console copy data and last line */
638cbc8e155SToomas Soome 	c_copy.s_row = fb_info.terminal_origin.y + boot_fb_font.vf_height;
63929a77b73SToomas Soome 	c_copy.s_col = fb_info.terminal_origin.x;
64029a77b73SToomas Soome 	c_copy.e_row = fb_info.screen.y - fb_info.terminal_origin.y;
64129a77b73SToomas Soome 	c_copy.e_col = fb_info.screen.x - fb_info.terminal_origin.x;
64229a77b73SToomas Soome 	c_copy.t_row = fb_info.terminal_origin.y;
64329a77b73SToomas Soome 	c_copy.t_col = fb_info.terminal_origin.x;
64429a77b73SToomas Soome 
64529a77b73SToomas Soome 	boot_fb_conscopy(&c_copy);
64629a77b73SToomas Soome 
64729a77b73SToomas Soome 	/* now clean up the last line */
64829a77b73SToomas Soome 	boot_fb_eraseline_impl(fb_info.terminal_origin.x,
64929a77b73SToomas Soome 	    fb_info.terminal_origin.y +
650cbc8e155SToomas Soome 	    (fb_info.terminal.y - 1) * boot_fb_font.vf_height);
6518e6d016fSToomas Soome }
6528e6d016fSToomas Soome 
6538e6d016fSToomas Soome /*
6548e6d016fSToomas Soome  * Very simple block cursor. Save space below the cursor and restore
6558e6d016fSToomas Soome  * when cursor is invisible.
6568e6d016fSToomas Soome  */
6578e6d016fSToomas Soome void
6588e6d016fSToomas Soome boot_fb_cursor(boolean_t visible)
6598e6d016fSToomas Soome {
660cbc8e155SToomas Soome 	uint32_t offset, size, j;
6618e6d016fSToomas Soome 	uint32_t *fb32, *sfb32 = NULL;
6628e6d016fSToomas Soome 	uint32_t fg, bg;
6638e6d016fSToomas Soome 	uint16_t *fb16, *sfb16 = NULL;
6648e6d016fSToomas Soome 	uint8_t *fb8, *sfb8 = NULL;
6658e6d016fSToomas Soome 	int i, pitch;
6668e6d016fSToomas Soome 
6678e6d016fSToomas Soome 	if (fb_info.cursor.visible == visible)
6688e6d016fSToomas Soome 		return;
6698e6d016fSToomas Soome 
6708e6d016fSToomas Soome 	boot_get_color(&fg, &bg);
6718e6d016fSToomas Soome 	fg = boot_color_map(fg);
6728e6d016fSToomas Soome 	bg = boot_color_map(bg);
6738e6d016fSToomas Soome 
6748e6d016fSToomas Soome 	fb_info.cursor.visible = visible;
6758e6d016fSToomas Soome 	pitch = fb_info.pitch;
676cbc8e155SToomas Soome 	size = boot_fb_font.vf_width * fb_info.bpp;
6778e6d016fSToomas Soome 
6788e6d016fSToomas Soome 	/*
6798e6d016fSToomas Soome 	 * Build cursor image. We are building mirror image of data on
6808e6d016fSToomas Soome 	 * frame buffer by (D xor FG) xor BG.
6818e6d016fSToomas Soome 	 */
6828e6d016fSToomas Soome 	offset = fb_info.cursor.origin.x * fb_info.bpp +
6838e6d016fSToomas Soome 	    fb_info.cursor.origin.y * pitch;
6848e6d016fSToomas Soome 	switch (fb_info.depth) {
6858e6d016fSToomas Soome 	case 8:
686cbc8e155SToomas Soome 		for (i = 0; i < boot_fb_font.vf_height; i++) {
6878e6d016fSToomas Soome 			fb8 = fb_info.fb + offset + i * pitch;
6888e6d016fSToomas Soome 			if (fb_info.shadow_fb != NULL)
6898e6d016fSToomas Soome 				sfb8 = fb_info.shadow_fb + offset + i * pitch;
690cbc8e155SToomas Soome 			for (j = 0; j < size; j += 1) {
6918e6d016fSToomas Soome 				fb8[j] = (fb8[j] ^ (fg & 0xff)) ^ (bg & 0xff);
6928e6d016fSToomas Soome 
6938e6d016fSToomas Soome 				if (sfb8 == NULL)
6948e6d016fSToomas Soome 					continue;
6958e6d016fSToomas Soome 
6968e6d016fSToomas Soome 				sfb8[j] = (sfb8[j] ^ (fg & 0xff)) ^ (bg & 0xff);
6978e6d016fSToomas Soome 			}
6988e6d016fSToomas Soome 		}
6998e6d016fSToomas Soome 		break;
7008e6d016fSToomas Soome 	case 15:
7018e6d016fSToomas Soome 	case 16:
702cbc8e155SToomas Soome 		for (i = 0; i < boot_fb_font.vf_height; i++) {
7038e6d016fSToomas Soome 			fb16 = (uint16_t *)(fb_info.fb + offset + i * pitch);
7048e6d016fSToomas Soome 			if (fb_info.shadow_fb != NULL)
7058e6d016fSToomas Soome 				sfb16 = (uint16_t *)
7068e6d016fSToomas Soome 				    (fb_info.shadow_fb + offset + i * pitch);
707cbc8e155SToomas Soome 			for (j = 0; j < boot_fb_font.vf_width; j++) {
7088e6d016fSToomas Soome 				fb16[j] = (fb16[j] ^ (fg & 0xffff)) ^
7098e6d016fSToomas Soome 				    (bg & 0xffff);
7108e6d016fSToomas Soome 
7118e6d016fSToomas Soome 				if (sfb16 == NULL)
7128e6d016fSToomas Soome 					continue;
7138e6d016fSToomas Soome 
7148e6d016fSToomas Soome 				sfb16[j] = (sfb16[j] ^ (fg & 0xffff)) ^
7158e6d016fSToomas Soome 				    (bg & 0xffff);
7168e6d016fSToomas Soome 			}
7178e6d016fSToomas Soome 		}
7188e6d016fSToomas Soome 		break;
7198e6d016fSToomas Soome 	case 24:
720cbc8e155SToomas Soome 		for (i = 0; i < boot_fb_font.vf_height; i++) {
7218e6d016fSToomas Soome 			fb8 = fb_info.fb + offset + i * pitch;
7228e6d016fSToomas Soome 			if (fb_info.shadow_fb != NULL)
7238e6d016fSToomas Soome 				sfb8 = fb_info.shadow_fb + offset + i * pitch;
724cbc8e155SToomas Soome 			for (j = 0; j < size; j += 3) {
7258e6d016fSToomas Soome 				fb8[j] = (fb8[j] ^ ((fg >> 16) & 0xff)) ^
7268e6d016fSToomas Soome 				    ((bg >> 16) & 0xff);
7278e6d016fSToomas Soome 				fb8[j+1] = (fb8[j+1] ^ ((fg >> 8) & 0xff)) ^
7288e6d016fSToomas Soome 				    ((bg >> 8) & 0xff);
7298e6d016fSToomas Soome 				fb8[j+2] = (fb8[j+2] ^ (fg & 0xff)) ^
7308e6d016fSToomas Soome 				    (bg & 0xff);
7318e6d016fSToomas Soome 
7328e6d016fSToomas Soome 				if (sfb8 == NULL)
7338e6d016fSToomas Soome 					continue;
7348e6d016fSToomas Soome 
7358e6d016fSToomas Soome 				sfb8[j] = (sfb8[j] ^ ((fg >> 16) & 0xff)) ^
7368e6d016fSToomas Soome 				    ((bg >> 16) & 0xff);
7378e6d016fSToomas Soome 				sfb8[j+1] = (sfb8[j+1] ^ ((fg >> 8) & 0xff)) ^
7388e6d016fSToomas Soome 				    ((bg >> 8) & 0xff);
7398e6d016fSToomas Soome 				sfb8[j+2] = (sfb8[j+2] ^ (fg & 0xff)) ^
7408e6d016fSToomas Soome 				    (bg & 0xff);
7418e6d016fSToomas Soome 			}
7428e6d016fSToomas Soome 		}
7438e6d016fSToomas Soome 		break;
7448e6d016fSToomas Soome 	case 32:
745cbc8e155SToomas Soome 		for (i = 0; i < boot_fb_font.vf_height; i++) {
7468e6d016fSToomas Soome 			fb32 = (uint32_t *)(fb_info.fb + offset + i * pitch);
7478e6d016fSToomas Soome 			if (fb_info.shadow_fb != NULL) {
7488e6d016fSToomas Soome 				sfb32 = (uint32_t *)
7498e6d016fSToomas Soome 				    (fb_info.shadow_fb + offset + i * pitch);
7508e6d016fSToomas Soome 			}
751cbc8e155SToomas Soome 			for (j = 0; j < boot_fb_font.vf_width; j++) {
7528e6d016fSToomas Soome 				fb32[j] = (fb32[j] ^ fg) ^ bg;
7538e6d016fSToomas Soome 
7548e6d016fSToomas Soome 				if (sfb32 == NULL)
7558e6d016fSToomas Soome 					continue;
7568e6d016fSToomas Soome 
7578e6d016fSToomas Soome 				sfb32[j] = (sfb32[j] ^ fg) ^ bg;
7588e6d016fSToomas Soome 			}
7598e6d016fSToomas Soome 		}
7608e6d016fSToomas Soome 		break;
7618e6d016fSToomas Soome 	}
7628e6d016fSToomas Soome }
7638e6d016fSToomas Soome 
7648e6d016fSToomas Soome static void
76529a77b73SToomas Soome boot_fb_setpos(int row, int col)
7668e6d016fSToomas Soome {
76729a77b73SToomas Soome 	if (row < 0)
76829a77b73SToomas Soome 		row = 0;
76929a77b73SToomas Soome 	if (row >= fb_info.terminal.y)
77029a77b73SToomas Soome 		row = fb_info.terminal.y - 1;
77129a77b73SToomas Soome 	if (col < 0)
77229a77b73SToomas Soome 		col = 0;
77329a77b73SToomas Soome 	if (col >= fb_info.terminal.x)
77429a77b73SToomas Soome 		col = fb_info.terminal.x - 1;
77529a77b73SToomas Soome 
77629a77b73SToomas Soome 	fb_info.cursor.pos.x = col;
77729a77b73SToomas Soome 	fb_info.cursor.pos.y = row;
7788e6d016fSToomas Soome 	fb_info.cursor.origin.x = fb_info.terminal_origin.x;
779cbc8e155SToomas Soome 	fb_info.cursor.origin.x += col * boot_fb_font.vf_width;
78029a77b73SToomas Soome 	fb_info.cursor.origin.y = fb_info.terminal_origin.y;
781cbc8e155SToomas Soome 	fb_info.cursor.origin.y += row * boot_fb_font.vf_height;
7828e6d016fSToomas Soome }
7838e6d016fSToomas Soome 
7848e6d016fSToomas Soome static void
78529a77b73SToomas Soome boot_fb_putchar(int c)
7868e6d016fSToomas Soome {
7878e6d016fSToomas Soome 	struct vis_consdisplay display;
78829a77b73SToomas Soome 	int rows, cols;
78929a77b73SToomas Soome 
79029a77b73SToomas Soome 	rows = fb_info.cursor.pos.y;
79129a77b73SToomas Soome 	cols = fb_info.cursor.pos.x;
79229a77b73SToomas Soome 
79329a77b73SToomas Soome 	if (c == '\n') {
79429a77b73SToomas Soome 		if (rows < fb_info.terminal.y - 1)
79529a77b73SToomas Soome 			boot_fb_setpos(rows + 1, cols);
79629a77b73SToomas Soome 		else
79729a77b73SToomas Soome 			boot_fb_scroll();
7988e6d016fSToomas Soome 		return;
7998e6d016fSToomas Soome 	}
8008e6d016fSToomas Soome 
8018e6d016fSToomas Soome 	bit_to_pix(c);
8028e6d016fSToomas Soome 	display.col = fb_info.cursor.origin.x;
8038e6d016fSToomas Soome 	display.row = fb_info.cursor.origin.y;
804cbc8e155SToomas Soome 	display.width = boot_fb_font.vf_width;
805cbc8e155SToomas Soome 	display.height = boot_fb_font.vf_height;
8068e6d016fSToomas Soome 	display.data = glyph;
8078e6d016fSToomas Soome 
8088e6d016fSToomas Soome 	boot_fb_blit(&display);
80929a77b73SToomas Soome 	if (cols < fb_info.terminal.x - 1)
81029a77b73SToomas Soome 		boot_fb_setpos(rows, cols + 1);
81129a77b73SToomas Soome 	else if (rows < fb_info.terminal.y - 1)
81229a77b73SToomas Soome 		boot_fb_setpos(rows + 1, 0);
81329a77b73SToomas Soome 	else {
81429a77b73SToomas Soome 		boot_fb_setpos(rows, 0);
81529a77b73SToomas Soome 		boot_fb_scroll();
81629a77b73SToomas Soome 	}
8178e6d016fSToomas Soome }
818