Bladeren bron

[fbcon] Add generic concept of a frame buffer console

Add support for a simple frame buffer console, using single buffering
and a fixed-width bitmap font.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
tags/v1.20.1
Michael Brown 11 jaren geleden
bovenliggende
commit
decf9dd133
4 gewijzigde bestanden met toevoegingen van 894 en 1 verwijderingen
  1. 732
    0
      src/core/fbcon.c
  2. 1
    1
      src/include/ipxe/ansiesc.h
  3. 1
    0
      src/include/ipxe/errfile.h
  4. 160
    0
      src/include/ipxe/fbcon.h

+ 732
- 0
src/core/fbcon.c Bestand weergeven

@@ -0,0 +1,732 @@
1
+/*
2
+ * Copyright (C) 2013 Michael Brown <mbrown@fensystems.co.uk>.
3
+ *
4
+ * This program is free software; you can redistribute it and/or
5
+ * modify it under the terms of the GNU General Public License as
6
+ * published by the Free Software Foundation; either version 2 of the
7
+ * License, or any later version.
8
+ *
9
+ * This program is distributed in the hope that it will be useful, but
10
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12
+ * General Public License for more details.
13
+ *
14
+ * You should have received a copy of the GNU General Public License
15
+ * along with this program; if not, write to the Free Software
16
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17
+ * 02110-1301, USA.
18
+ */
19
+
20
+FILE_LICENCE ( GPL2_OR_LATER );
21
+
22
+/** @file
23
+ *
24
+ * Frame buffer console
25
+ *
26
+ */
27
+
28
+#include <string.h>
29
+#include <errno.h>
30
+#include <assert.h>
31
+#include <byteswap.h>
32
+#include <ipxe/ansiesc.h>
33
+#include <ipxe/image.h>
34
+#include <ipxe/pixbuf.h>
35
+#include <ipxe/umalloc.h>
36
+#include <ipxe/fbcon.h>
37
+
38
+/**
39
+ * Calculate raw colour value
40
+ *
41
+ * @v fbcon		Frame buffer console
42
+ * @v rgb		24-bit RGB value
43
+ * @ret raw		Raw colour
44
+ */
45
+static uint32_t fbcon_colour ( struct fbcon *fbcon, uint32_t rgb ) {
46
+	struct fbcon_colour_map *map = fbcon->map;
47
+	uint8_t red = ( rgb >> 16 );
48
+	uint8_t green = ( rgb >> 8 );
49
+	uint8_t blue = ( rgb >> 0 );
50
+	uint32_t mapped;
51
+
52
+	mapped = ( ( ( red >> map->red_scale ) << map->red_lsb ) |
53
+		   ( ( green >> map->green_scale ) << map->green_lsb ) |
54
+		   ( ( blue >> map->blue_scale ) << map->blue_lsb ) );
55
+	return cpu_to_le32 ( mapped );
56
+}
57
+
58
+/**
59
+ * Calculate ANSI font colour
60
+ *
61
+ * @v fbcon		Frame buffer console
62
+ * @v ansicol		ANSI colour value (0-based)
63
+ * @ret colour		Raw colour
64
+ */
65
+static uint32_t fbcon_ansi_colour ( struct fbcon *fbcon,
66
+				    unsigned int ansicol ) {
67
+	uint32_t rgb;
68
+
69
+	/* Treat ansicol as 3-bit BGR with intensity 0xaa */
70
+	rgb = ( ( ( ansicol & ( 1 << 0 ) ) ? 0xaa0000 : 0 ) |
71
+		( ( ansicol & ( 1 << 1 ) ) ? 0x00aa00 : 0 ) |
72
+		( ( ansicol & ( 1 << 2 ) ) ? 0x0000aa : 0 ) );
73
+
74
+	return fbcon_colour ( fbcon, rgb );
75
+}
76
+
77
+/**
78
+ * Set default foreground colour
79
+ *
80
+ * @v fbcon		Frame buffer console
81
+ */
82
+static void fbcon_set_default_foreground ( struct fbcon *fbcon ) {
83
+
84
+	/* Default to non-bold white foreground */
85
+	fbcon->foreground = fbcon_ansi_colour ( fbcon, 0x7 );
86
+	fbcon->bold = 0;
87
+}
88
+
89
+/**
90
+ * Set default background colour
91
+ *
92
+ * @v fbcon		Frame buffer console
93
+ */
94
+static void fbcon_set_default_background ( struct fbcon *fbcon ) {
95
+
96
+	/* Default to transparent background */
97
+	fbcon->background = FBCON_TRANSPARENT;
98
+}
99
+
100
+/**
101
+ * Store character at specified position
102
+ *
103
+ * @v fbcon		Frame buffer console
104
+ * @v cell		Text cell
105
+ * @v xpos		X position
106
+ * @v ypos		Y position
107
+ */
108
+static void fbcon_store_character ( struct fbcon *fbcon,
109
+				    struct fbcon_text_cell *cell,
110
+				    unsigned int xpos, unsigned int ypos ) {
111
+	size_t offset;
112
+
113
+	/* Store cell */
114
+	offset = ( ( ( ypos * fbcon->character.width ) + xpos ) *
115
+		   sizeof ( *cell ) );
116
+	copy_to_user ( fbcon->text.start, offset, cell, sizeof ( *cell ) );
117
+}
118
+
119
+/**
120
+ * Draw character at specified position
121
+ *
122
+ * @v fbcon		Frame buffer console
123
+ * @v cell		Text cell
124
+ * @v xpos		X position
125
+ * @v ypos		Y position
126
+ */
127
+static void fbcon_draw_character ( struct fbcon *fbcon,
128
+				   struct fbcon_text_cell *cell,
129
+				   unsigned int xpos, unsigned int ypos ) {
130
+	static uint32_t black[FBCON_CHAR_WIDTH];
131
+	struct fbcon_font_glyph glyph;
132
+	userptr_t picture_start;
133
+	size_t picture_offset;
134
+	size_t picture_stride;
135
+	size_t offset;
136
+	size_t pixel_len;
137
+	size_t skip_len;
138
+	unsigned int row;
139
+	unsigned int column;
140
+	uint8_t bitmask;
141
+	int transparent;
142
+	void *src;
143
+
144
+	/* Get font character */
145
+	copy_from_user ( &glyph, fbcon->font->start,
146
+			 ( cell->character * sizeof ( glyph ) ),
147
+			 sizeof ( glyph ) );
148
+
149
+	/* Calculate pixel geometry */
150
+	offset = ( fbcon->indent +
151
+		   ( ypos * fbcon->character.stride ) +
152
+		   ( xpos * fbcon->character.len ) );
153
+	pixel_len = fbcon->pixel->len;
154
+	skip_len = ( fbcon->pixel->stride - fbcon->character.len );
155
+
156
+	/* Calculate background picture geometry */
157
+	if ( ( xpos < fbcon->picture.character.width ) &&
158
+	     ( ypos < fbcon->picture.character.height ) ) {
159
+		picture_start = fbcon->picture.start;
160
+		picture_offset = ( fbcon->picture.indent +
161
+				   ( ypos * fbcon->picture.character.stride ) +
162
+				   ( xpos * fbcon->picture.character.len ) );
163
+		picture_stride = fbcon->picture.pixel.stride;
164
+	} else {
165
+		picture_start = virt_to_user ( black );
166
+		picture_offset = 0;
167
+		picture_stride = 0;
168
+	}
169
+	assert ( fbcon->character.len <= sizeof ( black ) );
170
+
171
+	/* Check for transparent background colour */
172
+	transparent = ( cell->background == FBCON_TRANSPARENT );
173
+
174
+	/* Draw character rows */
175
+	for ( row = 0 ; row < FBCON_CHAR_HEIGHT ; row++ ) {
176
+
177
+		/* Draw background picture */
178
+		memcpy_user ( fbcon->start, offset, picture_start,
179
+			      picture_offset, fbcon->character.len );
180
+
181
+		/* Draw character row */
182
+		for ( column = FBCON_CHAR_WIDTH, bitmask = glyph.bitmask[row] ;
183
+		      column ; column--, bitmask <<= 1, offset += pixel_len ) {
184
+			if ( bitmask & 0x80 ) {
185
+				src = &cell->foreground;
186
+			} else if ( ! transparent ) {
187
+				src = &cell->background;
188
+			} else {
189
+				continue;
190
+			}
191
+			copy_to_user ( fbcon->start, offset, src, pixel_len );
192
+		}
193
+
194
+		/* Move to next row */
195
+		offset += skip_len;
196
+		picture_offset += picture_stride;
197
+	}
198
+}
199
+
200
+/**
201
+ * Redraw margins
202
+ *
203
+ * @v fbcon		Frame buffer console
204
+ */
205
+static void fbcon_redraw_margins ( struct fbcon *fbcon ) {
206
+	struct fbcon_picture *picture = &fbcon->picture;
207
+	size_t pixel_len = fbcon->pixel->len;
208
+	size_t offset = 0;
209
+	size_t picture_offset = 0;
210
+	size_t row_len;
211
+	size_t left_len;
212
+	size_t right_len;
213
+	size_t right_offset;
214
+	unsigned int y;
215
+
216
+	/* Calculate margin parameters */
217
+	row_len = ( picture->pixel.width * pixel_len );
218
+	left_len = ( picture->margin.left * pixel_len );
219
+	right_offset = ( picture->margin.right * pixel_len );
220
+	right_len = ( ( picture->pixel.width - picture->margin.right ) *
221
+		      pixel_len );
222
+
223
+	/* Redraw margins */
224
+	for ( y = 0 ; y < picture->pixel.height ; y++ ) {
225
+		if ( ( y < picture->margin.top ) ||
226
+		     ( y >= picture->margin.bottom ) ) {
227
+
228
+			/* Within top or bottom margin: draw whole row */
229
+			memcpy_user ( fbcon->start, offset, picture->start,
230
+				      picture_offset, row_len );
231
+
232
+		} else {
233
+
234
+			/* Otherwise, draw left and right margins */
235
+			memcpy_user ( fbcon->start, offset, picture->start,
236
+				      picture_offset, left_len );
237
+			memcpy_user ( fbcon->start, ( offset + right_offset ),
238
+				      picture->start,
239
+				      ( picture_offset + right_offset ),
240
+				      right_len );
241
+		}
242
+		offset += fbcon->pixel->stride;
243
+		picture_offset += picture->pixel.stride;
244
+	}
245
+}
246
+
247
+/**
248
+ * Redraw characters
249
+ *
250
+ * @v fbcon		Frame buffer console
251
+ */
252
+static void fbcon_redraw_characters ( struct fbcon *fbcon ) {
253
+	struct fbcon_text_cell cell;
254
+	size_t offset = 0;
255
+	unsigned int xpos;
256
+	unsigned int ypos;
257
+
258
+	/* Redraw characters */
259
+	for ( ypos = 0 ; ypos < fbcon->character.height ; ypos++ ) {
260
+		for ( xpos = 0 ; xpos < fbcon->character.width ; xpos++ ) {
261
+			copy_from_user ( &cell, fbcon->text.start, offset,
262
+					 sizeof ( cell ) );
263
+			fbcon_draw_character ( fbcon, &cell, xpos, ypos );
264
+			offset += sizeof ( cell );
265
+		}
266
+	}
267
+}
268
+
269
+/**
270
+ * Redraw screen
271
+ *
272
+ * @v fbcon		Frame buffer console
273
+ */
274
+static void fbcon_redraw ( struct fbcon *fbcon ) {
275
+
276
+	/* Redraw margins */
277
+	fbcon_redraw_margins ( fbcon );
278
+
279
+	/* Redraw characters */
280
+	fbcon_redraw_characters ( fbcon );
281
+}
282
+
283
+/**
284
+ * Clear portion of screen
285
+ *
286
+ * @v fbcon		Frame buffer console
287
+ * @v ypos		Starting Y position
288
+ */
289
+static void fbcon_clear ( struct fbcon *fbcon, unsigned int ypos ) {
290
+	struct fbcon_text_cell cell = {
291
+		.foreground = 0,
292
+		.background = fbcon->background,
293
+		.character = ' ',
294
+	};
295
+	size_t offset;
296
+	unsigned int xpos;
297
+
298
+	/* Clear stored character array */
299
+	for ( ; ypos < fbcon->character.height ; ypos++ ) {
300
+		offset = ( ypos * fbcon->character.width * sizeof ( cell ) );
301
+		for ( xpos = 0 ; xpos < fbcon->character.width ; xpos++ ) {
302
+			copy_to_user ( fbcon->text.start, offset, &cell,
303
+				       sizeof ( cell ) );
304
+			offset += sizeof ( cell );
305
+		}
306
+	}
307
+
308
+	/* Redraw screen */
309
+	fbcon_redraw ( fbcon );
310
+}
311
+
312
+/**
313
+ * Scroll screen
314
+ *
315
+ * @v fbcon		Frame buffer console
316
+ */
317
+static void fbcon_scroll ( struct fbcon *fbcon ) {
318
+	size_t row_len;
319
+
320
+	/* If we are not yet at the bottom of the screen, just update
321
+	 * the cursor position.
322
+	 */
323
+	if ( fbcon->ypos < ( fbcon->character.height - 1 ) ) {
324
+		fbcon->ypos++;
325
+		return;
326
+	}
327
+
328
+	/* Otherwise, scroll up character array */
329
+	row_len = ( fbcon->character.width * sizeof ( struct fbcon_text_cell ));
330
+	memmove_user ( fbcon->text.start, 0, fbcon->text.start, row_len,
331
+		       ( row_len * ( fbcon->character.height - 1 ) ) );
332
+	fbcon_clear ( fbcon, ( fbcon->character.height - 1 ) );
333
+}
334
+
335
+/**
336
+ * Handle ANSI CUP (cursor position)
337
+ *
338
+ * @v ctx		ANSI escape sequence context
339
+ * @v count		Parameter count
340
+ * @v params[0]		Row (1 is top)
341
+ * @v params[1]		Column (1 is left)
342
+ */
343
+static void fbcon_handle_cup ( struct ansiesc_context *ctx,
344
+			       unsigned int count __unused, int params[] ) {
345
+	struct fbcon *fbcon = container_of ( ctx, struct fbcon, ctx );
346
+	int cx = ( params[1] - 1 );
347
+	int cy = ( params[0] - 1 );
348
+
349
+	fbcon->xpos = cx;
350
+	if ( fbcon->xpos >= fbcon->character.width )
351
+		fbcon->xpos = ( fbcon->character.width - 1 );
352
+	fbcon->ypos = cy;
353
+	if ( fbcon->ypos >= fbcon->character.height )
354
+		fbcon->ypos = ( fbcon->character.height - 1 );
355
+}
356
+
357
+/**
358
+ * Handle ANSI ED (erase in page)
359
+ *
360
+ * @v ctx		ANSI escape sequence context
361
+ * @v count		Parameter count
362
+ * @v params[0]		Region to erase
363
+ */
364
+static void fbcon_handle_ed ( struct ansiesc_context *ctx,
365
+			      unsigned int count __unused,
366
+			      int params[] __unused ) {
367
+	struct fbcon *fbcon = container_of ( ctx, struct fbcon, ctx );
368
+
369
+	/* We assume that we always clear the whole screen */
370
+	assert ( params[0] == ANSIESC_ED_ALL );
371
+
372
+	/* Clear screen */
373
+	fbcon_clear ( fbcon, 0 );
374
+
375
+	/* Reset cursor position */
376
+	fbcon->xpos = 0;
377
+	fbcon->ypos = 0;
378
+}
379
+
380
+/**
381
+ * Handle ANSI SGR (set graphics rendition)
382
+ *
383
+ * @v ctx		ANSI escape sequence context
384
+ * @v count		Parameter count
385
+ * @v params		List of graphic rendition aspects
386
+ */
387
+static void fbcon_handle_sgr ( struct ansiesc_context *ctx, unsigned int count,
388
+			       int params[] ) {
389
+	struct fbcon *fbcon = container_of ( ctx, struct fbcon, ctx );
390
+	uint32_t *custom = NULL;
391
+	uint32_t rgb;
392
+	unsigned int end;
393
+	unsigned int i;
394
+	int aspect;
395
+
396
+	for ( i = 0 ; i < count ; i++ ) {
397
+
398
+		/* Process aspect */
399
+		aspect = params[i];
400
+		if ( aspect == 0 ) {
401
+			fbcon_set_default_foreground ( fbcon );
402
+			fbcon_set_default_background ( fbcon );
403
+		} else if ( aspect == 1 ) {
404
+			fbcon->bold = fbcon_colour ( fbcon, FBCON_BOLD );
405
+		} else if ( aspect == 22 ) {
406
+			fbcon->bold = 0;
407
+		} else if ( ( aspect >= 30 ) && ( aspect <= 37 ) ) {
408
+			fbcon->foreground =
409
+				fbcon_ansi_colour ( fbcon, aspect - 30 );
410
+		} else if ( aspect == 38 ) {
411
+			custom = &fbcon->foreground;
412
+		} else if ( aspect == 39 ) {
413
+			fbcon_set_default_foreground ( fbcon );
414
+		} else if ( ( aspect >= 40 ) && ( aspect <= 47 ) ) {
415
+			fbcon->background =
416
+				fbcon_ansi_colour ( fbcon, aspect - 40 );
417
+		} else if ( aspect == 48 ) {
418
+			custom = &fbcon->background;
419
+		} else if ( aspect == 49 ) {
420
+			fbcon_set_default_background ( fbcon );
421
+		}
422
+
423
+		/* Process custom RGB colour, if applicable
424
+		 *
425
+		 * We support the xterm-compatible
426
+		 * "<ESC>[38;2;<red>;<green>;<blue>m" and
427
+		 * "<ESC>[48;2;<red>;<green>;<blue>m" sequences.
428
+		 */
429
+		if ( custom ) {
430
+			rgb = 0;
431
+			end = ( i + 5 );
432
+			for ( ; ( i < count ) && ( i < end ) ; i++ )
433
+				rgb = ( ( rgb << 8 ) | params[i] );
434
+			*custom = fbcon_colour ( fbcon, rgb );
435
+			custom = NULL;
436
+		}
437
+	}
438
+}
439
+
440
+/** ANSI escape sequence handlers */
441
+static struct ansiesc_handler fbcon_ansiesc_handlers[] = {
442
+	{ ANSIESC_CUP, fbcon_handle_cup },
443
+	{ ANSIESC_ED, fbcon_handle_ed },
444
+	{ ANSIESC_SGR, fbcon_handle_sgr },
445
+	{ 0, NULL }
446
+};
447
+
448
+/**
449
+ * Print a character to current cursor position
450
+ *
451
+ * @v fbcon		Frame buffer console
452
+ * @v character		Character
453
+ */
454
+void fbcon_putchar ( struct fbcon *fbcon, int character ) {
455
+	struct fbcon_text_cell cell;
456
+
457
+	/* Intercept ANSI escape sequences */
458
+	character = ansiesc_process ( &fbcon->ctx, character );
459
+	if ( character < 0 )
460
+		return;
461
+
462
+	/* Handle control characters */
463
+	switch ( character ) {
464
+	case '\r':
465
+		fbcon->xpos = 0;
466
+		return;
467
+	case '\n':
468
+		fbcon->xpos = 0;
469
+		fbcon_scroll ( fbcon );
470
+		return;
471
+	case '\b':
472
+		if ( fbcon->xpos ) {
473
+			fbcon->xpos--;
474
+		} else if ( fbcon->ypos ) {
475
+			fbcon->xpos = ( fbcon->character.width - 1 );
476
+			fbcon->ypos--;
477
+		}
478
+		return;
479
+	}
480
+
481
+	/* Print character at current cursor position */
482
+	cell.foreground = ( fbcon->foreground | fbcon->bold );
483
+	cell.background = fbcon->background;
484
+	cell.character = character;
485
+	fbcon_store_character ( fbcon, &cell, fbcon->xpos, fbcon->ypos );
486
+	fbcon_draw_character ( fbcon, &cell, fbcon->xpos, fbcon->ypos );
487
+
488
+	/* Advance cursor */
489
+	fbcon->xpos++;
490
+	if ( fbcon->xpos >= fbcon->character.width ) {
491
+		fbcon->xpos = 0;
492
+		fbcon_scroll ( fbcon );
493
+	}
494
+}
495
+
496
+/**
497
+ * Calculate character geometry from pixel geometry
498
+ *
499
+ * @v pixel		Pixel geometry
500
+ * @v character		Character geometry to fill in
501
+ */
502
+static void fbcon_char_geometry ( const struct fbcon_geometry *pixel,
503
+				  struct fbcon_geometry *character ) {
504
+
505
+	character->width = ( pixel->width / FBCON_CHAR_WIDTH );
506
+	character->height = ( pixel->height / FBCON_CHAR_HEIGHT );
507
+	character->len = ( pixel->len * FBCON_CHAR_WIDTH );
508
+	character->stride = ( pixel->stride * FBCON_CHAR_HEIGHT );
509
+}
510
+
511
+/**
512
+ * Calculate margins from pixel geometry
513
+ *
514
+ * @v pixel		Pixel geometry
515
+ * @v margin		Margins to fill in
516
+ */
517
+static void fbcon_margin ( const struct fbcon_geometry *pixel,
518
+			   struct fbcon_margin *margin ) {
519
+	unsigned int xgap;
520
+	unsigned int ygap;
521
+
522
+	xgap = ( pixel->width % FBCON_CHAR_WIDTH );
523
+	ygap = ( pixel->height % FBCON_CHAR_HEIGHT );
524
+	margin->left = ( xgap / 2 );
525
+	margin->top = ( ygap / 2 );
526
+	margin->right = ( pixel->width - ( xgap - margin->left ) );
527
+	margin->bottom = ( pixel->height - ( ygap - margin->top ) );
528
+}
529
+
530
+/**
531
+ * Align to first indented boundary
532
+ *
533
+ * @v value		Original value
534
+ * @v blocksize		Block size
535
+ * @v indent		Indent
536
+ * @v max		Maximum allowed value
537
+ * @ret value		Aligned value
538
+ */
539
+static unsigned int fbcon_align ( unsigned int value, unsigned int blocksize,
540
+				  unsigned int indent, unsigned int max ) {
541
+	unsigned int overhang;
542
+
543
+	/* Special case: 0 is always a boundary regardless of the indent */
544
+	if ( value == 0 )
545
+		return value;
546
+
547
+	/* Special case: first boundary is the indent */
548
+	if ( value < indent )
549
+		return indent;
550
+
551
+	/* Round up to next indented boundary */
552
+	overhang = ( ( value - indent ) % blocksize );
553
+	value = ( value + ( ( blocksize - overhang ) % blocksize ) );
554
+
555
+	/* Limit to maximum value */
556
+	if ( value > max )
557
+		value = max;
558
+
559
+	return value;
560
+}
561
+
562
+/**
563
+ * Initialise background picture
564
+ *
565
+ * @v fbcon		Frame buffer console
566
+ * @v pixbuf		Background picture
567
+ * @ret rc		Return status code
568
+ */
569
+static int fbcon_picture_init ( struct fbcon *fbcon,
570
+				struct pixel_buffer *pixbuf ) {
571
+	struct fbcon_picture *picture = &fbcon->picture;
572
+	size_t pixel_len = fbcon->pixel->len;
573
+	size_t len;
574
+	size_t offset;
575
+	size_t pixbuf_offset;
576
+	uint32_t rgb;
577
+	uint32_t raw;
578
+	unsigned int x;
579
+	unsigned int y;
580
+	int rc;
581
+
582
+	/* Calculate pixel geometry */
583
+	picture->pixel.width = fbcon_align ( pixbuf->width, FBCON_CHAR_WIDTH,
584
+					     fbcon->margin.left,
585
+					     fbcon->pixel->width );
586
+	picture->pixel.height = fbcon_align ( pixbuf->height, FBCON_CHAR_HEIGHT,
587
+					      fbcon->margin.top,
588
+					      fbcon->pixel->height );
589
+	picture->pixel.len = pixel_len;
590
+	picture->pixel.stride = ( picture->pixel.width * picture->pixel.len );
591
+
592
+	/* Calculate character geometry */
593
+	fbcon_char_geometry ( &picture->pixel, &picture->character );
594
+
595
+	/* Calculate margins */
596
+	memcpy ( &picture->margin, &fbcon->margin, sizeof ( picture->margin ) );
597
+	if ( picture->margin.left > picture->pixel.width )
598
+		picture->margin.left = picture->pixel.width;
599
+	if ( picture->margin.top > picture->pixel.height )
600
+		picture->margin.top = picture->pixel.height;
601
+	if ( picture->margin.right > picture->pixel.width )
602
+		picture->margin.right = picture->pixel.width;
603
+	if ( picture->margin.bottom > picture->pixel.height )
604
+		picture->margin.bottom = picture->pixel.height;
605
+	picture->indent = ( ( picture->margin.top * picture->pixel.stride ) +
606
+			    ( picture->margin.left * picture->pixel.len ) );
607
+	DBGC ( fbcon, "FBCON %p picture is pixel %dx%d, char %dx%d at "
608
+	       "[%d-%d),[%d-%d)\n", fbcon, picture->pixel.width,
609
+	       picture->pixel.height, picture->character.width,
610
+	       picture->character.height, picture->margin.left,
611
+	       picture->margin.right, picture->margin.top,
612
+	       picture->margin.bottom );
613
+
614
+	/* Allocate buffer */
615
+	len = ( picture->pixel.width * picture->pixel.height *
616
+		picture->pixel.len );
617
+	picture->start = umalloc ( len );
618
+	if ( ! picture->start ) {
619
+		DBGC ( fbcon, "FBCON %p could not allocate %zd bytes for "
620
+		       "picture\n", fbcon, len );
621
+		rc = -ENOMEM;
622
+		goto err_umalloc;
623
+	}
624
+
625
+	/* Convert to frame buffer raw format */
626
+	memset_user ( picture->start, 0, 0, len );
627
+	pixbuf_offset = 0;
628
+	for ( y = 0 ; ( y < pixbuf->height ) &&
629
+		      ( y < picture->pixel.height ) ; y++ ) {
630
+		offset = ( y * picture->pixel.stride );
631
+		pixbuf_offset = ( y * pixbuf->width * sizeof ( rgb ) );
632
+		for ( x = 0 ; ( x < pixbuf->width ) &&
633
+			      ( x < picture->pixel.width ) ; x++ ) {
634
+			copy_from_user ( &rgb, pixbuf->data, pixbuf_offset,
635
+					 sizeof ( rgb ) );
636
+			raw = fbcon_colour ( fbcon, rgb );
637
+			copy_to_user ( picture->start, offset, &raw, pixel_len);
638
+			offset += pixel_len;
639
+			pixbuf_offset += sizeof ( rgb );
640
+		}
641
+	}
642
+
643
+	return 0;
644
+
645
+	ufree ( picture->start );
646
+ err_umalloc:
647
+	return rc;
648
+}
649
+
650
+/**
651
+ * Initialise frame buffer console
652
+ *
653
+ * @v fbcon		Frame buffer console
654
+ * @v start		Start address
655
+ * @v pixel		Pixel geometry
656
+ * @v map		Colour mapping
657
+ * @v font		Font definition
658
+ * @v pixbuf		Background picture (if any)
659
+ * @ret rc		Return status code
660
+ */
661
+int fbcon_init ( struct fbcon *fbcon, userptr_t start,
662
+		 struct fbcon_geometry *pixel,
663
+		 struct fbcon_colour_map *map,
664
+		 struct fbcon_font *font,
665
+		 struct pixel_buffer *pixbuf ) {
666
+	int rc;
667
+
668
+	/* Initialise data structure */
669
+	memset ( fbcon, 0, sizeof ( *fbcon ) );
670
+	fbcon->start = start;
671
+	fbcon->pixel = pixel;
672
+	assert ( pixel->len <= sizeof ( uint32_t ) );
673
+	fbcon->map = map;
674
+	fbcon->font = font;
675
+	fbcon->ctx.handlers = fbcon_ansiesc_handlers;
676
+
677
+	/* Derive overall length */
678
+	fbcon->len = ( pixel->height * pixel->stride );
679
+	DBGC ( fbcon, "FBCON %p at [%08lx,%08lx)\n", fbcon,
680
+	       user_to_phys ( fbcon->start, 0 ),
681
+	       user_to_phys ( fbcon->start, fbcon->len ) );
682
+
683
+	/* Derive character geometry from pixel geometry */
684
+	fbcon_char_geometry ( pixel, &fbcon->character );
685
+	fbcon_margin ( pixel, &fbcon->margin );
686
+	fbcon->indent = ( ( fbcon->margin.top * pixel->stride ) +
687
+			  ( fbcon->margin.left * pixel->len ) );
688
+	DBGC ( fbcon, "FBCON %p is pixel %dx%d, char %dx%d at "
689
+	       "[%d-%d),[%d-%d)\n", fbcon, fbcon->pixel->width,
690
+	       fbcon->pixel->height, fbcon->character.width,
691
+	       fbcon->character.height, fbcon->margin.left, fbcon->margin.right,
692
+	       fbcon->margin.top, fbcon->margin.bottom );
693
+
694
+	/* Set default colours */
695
+	fbcon_set_default_foreground ( fbcon );
696
+	fbcon_set_default_background ( fbcon );
697
+
698
+	/* Allocate stored character array */
699
+	fbcon->text.start = umalloc ( fbcon->character.width *
700
+				      fbcon->character.height *
701
+				      sizeof ( struct fbcon_text_cell ) );
702
+	if ( ! fbcon->text.start ) {
703
+		rc = -ENOMEM;
704
+		goto err_text;
705
+	}
706
+
707
+	/* Generate pixel buffer from background image, if applicable */
708
+	if ( pixbuf && ( ( rc = fbcon_picture_init ( fbcon, pixbuf ) ) != 0 ) )
709
+		goto err_picture;
710
+
711
+	/* Clear screen */
712
+	fbcon_clear ( fbcon, 0 );
713
+
714
+	return 0;
715
+
716
+	ufree ( fbcon->picture.start );
717
+ err_picture:
718
+	ufree ( fbcon->text.start );
719
+ err_text:
720
+	return rc;
721
+}
722
+
723
+/**
724
+ * Finalise frame buffer console
725
+ *
726
+ * @v fbcon		Frame buffer console
727
+ */
728
+void fbcon_fini ( struct fbcon *fbcon ) {
729
+
730
+	ufree ( fbcon->text.start );
731
+	ufree ( fbcon->picture.start );
732
+}

+ 1
- 1
src/include/ipxe/ansiesc.h Bestand weergeven

@@ -62,7 +62,7 @@ struct ansiesc_handler {
62 62
 };
63 63
 
64 64
 /** Maximum number of parameters within a single escape sequence */
65
-#define ANSIESC_MAX_PARAMS 4
65
+#define ANSIESC_MAX_PARAMS 5
66 66
 
67 67
 /**
68 68
  * ANSI escape sequence context

+ 1
- 0
src/include/ipxe/errfile.h Bestand weergeven

@@ -65,6 +65,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
65 65
 #define ERRFILE_pending		       ( ERRFILE_CORE | 0x00190000 )
66 66
 #define ERRFILE_null_reboot	       ( ERRFILE_CORE | 0x001a0000 )
67 67
 #define ERRFILE_pinger		       ( ERRFILE_CORE | 0x001b0000 )
68
+#define ERRFILE_fbcon		       ( ERRFILE_CORE | 0x001c0000 )
68 69
 
69 70
 #define ERRFILE_eisa		     ( ERRFILE_DRIVER | 0x00000000 )
70 71
 #define ERRFILE_isa		     ( ERRFILE_DRIVER | 0x00010000 )

+ 160
- 0
src/include/ipxe/fbcon.h Bestand weergeven

@@ -0,0 +1,160 @@
1
+#ifndef _IPXE_FBCON_H
2
+#define _IPXE_FBCON_H
3
+
4
+/** @file
5
+ *
6
+ * Frame buffer console
7
+ *
8
+ */
9
+
10
+FILE_LICENCE ( GPL2_OR_LATER );
11
+
12
+#include <stdint.h>
13
+#include <ipxe/ansiesc.h>
14
+#include <ipxe/uaccess.h>
15
+
16
+struct pixel_buffer;
17
+
18
+/** Character width, in pixels */
19
+#define FBCON_CHAR_WIDTH 9
20
+
21
+/** Character height, in pixels */
22
+#define FBCON_CHAR_HEIGHT 16
23
+
24
+/** Bold colour modifier (RGB value) */
25
+#define FBCON_BOLD 0x555555
26
+
27
+/** Transparent background magic colour (raw colour value) */
28
+#define FBCON_TRANSPARENT 0xffffffff
29
+
30
+/** A font glyph */
31
+struct fbcon_font_glyph {
32
+	/** Row bitmask */
33
+	uint8_t bitmask[FBCON_CHAR_HEIGHT];
34
+} __attribute__ (( packed ));
35
+
36
+/** A font definition */
37
+struct fbcon_font {
38
+	/** Character glyphs */
39
+	userptr_t start;
40
+} __attribute__ (( packed ));
41
+
42
+/** A frame buffer geometry
43
+ *
44
+ * The geometry is defined in terms of "entities" (which can be either
45
+ * pixels or characters).
46
+ */
47
+struct fbcon_geometry {
48
+	/** Width (number of entities per displayed row) */
49
+	unsigned int width;
50
+	/** Height (number of entities per displayed column) */
51
+	unsigned int height;
52
+	/** Length of a single entity */
53
+	size_t len;
54
+	/** Stride (offset between vertically adjacent entities) */
55
+	size_t stride;
56
+};
57
+
58
+/** A frame buffer margin */
59
+struct fbcon_margin {
60
+	/** Left margin */
61
+	unsigned int left;
62
+	/** Right margin */
63
+	unsigned int right;
64
+	/** Top margin */
65
+	unsigned int top;
66
+	/** Bottom margin */
67
+	unsigned int bottom;
68
+};
69
+
70
+/** A frame buffer colour mapping */
71
+struct fbcon_colour_map {
72
+	/** Red scale (right shift amount from 24-bit RGB) */
73
+	uint8_t red_scale;
74
+	/** Green scale (right shift amount from 24-bit RGB) */
75
+	uint8_t green_scale;
76
+	/** Blue scale (right shift amount from 24-bit RGB) */
77
+	uint8_t blue_scale;
78
+	/** Red LSB */
79
+	uint8_t red_lsb;
80
+	/** Green LSB */
81
+	uint8_t green_lsb;
82
+	/** Blue LSB */
83
+	uint8_t blue_lsb;
84
+};
85
+
86
+/** A frame buffer text cell */
87
+struct fbcon_text_cell {
88
+	/** Foreground colour */
89
+	uint32_t foreground;
90
+	/** Background colour */
91
+	uint32_t background;
92
+	/** Character */
93
+	unsigned int character;
94
+};
95
+
96
+/** A frame buffer text array */
97
+struct fbcon_text {
98
+	/** Stored text cells */
99
+	userptr_t start;
100
+};
101
+
102
+/** A frame buffer background picture */
103
+struct fbcon_picture {
104
+	/** Start address */
105
+	userptr_t start;
106
+	/** Pixel geometry */
107
+	struct fbcon_geometry pixel;
108
+	/** Character geometry */
109
+	struct fbcon_geometry character;
110
+	/** Margin */
111
+	struct fbcon_margin margin;
112
+	/** Indent to first character (in bytes) */
113
+	size_t indent;
114
+};
115
+
116
+/** A frame buffer console */
117
+struct fbcon {
118
+	/** Start address */
119
+	userptr_t start;
120
+	/** Length of one complete displayed screen */
121
+	size_t len;
122
+	/** Pixel geometry */
123
+	struct fbcon_geometry *pixel;
124
+	/** Character geometry */
125
+	struct fbcon_geometry character;
126
+	/** Margin */
127
+	struct fbcon_margin margin;
128
+	/** Indent to first character (in bytes) */
129
+	size_t indent;
130
+	/** Colour mapping */
131
+	struct fbcon_colour_map *map;
132
+	/** Font definition */
133
+	struct fbcon_font *font;
134
+	/** Text foreground raw colour */
135
+	uint32_t foreground;
136
+	/** Text background raw colour */
137
+	uint32_t background;
138
+	/** Bold colour modifier raw colour */
139
+	uint32_t bold;
140
+	/** Text cursor X position */
141
+	unsigned int xpos;
142
+	/** Text cursor Y position */
143
+	unsigned int ypos;
144
+	/** ANSI escape sequence context */
145
+	struct ansiesc_context ctx;
146
+	/** Text array */
147
+	struct fbcon_text text;
148
+	/** Background picture */
149
+	struct fbcon_picture picture;
150
+};
151
+
152
+extern int fbcon_init ( struct fbcon *fbcon, userptr_t start,
153
+			struct fbcon_geometry *pixel,
154
+			struct fbcon_colour_map *map,
155
+			struct fbcon_font *font,
156
+			struct pixel_buffer *pixbuf );
157
+extern void fbcon_fini ( struct fbcon *fbcon );
158
+extern void fbcon_putchar ( struct fbcon *fbcon, int character );
159
+
160
+#endif /* _IPXE_FBCON_H */

Laden…
Annuleren
Opslaan