[U-Boot,v3,21/21] efi_loader: Some console improvements for vidconsole

Message ID 20170913220546.19560-22-robdclark@gmail.com
State Accepted
Delegated to: Alexander Graf
Headers show
Series
  • efi_loader: enough UEFI for standard distro boot
Related show

Commit Message

Rob Clark Sept. 13, 2017, 10:05 p.m.
1) use fputs() to reduce cache flushes from once-per-char to
   once-per-string
2) handle \r, \t, and \b in addition to just \n for tracking
   cursor position
3) cursor row/col are zero based, not one based

Signed-off-by: Rob Clark <robdclark@gmail.com>
---
 include/efi_api.h            |  6 +++--
 lib/efi_loader/efi_console.c | 58 ++++++++++++++++++++++++++------------------
 2 files changed, 39 insertions(+), 25 deletions(-)

Comments

Alexander Graf Sept. 21, 2017, 7:05 a.m. | #1
> 1) use fputs() to reduce cache flushes from once-per-char to
>    once-per-string
> 2) handle \r, \t, and \b in addition to just \n for tracking
>    cursor position
> 3) cursor row/col are zero based, not one based
> 
> Signed-off-by: Rob Clark <robdclark@gmail.com>

Thanks, applied to efi-next

Alex

Patch

diff --git a/include/efi_api.h b/include/efi_api.h
index 604c5b7ec4..c3b9032a48 100644
--- a/include/efi_api.h
+++ b/include/efi_api.h
@@ -29,6 +29,8 @@  enum efi_timer_delay {
 };
 
 #define UINTN size_t
+typedef long INTN;
+typedef uint16_t *efi_string_t;
 
 #define EVT_TIMER				0x80000000
 #define EVT_RUNTIME				0x40000000
@@ -427,10 +429,10 @@  struct efi_simple_text_output_protocol {
 	void *reset;
 	efi_status_t (EFIAPI *output_string)(
 			struct efi_simple_text_output_protocol *this,
-			const unsigned short *str);
+			const efi_string_t str);
 	efi_status_t (EFIAPI *test_string)(
 			struct efi_simple_text_output_protocol *this,
-			const unsigned short *str);
+			const efi_string_t str);
 	efi_status_t(EFIAPI *query_mode)(
 			struct efi_simple_text_output_protocol *this,
 			unsigned long mode_number, unsigned long *columns,
diff --git a/lib/efi_loader/efi_console.c b/lib/efi_loader/efi_console.c
index 9048a8d32c..afc725a2c7 100644
--- a/lib/efi_loader/efi_console.c
+++ b/lib/efi_loader/efi_console.c
@@ -140,34 +140,46 @@  static efi_status_t EFIAPI efi_cout_reset(
 	return EFI_EXIT(EFI_UNSUPPORTED);
 }
 
-static void print_unicode_in_utf8(u16 c)
-{
-	char utf8[MAX_UTF8_PER_UTF16] = { 0 };
-	utf16_to_utf8((u8 *)utf8, &c, 1);
-	puts(utf8);
-}
-
 static efi_status_t EFIAPI efi_cout_output_string(
 			struct efi_simple_text_output_protocol *this,
-			const unsigned short *string)
+			const efi_string_t string)
 {
-	struct cout_mode *mode;
-	u16 ch;
+	struct simple_text_output_mode *con = &efi_con_mode;
+	struct cout_mode *mode = &efi_cout_modes[con->mode];
 
-	mode = &efi_cout_modes[efi_con_mode.mode];
 	EFI_ENTRY("%p, %p", this, string);
-	for (;(ch = *string); string++) {
-		print_unicode_in_utf8(ch);
-		efi_con_mode.cursor_column++;
-		if (ch == '\n') {
-			efi_con_mode.cursor_column = 1;
-			efi_con_mode.cursor_row++;
-		} else if (efi_con_mode.cursor_column > mode->columns) {
-			efi_con_mode.cursor_column = 1;
-			efi_con_mode.cursor_row++;
+
+	unsigned n16 = utf16_strlen(string);
+	char buf[MAX_UTF8_PER_UTF16 * n16 + 1];
+	char *p;
+
+	*utf16_to_utf8((u8 *)buf, string, n16) = '\0';
+
+	fputs(stdout, buf);
+
+	for (p = buf; *p; p++) {
+		switch (*p) {
+		case '\r':   /* carriage-return */
+			con->cursor_column = 0;
+			break;
+		case '\n':   /* newline */
+			con->cursor_column = 0;
+			con->cursor_row++;
+			break;
+		case '\t':   /* tab, assume 8 char align */
+			break;
+		case '\b':   /* backspace */
+			con->cursor_column = max(0, con->cursor_column - 1);
+			break;
+		default:
+			con->cursor_column++;
+			break;
+		}
+		if (con->cursor_column >= mode->columns) {
+			con->cursor_column = 0;
+			con->cursor_row++;
 		}
-		if (efi_con_mode.cursor_row > mode->rows)
-			efi_con_mode.cursor_row = mode->rows;
+		con->cursor_row = min(con->cursor_row, (s32)mode->rows - 1);
 	}
 
 	return EFI_EXIT(EFI_SUCCESS);
@@ -175,7 +187,7 @@  static efi_status_t EFIAPI efi_cout_output_string(
 
 static efi_status_t EFIAPI efi_cout_test_string(
 			struct efi_simple_text_output_protocol *this,
-			const unsigned short *string)
+			const efi_string_t string)
 {
 	EFI_ENTRY("%p, %p", this, string);
 	return EFI_EXIT(EFI_SUCCESS);