boot_fb.c (8e6d016f) boot_fb.c (29a77b73)
1/*
2 * This file and its contents are supplied under the terms of the
3 * Common Development and Distribution License ("CDDL"), version 1.0.
4 * You may only use this file in accordance with the terms of version
5 * 1.0 of the CDDL.
6 *
7 * A full copy of the text of the CDDL should have accompanied this
8 * source. A copy of the CDDL is also available via the Internet at
9 * http://www.illumos.org/license/CDDL.
10 */
11
12/*
13 * Copyright 2016 Toomas Soome <tsoome@me.com>
14 */
15
16/*
17 * dboot and early kernel needs simple putchar(int) interface to implement
18 * printf() support. So we implement simple interface on top of
19 * linear frame buffer, since we can not use tem directly, we are
20 * just borrowing bits from it.
21 *
22 * Note, this implementation is assuming UEFI linear frame buffer and
23 * 32-bit depth, which should not be issue as GOP is supposed to provide those.
24 * At the time of writing, this is the only case for frame buffer anyhow.
25 */
26
27#include <sys/types.h>
28#include <sys/systm.h>
29#include <sys/multiboot2.h>
30#include <sys/framebuffer.h>
31#include <sys/bootinfo.h>
32#include <sys/boot_console.h>
33#include <sys/bootconf.h>
1/*
2 * This file and its contents are supplied under the terms of the
3 * Common Development and Distribution License ("CDDL"), version 1.0.
4 * You may only use this file in accordance with the terms of version
5 * 1.0 of the CDDL.
6 *
7 * A full copy of the text of the CDDL should have accompanied this
8 * source. A copy of the CDDL is also available via the Internet at
9 * http://www.illumos.org/license/CDDL.
10 */
11
12/*
13 * Copyright 2016 Toomas Soome <tsoome@me.com>
14 */
15
16/*
17 * dboot and early kernel needs simple putchar(int) interface to implement
18 * printf() support. So we implement simple interface on top of
19 * linear frame buffer, since we can not use tem directly, we are
20 * just borrowing bits from it.
21 *
22 * Note, this implementation is assuming UEFI linear frame buffer and
23 * 32-bit depth, which should not be issue as GOP is supposed to provide those.
24 * At the time of writing, this is the only case for frame buffer anyhow.
25 */
26
27#include <sys/types.h>
28#include <sys/systm.h>
29#include <sys/multiboot2.h>
30#include <sys/framebuffer.h>
31#include <sys/bootinfo.h>
32#include <sys/boot_console.h>
33#include <sys/bootconf.h>
34#include "boot_console_impl.h"
34
35#define P2ROUNDUP(x, align) (-(-(x) & -(align)))
36#define MIN(a, b) ((a) < (b) ? (a) : (b))
37
38/*
39 * Simplified visual_io data structures from visual_io.h
40 */
41
42struct vis_consdisplay {
43 uint16_t row; /* Row to display data at */
44 uint16_t col; /* Col to display data at */
45 uint16_t width; /* Width of data */
46 uint16_t height; /* Height of data */
47 uint8_t *data; /* Data to display */
48};
49
50struct vis_conscopy {
51 uint16_t s_row; /* Starting row */
52 uint16_t s_col; /* Starting col */
53 uint16_t e_row; /* Ending row */
54 uint16_t e_col; /* Ending col */
55 uint16_t t_row; /* Row to move to */
56 uint16_t t_col; /* Col to move to */
57};
58
59/* we have built in fonts 12x22, 6x10, 7x14 and depth 32. */
60#define MAX_GLYPH (12 * 22 * 4)
61
62static struct font boot_fb_font; /* set by set_font() */
63static uint8_t glyph[MAX_GLYPH];
35
36#define P2ROUNDUP(x, align) (-(-(x) & -(align)))
37#define MIN(a, b) ((a) < (b) ? (a) : (b))
38
39/*
40 * Simplified visual_io data structures from visual_io.h
41 */
42
43struct vis_consdisplay {
44 uint16_t row; /* Row to display data at */
45 uint16_t col; /* Col to display data at */
46 uint16_t width; /* Width of data */
47 uint16_t height; /* Height of data */
48 uint8_t *data; /* Data to display */
49};
50
51struct vis_conscopy {
52 uint16_t s_row; /* Starting row */
53 uint16_t s_col; /* Starting col */
54 uint16_t e_row; /* Ending row */
55 uint16_t e_col; /* Ending col */
56 uint16_t t_row; /* Row to move to */
57 uint16_t t_col; /* Col to move to */
58};
59
60/* we have built in fonts 12x22, 6x10, 7x14 and depth 32. */
61#define MAX_GLYPH (12 * 22 * 4)
62
63static struct font boot_fb_font; /* set by set_font() */
64static uint8_t glyph[MAX_GLYPH];
64static uint32_t last_line_size;
65static fb_info_pixel_coord_t last_line;
66
67/* color translation */
68typedef struct {
69 uint8_t red[16];
70 uint8_t green[16];
71 uint8_t blue[16];
72} text_cmap_t;
73
74/* BEGIN CSTYLED */
75/* Bk Rd Gr Br Bl Mg Cy Wh */
76static uint8_t dim_xlate[] = { 1, 5, 3, 7, 2, 6, 4, 8 };
77static uint8_t brt_xlate[] = { 9, 13, 11, 15, 10, 14, 12, 0 };
78/* END CSTYLED */
79
80static text_cmap_t cmap4_to_24 = {
81/* BEGIN CSTYLED */
82/* 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
83 Wh+ Bk Bl Gr Cy Rd Mg Br Wh Bk+ Bl+ Gr+ Cy+ Rd+ Mg+ Yw */
84 0xff,0x00,0x00,0x00,0x00,0x80,0x80,0x80,0x80,0x40,0x00,0x00,0x00,0xff,0xff,0xff,
85 0xff,0x00,0x00,0x80,0x80,0x00,0x00,0x80,0x80,0x40,0x00,0xff,0xff,0x00,0x00,0xff,
86 0xff,0x00,0x80,0x00,0x80,0x00,0x80,0x00,0x80,0x40,0xff,0x00,0xff,0x00,0xff,0x00
87/* END CSTYLED */
88};
89
65
66/* color translation */
67typedef struct {
68 uint8_t red[16];
69 uint8_t green[16];
70 uint8_t blue[16];
71} text_cmap_t;
72
73/* BEGIN CSTYLED */
74/* Bk Rd Gr Br Bl Mg Cy Wh */
75static uint8_t dim_xlate[] = { 1, 5, 3, 7, 2, 6, 4, 8 };
76static uint8_t brt_xlate[] = { 9, 13, 11, 15, 10, 14, 12, 0 };
77/* END CSTYLED */
78
79static text_cmap_t cmap4_to_24 = {
80/* BEGIN CSTYLED */
81/* 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
82 Wh+ Bk Bl Gr Cy Rd Mg Br Wh Bk+ Bl+ Gr+ Cy+ Rd+ Mg+ Yw */
83 0xff,0x00,0x00,0x00,0x00,0x80,0x80,0x80,0x80,0x40,0x00,0x00,0x00,0xff,0xff,0xff,
84 0xff,0x00,0x00,0x80,0x80,0x00,0x00,0x80,0x80,0x40,0x00,0xff,0xff,0x00,0x00,0xff,
85 0xff,0x00,0x80,0x00,0x80,0x00,0x80,0x00,0x80,0x40,0xff,0x00,0xff,0x00,0xff,0x00
86/* END CSTYLED */
87};
88
89static void boot_fb_putchar(int);
90static void boot_fb_eraseline(void);
91static void boot_fb_setpos(int, int);
92static void boot_fb_shiftline(int);
93static void boot_fb_eraseline_impl(uint16_t, uint16_t);
94
90/*
91 * extract data from MB2 framebuffer tag and set up initial frame buffer.
92 */
93boolean_t
95/*
96 * extract data from MB2 framebuffer tag and set up initial frame buffer.
97 */
98boolean_t
94xbi_fb_init(struct xboot_info *xbi)
99xbi_fb_init(struct xboot_info *xbi, bcons_dev_t *bcons_dev)
95{
96 multiboot_tag_framebuffer_t *tag;
97 boot_framebuffer_t *xbi_fb;
98
99 xbi_fb = (boot_framebuffer_t *)(uintptr_t)xbi->bi_framebuffer;
100 if (xbi_fb == NULL)
101 return (B_FALSE);
102
103#if !defined(_BOOT)
104 /* For early kernel, we get cursor position from dboot. */
105 fb_info.cursor.origin.x = xbi_fb->cursor.origin.x;
106 fb_info.cursor.origin.y = xbi_fb->cursor.origin.y;
107 fb_info.cursor.pos.x = xbi_fb->cursor.pos.x;
108 fb_info.cursor.pos.y = xbi_fb->cursor.pos.y;
109 fb_info.cursor.visible = xbi_fb->cursor.visible;
110#endif
111
112 tag = (multiboot_tag_framebuffer_t *)(uintptr_t)xbi_fb->framebuffer;
113 if (tag == NULL) {
114 return (B_FALSE);
115 }
116
117 fb_info.paddr = tag->framebuffer_common.framebuffer_addr;
118 fb_info.pitch = tag->framebuffer_common.framebuffer_pitch;
119 fb_info.depth = tag->framebuffer_common.framebuffer_bpp;
120 fb_info.bpp = P2ROUNDUP(fb_info.depth, 8) >> 3;
121 fb_info.screen.x = tag->framebuffer_common.framebuffer_width;
122 fb_info.screen.y = tag->framebuffer_common.framebuffer_height;
123 fb_info.fb_size = fb_info.screen.y * fb_info.pitch;
124
100{
101 multiboot_tag_framebuffer_t *tag;
102 boot_framebuffer_t *xbi_fb;
103
104 xbi_fb = (boot_framebuffer_t *)(uintptr_t)xbi->bi_framebuffer;
105 if (xbi_fb == NULL)
106 return (B_FALSE);
107
108#if !defined(_BOOT)
109 /* For early kernel, we get cursor position from dboot. */
110 fb_info.cursor.origin.x = xbi_fb->cursor.origin.x;
111 fb_info.cursor.origin.y = xbi_fb->cursor.origin.y;
112 fb_info.cursor.pos.x = xbi_fb->cursor.pos.x;
113 fb_info.cursor.pos.y = xbi_fb->cursor.pos.y;
114 fb_info.cursor.visible = xbi_fb->cursor.visible;
115#endif
116
117 tag = (multiboot_tag_framebuffer_t *)(uintptr_t)xbi_fb->framebuffer;
118 if (tag == NULL) {
119 return (B_FALSE);
120 }
121
122 fb_info.paddr = tag->framebuffer_common.framebuffer_addr;
123 fb_info.pitch = tag->framebuffer_common.framebuffer_pitch;
124 fb_info.depth = tag->framebuffer_common.framebuffer_bpp;
125 fb_info.bpp = P2ROUNDUP(fb_info.depth, 8) >> 3;
126 fb_info.screen.x = tag->framebuffer_common.framebuffer_width;
127 fb_info.screen.y = tag->framebuffer_common.framebuffer_height;
128 fb_info.fb_size = fb_info.screen.y * fb_info.pitch;
129
130 bcons_dev->bd_putchar = boot_fb_putchar;
131 bcons_dev->bd_eraseline = boot_fb_eraseline;
132 bcons_dev->bd_cursor = boot_fb_cursor;
133 bcons_dev->bd_setpos = boot_fb_setpos;
134 bcons_dev->bd_shift = boot_fb_shiftline;
135
125 if (fb_info.paddr == 0)
126 fb_info.fb_type = FB_TYPE_UNKNOWN;
127
128 switch (tag->framebuffer_common.framebuffer_type) {
129 case MULTIBOOT_FRAMEBUFFER_TYPE_EGA_TEXT:
130 fb_info.fb_type = FB_TYPE_EGA_TEXT;
131 return (B_FALSE);
132
133 case MULTIBOOT_FRAMEBUFFER_TYPE_INDEXED:
134 if (fb_info.paddr != 0)
135 fb_info.fb_type = FB_TYPE_INDEXED;
136 return (B_TRUE);
137
138 case MULTIBOOT_FRAMEBUFFER_TYPE_RGB:
139 if (fb_info.paddr != 0)
140 fb_info.fb_type = FB_TYPE_RGB;
141 break;
142
143 default:
144 return (B_FALSE);
145 }
146
147 fb_info.rgb.red.size = tag->u.fb2.framebuffer_red_mask_size;
148 fb_info.rgb.red.pos = tag->u.fb2.framebuffer_red_field_position;
149 fb_info.rgb.green.size = tag->u.fb2.framebuffer_green_mask_size;
150 fb_info.rgb.green.pos = tag->u.fb2.framebuffer_green_field_position;
151 fb_info.rgb.blue.size = tag->u.fb2.framebuffer_blue_mask_size;
152 fb_info.rgb.blue.pos = tag->u.fb2.framebuffer_blue_field_position;
153
154 return (B_TRUE);
155}
156
157/* set font and pass the data to fb_info */
158static void
159boot_fb_set_font(uint16_t height, uint16_t width)
160{
161 short h, w;
162
163 h = MIN(height, 4096);
164 w = MIN(width, 4096);
165
166 set_font(&boot_fb_font, (short *)&fb_info.terminal.y,
167 (short *)&fb_info.terminal.x, h, w);
168 fb_info.font_width = boot_fb_font.width;
169 fb_info.font_height = boot_fb_font.height;
170}
171
172/* fill framebuffer */
173static void
174boot_fb_fill(uint8_t *dst, uint32_t data, uint32_t len)
175{
176 uint16_t *dst16;
177 uint32_t *dst32;
178 uint32_t i;
179
180 switch (fb_info.depth) {
181 case 24:
182 case 8:
183 for (i = 0; i < len; i++)
184 dst[i] = (uint8_t)data;
185 break;
186 case 15:
187 case 16:
188 dst16 = (uint16_t *)dst;
189 len /= 2;
136 if (fb_info.paddr == 0)
137 fb_info.fb_type = FB_TYPE_UNKNOWN;
138
139 switch (tag->framebuffer_common.framebuffer_type) {
140 case MULTIBOOT_FRAMEBUFFER_TYPE_EGA_TEXT:
141 fb_info.fb_type = FB_TYPE_EGA_TEXT;
142 return (B_FALSE);
143
144 case MULTIBOOT_FRAMEBUFFER_TYPE_INDEXED:
145 if (fb_info.paddr != 0)
146 fb_info.fb_type = FB_TYPE_INDEXED;
147 return (B_TRUE);
148
149 case MULTIBOOT_FRAMEBUFFER_TYPE_RGB:
150 if (fb_info.paddr != 0)
151 fb_info.fb_type = FB_TYPE_RGB;
152 break;
153
154 default:
155 return (B_FALSE);
156 }
157
158 fb_info.rgb.red.size = tag->u.fb2.framebuffer_red_mask_size;
159 fb_info.rgb.red.pos = tag->u.fb2.framebuffer_red_field_position;
160 fb_info.rgb.green.size = tag->u.fb2.framebuffer_green_mask_size;
161 fb_info.rgb.green.pos = tag->u.fb2.framebuffer_green_field_position;
162 fb_info.rgb.blue.size = tag->u.fb2.framebuffer_blue_mask_size;
163 fb_info.rgb.blue.pos = tag->u.fb2.framebuffer_blue_field_position;
164
165 return (B_TRUE);
166}
167
168/* set font and pass the data to fb_info */
169static void
170boot_fb_set_font(uint16_t height, uint16_t width)
171{
172 short h, w;
173
174 h = MIN(height, 4096);
175 w = MIN(width, 4096);
176
177 set_font(&boot_fb_font, (short *)&fb_info.terminal.y,
178 (short *)&fb_info.terminal.x, h, w);
179 fb_info.font_width = boot_fb_font.width;
180 fb_info.font_height = boot_fb_font.height;
181}
182
183/* fill framebuffer */
184static void
185boot_fb_fill(uint8_t *dst, uint32_t data, uint32_t len)
186{
187 uint16_t *dst16;
188 uint32_t *dst32;
189 uint32_t i;
190
191 switch (fb_info.depth) {
192 case 24:
193 case 8:
194 for (i = 0; i < len; i++)
195 dst[i] = (uint8_t)data;
196 break;
197 case 15:
198 case 16:
199 dst16 = (uint16_t *)dst;
200 len /= 2;
190 for (i = 0; i < len; i++) {
201 for (i = 0; i < len; i++)
191 dst16[i] = (uint16_t)data;
202 dst16[i] = (uint16_t)data;
192 }
193 break;
194 case 32:
195 dst32 = (uint32_t *)dst;
196 len /= 4;
203 break;
204 case 32:
205 dst32 = (uint32_t *)dst;
206 len /= 4;
197 for (i = 0; i < len; i++) {
207 for (i = 0; i < len; i++)
198 dst32[i] = data;
208 dst32[i] = data;
199 }
200 break;
201 }
202}
203
204/* copy data to framebuffer */
205static void
206boot_fb_cpy(uint8_t *dst, uint8_t *src, uint32_t len)
207{
208 uint16_t *dst16, *src16;
209 uint32_t *dst32, *src32;
209 break;
210 }
211}
212
213/* copy data to framebuffer */
214static void
215boot_fb_cpy(uint8_t *dst, uint8_t *src, uint32_t len)
216{
217 uint16_t *dst16, *src16;
218 uint32_t *dst32, *src32;
210 uint32_t i;
211
212 switch (fb_info.depth) {
213 case 24:
214 case 8:
219
220 switch (fb_info.depth) {
221 case 24:
222 case 8:
215 for (i = 0; i < len; i++)
216 dst[i] = src[i];
223 default:
224 if (dst <= src) {
225 do {
226 *dst++ = *src++;
227 } while (--len != 0);
228 } else {
229 dst += len;
230 src += len;
231 do {
232 *--dst = *--src;
233 } while (--len != 0);
234 }
217 break;
218 case 15:
219 case 16:
220 dst16 = (uint16_t *)dst;
221 src16 = (uint16_t *)src;
235 break;
236 case 15:
237 case 16:
238 dst16 = (uint16_t *)dst;
239 src16 = (uint16_t *)src;
222 for (i = 0; i < len >> 1; i++) {
223 dst16[i] = src16[i];
240 len /= 2;
241 if (dst16 <= src16) {
242 do {
243 *dst16++ = *src16++;
244 } while (--len != 0);
245 } else {
246 dst16 += len;
247 src16 += len;
248 do {
249 *--dst16 = *--src16;
250 } while (--len != 0);
224 }
225 break;
226 case 32:
227 dst32 = (uint32_t *)dst;
228 src32 = (uint32_t *)src;
251 }
252 break;
253 case 32:
254 dst32 = (uint32_t *)dst;
255 src32 = (uint32_t *)src;
229 for (i = 0; i < len >> 2; i++) {
230 dst32[i] = src32[i];
256 len /= 4;
257 if (dst32 <= src32) {
258 do {
259 *dst32++ = *src32++;
260 } while (--len != 0);
261 } else {
262 dst32 += len;
263 src32 += len;
264 do {
265 *--dst32 = *--src32;
266 } while (--len != 0);
231 }
232 break;
233 }
234}
235
236/*
237 * Allocate shadow frame buffer, called from fakebop.c when early boot
238 * allocator is ready.
239 */
240void
241boot_fb_shadow_init(bootops_t *bops)
242{
243 if (boot_console_type(NULL) != CONS_FRAMEBUFFER)
244 return; /* nothing to do */
245
246 fb_info.shadow_fb = (uint8_t *)bops->bsys_alloc(NULL, NULL,
247 fb_info.fb_size, MMU_PAGESIZE);
248
249 if (fb_info.shadow_fb == NULL)
250 return;
251
252 /* Copy FB to shadow */
253 boot_fb_cpy(fb_info.shadow_fb, fb_info.fb, fb_info.fb_size);
254}
255
256/*
257 * Translate ansi color based on inverses and brightness.
258 */
267 }
268 break;
269 }
270}
271
272/*
273 * Allocate shadow frame buffer, called from fakebop.c when early boot
274 * allocator is ready.
275 */
276void
277boot_fb_shadow_init(bootops_t *bops)
278{
279 if (boot_console_type(NULL) != CONS_FRAMEBUFFER)
280 return; /* nothing to do */
281
282 fb_info.shadow_fb = (uint8_t *)bops->bsys_alloc(NULL, NULL,
283 fb_info.fb_size, MMU_PAGESIZE);
284
285 if (fb_info.shadow_fb == NULL)
286 return;
287
288 /* Copy FB to shadow */
289 boot_fb_cpy(fb_info.shadow_fb, fb_info.fb, fb_info.fb_size);
290}
291
292/*
293 * Translate ansi color based on inverses and brightness.
294 */
259static void
295void
260boot_get_color(uint32_t *fg, uint32_t *bg)
261{
262 /* ansi to solaris colors, see also boot_console.c */
263 if (fb_info.inverse == B_TRUE ||
264 fb_info.inverse_screen == B_TRUE) {
265 *bg = dim_xlate[fb_info.fg_color];
266 *fg = brt_xlate[fb_info.bg_color];
267 } else {
268 if (fb_info.bg_color == 7)
269 *bg = brt_xlate[fb_info.bg_color];
270 else
271 *bg = dim_xlate[fb_info.bg_color];
272 *fg = dim_xlate[fb_info.fg_color];
273 }
274}
275
276/*
277 * Map indexed color to RGB value.
278 */
279static uint32_t
280boot_color_map(uint8_t index)
281{
282 uint8_t c;
283 int pos, size;
284 uint32_t color;
285
286 /* 8bit depth is for indexed colors */
287 if (fb_info.depth == 8)
288 return (index);
289
290 if (index >= sizeof (cmap4_to_24.red))
291 index = 0;
292
293 c = cmap4_to_24.red[index];
294 pos = fb_info.rgb.red.pos;
295 size = fb_info.rgb.red.size;
296 color = ((c >> 8 - size) & ((1 << size) - 1)) << pos;
297
298 c = cmap4_to_24.green[index];
299 pos = fb_info.rgb.green.pos;
300 size = fb_info.rgb.green.size;
301 color |= ((c >> 8 - size) & ((1 << size) - 1)) << pos;
302
303 c = cmap4_to_24.blue[index];
304 pos = fb_info.rgb.blue.pos;
305 size = fb_info.rgb.blue.size;
306 color |= ((c >> 8 - size) & ((1 << size) - 1)) << pos;
307
308 return (color);
309}
310
311/* set up out simple console. */
312/*ARGSUSED*/
313void
314boot_fb_init(int console)
315{
316 fb_info_pixel_coord_t window;
317
318 /* frame buffer address is mapped in dboot. */
319 fb_info.fb = (uint8_t *)(uintptr_t)fb_info.paddr;
320
321 boot_fb_set_font(fb_info.screen.y, fb_info.screen.x);
322 window.x =
323 (fb_info.screen.x - fb_info.terminal.x * boot_fb_font.width) / 2;
324 window.y =
325 (fb_info.screen.y - fb_info.terminal.y * boot_fb_font.height) / 2;
326 fb_info.terminal_origin.x = window.x;
327 fb_info.terminal_origin.y = window.y;
328
329#if defined(_BOOT)
330 /*
331 * Being called from dboot, we can have cursor terminal
332 * position passed from boot loader. In such case, fix the
333 * cursor screen coords.
334 */
335 if (fb_info.cursor.pos.x != 0 || fb_info.cursor.pos.y != 0) {
336 fb_info.cursor.origin.x = window.x +
337 fb_info.cursor.pos.x * boot_fb_font.width;
338 fb_info.cursor.origin.y = window.y +
339 fb_info.cursor.pos.y * boot_fb_font.height;
340 }
341#endif
342
343 /* If the cursor terminal position is 0,0 just reset screen coords */
344 if (fb_info.cursor.pos.x == 0 && fb_info.cursor.pos.y == 0) {
345 fb_info.cursor.origin.x = window.x;
346 fb_info.cursor.origin.y = window.y;
347 }
348
349 /*
350 * Validate cursor coords with screen/terminal dimensions,
351 * if anything is off, reset to 0,0
352 */
353 if (fb_info.cursor.pos.x > fb_info.terminal.x ||
354 fb_info.cursor.pos.y > fb_info.terminal.y ||
355 fb_info.cursor.origin.x > fb_info.screen.x ||
356 fb_info.cursor.origin.y > fb_info.screen.y) {
357
358 fb_info.cursor.origin.x = window.x;
359 fb_info.cursor.origin.y = window.y;
360 fb_info.cursor.pos.x = 0;
361 fb_info.cursor.pos.y = 0;
362 }
363
364#if defined(_BOOT)
365 /* clear the screen if cursor is set to 0,0 */
296boot_get_color(uint32_t *fg, uint32_t *bg)
297{
298 /* ansi to solaris colors, see also boot_console.c */
299 if (fb_info.inverse == B_TRUE ||
300 fb_info.inverse_screen == B_TRUE) {
301 *bg = dim_xlate[fb_info.fg_color];
302 *fg = brt_xlate[fb_info.bg_color];
303 } else {
304 if (fb_info.bg_color == 7)
305 *bg = brt_xlate[fb_info.bg_color];
306 else
307 *bg = dim_xlate[fb_info.bg_color];
308 *fg = dim_xlate[fb_info.fg_color];
309 }
310}
311
312/*
313 * Map indexed color to RGB value.
314 */
315static uint32_t
316boot_color_map(uint8_t index)
317{
318 uint8_t c;
319 int pos, size;
320 uint32_t color;
321
322 /* 8bit depth is for indexed colors */
323 if (fb_info.depth == 8)
324 return (index);
325
326 if (index >= sizeof (cmap4_to_24.red))
327 index = 0;
328
329 c = cmap4_to_24.red[index];
330 pos = fb_info.rgb.red.pos;
331 size = fb_info.rgb.red.size;
332 color = ((c >> 8 - size) & ((1 << size) - 1)) << pos;
333
334 c = cmap4_to_24.green[index];
335 pos = fb_info.rgb.green.pos;
336 size = fb_info.rgb.green.size;
337 color |= ((c >> 8 - size) & ((1 << size) - 1)) << pos;
338
339 c = cmap4_to_24.blue[index];
340 pos = fb_info.rgb.blue.pos;
341 size = fb_info.rgb.blue.size;
342 color |= ((c >> 8 - size) & ((1 << size) - 1)) << pos;
343
344 return (color);
345}
346
347/* set up out simple console. */
348/*ARGSUSED*/
349void
350boot_fb_init(int console)
351{
352 fb_info_pixel_coord_t window;
353
354 /* frame buffer address is mapped in dboot. */
355 fb_info.fb = (uint8_t *)(uintptr_t)fb_info.paddr;
356
357 boot_fb_set_font(fb_info.screen.y, fb_info.screen.x);
358 window.x =
359 (fb_info.screen.x - fb_info.terminal.x * boot_fb_font.width) / 2;
360 window.y =
361 (fb_info.screen.y - fb_info.terminal.y * boot_fb_font.height) / 2;
362 fb_info.terminal_origin.x = window.x;
363 fb_info.terminal_origin.y = window.y;
364
365#if defined(_BOOT)
366 /*
367 * Being called from dboot, we can have cursor terminal
368 * position passed from boot loader. In such case, fix the
369 * cursor screen coords.
370 */
371 if (fb_info.cursor.pos.x != 0 || fb_info.cursor.pos.y != 0) {
372 fb_info.cursor.origin.x = window.x +
373 fb_info.cursor.pos.x * boot_fb_font.width;
374 fb_info.cursor.origin.y = window.y +
375 fb_info.cursor.pos.y * boot_fb_font.height;
376 }
377#endif
378
379 /* If the cursor terminal position is 0,0 just reset screen coords */
380 if (fb_info.cursor.pos.x == 0 && fb_info.cursor.pos.y == 0) {
381 fb_info.cursor.origin.x = window.x;
382 fb_info.cursor.origin.y = window.y;
383 }
384
385 /*
386 * Validate cursor coords with screen/terminal dimensions,
387 * if anything is off, reset to 0,0
388 */
389 if (fb_info.cursor.pos.x > fb_info.terminal.x ||
390 fb_info.cursor.pos.y > fb_info.terminal.y ||
391 fb_info.cursor.origin.x > fb_info.screen.x ||
392 fb_info.cursor.origin.y > fb_info.screen.y) {
393
394 fb_info.cursor.origin.x = window.x;
395 fb_info.cursor.origin.y = window.y;
396 fb_info.cursor.pos.x = 0;
397 fb_info.cursor.pos.y = 0;
398 }
399
400#if defined(_BOOT)
401 /* clear the screen if cursor is set to 0,0 */
366 fb_info.cursor.pos.x = fb_info.cursor.pos.y = 0;
367 if (console == CONS_FRAMEBUFFER &&
368 fb_info.cursor.pos.x == 0 && fb_info.cursor.pos.y == 0) {
369 uint32_t fg, bg;
370 int i;
402 if (fb_info.cursor.pos.x == 0 && fb_info.cursor.pos.y == 0) {
403 uint32_t fg, bg, toffset;
404 uint16_t y;
371
372 boot_get_color(&fg, &bg);
373 bg = boot_color_map(bg);
374
405
406 boot_get_color(&fg, &bg);
407 bg = boot_color_map(bg);
408
375 for (i = 0; i < fb_info.screen.y; i++) {
376 uint8_t *dest = fb_info.fb + i * fb_info.pitch;
409 toffset = 0;
410 for (y = 0; y < fb_info.screen.y; y++) {
411 uint8_t *dest = fb_info.fb + toffset;
412
377 boot_fb_fill(dest, bg, fb_info.pitch);
413 boot_fb_fill(dest, bg, fb_info.pitch);
414 toffset += fb_info.pitch;
378 }
379 }
380#endif
415 }
416 }
417#endif
381 /* set up pre-calculated last line */
382 last_line_size = fb_info.terminal.x * boot_fb_font.width *
383 fb_info.bpp;
384 last_line.x = window.x;
385 last_line.y = window.y + (fb_info.terminal.y - 1) * boot_fb_font.height;
386
387}
388
389/* copy rectangle to framebuffer. */
390static void
391boot_fb_blit(struct vis_consdisplay *rect)
392{
418}
419
420/* copy rectangle to framebuffer. */
421static void
422boot_fb_blit(struct vis_consdisplay *rect)
423{
393 uint32_t size; /* write size per scanline */
394 uint8_t *fbp, *sfbp; /* fb + calculated offset */
424 uint32_t offset, size; /* write size per scanline */
425 uint8_t *fbp, *sfbp = NULL; /* fb + calculated offset */
395 int i;
396
397 /* make sure we will not write past FB */
398 if (rect->col >= fb_info.screen.x ||
399 rect->row >= fb_info.screen.y ||
400 rect->col + rect->width >= fb_info.screen.x ||
401 rect->row + rect->height >= fb_info.screen.y)
402 return;
403
404 size = rect->width * fb_info.bpp;
426 int i;
427
428 /* make sure we will not write past FB */
429 if (rect->col >= fb_info.screen.x ||
430 rect->row >= fb_info.screen.y ||
431 rect->col + rect->width >= fb_info.screen.x ||
432 rect->row + rect->height >= fb_info.screen.y)
433 return;
434
435 size = rect->width * fb_info.bpp;
405 fbp = fb_info.fb + rect->col * fb_info.bpp +
406 rect->row * fb_info.pitch;
407 if (fb_info.shadow_fb != NULL) {
408 sfbp = fb_info.shadow_fb + rect->col * fb_info.bpp +
409 rect->row * fb_info.pitch;
410 } else {
411 sfbp = NULL;
412 }
436 offset = rect->col * fb_info.bpp + rect->row * fb_info.pitch;
437 fbp = fb_info.fb + offset;
438 if (fb_info.shadow_fb != NULL)
439 sfbp = fb_info.shadow_fb + offset;
413
414 /* write all scanlines in rectangle */
415 for (i = 0; i < rect->height; i++) {
416 uint8_t *dest = fbp + i * fb_info.pitch;
417 uint8_t *src = rect->data + i * size;
418 boot_fb_cpy(dest, src, size);
419 if (sfbp != NULL) {
420 dest = sfbp + i * fb_info.pitch;
421 boot_fb_cpy(dest, src, size);
422 }
423 }
424}
425
426static void
427bit_to_pix(uchar_t c)
428{
429 uint32_t fg, bg;
430
431 boot_get_color(&fg, &bg);
432 fg = boot_color_map(fg);
433 bg = boot_color_map(bg);
434
435 switch (fb_info.depth) {
436 case 8:
437 font_bit_to_pix8(&boot_fb_font, (uint8_t *)glyph, c, fg, bg);
438 break;
439 case 15:
440 case 16:
441 font_bit_to_pix16(&boot_fb_font, (uint16_t *)glyph, c,
442 (uint16_t)fg, (uint16_t)bg);
443 break;
444 case 24:
445 font_bit_to_pix24(&boot_fb_font, (uint8_t *)glyph, c, fg, bg);
446 break;
447 case 32:
448 font_bit_to_pix32(&boot_fb_font, (uint32_t *)glyph, c, fg, bg);
449 break;
450 }
451}
452
440
441 /* write all scanlines in rectangle */
442 for (i = 0; i < rect->height; i++) {
443 uint8_t *dest = fbp + i * fb_info.pitch;
444 uint8_t *src = rect->data + i * size;
445 boot_fb_cpy(dest, src, size);
446 if (sfbp != NULL) {
447 dest = sfbp + i * fb_info.pitch;
448 boot_fb_cpy(dest, src, size);
449 }
450 }
451}
452
453static void
454bit_to_pix(uchar_t c)
455{
456 uint32_t fg, bg;
457
458 boot_get_color(&fg, &bg);
459 fg = boot_color_map(fg);
460 bg = boot_color_map(bg);
461
462 switch (fb_info.depth) {
463 case 8:
464 font_bit_to_pix8(&boot_fb_font, (uint8_t *)glyph, c, fg, bg);
465 break;
466 case 15:
467 case 16:
468 font_bit_to_pix16(&boot_fb_font, (uint16_t *)glyph, c,
469 (uint16_t)fg, (uint16_t)bg);
470 break;
471 case 24:
472 font_bit_to_pix24(&boot_fb_font, (uint8_t *)glyph, c, fg, bg);
473 break;
474 case 32:
475 font_bit_to_pix32(&boot_fb_font, (uint32_t *)glyph, c, fg, bg);
476 break;
477 }
478}
479
453/*
454 * move the terminal window lines [1..y] to [0..y-1] and clear last line.
455 */
456static void
480static void
457boot_fb_scroll(void)
481boot_fb_eraseline_impl(uint16_t x, uint16_t y)
458{
482{
459 struct vis_conscopy c_copy;
460 uint32_t soffset, toffset;
461 uint32_t width, height;
483 uint32_t toffset, size;
462 uint32_t fg, bg;
484 uint32_t fg, bg;
463 uint8_t *src, *dst, *sdst;
485 uint8_t *dst, *sdst;
464 int i;
465
466 boot_get_color(&fg, &bg);
467 bg = boot_color_map(bg);
468
486 int i;
487
488 boot_get_color(&fg, &bg);
489 bg = boot_color_map(bg);
490
469 /* support for scrolling. set up the console copy data and last line */
470 c_copy.s_row = fb_info.terminal_origin.y + boot_fb_font.height;
471 c_copy.s_col = fb_info.terminal_origin.x;
472 c_copy.e_row = fb_info.screen.y - fb_info.terminal_origin.y;
473 c_copy.e_col = fb_info.screen.x - fb_info.terminal_origin.x;
474 c_copy.t_row = fb_info.terminal_origin.y;
475 c_copy.t_col = fb_info.terminal_origin.x;
491 size = fb_info.terminal.x * boot_fb_font.width * fb_info.bpp;
476
492
477 soffset = c_copy.s_col * fb_info.bpp + c_copy.s_row * fb_info.pitch;
478 toffset = c_copy.t_col * fb_info.bpp + c_copy.t_row * fb_info.pitch;
493 toffset = x * fb_info.bpp + y * fb_info.pitch;
494 dst = fb_info.fb + toffset;
495 if (fb_info.shadow_fb != NULL)
496 sdst = fb_info.shadow_fb + toffset;
497
498 for (i = 0; i < boot_fb_font.height; i++) {
499 uint8_t *dest = dst + i * fb_info.pitch;
500 if (fb_info.fb + fb_info.fb_size >= dest + size)
501 boot_fb_fill(dest, bg, size);
502 if (fb_info.shadow_fb != NULL) {
503 dest = sdst + i * fb_info.pitch;
504 if (fb_info.shadow_fb + fb_info.fb_size >=
505 dest + size) {
506 boot_fb_fill(dest, bg, size);
507 }
508 }
509 }
510}
511
512static void
513boot_fb_eraseline(void)
514{
515 boot_fb_eraseline_impl(fb_info.cursor.origin.x,
516 fb_info.cursor.origin.y);
517}
518
519/*
520 * Copy rectangle from console to console.
521 * If shadow buffer is available, use shadow as source.
522 */
523static void
524boot_fb_conscopy(struct vis_conscopy *c_copy)
525{
526 uint32_t soffset, toffset;
527 uint32_t width, height, increment;
528 uint8_t *src, *dst, *sdst = NULL;
529 int i;
530
531 soffset = c_copy->s_col * fb_info.bpp + c_copy->s_row * fb_info.pitch;
532 toffset = c_copy->t_col * fb_info.bpp + c_copy->t_row * fb_info.pitch;
533
534 src = fb_info.fb + soffset;
535 dst = fb_info.fb + toffset;
536
479 if (fb_info.shadow_fb != NULL) {
480 src = fb_info.shadow_fb + soffset;
481 sdst = fb_info.shadow_fb + toffset;
537 if (fb_info.shadow_fb != NULL) {
538 src = fb_info.shadow_fb + soffset;
539 sdst = fb_info.shadow_fb + toffset;
482 } else {
483 src = fb_info.fb + soffset;
484 sdst = NULL;
485 }
540 }
486 dst = fb_info.fb + toffset;
487
541
488 width = (c_copy.e_col - c_copy.s_col + 1) * fb_info.bpp;
489 height = c_copy.e_row - c_copy.s_row + 1;
542 width = (c_copy->e_col - c_copy->s_col + 1) * fb_info.bpp;
543 height = c_copy->e_row - c_copy->s_row + 1;
544
490 for (i = 0; i < height; i++) {
545 for (i = 0; i < height; i++) {
491 uint32_t increment = i * fb_info.pitch;
546 increment = i * fb_info.pitch;
547
548 /* Make sure we fit into FB size. */
549 if (soffset + increment + width >= fb_info.fb_size ||
550 toffset + increment + width >= fb_info.fb_size)
551 break;
552
492 boot_fb_cpy(dst + increment, src + increment, width);
553 boot_fb_cpy(dst + increment, src + increment, width);
554
493 if (sdst != NULL)
494 boot_fb_cpy(sdst + increment, src + increment, width);
495 }
555 if (sdst != NULL)
556 boot_fb_cpy(sdst + increment, src + increment, width);
557 }
558}
496
559
497 /* now clean up the last line */
498 toffset = last_line.x * fb_info.bpp + last_line.y * fb_info.pitch;
499 dst = fb_info.fb + toffset;
500 if (fb_info.shadow_fb != NULL)
501 sdst = fb_info.shadow_fb + toffset;
560/* Shift the line content by chars. */
561static void
562boot_fb_shiftline(int chars)
563{
564 struct vis_conscopy c_copy;
502
565
503 for (i = 0; i < boot_fb_font.height; i++) {
504 uint8_t *dest = dst + i * fb_info.pitch;
505 if (fb_info.fb + fb_info.fb_size >= dest + last_line_size)
506 boot_fb_fill(dest, bg, last_line_size);
507 if (sdst != NULL) {
508 dest = sdst + i * fb_info.pitch;
509 if (fb_info.shadow_fb + fb_info.fb_size >=
510 dest + last_line_size) {
511 boot_fb_fill(dest, bg, last_line_size);
512 }
513 }
514 }
566 c_copy.s_col = fb_info.cursor.origin.x;
567 c_copy.s_row = fb_info.cursor.origin.y;
568
569 c_copy.e_col = (fb_info.terminal.x - chars) * boot_fb_font.width;
570 c_copy.e_col += fb_info.terminal_origin.x;
571 c_copy.e_row = c_copy.s_row + boot_fb_font.height;
572
573 c_copy.t_col = fb_info.cursor.origin.x + chars * boot_fb_font.width;
574 c_copy.t_row = fb_info.cursor.origin.y;
575
576 boot_fb_conscopy(&c_copy);
515}
516
517/*
577}
578
579/*
580 * move the terminal window lines [1..y] to [0..y-1] and clear last line.
581 */
582static void
583boot_fb_scroll(void)
584{
585 struct vis_conscopy c_copy;
586
587 /* support for scrolling. set up the console copy data and last line */
588 c_copy.s_row = fb_info.terminal_origin.y + boot_fb_font.height;
589 c_copy.s_col = fb_info.terminal_origin.x;
590 c_copy.e_row = fb_info.screen.y - fb_info.terminal_origin.y;
591 c_copy.e_col = fb_info.screen.x - fb_info.terminal_origin.x;
592 c_copy.t_row = fb_info.terminal_origin.y;
593 c_copy.t_col = fb_info.terminal_origin.x;
594
595 boot_fb_conscopy(&c_copy);
596
597 /* now clean up the last line */
598 boot_fb_eraseline_impl(fb_info.terminal_origin.x,
599 fb_info.terminal_origin.y +
600 (fb_info.terminal.y - 1) * boot_fb_font.height);
601}
602
603/*
518 * Very simple block cursor. Save space below the cursor and restore
519 * when cursor is invisible.
520 */
521void
522boot_fb_cursor(boolean_t visible)
523{
524 uint32_t offset, size;
525 uint32_t *fb32, *sfb32 = NULL;
526 uint32_t fg, bg;
527 uint16_t *fb16, *sfb16 = NULL;
528 uint8_t *fb8, *sfb8 = NULL;
529 int i, pitch;
530
531 if (fb_info.cursor.visible == visible)
532 return;
533
534 boot_get_color(&fg, &bg);
535 fg = boot_color_map(fg);
536 bg = boot_color_map(bg);
537
538 fb_info.cursor.visible = visible;
539 pitch = fb_info.pitch;
540 size = boot_fb_font.width * fb_info.bpp;
541
542 /*
543 * Build cursor image. We are building mirror image of data on
544 * frame buffer by (D xor FG) xor BG.
545 */
546 offset = fb_info.cursor.origin.x * fb_info.bpp +
547 fb_info.cursor.origin.y * pitch;
548 switch (fb_info.depth) {
549 case 8:
550 for (i = 0; i < boot_fb_font.height; i++) {
551 fb8 = fb_info.fb + offset + i * pitch;
552 if (fb_info.shadow_fb != NULL)
553 sfb8 = fb_info.shadow_fb + offset + i * pitch;
554 for (uint32_t j = 0; j < size; j += 1) {
555 fb8[j] = (fb8[j] ^ (fg & 0xff)) ^ (bg & 0xff);
556
557 if (sfb8 == NULL)
558 continue;
559
560 sfb8[j] = (sfb8[j] ^ (fg & 0xff)) ^ (bg & 0xff);
561 }
562 }
563 break;
564 case 15:
565 case 16:
566 for (i = 0; i < boot_fb_font.height; i++) {
567 fb16 = (uint16_t *)(fb_info.fb + offset + i * pitch);
568 if (fb_info.shadow_fb != NULL)
569 sfb16 = (uint16_t *)
570 (fb_info.shadow_fb + offset + i * pitch);
571 for (int j = 0; j < boot_fb_font.width; j++) {
572 fb16[j] = (fb16[j] ^ (fg & 0xffff)) ^
573 (bg & 0xffff);
574
575 if (sfb16 == NULL)
576 continue;
577
578 sfb16[j] = (sfb16[j] ^ (fg & 0xffff)) ^
579 (bg & 0xffff);
580 }
581 }
582 break;
583 case 24:
584 for (i = 0; i < boot_fb_font.height; i++) {
585 fb8 = fb_info.fb + offset + i * pitch;
586 if (fb_info.shadow_fb != NULL)
587 sfb8 = fb_info.shadow_fb + offset + i * pitch;
588 for (uint32_t j = 0; j < size; j += 3) {
589 fb8[j] = (fb8[j] ^ ((fg >> 16) & 0xff)) ^
590 ((bg >> 16) & 0xff);
591 fb8[j+1] = (fb8[j+1] ^ ((fg >> 8) & 0xff)) ^
592 ((bg >> 8) & 0xff);
593 fb8[j+2] = (fb8[j+2] ^ (fg & 0xff)) ^
594 (bg & 0xff);
595
596 if (sfb8 == NULL)
597 continue;
598
599 sfb8[j] = (sfb8[j] ^ ((fg >> 16) & 0xff)) ^
600 ((bg >> 16) & 0xff);
601 sfb8[j+1] = (sfb8[j+1] ^ ((fg >> 8) & 0xff)) ^
602 ((bg >> 8) & 0xff);
603 sfb8[j+2] = (sfb8[j+2] ^ (fg & 0xff)) ^
604 (bg & 0xff);
605 }
606 }
607 break;
608 case 32:
609 for (i = 0; i < boot_fb_font.height; i++) {
610 fb32 = (uint32_t *)(fb_info.fb + offset + i * pitch);
611 if (fb_info.shadow_fb != NULL) {
612 sfb32 = (uint32_t *)
613 (fb_info.shadow_fb + offset + i * pitch);
614 }
615 for (int j = 0; j < boot_fb_font.width; j++) {
616 fb32[j] = (fb32[j] ^ fg) ^ bg;
617
618 if (sfb32 == NULL)
619 continue;
620
621 sfb32[j] = (sfb32[j] ^ fg) ^ bg;
622 }
623 }
624 break;
625 }
626}
627
628static void
604 * Very simple block cursor. Save space below the cursor and restore
605 * when cursor is invisible.
606 */
607void
608boot_fb_cursor(boolean_t visible)
609{
610 uint32_t offset, size;
611 uint32_t *fb32, *sfb32 = NULL;
612 uint32_t fg, bg;
613 uint16_t *fb16, *sfb16 = NULL;
614 uint8_t *fb8, *sfb8 = NULL;
615 int i, pitch;
616
617 if (fb_info.cursor.visible == visible)
618 return;
619
620 boot_get_color(&fg, &bg);
621 fg = boot_color_map(fg);
622 bg = boot_color_map(bg);
623
624 fb_info.cursor.visible = visible;
625 pitch = fb_info.pitch;
626 size = boot_fb_font.width * fb_info.bpp;
627
628 /*
629 * Build cursor image. We are building mirror image of data on
630 * frame buffer by (D xor FG) xor BG.
631 */
632 offset = fb_info.cursor.origin.x * fb_info.bpp +
633 fb_info.cursor.origin.y * pitch;
634 switch (fb_info.depth) {
635 case 8:
636 for (i = 0; i < boot_fb_font.height; i++) {
637 fb8 = fb_info.fb + offset + i * pitch;
638 if (fb_info.shadow_fb != NULL)
639 sfb8 = fb_info.shadow_fb + offset + i * pitch;
640 for (uint32_t j = 0; j < size; j += 1) {
641 fb8[j] = (fb8[j] ^ (fg & 0xff)) ^ (bg & 0xff);
642
643 if (sfb8 == NULL)
644 continue;
645
646 sfb8[j] = (sfb8[j] ^ (fg & 0xff)) ^ (bg & 0xff);
647 }
648 }
649 break;
650 case 15:
651 case 16:
652 for (i = 0; i < boot_fb_font.height; i++) {
653 fb16 = (uint16_t *)(fb_info.fb + offset + i * pitch);
654 if (fb_info.shadow_fb != NULL)
655 sfb16 = (uint16_t *)
656 (fb_info.shadow_fb + offset + i * pitch);
657 for (int j = 0; j < boot_fb_font.width; j++) {
658 fb16[j] = (fb16[j] ^ (fg & 0xffff)) ^
659 (bg & 0xffff);
660
661 if (sfb16 == NULL)
662 continue;
663
664 sfb16[j] = (sfb16[j] ^ (fg & 0xffff)) ^
665 (bg & 0xffff);
666 }
667 }
668 break;
669 case 24:
670 for (i = 0; i < boot_fb_font.height; i++) {
671 fb8 = fb_info.fb + offset + i * pitch;
672 if (fb_info.shadow_fb != NULL)
673 sfb8 = fb_info.shadow_fb + offset + i * pitch;
674 for (uint32_t j = 0; j < size; j += 3) {
675 fb8[j] = (fb8[j] ^ ((fg >> 16) & 0xff)) ^
676 ((bg >> 16) & 0xff);
677 fb8[j+1] = (fb8[j+1] ^ ((fg >> 8) & 0xff)) ^
678 ((bg >> 8) & 0xff);
679 fb8[j+2] = (fb8[j+2] ^ (fg & 0xff)) ^
680 (bg & 0xff);
681
682 if (sfb8 == NULL)
683 continue;
684
685 sfb8[j] = (sfb8[j] ^ ((fg >> 16) & 0xff)) ^
686 ((bg >> 16) & 0xff);
687 sfb8[j+1] = (sfb8[j+1] ^ ((fg >> 8) & 0xff)) ^
688 ((bg >> 8) & 0xff);
689 sfb8[j+2] = (sfb8[j+2] ^ (fg & 0xff)) ^
690 (bg & 0xff);
691 }
692 }
693 break;
694 case 32:
695 for (i = 0; i < boot_fb_font.height; i++) {
696 fb32 = (uint32_t *)(fb_info.fb + offset + i * pitch);
697 if (fb_info.shadow_fb != NULL) {
698 sfb32 = (uint32_t *)
699 (fb_info.shadow_fb + offset + i * pitch);
700 }
701 for (int j = 0; j < boot_fb_font.width; j++) {
702 fb32[j] = (fb32[j] ^ fg) ^ bg;
703
704 if (sfb32 == NULL)
705 continue;
706
707 sfb32[j] = (sfb32[j] ^ fg) ^ bg;
708 }
709 }
710 break;
711 }
712}
713
714static void
629set_cursor_row(void)
715boot_fb_setpos(int row, int col)
630{
716{
631 fb_info.cursor.pos.y++;
632 fb_info.cursor.pos.x = 0;
633 fb_info.cursor.origin.x = fb_info.terminal_origin.x;
717 if (row < 0)
718 row = 0;
719 if (row >= fb_info.terminal.y)
720 row = fb_info.terminal.y - 1;
721 if (col < 0)
722 col = 0;
723 if (col >= fb_info.terminal.x)
724 col = fb_info.terminal.x - 1;
634
725
635 if (fb_info.cursor.pos.y < fb_info.terminal.y &&
636 fb_info.cursor.origin.y + boot_fb_font.height < fb_info.screen.y) {
637 fb_info.cursor.origin.y += boot_fb_font.height;
638 } else {
639 fb_info.cursor.pos.y = fb_info.terminal.y - 1;
640 /* fix the cursor origin y */
641 fb_info.cursor.origin.y = fb_info.terminal_origin.y +
642 boot_fb_font.height * fb_info.cursor.pos.y;
643 boot_fb_scroll();
644 }
726 fb_info.cursor.pos.x = col;
727 fb_info.cursor.pos.y = row;
728 fb_info.cursor.origin.x = fb_info.terminal_origin.x;
729 fb_info.cursor.origin.x += col * boot_fb_font.width;
730 fb_info.cursor.origin.y = fb_info.terminal_origin.y;
731 fb_info.cursor.origin.y += row * boot_fb_font.height;
645}
646
647static void
732}
733
734static void
648set_cursor_col(void)
735boot_fb_putchar(int c)
649{
736{
650 fb_info.cursor.pos.x++;
651 if (fb_info.cursor.pos.x < fb_info.terminal.x &&
652 fb_info.cursor.origin.x + boot_fb_font.width < fb_info.screen.x) {
653 fb_info.cursor.origin.x += boot_fb_font.width;
654 } else {
655 fb_info.cursor.pos.x = 0;
656 fb_info.cursor.origin.x = fb_info.terminal_origin.x;
657 set_cursor_row();
658 }
659}
660
661void
662boot_fb_putchar(uint8_t c)
663{
664 struct vis_consdisplay display;
737 struct vis_consdisplay display;
665 boolean_t bs = B_FALSE;
738 int rows, cols;
666
739
667 /* early tem startup will switch cursor off, if so, keep it off */
668 boot_fb_cursor(B_FALSE); /* cursor off */
669 switch (c) {
670 case '\n':
671 set_cursor_row();
672 boot_fb_cursor(B_TRUE);
740 rows = fb_info.cursor.pos.y;
741 cols = fb_info.cursor.pos.x;
742
743 if (c == '\n') {
744 if (rows < fb_info.terminal.y - 1)
745 boot_fb_setpos(rows + 1, cols);
746 else
747 boot_fb_scroll();
673 return;
748 return;
674 case '\r':
675 fb_info.cursor.pos.x = 0;
676 fb_info.cursor.origin.x = fb_info.terminal_origin.x;
677 boot_fb_cursor(B_TRUE);
678 return;
679 case '\b':
680 if (fb_info.cursor.pos.x > 0) {
681 fb_info.cursor.pos.x--;
682 fb_info.cursor.origin.x -= boot_fb_font.width;
683 }
684 c = ' ';
685 bs = B_TRUE;
686 break;
687 }
688
689 bit_to_pix(c);
690 display.col = fb_info.cursor.origin.x;
691 display.row = fb_info.cursor.origin.y;
692 display.width = boot_fb_font.width;
693 display.height = boot_fb_font.height;
694 display.data = glyph;
695
696 boot_fb_blit(&display);
749 }
750
751 bit_to_pix(c);
752 display.col = fb_info.cursor.origin.x;
753 display.row = fb_info.cursor.origin.y;
754 display.width = boot_fb_font.width;
755 display.height = boot_fb_font.height;
756 display.data = glyph;
757
758 boot_fb_blit(&display);
697 if (bs == B_FALSE)
698 set_cursor_col();
699 boot_fb_cursor(B_TRUE);
759 if (cols < fb_info.terminal.x - 1)
760 boot_fb_setpos(rows, cols + 1);
761 else if (rows < fb_info.terminal.y - 1)
762 boot_fb_setpos(rows + 1, 0);
763 else {
764 boot_fb_setpos(rows, 0);
765 boot_fb_scroll();
766 }
700}
767}