xref: /illumos-gate/usr/src/uts/i86pc/boot/boot_fb.c (revision fa9eb222)
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
xbi_init_font(struct xboot_info * xbi)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
xbi_fb_init(struct xboot_info * xbi,bcons_dev_t * bcons_dev)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 
161b70e9485SToomas 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;
209*fa9eb222SToomas Soome 	rgb_info = fb_info.rgb;
2108e6d016fSToomas Soome 
2118e6d016fSToomas Soome 	return (B_TRUE);
2128e6d016fSToomas Soome }
2138e6d016fSToomas Soome 
2148e6d016fSToomas Soome /* set font and pass the data to fb_info */
2158e6d016fSToomas Soome static void
boot_fb_set_font(uint16_t height,uint16_t width)2168e6d016fSToomas Soome boot_fb_set_font(uint16_t height, uint16_t width)
2178e6d016fSToomas Soome {
2188e6d016fSToomas Soome 	short h, w;
219cbc8e155SToomas Soome 	bitmap_data_t *bp;
220cbc8e155SToomas Soome 	int i;
2218e6d016fSToomas Soome 
2228e6d016fSToomas Soome 	h = MIN(height, 4096);
2238e6d016fSToomas Soome 	w = MIN(width, 4096);
2248e6d016fSToomas Soome 
225cbc8e155SToomas Soome 	bp = set_font((short *)&fb_info.terminal.y,
2268e6d016fSToomas Soome 	    (short *)&fb_info.terminal.x, h, w);
227cbc8e155SToomas Soome 
228cbc8e155SToomas Soome 	boot_fb_font.vf_bytes = bp->font->vf_bytes;
229cbc8e155SToomas Soome 	boot_fb_font.vf_width = bp->font->vf_width;
230cbc8e155SToomas Soome 	boot_fb_font.vf_height = bp->font->vf_height;
231cbc8e155SToomas Soome 	for (i = 0; i < VFNT_MAPS; i++) {
232cbc8e155SToomas Soome 		boot_fb_font.vf_map[i] = bp->font->vf_map[i];
233cbc8e155SToomas Soome 		boot_fb_font.vf_map_count[i] = bp->font->vf_map_count[i];
234cbc8e155SToomas Soome 	}
235cbc8e155SToomas Soome 
236cbc8e155SToomas Soome 	fb_info.font_width = boot_fb_font.vf_width;
237cbc8e155SToomas Soome 	fb_info.font_height = boot_fb_font.vf_height;
2388e6d016fSToomas Soome }
2398e6d016fSToomas Soome 
2408e6d016fSToomas Soome /* fill framebuffer */
2418e6d016fSToomas Soome static void
boot_fb_fill(uint8_t * dst,uint32_t data,uint32_t len)2428e6d016fSToomas Soome boot_fb_fill(uint8_t *dst, uint32_t data, uint32_t len)
2438e6d016fSToomas Soome {
2448e6d016fSToomas Soome 	uint16_t *dst16;
2458e6d016fSToomas Soome 	uint32_t *dst32;
2468e6d016fSToomas Soome 	uint32_t i;
2478e6d016fSToomas Soome 
2488e6d016fSToomas Soome 	switch (fb_info.depth) {
2498e6d016fSToomas Soome 	case 24:
2508e6d016fSToomas Soome 	case 8:
2518e6d016fSToomas Soome 		for (i = 0; i < len; i++)
2528e6d016fSToomas Soome 			dst[i] = (uint8_t)data;
2538e6d016fSToomas Soome 		break;
2548e6d016fSToomas Soome 	case 15:
2558e6d016fSToomas Soome 	case 16:
2568e6d016fSToomas Soome 		dst16 = (uint16_t *)dst;
2578e6d016fSToomas Soome 		len /= 2;
25829a77b73SToomas Soome 		for (i = 0; i < len; i++)
2598e6d016fSToomas Soome 			dst16[i] = (uint16_t)data;
2608e6d016fSToomas Soome 		break;
2618e6d016fSToomas Soome 	case 32:
2628e6d016fSToomas Soome 		dst32 = (uint32_t *)dst;
2638e6d016fSToomas Soome 		len /= 4;
26429a77b73SToomas Soome 		for (i = 0; i < len; i++)
2658e6d016fSToomas Soome 			dst32[i] = data;
2668e6d016fSToomas Soome 		break;
2678e6d016fSToomas Soome 	}
2688e6d016fSToomas Soome }
2698e6d016fSToomas Soome 
2708e6d016fSToomas Soome /* copy data to framebuffer */
2718e6d016fSToomas Soome static void
boot_fb_cpy(uint8_t * dst,uint8_t * src,uint32_t len)2728e6d016fSToomas Soome boot_fb_cpy(uint8_t *dst, uint8_t *src, uint32_t len)
2738e6d016fSToomas Soome {
2748e6d016fSToomas Soome 	uint16_t *dst16, *src16;
2758e6d016fSToomas Soome 	uint32_t *dst32, *src32;
2768e6d016fSToomas Soome 
2778e6d016fSToomas Soome 	switch (fb_info.depth) {
2788e6d016fSToomas Soome 	case 24:
2798e6d016fSToomas Soome 	case 8:
28029a77b73SToomas Soome 	default:
28129a77b73SToomas Soome 		if (dst <= src) {
28229a77b73SToomas Soome 			do {
28329a77b73SToomas Soome 				*dst++ = *src++;
28429a77b73SToomas Soome 			} while (--len != 0);
28529a77b73SToomas Soome 		} else {
28629a77b73SToomas Soome 			dst += len;
28729a77b73SToomas Soome 			src += len;
28829a77b73SToomas Soome 			do {
28929a77b73SToomas Soome 				*--dst = *--src;
29029a77b73SToomas Soome 			} while (--len != 0);
29129a77b73SToomas Soome 		}
2928e6d016fSToomas Soome 		break;
2938e6d016fSToomas Soome 	case 15:
2948e6d016fSToomas Soome 	case 16:
2958e6d016fSToomas Soome 		dst16 = (uint16_t *)dst;
2968e6d016fSToomas Soome 		src16 = (uint16_t *)src;
29729a77b73SToomas Soome 		len /= 2;
29829a77b73SToomas Soome 		if (dst16 <= src16) {
29929a77b73SToomas Soome 			do {
30029a77b73SToomas Soome 				*dst16++ = *src16++;
30129a77b73SToomas Soome 			} while (--len != 0);
30229a77b73SToomas Soome 		} else {
30329a77b73SToomas Soome 			dst16 += len;
30429a77b73SToomas Soome 			src16 += len;
30529a77b73SToomas Soome 			do {
30629a77b73SToomas Soome 				*--dst16 = *--src16;
30729a77b73SToomas Soome 			} while (--len != 0);
3088e6d016fSToomas Soome 		}
3098e6d016fSToomas Soome 		break;
3108e6d016fSToomas Soome 	case 32:
3118e6d016fSToomas Soome 		dst32 = (uint32_t *)dst;
3128e6d016fSToomas Soome 		src32 = (uint32_t *)src;
31329a77b73SToomas Soome 		len /= 4;
31429a77b73SToomas Soome 		if (dst32 <= src32) {
31529a77b73SToomas Soome 			do {
31629a77b73SToomas Soome 				*dst32++ = *src32++;
31729a77b73SToomas Soome 			} while (--len != 0);
31829a77b73SToomas Soome 		} else {
31929a77b73SToomas Soome 			dst32 += len;
32029a77b73SToomas Soome 			src32 += len;
32129a77b73SToomas Soome 			do {
32229a77b73SToomas Soome 				*--dst32 = *--src32;
32329a77b73SToomas Soome 			} while (--len != 0);
3248e6d016fSToomas Soome 		}
3258e6d016fSToomas Soome 		break;
3268e6d016fSToomas Soome 	}
3278e6d016fSToomas Soome }
3288e6d016fSToomas Soome 
3298e6d016fSToomas Soome /*
3308e6d016fSToomas Soome  * Allocate shadow frame buffer, called from fakebop.c when early boot
3318e6d016fSToomas Soome  * allocator is ready.
3328e6d016fSToomas Soome  */
3338e6d016fSToomas Soome void
boot_fb_shadow_init(bootops_t * bops)3348e6d016fSToomas Soome boot_fb_shadow_init(bootops_t *bops)
3358e6d016fSToomas Soome {
3368e6d016fSToomas Soome 	if (boot_console_type(NULL) != CONS_FRAMEBUFFER)
3378e6d016fSToomas Soome 		return;			/* nothing to do */
3388e6d016fSToomas Soome 
3398e6d016fSToomas Soome 	fb_info.shadow_fb = (uint8_t *)bops->bsys_alloc(NULL, NULL,
3408e6d016fSToomas Soome 	    fb_info.fb_size, MMU_PAGESIZE);
3418e6d016fSToomas Soome 
3428e6d016fSToomas Soome 	if (fb_info.shadow_fb == NULL)
3438e6d016fSToomas Soome 		return;
3448e6d016fSToomas Soome 
3458e6d016fSToomas Soome 	/* Copy FB to shadow */
3468e6d016fSToomas Soome 	boot_fb_cpy(fb_info.shadow_fb, fb_info.fb, fb_info.fb_size);
3478e6d016fSToomas Soome }
3488e6d016fSToomas Soome 
3498e6d016fSToomas Soome /*
3508e6d016fSToomas Soome  * Translate ansi color based on inverses and brightness.
3518e6d016fSToomas Soome  */
35229a77b73SToomas Soome void
boot_get_color(uint32_t * fg,uint32_t * bg)3538e6d016fSToomas Soome boot_get_color(uint32_t *fg, uint32_t *bg)
3548e6d016fSToomas Soome {
3558e6d016fSToomas Soome 	/* ansi to solaris colors, see also boot_console.c */
3568e6d016fSToomas Soome 	if (fb_info.inverse == B_TRUE ||
3578e6d016fSToomas Soome 	    fb_info.inverse_screen == B_TRUE) {
358e0721d5aSToomas Soome 		if (fb_info.fg_color < XLATE_NCOLORS) {
359e0721d5aSToomas Soome 			/*
360e0721d5aSToomas Soome 			 * white fg -> bright white bg
361e0721d5aSToomas Soome 			 */
362e0721d5aSToomas Soome 			if (fb_info.fg_color == pc_white)
363e0721d5aSToomas Soome 				*bg = brt_xlate[fb_info.fg_color];
364e0721d5aSToomas Soome 			else
365e0721d5aSToomas Soome 				*bg = dim_xlate[fb_info.fg_color];
366e0721d5aSToomas Soome 		} else {
367a4e6b9b6SToomas Soome 			*bg = fb_info.fg_color;
368e0721d5aSToomas Soome 		}
369a4e6b9b6SToomas Soome 
370e0721d5aSToomas Soome 		if (fb_info.bg_color < XLATE_NCOLORS) {
371e0721d5aSToomas Soome 			if (fb_info.bg_color == pc_white)
372e0721d5aSToomas Soome 				*fg = brt_xlate[fb_info.bg_color];
373e0721d5aSToomas Soome 			else
374e0721d5aSToomas Soome 				*fg = dim_xlate[fb_info.bg_color];
375e0721d5aSToomas Soome 		} else {
376a4e6b9b6SToomas Soome 			*fg = fb_info.bg_color;
377e0721d5aSToomas Soome 		}
3788e6d016fSToomas Soome 	} else {
379e0721d5aSToomas Soome 		if (fb_info.fg_color < XLATE_NCOLORS) {
380e0721d5aSToomas Soome 			if (fb_info.fg_color == pc_white)
381e0721d5aSToomas Soome 				*fg = brt_xlate[fb_info.fg_color];
382e0721d5aSToomas Soome 			else
383e0721d5aSToomas Soome 				*fg = dim_xlate[fb_info.fg_color];
384e0721d5aSToomas Soome 		} else {
385e0721d5aSToomas Soome 			*fg = fb_info.fg_color;
386e0721d5aSToomas Soome 		}
387e0721d5aSToomas Soome 
388e0721d5aSToomas Soome 		if (fb_info.bg_color < XLATE_NCOLORS) {
389e0721d5aSToomas Soome 			if (fb_info.bg_color == pc_white)
390a4e6b9b6SToomas Soome 				*bg = brt_xlate[fb_info.bg_color];
391a4e6b9b6SToomas Soome 			else
392a4e6b9b6SToomas Soome 				*bg = dim_xlate[fb_info.bg_color];
393a4e6b9b6SToomas Soome 		} else {
394a4e6b9b6SToomas Soome 			*bg = fb_info.bg_color;
395a4e6b9b6SToomas Soome 		}
3968e6d016fSToomas Soome 	}
3978e6d016fSToomas Soome }
3988e6d016fSToomas Soome 
3998e6d016fSToomas Soome /*
4008e6d016fSToomas Soome  * Map indexed color to RGB value.
4018e6d016fSToomas Soome  */
402a4e6b9b6SToomas Soome uint32_t
boot_color_map(uint8_t index)4038e6d016fSToomas Soome boot_color_map(uint8_t index)
4048e6d016fSToomas Soome {
405a4e6b9b6SToomas Soome 	if (fb_info.fb_type != FB_TYPE_RGB) {
406a4e6b9b6SToomas Soome 		if (index < nitems(solaris_color_to_pc_color))
407a4e6b9b6SToomas Soome 			return (solaris_color_to_pc_color[index]);
408a4e6b9b6SToomas Soome 		else
409a4e6b9b6SToomas Soome 			return (index);
410a4e6b9b6SToomas Soome 	}
4118e6d016fSToomas Soome 
412*fa9eb222SToomas Soome 	return (rgb_color_map(&fb_info.rgb, index, 0));
4138e6d016fSToomas Soome }
4148e6d016fSToomas Soome 
4158e6d016fSToomas Soome /* set up out simple console. */
4168e6d016fSToomas Soome /*ARGSUSED*/
4178e6d016fSToomas Soome void
boot_fb_init(int console)4188e6d016fSToomas Soome boot_fb_init(int console)
4198e6d016fSToomas Soome {
4208e6d016fSToomas Soome 	fb_info_pixel_coord_t window;
4218e6d016fSToomas Soome 
4228e6d016fSToomas Soome 	/* frame buffer address is mapped in dboot. */
4238e6d016fSToomas Soome 	fb_info.fb = (uint8_t *)(uintptr_t)fb_info.paddr;
4248e6d016fSToomas Soome 
4258e6d016fSToomas Soome 	boot_fb_set_font(fb_info.screen.y, fb_info.screen.x);
426cbc8e155SToomas Soome 	window.x = (fb_info.screen.x -
427cbc8e155SToomas Soome 	    fb_info.terminal.x * boot_fb_font.vf_width) / 2;
428cbc8e155SToomas Soome 	window.y = (fb_info.screen.y -
429cbc8e155SToomas Soome 	    fb_info.terminal.y * boot_fb_font.vf_height) / 2;
4308e6d016fSToomas Soome 	fb_info.terminal_origin.x = window.x;
4318e6d016fSToomas Soome 	fb_info.terminal_origin.y = window.y;
4328e6d016fSToomas Soome 
4338e6d016fSToomas Soome #if defined(_BOOT)
4348e6d016fSToomas Soome 	/*
4358e6d016fSToomas Soome 	 * Being called from dboot, we can have cursor terminal
4368e6d016fSToomas Soome 	 * position passed from boot loader. In such case, fix the
4378e6d016fSToomas Soome 	 * cursor screen coords.
4388e6d016fSToomas Soome 	 */
4398e6d016fSToomas Soome 	if (fb_info.cursor.pos.x != 0 || fb_info.cursor.pos.y != 0) {
4408e6d016fSToomas Soome 		fb_info.cursor.origin.x = window.x +
441cbc8e155SToomas Soome 		    fb_info.cursor.pos.x * boot_fb_font.vf_width;
4428e6d016fSToomas Soome 		fb_info.cursor.origin.y = window.y +
443cbc8e155SToomas Soome 		    fb_info.cursor.pos.y * boot_fb_font.vf_height;
4448e6d016fSToomas Soome 	}
4458e6d016fSToomas Soome #endif
4468e6d016fSToomas Soome 
4478e6d016fSToomas Soome 	/* If the cursor terminal position is 0,0 just reset screen coords */
4488e6d016fSToomas Soome 	if (fb_info.cursor.pos.x == 0 && fb_info.cursor.pos.y == 0) {
4498e6d016fSToomas Soome 		fb_info.cursor.origin.x = window.x;
4508e6d016fSToomas Soome 		fb_info.cursor.origin.y = window.y;
4518e6d016fSToomas Soome 	}
4528e6d016fSToomas Soome 
4538e6d016fSToomas Soome 	/*
4548e6d016fSToomas Soome 	 * Validate cursor coords with screen/terminal dimensions,
4558e6d016fSToomas Soome 	 * if anything is off, reset to 0,0
4568e6d016fSToomas Soome 	 */
4578e6d016fSToomas Soome 	if (fb_info.cursor.pos.x > fb_info.terminal.x ||
4588e6d016fSToomas Soome 	    fb_info.cursor.pos.y > fb_info.terminal.y ||
4598e6d016fSToomas Soome 	    fb_info.cursor.origin.x > fb_info.screen.x ||
4608e6d016fSToomas Soome 	    fb_info.cursor.origin.y > fb_info.screen.y) {
4618e6d016fSToomas Soome 
4628e6d016fSToomas Soome 		fb_info.cursor.origin.x = window.x;
4638e6d016fSToomas Soome 		fb_info.cursor.origin.y = window.y;
4648e6d016fSToomas Soome 		fb_info.cursor.pos.x = 0;
4658e6d016fSToomas Soome 		fb_info.cursor.pos.y = 0;
4668e6d016fSToomas Soome 	}
4678e6d016fSToomas Soome 
4688e6d016fSToomas Soome #if defined(_BOOT)
4698e6d016fSToomas Soome 	/* clear the screen if cursor is set to 0,0 */
47029a77b73SToomas Soome 	if (fb_info.cursor.pos.x == 0 && fb_info.cursor.pos.y == 0) {
47129a77b73SToomas Soome 		uint32_t fg, bg, toffset;
47229a77b73SToomas Soome 		uint16_t y;
4738e6d016fSToomas Soome 
4748e6d016fSToomas Soome 		boot_get_color(&fg, &bg);
4758e6d016fSToomas Soome 		bg = boot_color_map(bg);
4768e6d016fSToomas Soome 
47729a77b73SToomas Soome 		toffset = 0;
47829a77b73SToomas Soome 		for (y = 0; y < fb_info.screen.y; y++) {
47929a77b73SToomas Soome 			uint8_t *dest = fb_info.fb + toffset;
48029a77b73SToomas Soome 
4818e6d016fSToomas Soome 			boot_fb_fill(dest, bg, fb_info.pitch);
48229a77b73SToomas Soome 			toffset += fb_info.pitch;
4838e6d016fSToomas Soome 		}
4848e6d016fSToomas Soome 	}
4858e6d016fSToomas Soome #endif
4868e6d016fSToomas Soome }
4878e6d016fSToomas Soome 
4888e6d016fSToomas Soome /* copy rectangle to framebuffer. */
4898e6d016fSToomas Soome static void
boot_fb_blit(struct vis_consdisplay * rect)4908e6d016fSToomas Soome boot_fb_blit(struct vis_consdisplay *rect)
4918e6d016fSToomas Soome {
49229a77b73SToomas Soome 	uint32_t offset, size;		/* write size per scanline */
49329a77b73SToomas Soome 	uint8_t *fbp, *sfbp = NULL;	/* fb + calculated offset */
4948e6d016fSToomas Soome 	int i;
4958e6d016fSToomas Soome 
4968e6d016fSToomas Soome 	/* make sure we will not write past FB */
4978e6d016fSToomas Soome 	if (rect->col >= fb_info.screen.x ||
4988e6d016fSToomas Soome 	    rect->row >= fb_info.screen.y ||
4998e6d016fSToomas Soome 	    rect->col + rect->width >= fb_info.screen.x ||
5008e6d016fSToomas Soome 	    rect->row + rect->height >= fb_info.screen.y)
5018e6d016fSToomas Soome 		return;
5028e6d016fSToomas Soome 
5038e6d016fSToomas Soome 	size = rect->width * fb_info.bpp;
50429a77b73SToomas Soome 	offset = rect->col * fb_info.bpp + rect->row * fb_info.pitch;
50529a77b73SToomas Soome 	fbp = fb_info.fb + offset;
50629a77b73SToomas Soome 	if (fb_info.shadow_fb != NULL)
50729a77b73SToomas Soome 		sfbp = fb_info.shadow_fb + offset;
5088e6d016fSToomas Soome 
5098e6d016fSToomas Soome 	/* write all scanlines in rectangle */
5108e6d016fSToomas Soome 	for (i = 0; i < rect->height; i++) {
5118e6d016fSToomas Soome 		uint8_t *dest = fbp + i * fb_info.pitch;
5128e6d016fSToomas Soome 		uint8_t *src = rect->data + i * size;
5138e6d016fSToomas Soome 		boot_fb_cpy(dest, src, size);
5148e6d016fSToomas Soome 		if (sfbp != NULL) {
5158e6d016fSToomas Soome 			dest = sfbp + i * fb_info.pitch;
5168e6d016fSToomas Soome 			boot_fb_cpy(dest, src, size);
5178e6d016fSToomas Soome 		}
5188e6d016fSToomas Soome 	}
5198e6d016fSToomas Soome }
5208e6d016fSToomas Soome 
5218e6d016fSToomas Soome static void
bit_to_pix(uchar_t c)5228e6d016fSToomas Soome bit_to_pix(uchar_t c)
5238e6d016fSToomas Soome {
5248e6d016fSToomas Soome 	uint32_t fg, bg;
5258e6d016fSToomas Soome 
5268e6d016fSToomas Soome 	boot_get_color(&fg, &bg);
5278e6d016fSToomas Soome 	fg = boot_color_map(fg);
5288e6d016fSToomas Soome 	bg = boot_color_map(bg);
5298e6d016fSToomas Soome 
5308e6d016fSToomas Soome 	switch (fb_info.depth) {
5318e6d016fSToomas Soome 	case 8:
5328e6d016fSToomas Soome 		font_bit_to_pix8(&boot_fb_font, (uint8_t *)glyph, c, fg, bg);
5338e6d016fSToomas Soome 		break;
5348e6d016fSToomas Soome 	case 15:
5358e6d016fSToomas Soome 	case 16:
5368e6d016fSToomas Soome 		font_bit_to_pix16(&boot_fb_font, (uint16_t *)glyph, c,
5378e6d016fSToomas Soome 		    (uint16_t)fg, (uint16_t)bg);
5388e6d016fSToomas Soome 		break;
5398e6d016fSToomas Soome 	case 24:
5408e6d016fSToomas Soome 		font_bit_to_pix24(&boot_fb_font, (uint8_t *)glyph, c, fg, bg);
5418e6d016fSToomas Soome 		break;
5428e6d016fSToomas Soome 	case 32:
5438e6d016fSToomas Soome 		font_bit_to_pix32(&boot_fb_font, (uint32_t *)glyph, c, fg, bg);
5448e6d016fSToomas Soome 		break;
5458e6d016fSToomas Soome 	}
5468e6d016fSToomas Soome }
5478e6d016fSToomas Soome 
5488e6d016fSToomas Soome static void
boot_fb_eraseline_impl(uint16_t x,uint16_t y)54929a77b73SToomas Soome boot_fb_eraseline_impl(uint16_t x, uint16_t y)
5508e6d016fSToomas Soome {
55129a77b73SToomas Soome 	uint32_t toffset, size;
5528e6d016fSToomas Soome 	uint32_t fg, bg;
55329a77b73SToomas Soome 	uint8_t *dst, *sdst;
5548e6d016fSToomas Soome 	int i;
5558e6d016fSToomas Soome 
5568e6d016fSToomas Soome 	boot_get_color(&fg, &bg);
5578e6d016fSToomas Soome 	bg = boot_color_map(bg);
5588e6d016fSToomas Soome 
559cbc8e155SToomas Soome 	size = fb_info.terminal.x * boot_fb_font.vf_width * fb_info.bpp;
56029a77b73SToomas Soome 
56129a77b73SToomas Soome 	toffset = x * fb_info.bpp + y * fb_info.pitch;
56229a77b73SToomas Soome 	dst = fb_info.fb + toffset;
563a6f5e66aSToomas Soome 	sdst = fb_info.shadow_fb + toffset;
56429a77b73SToomas Soome 
565cbc8e155SToomas Soome 	for (i = 0; i < boot_fb_font.vf_height; i++) {
56629a77b73SToomas Soome 		uint8_t *dest = dst + i * fb_info.pitch;
56729a77b73SToomas Soome 		if (fb_info.fb + fb_info.fb_size >= dest + size)
56829a77b73SToomas Soome 			boot_fb_fill(dest, bg, size);
56929a77b73SToomas Soome 		if (fb_info.shadow_fb != NULL) {
57029a77b73SToomas Soome 			dest = sdst + i * fb_info.pitch;
57129a77b73SToomas Soome 			if (fb_info.shadow_fb + fb_info.fb_size >=
57229a77b73SToomas Soome 			    dest + size) {
57329a77b73SToomas Soome 				boot_fb_fill(dest, bg, size);
57429a77b73SToomas Soome 			}
57529a77b73SToomas Soome 		}
57629a77b73SToomas Soome 	}
57729a77b73SToomas Soome }
57829a77b73SToomas Soome 
57929a77b73SToomas Soome static void
boot_fb_eraseline(void)58029a77b73SToomas Soome boot_fb_eraseline(void)
58129a77b73SToomas Soome {
58229a77b73SToomas Soome 	boot_fb_eraseline_impl(fb_info.cursor.origin.x,
58329a77b73SToomas Soome 	    fb_info.cursor.origin.y);
58429a77b73SToomas Soome }
58529a77b73SToomas Soome 
58629a77b73SToomas Soome /*
58729a77b73SToomas Soome  * Copy rectangle from console to console.
58829a77b73SToomas Soome  * If shadow buffer is available, use shadow as source.
58929a77b73SToomas Soome  */
59029a77b73SToomas Soome static void
boot_fb_conscopy(struct vis_conscopy * c_copy)59129a77b73SToomas Soome boot_fb_conscopy(struct vis_conscopy *c_copy)
59229a77b73SToomas Soome {
59329a77b73SToomas Soome 	uint32_t soffset, toffset;
59429a77b73SToomas Soome 	uint32_t width, height, increment;
59529a77b73SToomas Soome 	uint8_t *src, *dst, *sdst = NULL;
59629a77b73SToomas Soome 	int i;
59729a77b73SToomas Soome 
59829a77b73SToomas Soome 	soffset = c_copy->s_col * fb_info.bpp + c_copy->s_row * fb_info.pitch;
59929a77b73SToomas Soome 	toffset = c_copy->t_col * fb_info.bpp + c_copy->t_row * fb_info.pitch;
60029a77b73SToomas Soome 
60129a77b73SToomas Soome 	src = fb_info.fb + soffset;
60229a77b73SToomas Soome 	dst = fb_info.fb + toffset;
6038e6d016fSToomas Soome 
6048e6d016fSToomas Soome 	if (fb_info.shadow_fb != NULL) {
6058e6d016fSToomas Soome 		src = fb_info.shadow_fb + soffset;
6068e6d016fSToomas Soome 		sdst = fb_info.shadow_fb + toffset;
6078e6d016fSToomas Soome 	}
6088e6d016fSToomas Soome 
60929a77b73SToomas Soome 	width = (c_copy->e_col - c_copy->s_col + 1) * fb_info.bpp;
61029a77b73SToomas Soome 	height = c_copy->e_row - c_copy->s_row + 1;
61129a77b73SToomas Soome 
6128e6d016fSToomas Soome 	for (i = 0; i < height; i++) {
61329a77b73SToomas Soome 		increment = i * fb_info.pitch;
61429a77b73SToomas Soome 
61529a77b73SToomas Soome 		/* Make sure we fit into FB size. */
61629a77b73SToomas Soome 		if (soffset + increment + width >= fb_info.fb_size ||
61729a77b73SToomas Soome 		    toffset + increment + width >= fb_info.fb_size)
61829a77b73SToomas Soome 			break;
61929a77b73SToomas Soome 
6208e6d016fSToomas Soome 		boot_fb_cpy(dst + increment, src + increment, width);
62129a77b73SToomas Soome 
6228e6d016fSToomas Soome 		if (sdst != NULL)
6238e6d016fSToomas Soome 			boot_fb_cpy(sdst + increment, src + increment, width);
6248e6d016fSToomas Soome 	}
62529a77b73SToomas Soome }
6268e6d016fSToomas Soome 
62729a77b73SToomas Soome /* Shift the line content by chars. */
62829a77b73SToomas Soome static void
boot_fb_shiftline(int chars)62929a77b73SToomas Soome boot_fb_shiftline(int chars)
63029a77b73SToomas Soome {
63129a77b73SToomas Soome 	struct vis_conscopy c_copy;
6328e6d016fSToomas Soome 
63329a77b73SToomas Soome 	c_copy.s_col = fb_info.cursor.origin.x;
63429a77b73SToomas Soome 	c_copy.s_row = fb_info.cursor.origin.y;
63529a77b73SToomas Soome 
636cbc8e155SToomas Soome 	c_copy.e_col = (fb_info.terminal.x - chars) * boot_fb_font.vf_width;
63729a77b73SToomas Soome 	c_copy.e_col += fb_info.terminal_origin.x;
638cbc8e155SToomas Soome 	c_copy.e_row = c_copy.s_row + boot_fb_font.vf_height;
63929a77b73SToomas Soome 
640cbc8e155SToomas Soome 	c_copy.t_col = fb_info.cursor.origin.x + chars * boot_fb_font.vf_width;
64129a77b73SToomas Soome 	c_copy.t_row = fb_info.cursor.origin.y;
64229a77b73SToomas Soome 
64329a77b73SToomas Soome 	boot_fb_conscopy(&c_copy);
64429a77b73SToomas Soome }
64529a77b73SToomas Soome 
64629a77b73SToomas Soome /*
64729a77b73SToomas Soome  * move the terminal window lines [1..y] to [0..y-1] and clear last line.
64829a77b73SToomas Soome  */
64929a77b73SToomas Soome static void
boot_fb_scroll(void)65029a77b73SToomas Soome boot_fb_scroll(void)
65129a77b73SToomas Soome {
65229a77b73SToomas Soome 	struct vis_conscopy c_copy;
65329a77b73SToomas Soome 
65429a77b73SToomas Soome 	/* support for scrolling. set up the console copy data and last line */
655cbc8e155SToomas Soome 	c_copy.s_row = fb_info.terminal_origin.y + boot_fb_font.vf_height;
65629a77b73SToomas Soome 	c_copy.s_col = fb_info.terminal_origin.x;
65729a77b73SToomas Soome 	c_copy.e_row = fb_info.screen.y - fb_info.terminal_origin.y;
65829a77b73SToomas Soome 	c_copy.e_col = fb_info.screen.x - fb_info.terminal_origin.x;
65929a77b73SToomas Soome 	c_copy.t_row = fb_info.terminal_origin.y;
66029a77b73SToomas Soome 	c_copy.t_col = fb_info.terminal_origin.x;
66129a77b73SToomas Soome 
66229a77b73SToomas Soome 	boot_fb_conscopy(&c_copy);
66329a77b73SToomas Soome 
66429a77b73SToomas Soome 	/* now clean up the last line */
66529a77b73SToomas Soome 	boot_fb_eraseline_impl(fb_info.terminal_origin.x,
66629a77b73SToomas Soome 	    fb_info.terminal_origin.y +
667cbc8e155SToomas Soome 	    (fb_info.terminal.y - 1) * boot_fb_font.vf_height);
6688e6d016fSToomas Soome }
6698e6d016fSToomas Soome 
6708e6d016fSToomas Soome /*
6718e6d016fSToomas Soome  * Very simple block cursor. Save space below the cursor and restore
6728e6d016fSToomas Soome  * when cursor is invisible.
6738e6d016fSToomas Soome  */
6748e6d016fSToomas Soome void
boot_fb_cursor(boolean_t visible)6758e6d016fSToomas Soome boot_fb_cursor(boolean_t visible)
6768e6d016fSToomas Soome {
677cbc8e155SToomas Soome 	uint32_t offset, size, j;
6788e6d016fSToomas Soome 	uint32_t *fb32, *sfb32 = NULL;
6798e6d016fSToomas Soome 	uint32_t fg, bg;
6808e6d016fSToomas Soome 	uint16_t *fb16, *sfb16 = NULL;
6818e6d016fSToomas Soome 	uint8_t *fb8, *sfb8 = NULL;
6828e6d016fSToomas Soome 	int i, pitch;
6838e6d016fSToomas Soome 
6848e6d016fSToomas Soome 	if (fb_info.cursor.visible == visible)
6858e6d016fSToomas Soome 		return;
6868e6d016fSToomas Soome 
6878e6d016fSToomas Soome 	boot_get_color(&fg, &bg);
6888e6d016fSToomas Soome 	fg = boot_color_map(fg);
6898e6d016fSToomas Soome 	bg = boot_color_map(bg);
6908e6d016fSToomas Soome 
6918e6d016fSToomas Soome 	fb_info.cursor.visible = visible;
6928e6d016fSToomas Soome 	pitch = fb_info.pitch;
693cbc8e155SToomas Soome 	size = boot_fb_font.vf_width * fb_info.bpp;
6948e6d016fSToomas Soome 
6958e6d016fSToomas Soome 	/*
6968e6d016fSToomas Soome 	 * Build cursor image. We are building mirror image of data on
6978e6d016fSToomas Soome 	 * frame buffer by (D xor FG) xor BG.
6988e6d016fSToomas Soome 	 */
6998e6d016fSToomas Soome 	offset = fb_info.cursor.origin.x * fb_info.bpp +
7008e6d016fSToomas Soome 	    fb_info.cursor.origin.y * pitch;
7018e6d016fSToomas Soome 	switch (fb_info.depth) {
7028e6d016fSToomas Soome 	case 8:
703cbc8e155SToomas Soome 		for (i = 0; i < boot_fb_font.vf_height; i++) {
7048e6d016fSToomas Soome 			fb8 = fb_info.fb + offset + i * pitch;
7058e6d016fSToomas Soome 			if (fb_info.shadow_fb != NULL)
7068e6d016fSToomas Soome 				sfb8 = fb_info.shadow_fb + offset + i * pitch;
707cbc8e155SToomas Soome 			for (j = 0; j < size; j += 1) {
7088e6d016fSToomas Soome 				fb8[j] = (fb8[j] ^ (fg & 0xff)) ^ (bg & 0xff);
7098e6d016fSToomas Soome 
7108e6d016fSToomas Soome 				if (sfb8 == NULL)
7118e6d016fSToomas Soome 					continue;
7128e6d016fSToomas Soome 
7138e6d016fSToomas Soome 				sfb8[j] = (sfb8[j] ^ (fg & 0xff)) ^ (bg & 0xff);
7148e6d016fSToomas Soome 			}
7158e6d016fSToomas Soome 		}
7168e6d016fSToomas Soome 		break;
7178e6d016fSToomas Soome 	case 15:
7188e6d016fSToomas Soome 	case 16:
719cbc8e155SToomas Soome 		for (i = 0; i < boot_fb_font.vf_height; i++) {
7208e6d016fSToomas Soome 			fb16 = (uint16_t *)(fb_info.fb + offset + i * pitch);
7218e6d016fSToomas Soome 			if (fb_info.shadow_fb != NULL)
7228e6d016fSToomas Soome 				sfb16 = (uint16_t *)
7238e6d016fSToomas Soome 				    (fb_info.shadow_fb + offset + i * pitch);
724cbc8e155SToomas Soome 			for (j = 0; j < boot_fb_font.vf_width; j++) {
7258e6d016fSToomas Soome 				fb16[j] = (fb16[j] ^ (fg & 0xffff)) ^
7268e6d016fSToomas Soome 				    (bg & 0xffff);
7278e6d016fSToomas Soome 
7288e6d016fSToomas Soome 				if (sfb16 == NULL)
7298e6d016fSToomas Soome 					continue;
7308e6d016fSToomas Soome 
7318e6d016fSToomas Soome 				sfb16[j] = (sfb16[j] ^ (fg & 0xffff)) ^
7328e6d016fSToomas Soome 				    (bg & 0xffff);
7338e6d016fSToomas Soome 			}
7348e6d016fSToomas Soome 		}
7358e6d016fSToomas Soome 		break;
7368e6d016fSToomas Soome 	case 24:
737cbc8e155SToomas Soome 		for (i = 0; i < boot_fb_font.vf_height; i++) {
7388e6d016fSToomas Soome 			fb8 = fb_info.fb + offset + i * pitch;
7398e6d016fSToomas Soome 			if (fb_info.shadow_fb != NULL)
7408e6d016fSToomas Soome 				sfb8 = fb_info.shadow_fb + offset + i * pitch;
741cbc8e155SToomas Soome 			for (j = 0; j < size; j += 3) {
7428e6d016fSToomas Soome 				fb8[j] = (fb8[j] ^ ((fg >> 16) & 0xff)) ^
7438e6d016fSToomas Soome 				    ((bg >> 16) & 0xff);
7448e6d016fSToomas Soome 				fb8[j+1] = (fb8[j+1] ^ ((fg >> 8) & 0xff)) ^
7458e6d016fSToomas Soome 				    ((bg >> 8) & 0xff);
7468e6d016fSToomas Soome 				fb8[j+2] = (fb8[j+2] ^ (fg & 0xff)) ^
7478e6d016fSToomas Soome 				    (bg & 0xff);
7488e6d016fSToomas Soome 
7498e6d016fSToomas Soome 				if (sfb8 == NULL)
7508e6d016fSToomas Soome 					continue;
7518e6d016fSToomas Soome 
7528e6d016fSToomas Soome 				sfb8[j] = (sfb8[j] ^ ((fg >> 16) & 0xff)) ^
7538e6d016fSToomas Soome 				    ((bg >> 16) & 0xff);
7548e6d016fSToomas Soome 				sfb8[j+1] = (sfb8[j+1] ^ ((fg >> 8) & 0xff)) ^
7558e6d016fSToomas Soome 				    ((bg >> 8) & 0xff);
7568e6d016fSToomas Soome 				sfb8[j+2] = (sfb8[j+2] ^ (fg & 0xff)) ^
7578e6d016fSToomas Soome 				    (bg & 0xff);
7588e6d016fSToomas Soome 			}
7598e6d016fSToomas Soome 		}
7608e6d016fSToomas Soome 		break;
7618e6d016fSToomas Soome 	case 32:
762cbc8e155SToomas Soome 		for (i = 0; i < boot_fb_font.vf_height; i++) {
7638e6d016fSToomas Soome 			fb32 = (uint32_t *)(fb_info.fb + offset + i * pitch);
7648e6d016fSToomas Soome 			if (fb_info.shadow_fb != NULL) {
7658e6d016fSToomas Soome 				sfb32 = (uint32_t *)
7668e6d016f