From dd3547543811dd2e996b910bdadb609414904352 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Tue, 15 Mar 2022 15:04:22 +0000 Subject: [efi] Support Unicode character output via framebuffer console Extend the glyph cache to include a number of dynamic entries that are populated on demand whenever a non-ASCII character needs to be drawn. Signed-off-by: Michael Brown --- src/interface/efi/efi_fbcon.c | 51 ++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 48 insertions(+), 3 deletions(-) diff --git a/src/interface/efi/efi_fbcon.c b/src/interface/efi/efi_fbcon.c index d9e3e69e6..d388e0317 100644 --- a/src/interface/efi/efi_fbcon.c +++ b/src/interface/efi/efi_fbcon.c @@ -65,6 +65,9 @@ struct console_driver efi_console __attribute__ (( weak )); /** Number of ASCII glyphs in cache */ #define EFIFB_ASCII 128 +/** Number of dynamic non-ASCII glyphs in cache */ +#define EFIFB_DYNAMIC 32 + /* Forward declaration */ struct console_driver efifb_console __console_driver; @@ -89,6 +92,10 @@ struct efifb { struct fbcon_font font; /** Character glyph cache */ userptr_t glyphs; + /** Dynamic characters in cache */ + unsigned int dynamic[EFIFB_DYNAMIC]; + /** Next dynamic character cache entry to evict */ + unsigned int next; }; /** The EFI frame buffer */ @@ -177,6 +184,41 @@ static int efifb_draw_unknown ( unsigned int index ) { return efifb_draw ( '?', index, -1U ); } +/** + * Get dynamic glyph index + * + * @v character Unicode character + * @ret index Glyph cache index + */ +static unsigned int efifb_dynamic ( unsigned int character ) { + unsigned int dynamic; + unsigned int index; + unsigned int i; + int height; + + /* Search existing cached entries */ + for ( i = 0 ; i < EFIFB_DYNAMIC ; i++ ) { + if ( character == efifb.dynamic[i] ) + return ( EFIFB_ASCII + i ); + } + + /* Overwrite the oldest cache entry */ + dynamic = ( efifb.next++ % EFIFB_DYNAMIC ); + index = ( EFIFB_ASCII + dynamic ); + DBGC2 ( &efifb, "EFIFB dynamic %#02x is glyph %#02x\n", + dynamic, character ); + + /* Draw glyph */ + height = efifb_draw ( character, index, 0 ); + if ( height < 0 ) + efifb_draw_unknown ( index ); + + /* Record cached character */ + efifb.dynamic[dynamic] = character; + + return index; +} + /** * Get character glyph * @@ -195,8 +237,8 @@ static void efifb_glyph ( unsigned int character, uint8_t *glyph ) { } else { - /* Non-ASCII character: use an "unknown" glyph */ - index = 0; + /* Non-ASCII character: use dynamic glyph cache */ + index = efifb_dynamic ( character ); } /* Copy cached glyph */ @@ -248,7 +290,7 @@ static int efifb_glyphs ( void ) { efifb.font.height = max; /* Allocate glyph data */ - len = ( EFIFB_ASCII * efifb.font.height ); + len = ( ( EFIFB_ASCII + EFIFB_DYNAMIC ) * efifb.font.height ); efifb.glyphs = umalloc ( len ); if ( ! efifb.glyphs ) { rc = -ENOMEM; @@ -273,6 +315,9 @@ static int efifb_glyphs ( void ) { } } + /* Clear dynamic glyph character cache */ + memset ( efifb.dynamic, 0, sizeof ( efifb.dynamic ) ); + efifb.font.glyph = efifb_glyph; return 0; -- cgit