xref: /illumos-gate/usr/src/uts/i86pc/boot/boot_fb.c (revision a4e6b9b6)
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))
39*a4e6b9b6SToomas 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 
1618e6d016fSToomas Soome 	tag = (multiboot_tag_framebuffer_t *)(uintptr_t)xbi_fb->framebuffer;
1628e6d016fSToomas Soome 	if (tag == NULL) {
1638e6d016fSToomas Soome 		return (B_FALSE);
1648e6d016fSToomas Soome 	}
1658e6d016fSToomas Soome 
166cbc8e155SToomas Soome 	xbi_init_font(xbi);
167cbc8e155SToomas Soome 
1688e6d016fSToomas Soome 	fb_info.paddr = tag->framebuffer_common.framebuffer_addr;
1698e6d016fSToomas Soome 	fb_info.pitch = tag->framebuffer_common.framebuffer_pitch;
1708e6d016fSToomas Soome 	fb_info.depth = tag->framebuffer_common.framebuffer_bpp;
1718e6d016fSToomas Soome 	fb_info.bpp = P2ROUNDUP(fb_info.depth, 8) >> 3;
1728e6d016fSToomas Soome 	fb_info.screen.x = tag->framebuffer_common.framebuffer_width;
1738e6d016fSToomas Soome 	fb_info.screen.y = tag->framebuffer_common.framebuffer_height;
1748e6d016fSToomas Soome 	fb_info.fb_size = fb_info.screen.y * fb_info.pitch;
1758e6d016fSToomas Soome 
17629a77b73SToomas Soome 	bcons_dev->bd_putchar = boot_fb_putchar;
17729a77b73SToomas Soome 	bcons_dev->bd_eraseline = boot_fb_eraseline;
17829a77b73SToomas Soome 	bcons_dev->bd_cursor = boot_fb_cursor;
17929a77b73SToomas Soome 	bcons_dev->bd_setpos = boot_fb_setpos;
18029a77b73SToomas Soome 	bcons_dev->bd_shift = boot_fb_shiftline;
18129a77b73SToomas Soome 
1828e6d016fSToomas Soome 	if (fb_info.paddr == 0)
1838e6d016fSToomas Soome 		fb_info.fb_type = FB_TYPE_UNKNOWN;
1848e6d016fSToomas Soome 
1858e6d016fSToomas Soome 	switch (tag->framebuffer_common.framebuffer_type) {
1868e6d016fSToomas Soome 	case MULTIBOOT_FRAMEBUFFER_TYPE_EGA_TEXT:
1878e6d016fSToomas Soome 		fb_info.fb_type = FB_TYPE_EGA_TEXT;
1888e6d016fSToomas Soome 		return (B_FALSE);
1898e6d016fSToomas Soome 
1908e6d016fSToomas Soome 	case MULTIBOOT_FRAMEBUFFER_TYPE_INDEXED:
1918e6d016fSToomas Soome 		if (fb_info.paddr != 0)
1928e6d016fSToomas Soome 			fb_info.fb_type = FB_TYPE_INDEXED;
1938e6d016fSToomas Soome 		return (B_TRUE);
1948e6d016fSToomas Soome 
1958e6d016fSToomas Soome 	case MULTIBOOT_FRAMEBUFFER_TYPE_RGB:
1968e6d016fSToomas Soome 		if (fb_info.paddr != 0)
1978e6d016fSToomas Soome 			fb_info.fb_type = FB_TYPE_RGB;
1988e6d016fSToomas Soome 		break;
1998e6d016fSToomas Soome 
2008e6d016fSToomas Soome 	default:
2018e6d016fSToomas Soome 		return (B_FALSE);
2028e6d016fSToomas Soome 	}
2038e6d016fSToomas Soome 
2048e6d016fSToomas Soome 	fb_info.rgb.red.size = tag->u.fb2.framebuffer_red_mask_size;
2058e6d016fSToomas Soome 	fb_info.rgb.red.pos = tag->u.fb2.framebuffer_red_field_position;
2068e6d016fSToomas Soome 	fb_info.rgb.green.size = tag->u.fb2.framebuffer_green_mask_size;
2078e6d016fSToomas Soome 	fb_info.rgb.green.pos = tag->u.fb2.framebuffer_green_field_position;
2088e6d016fSToomas Soome 	fb_info.rgb.blue.size = tag->u.fb2.framebuffer_blue_mask_size;
2098e6d016fSToomas Soome 	fb_info.rgb.blue.pos = tag->u.fb2.framebuffer_blue_field_position;
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
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
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
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
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
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) {
358*a4e6b9b6SToomas Soome 		if (fb_info.fg_color < 16)
359*a4e6b9b6SToomas Soome 			*bg = dim_xlate[fb_info.fg_color];
360*a4e6b9b6SToomas Soome 		else
361*a4e6b9b6SToomas Soome 			*bg = fb_info.fg_color;
362*a4e6b9b6SToomas Soome 
363*a4e6b9b6SToomas Soome 		if (fb_info.bg_color < 16)
364*a4e6b9b6SToomas Soome 			*fg = brt_xlate[fb_info.bg_color];
365*a4e6b9b6SToomas Soome 		else
366*a4e6b9b6SToomas Soome 			*fg = fb_info.bg_color;
3678e6d016fSToomas Soome 	} else {
368*a4e6b9b6SToomas Soome 		if (fb_info.bg_color < 16) {
369*a4e6b9b6SToomas Soome 			if (fb_info.bg_color == 7)
370*a4e6b9b6SToomas Soome 				*bg = brt_xlate[fb_info.bg_color];
371*a4e6b9b6SToomas Soome 			else
372*a4e6b9b6SToomas Soome 				*bg = dim_xlate[fb_info.bg_color];
373*a4e6b9b6SToomas Soome 		} else {
374*a4e6b9b6SToomas Soome 			*bg = fb_info.bg_color;
375*a4e6b9b6SToomas Soome 		}
376*a4e6b9b6SToomas Soome 		if (fb_info.fg_color < 16)
377*a4e6b9b6SToomas Soome 			*fg = dim_xlate[fb_info.fg_color];
3788e6d016fSToomas Soome 		else
379*a4e6b9b6SToomas Soome 			*fg = fb_info.fg_color;
3808e6d016fSToomas Soome 	}
3818e6d016fSToomas Soome }
3828e6d016fSToomas Soome 
3838e6d016fSToomas Soome /*
3848e6d016fSToomas Soome  * Map indexed color to RGB value.
3858e6d016fSToomas Soome  */
386*a4e6b9b6SToomas Soome uint32_t
3878e6d016fSToomas Soome boot_color_map(uint8_t index)
3888e6d016fSToomas Soome {
389*a4e6b9b6SToomas Soome 	if (fb_info.fb_type != FB_TYPE_RGB) {
390*a4e6b9b6SToomas Soome 		if (index < nitems(solaris_color_to_pc_color))
391*a4e6b9b6SToomas Soome 			return (solaris_color_to_pc_color[index]);
392*a4e6b9b6SToomas Soome 		else
393*a4e6b9b6SToomas Soome 			return (index);
394*a4e6b9b6SToomas Soome 	}
3958e6d016fSToomas Soome 
396*a4e6b9b6SToomas Soome 	return (rgb_color_map(&fb_info.rgb, index));
3978e6d016fSToomas Soome }
3988e6d016fSToomas Soome 
3998e6d016fSToomas Soome /* set up out simple console. */
4008e6d016fSToomas Soome /*ARGSUSED*/
4018e6d016fSToomas Soome void
4028e6d016fSToomas Soome boot_fb_init(int console)
4038e6d016fSToomas Soome {
4048e6d016fSToomas Soome 	fb_info_pixel_coord_t window;
4058e6d016fSToomas Soome 
4068e6d016fSToomas Soome 	/* frame buffer address is mapped in dboot. */
4078e6d016fSToomas Soome 	fb_info.fb = (uint8_t *)(uintptr_t)fb_info.paddr;
4088e6d016fSToomas Soome 
4098e6d016fSToomas Soome 	boot_fb_set_font(fb_info.screen.y, fb_info.screen.x);
410cbc8e155SToomas Soome 	window.x = (fb_info.screen.x -
411cbc8e155SToomas Soome 	    fb_info.terminal.x * boot_fb_font.vf_width) / 2;
412cbc8e155SToomas Soome 	window.y = (fb_info.screen.y -
413cbc8e155SToomas Soome 	    fb_info.terminal.y * boot_fb_font.vf_height) / 2;
4148e6d016fSToomas Soome 	fb_info.terminal_origin.x = window.x;
4158e6d016fSToomas Soome 	fb_info.terminal_origin.y = window.y;
4168e6d016fSToomas Soome 
4178e6d016fSToomas Soome #if defined(_BOOT)
4188e6d016fSToomas Soome 	/*
4198e6d016fSToomas Soome 	 * Being called from dboot, we can have cursor terminal
4208e6d016fSToomas Soome 	 * position passed from boot loader. In such case, fix the
4218e6d016fSToomas Soome 	 * cursor screen coords.
4228e6d016fSToomas Soome 	 */
4238e6d016fSToomas Soome 	if (fb_info.cursor.pos.x != 0 || fb_info.cursor.pos.y != 0) {
4248e6d016fSToomas Soome 		fb_info.cursor.origin.x = window.x +
425cbc8e155SToomas Soome 		    fb_info.cursor.pos.x * boot_fb_font.vf_width;
4268e6d016fSToomas Soome 		fb_info.cursor.origin.y = window.y +
427cbc8e155SToomas Soome 		    fb_info.cursor.pos.y * boot_fb_font.vf_height;
4288e6d016fSToomas Soome 	}
4298e6d016fSToomas Soome #endif
4308e6d016fSToomas Soome 
4318e6d016fSToomas Soome 	/* If the cursor terminal position is 0,0 just reset screen coords */
4328e6d016fSToomas Soome 	if (fb_info.cursor.pos.x == 0 && fb_info.cursor.pos.y == 0) {
4338e6d016fSToomas Soome 		fb_info.cursor.origin.x = window.x;
4348e6d016fSToomas Soome 		fb_info.cursor.origin.y = window.y;
4358e6d016fSToomas Soome 	}
4368e6d016fSToomas Soome 
4378e6d016fSToomas Soome 	/*
4388e6d016fSToomas Soome 	 * Validate cursor coords with screen/terminal dimensions,
4398e6d016fSToomas Soome 	 * if anything is off, reset to 0,0
4408e6d016fSToomas Soome 	 */
4418e6d016fSToomas Soome 	if (fb_info.cursor.pos.x > fb_info.terminal.x ||
4428e6d016fSToomas Soome 	    fb_info.cursor.pos.y > fb_info.terminal.y ||
4438e6d016fSToomas Soome 	    fb_info.cursor.origin.x > fb_info.screen.x ||
4448e6d016fSToomas Soome 	    fb_info.cursor.origin.y > fb_info.screen.y) {
4458e6d016fSToomas Soome 
4468e6d016fSToomas Soome 		fb_info.cursor.origin.x = window.x;
4478e6d016fSToomas Soome 		fb_info.cursor.origin.y = window.y;
4488e6d016fSToomas Soome 		fb_info.cursor.pos.x = 0;
4498e6d016fSToomas Soome 		fb_info.cursor.pos.y = 0;
4508e6d016fSToomas Soome 	}
4518e6d016fSToomas Soome 
4528e6d016fSToomas Soome #if defined(_BOOT)
4538e6d016fSToomas Soome 	/* clear the screen if cursor is set to 0,0 */
45429a77b73SToomas Soome 	if (fb_info.cursor.pos.x == 0 && fb_info.cursor.pos.y == 0) {
45529a77b73SToomas Soome 		uint32_t fg, bg, toffset;
45629a77b73SToomas Soome 		uint16_t y;
4578e6d016fSToomas Soome 
4588e6d016fSToomas Soome 		boot_get_color(&fg, &bg);
4598e6d016fSToomas Soome 		bg = boot_color_map(bg);
4608e6d016fSToomas Soome 
46129a77b73SToomas Soome 		toffset = 0;
46229a77b73SToomas Soome 		for (y = 0; y < fb_info.screen.y; y++) {
46329a77b73SToomas Soome 			uint8_t *dest = fb_info.fb + toffset;
46429a77b73SToomas Soome 
4658e6d016fSToomas Soome 			boot_fb_fill(dest, bg, fb_info.pitch);
46629a77b73SToomas Soome 			toffset += fb_info.pitch;
4678e6d016fSToomas Soome 		}
4688e6d016fSToomas Soome 	}
4698e6d016fSToomas Soome #endif
4708e6d016fSToomas Soome }
4718e6d016fSToomas Soome 
4728e6d016fSToomas Soome /* copy rectangle to framebuffer. */
4738e6d016fSToomas Soome static void
4748e6d016fSToomas Soome boot_fb_blit(struct vis_consdisplay *rect)
4758e6d016fSToomas Soome {
47629a77b73SToomas Soome 	uint32_t offset, size;		/* write size per scanline */
47729a77b73SToomas Soome 	uint8_t *fbp, *sfbp = NULL;	/* fb + calculated offset */
4788e6d016fSToomas Soome 	int i;
4798e6d016fSToomas Soome 
4808e6d016fSToomas Soome 	/* make sure we will not write past FB */
4818e6d016fSToomas Soome 	if (rect->col >= fb_info.screen.x ||
4828e6d016fSToomas Soome 	    rect->row >= fb_info.screen.y ||
4838e6d016fSToomas Soome 	    rect->col + rect->width >= fb_info.screen.x ||
4848e6d016fSToomas Soome 	    rect->row + rect->height >= fb_info.screen.y)
4858e6d016fSToomas Soome 		return;
4868e6d016fSToomas Soome 
4878e6d016fSToomas Soome 	size = rect->width * fb_info.bpp;
48829a77b73SToomas Soome 	offset = rect->col * fb_info.bpp + rect->row * fb_info.pitch;
48929a77b73SToomas Soome 	fbp = fb_info.fb + offset;
49029a77b73SToomas Soome 	if (fb_info.shadow_fb != NULL)
49129a77b73SToomas Soome 		sfbp = fb_info.shadow_fb + offset;
4928e6d016fSToomas Soome 
4938e6d016fSToomas Soome 	/* write all scanlines in rectangle */
4948e6d016fSToomas Soome 	for (i = 0; i < rect->height; i++) {
4958e6d016fSToomas Soome 		uint8_t *dest = fbp + i * fb_info.pitch;
4968e6d016fSToomas Soome 		uint8_t *src = rect->data + i * size;
4978e6d016fSToomas Soome 		boot_fb_cpy(dest, src, size);
4988e6d016fSToomas Soome 		if (sfbp != NULL) {
4998e6d016fSToomas Soome 			dest = sfbp + i * fb_info.pitch;
5008e6d016fSToomas Soome 			boot_fb_cpy(dest, src, size);
5018e6d016fSToomas Soome 		}
5028e6d016fSToomas Soome 	}
5038e6d016fSToomas Soome }
5048e6d016fSToomas Soome 
5058e6d016fSToomas Soome static void
5068e6d016fSToomas Soome bit_to_pix(uchar_t c)
5078e6d016fSToomas Soome {
5088e6d016fSToomas Soome 	uint32_t fg, bg;
5098e6d016fSToomas Soome 
5108e6d016fSToomas Soome 	boot_get_color(&fg, &bg);
5118e6d016fSToomas Soome 	fg = boot_color_map(fg);
5128e6d016fSToomas Soome 	bg = boot_color_map(bg);
5138e6d016fSToomas Soome 
5148e6d016fSToomas Soome 	switch (fb_info.depth) {
5158e6d016fSToomas Soome 	case 8:
5168e6d016fSToomas Soome 		font_bit_to_pix8(&boot_fb_font, (uint8_t *)glyph, c, fg, bg);
5178e6d016fSToomas Soome 		break;
5188e6d016fSToomas Soome 	case 15:
5198e6d016fSToomas Soome 	case 16:
5208e6d016fSToomas Soome 		font_bit_to_pix16(&boot_fb_font, (uint16_t *)glyph, c,
5218e6d016fSToomas Soome 		    (uint16_t)fg, (uint16_t)bg);
5228e6d016fSToomas Soome 		break;
5238e6d016fSToomas Soome 	case 24:
5248e6d016fSToomas Soome 		font_bit_to_pix24(&boot_fb_font, (uint8_t *)glyph, c, fg, bg);
5258e6d016fSToomas Soome 		break;
5268e6d016fSToomas Soome 	case 32:
5278e6d016fSToomas Soome 		font_bit_to_pix32(&boot_fb_font, (uint32_t *)glyph, c, fg, bg);
5288e6d016fSToomas Soome 		break;
5298e6d016fSToomas Soome 	}
5308e6d016fSToomas Soome }
5318e6d016fSToomas Soome 
5328e6d016fSToomas Soome static void
53329a77b73SToomas Soome boot_fb_eraseline_impl(uint16_t x, uint16_t y)
5348e6d016fSToomas Soome {
53529a77b73SToomas Soome 	uint32_t toffset, size;
5368e6d016fSToomas Soome 	uint32_t fg, bg;
53729a77b73SToomas Soome 	uint8_t *dst, *sdst;
5388e6d016fSToomas Soome 	int i;
5398e6d016fSToomas Soome 
5408e6d016fSToomas Soome 	boot_get_color(&fg, &bg);
5418e6d016fSToomas Soome 	bg = boot_color_map(bg);
5428e6d016fSToomas Soome 
543cbc8e155SToomas Soome 	size = fb_info.terminal.x * boot_fb_font.vf_width * fb_info.bpp;
54429a77b73SToomas Soome 
54529a77b73SToomas Soome 	toffset = x * fb_info.bpp + y * fb_info.pitch;
54629a77b73SToomas Soome 	dst = fb_info.fb + toffset;
547a6f5e66aSToomas Soome 	sdst = fb_info.shadow_fb + toffset;
54829a77b73SToomas Soome 
549cbc8e155SToomas Soome 	for (i = 0; i < boot_fb_font.vf_height; i++) {
55029a77b73SToomas Soome 		uint8_t *dest = dst + i * fb_info.pitch;
55129a77b73SToomas Soome 		if (fb_info.fb + fb_info.fb_size >= dest + size)
55229a77b73SToomas Soome 			boot_fb_fill(dest, bg, size);
55329a77b73SToomas Soome 		if (fb_info.shadow_fb != NULL) {
55429a77b73SToomas Soome 			dest = sdst + i * fb_info.pitch;
55529a77b73SToomas Soome 			if (fb_info.shadow_fb + fb_info.fb_size >=
55629a77b73SToomas Soome 			    dest + size) {
55729a77b73SToomas Soome 				boot_fb_fill(dest, bg, size);
55829a77b73SToomas Soome 			}
55929a77b73SToomas Soome 		}
56029a77b73SToomas Soome 	}
56129a77b73SToomas Soome }
56229a77b73SToomas Soome 
56329a77b73SToomas Soome static void
56429a77b73SToomas Soome boot_fb_eraseline(void)
56529a77b73SToomas Soome {
56629a77b73SToomas Soome 	boot_fb_eraseline_impl(fb_info.cursor.origin.x,
56729a77b73SToomas Soome 	    fb_info.cursor.origin.y);
56829a77b73SToomas Soome }
56929a77b73SToomas Soome 
57029a77b73SToomas Soome /*
57129a77b73SToomas Soome  * Copy rectangle from console to console.
57229a77b73SToomas Soome  * If shadow buffer is available, use shadow as source.
57329a77b73SToomas Soome  */
57429a77b73SToomas Soome static void
57529a77b73SToomas Soome boot_fb_conscopy(struct vis_conscopy *c_copy)
57629a77b73SToomas Soome {
57729a77b73SToomas Soome 	uint32_t soffset, toffset;
57829a77b73SToomas Soome 	uint32_t width, height, increment;
57929a77b73SToomas Soome 	uint8_t *src, *dst, *sdst = NULL;
58029a77b73SToomas Soome 	int i;
58129a77b73SToomas Soome 
58229a77b73SToomas Soome 	soffset = c_copy->s_col * fb_info.bpp + c_copy->s_row * fb_info.pitch;
58329a77b73SToomas Soome 	toffset = c_copy->t_col * fb_info.bpp + c_copy->t_row * fb_info.pitch;
58429a77b73SToomas Soome 
58529a77b73SToomas Soome 	src = fb_info.fb + soffset;
58629a77b73SToomas Soome 	dst = fb_info.fb + toffset;
5878e6d016fSToomas Soome 
5888e6d016fSToomas Soome 	if (fb_info.shadow_fb != NULL) {
5898e6d016fSToomas Soome 		src = fb_info.shadow_fb + soffset;
5908e6d016fSToomas Soome 		sdst = fb_info.shadow_fb + toffset;
5918e6d016fSToomas Soome 	}
5928e6d016fSToomas Soome 
59329a77b73SToomas Soome 	width = (c_copy->e_col - c_copy->s_col + 1) * fb_info.bpp;
59429a77b73SToomas Soome 	height = c_copy->e_row - c_copy->s_row + 1;
59529a77b73SToomas Soome 
5968e6d016fSToomas Soome 	for (i = 0; i < height; i++) {
59729a77b73SToomas Soome 		increment = i * fb_info.pitch;
59829a77b73SToomas Soome 
59929a77b73SToomas Soome 		/* Make sure we fit into FB size. */
60029a77b73SToomas Soome 		if (soffset + increment + width >= fb_info.fb_size ||
60129a77b73SToomas Soome 		    toffset + increment + width >= fb_info.fb_size)
60229a77b73SToomas Soome 			break;
60329a77b73SToomas Soome 
6048e6d016fSToomas Soome 		boot_fb_cpy(dst + increment, src + increment, width);
60529a77b73SToomas Soome 
6068e6d016fSToomas Soome 		if (sdst != NULL)
6078e6d016fSToomas Soome 			boot_fb_cpy(sdst + increment, src + increment, width);
6088e6d016fSToomas Soome 	}
60929a77b73SToomas Soome }
6108e6d016fSToomas Soome 
61129a77b73SToomas Soome /* Shift the line content by chars. */
61229a77b73SToomas Soome static void
61329a77b73SToomas Soome boot_fb_shiftline(int chars)
61429a77b73SToomas Soome {
61529a77b73SToomas Soome 	struct vis_conscopy c_copy;
6168e6d016fSToomas Soome 
61729a77b73SToomas Soome 	c_copy.s_col = fb_info.cursor.origin.x;
61829a77b73SToomas Soome 	c_copy.s_row = fb_info.cursor.origin.y;
61929a77b73SToomas Soome 
620cbc8e155SToomas Soome 	c_copy.e_col = (fb_info.terminal.x - chars) * boot_fb_font.vf_width;
62129a77b73SToomas Soome 	c_copy.e_col += fb_info.terminal_origin.x;
622cbc8e155SToomas Soome 	c_copy.e_row = c_copy.s_row + boot_fb_font.vf_height;
62329a77b73SToomas Soome 
624cbc8e155SToomas Soome 	c_copy.t_col = fb_info.cursor.origin.x + chars * boot_fb_font.vf_width;
62529a77b73SToomas Soome 	c_copy.t_row = fb_info.cursor.origin.y;
62629a77b73SToomas Soome 
62729a77b73SToomas Soome 	boot_fb_conscopy(&c_copy);
62829a77b73SToomas Soome }
62929a77b73SToomas Soome 
63029a77b73SToomas Soome /*
63129a77b73SToomas Soome  * move the terminal window lines [1..y] to [0..y-1] and clear last line.
63229a77b73SToomas Soome  */
63329a77b73SToomas Soome static void
63429a77b73SToomas Soome boot_fb_scroll(void)
63529a77b73SToomas Soome {
63629a77b73SToomas Soome 	struct vis_conscopy c_copy;
63729a77b73SToomas Soome 
63829a77b73SToomas Soome 	/* support for scrolling. set up the console copy data and last line */
639cbc8e155SToomas Soome 	c_copy.s_row = fb_info.terminal_origin.y + boot_fb_font.vf_height;
64029a77b73SToomas Soome 	c_copy.s_col = fb_info.terminal_origin.x;
64129a77b73SToomas Soome 	c_copy.e_row = fb_info.screen.y - fb_info.terminal_origin.y;
64229a77b73SToomas Soome 	c_copy.e_col = fb_info.screen.x - fb_info.terminal_origin.x;
64329a77b73SToomas Soome 	c_copy.t_row = fb_info.terminal_origin.y;
64429a77b73SToomas Soome 	c_copy.t_col = fb_info.terminal_origin.x;
64529a77b73SToomas Soome 
64629a77b73SToomas Soome 	boot_fb_conscopy(&c_copy);
64729a77b73SToomas Soome 
64829a77b73SToomas Soome 	/* now clean up the last line */
64929a77b73SToomas Soome 	boot_fb_eraseline_impl(fb_info.terminal_origin.x,
65029a77b73SToomas Soome 	    fb_info.terminal_origin.y +
651cbc8e155SToomas Soome 	    (fb_info.terminal.y - 1) * boot_fb_font.vf_height);
6528e6d016fSToomas Soome }
6538e6d016fSToomas Soome 
6548e6d016fSToomas Soome /*
6558e6d016fSToomas Soome  * Very simple block cursor. Save space below the cursor and restore
6568e6d016fSToomas Soome  * when cursor is invisible.
6578e6d016fSToomas Soome  */
6588e6d016fSToomas Soome void
6598e6d016fSToomas Soome boot_fb_cursor(boolean_t visible)
6608e6d016fSToomas Soome {
661cbc8e155SToomas Soome 	uint32_t offset, size, j;
6628e6d016fSToomas Soome 	uint32_t *fb32, *sfb32 = NULL;
6638e6d016fSToomas Soome 	uint32_t fg, bg;
6648e6d016fSToomas Soome 	uint16_t *fb16, *sfb16 = NULL;
6658e6d016fSToomas Soome 	uint8_t *fb8, *sfb8 = NULL;
6668e6d016fSToomas Soome 	int i, pitch;
6678e6d016fSToomas Soome 
6688e6d016fSToomas Soome 	if (fb_info.cursor.visible == visible)
6698e6d016fSToomas Soome 		return;
6708e6d016fSToomas Soome 
6718e6d016fSToomas Soome 	boot_get_color(&fg, &bg);
6728e6d016fSToomas Soome 	fg = boot_color_map(fg);
6738e6d016fSToomas Soome 	bg = boot_color_map(bg);
6748e6d016fSToomas Soome 
6758e6d016fSToomas Soome 	fb_info.cursor.visible = visible;
6768e6d016fSToomas Soome 	pitch = fb_info.pitch;
677cbc8e155SToomas Soome 	size = boot_fb_font.vf_width * fb_info.bpp;
6788e6d016fSToomas Soome 
6798e6d016fSToomas Soome 	/*
6808e6d016fSToomas Soome 	 * Build cursor image. We are building mirror image of data on
6818e6d016fSToomas Soome 	 * frame buffer by (D xor FG) xor BG.
6828e6d016fSToomas Soome 	 */
6838e6d016fSToomas Soome 	offset = fb_info.cursor.origin.x * fb_info.bpp +
6848e6d016fSToomas Soome 	    fb_info.cursor.origin.y * pitch;
6858e6d016fSToomas Soome 	switch (fb_info.depth) {
6868e6d016fSToomas Soome 	case 8:
687cbc8e155SToomas Soome 		for (i = 0; i < boot_fb_font.vf_height; i++) {
6888e6d016fSToomas Soome 			fb8 = fb_info.fb + offset + i * pitch;
6898e6d016fSToomas Soome 			if (fb_info.shadow_fb != NULL)
6908e6d016fSToomas Soome 				sfb8 = fb_info.shadow_fb + offset + i * pitch;
691cbc8e155SToomas Soome 			for (j = 0; j < size; j += 1) {
6928e6d016fSToomas Soome 				fb8[j] = (fb8[j] ^ (fg & 0xff)) ^ (bg & 0xff);
6938e6d016fSToomas Soome 
6948e6d016fSToomas Soome 				if (sfb8 == NULL)
6958e6d016fSToomas Soome 					continue;
6968e6d016fSToomas Soome 
6978e6d016fSToomas Soome 				sfb8[j] = (sfb8[j] ^ (fg & 0xff)) ^ (bg & 0xff);
6988e6d016fSToomas Soome 			}
6998e6d016fSToomas Soome 		}
7008e6d016fSToomas Soome 		break;
7018e6d016fSToomas Soome 	case 15:
7028e6d016fSToomas Soome 	case 16:
703cbc8e155SToomas Soome 		for (i = 0; i < boot_fb_font.vf_height; i++) {
7048e6d016fSToomas Soome 			fb16 = (uint16_t *)(fb_info.fb + offset + i * pitch);
7058e6d016fSToomas Soome 			if (fb_info.shadow_fb != NULL)
7068e6d016fSToomas Soome 				sfb16 = (uint16_t *)
7078e6d016fSToomas Soome 				    (fb_info.shadow_fb + offset + i * pitch);
708cbc8e155SToomas Soome 			for (j = 0; j < boot_fb_font.vf_width; j++) {
7098e6d016fSToomas Soome 				fb16[j] = (fb16[j] ^ (fg & 0xffff)) ^
7108e6d016fSToomas Soome 				    (bg & 0xffff);
7118e6d016fSToomas Soome 
7128e6d016fSToomas Soome 				if (sfb16 == NULL)
7138e6d016fSToomas Soome 					continue;
7148e6d016fSToomas Soome 
7158e6d016fSToomas Soome 				sfb16[j] = (sfb16[j] ^ (fg & 0xffff)) ^
7168e6d016fSToomas Soome 				    (bg & 0xffff);
7178e6d016fSToomas Soome 			}
7188e6d016fSToomas Soome 		}
7198e6d016fSToomas Soome 		break;
7208e6d016fSToomas Soome 	case 24:
721cbc8e155SToomas Soome 		for (i = 0; i < boot_fb_font.vf_height; i++) {
7228e6d016fSToomas Soome 			fb8 = fb_info.fb + offset + i * pitch;
7238e6d016fSToomas Soome 			if (fb_info.shadow_fb != NULL)
7248e6d016fSToomas Soome 				sfb8 = fb_info.shadow_fb + offset + i * pitch;
725cbc8e155SToomas Soome 			for (j = 0; j < size; j += 3) {
7268e6d016fSToomas Soome 				fb8[j] = (fb8[j] ^ ((fg >> 16) & 0xff)) ^
7278e6d016fSToomas Soome 				    ((bg >> 16) & 0xff);
7288e6d016fSToomas Soome 				fb8[j+1] = (fb8[j+1] ^ ((fg >> 8) & 0xff)) ^
7298e6d016fSToomas Soome 				    ((bg >> 8) & 0xff);
7308e6d016fSToomas Soome 				fb8[j+2] = (fb8[j+2] ^ (fg & 0xff)) ^
7318e6d016fSToomas Soome 				    (bg & 0xff);
7328e6d016fSToomas Soome 
7338e6d016fSToomas Soome 				if (sfb8 == NULL)
7348e6d016fSToomas Soome 					continue;
7358e6d016fSToomas Soome 
7368e6d016fSToomas Soome 				sfb8[j] = (sfb8[j] ^ ((fg >> 16) & 0xff)) ^
7378e6d016fSToomas Soome 				    ((bg >> 16) & 0xff);
7388e6d016fSToomas Soome 				sfb8[j+1] = (sfb8[j+1] ^ ((fg >> 8) & 0xff)) ^
7398e6d016fSToomas Soome 				    ((bg >> 8) & 0xff);
7408e6d016fSToomas Soome 				sfb8[j+2] = (sfb8[j+2] ^ (fg & 0xff)) ^
7418e6d016fSToomas Soome 				    (bg & 0xff);
7428e6d016fSToomas Soome 			}
7438e6d016fSToomas Soome 		}
7448e6d016fSToomas Soome 		break;
7458e6d016fSToomas Soome 	case 32:
746cbc8e155SToomas Soome 		for (i = 0; i < boot_fb_font.vf_height; i++) {
7478e6d016fSToomas Soome 			fb32 = (uint32_t *)(fb_info.fb + offset + i * pitch);
7488e6d016fSToomas Soome 			if (fb_info.shadow_fb != NULL) {
7498e6d016fSToomas Soome 				sfb32 = (uint32_t *)
7508e6d016fSToomas Soome 				    (fb_info.shadow_fb + offset + i * pitch);
7518e6d016fSToomas Soome 			}
752cbc8e155SToomas Soome 			for (j = 0; j < boot_fb_font.vf_width; j++) {
7538e6d016fSToomas Soome 				fb32[j] = (fb32[j] ^ fg) ^ bg;
7548e6d016fSToomas Soome 
7558e6d016fSToomas Soome 				if (sfb32 == NULL)
7568e6d016fSToomas Soome 					continue;
7578e6d016fSToomas Soome 
7588e6d016fSToomas Soome 				sfb32[j] = (sfb32[j] ^ fg) ^ bg;
7598e6d016fSToomas Soome 			}
7608e6d016fSToomas Soome 		}
7618e6d016fSToomas Soome 		break;
7628e6d016fSToomas Soome 	}
7638e6d016fSToomas Soome }
7648e6d016fSToomas Soome 
7658e6d016fSToomas Soome static void
76629a77b73SToomas Soome boot_fb_setpos(int row, int col)
7678e6d016fSToomas Soome {
76829a77b73SToomas Soome 	if (row < 0)
76929a77b73SToomas Soome 		row = 0;
77029a77b73SToomas Soome 	if (row >= fb_info.terminal.y)
77129a77b73SToomas Soome 		row = fb_info.terminal.y - 1;
77229a77b73SToomas Soome 	if (col < 0)
77329a77b73SToomas Soome 		col = 0;
77429a77b73SToomas Soome 	if (col >= fb_info.terminal.x)
77529a77b73SToomas Soome 		col = fb_info.terminal.x - 1;
77629a77b73SToomas Soome 
77729a77b73SToomas Soome 	fb_info.cursor.pos.x = col;
77829a77b73SToomas Soome 	fb_info.cursor.pos.y = row;
7798e6d016fSToomas Soome 	fb_info.cursor.origin.x = fb_info.terminal_origin.x;
780cbc8e155SToomas Soome 	fb_info.cursor.origin.x += col * boot_fb_font.vf_width;
78129a77b73SToomas Soome 	fb_info.cursor.origin.y = fb_info.terminal_origin.y;
782cbc8e155SToomas Soome 	fb_info.cursor.origin.y += row * boot_fb_font.vf_height;
7838e6d016fSToomas Soome }
7848e6d016fSToomas Soome 
7858e6d016fSToomas Soome static void
78629a77b73SToomas Soome boot_fb_putchar(int c)
7878e6d016fSToomas Soome {
7888e6d016fSToomas Soome 	struct vis_consdisplay display;
78929a77b73SToomas Soome 	int rows, cols;
79029a77b73SToomas Soome 
79129a77b73SToomas Soome 	rows = fb_info.cursor.pos.y;
79229a77b73SToomas Soome 	cols = fb_info.cursor.pos.x;
79329a77b73SToomas Soome 
79429a77b73SToomas Soome 	if (c == '\n') {
79529a77b73SToomas Soome 		if (rows < fb_info.terminal.y - 1)
79629a77b73SToomas Soome 			boot_fb_setpos(rows + 1, cols);
79729a77b73SToomas Soome 		else
79829a77b73SToomas Soome 			boot_fb_scroll();
7998e6d016fSToomas Soome 		return;
8008e6d016fSToomas Soome 	}
8018e6d016fSToomas Soome 
8028e6d016fSToomas Soome 	bit_to_pix(c);
8038e6d016fSToomas Soome 	display.col = fb_info.cursor.origin.x;
8048e6d016fSToomas Soome 	display.row = fb_info.cursor.origin.y;
805cbc8e155SToomas Soome 	display.width = boot_fb_font.vf_width;
806cbc8e155SToomas Soome 	display.height = boot_fb_font.vf_height;
8078e6d016fSToomas Soome 	display.data = glyph;
8088e6d016fSToomas Soome 
8098e6d016fSToomas Soome 	boot_fb_blit(&display);
81029a77b73SToomas Soome 	if (cols < fb_info.terminal.x - 1)
81129a77b73SToomas Soome 		boot_fb_setpos(rows, cols + 1);
81229a77b73SToomas Soome 	else if (rows < fb_info.terminal.y - 1)
81329a77b73SToomas Soome 		boot_fb_setpos(rows + 1, 0);
81429a77b73SToomas Soome 	else {
81529a77b73SToomas Soome 		boot_fb_setpos(rows, 0);
81629a77b73SToomas Soome 		boot_fb_scroll();
81729a77b73SToomas Soome 	}
8188e6d016fSToomas Soome }
819