Skip to contentSkip to conversation

efi_loader: Decouple EFI input/output from stdin/stdout

PATCH New Rob Clark 3 participants 4 messages Sep 11, 2017 – Oct 22, 2017

lore
Share & tools
lore

Rob Clark

author
#0 lore raw

PATCH 1/1 efi_loader: Decouple EFI input/output from stdin/stdout

In some cases, it is quite useful to have (for example) EFI on screen but u-boot on serial port.

---
Applies on top of my previous efi_loader patchset.

 lib/efi_loader/efi_console.c | 104 +++++++++++++++++++++++++++++++++----------
 1 file changed, 80 insertions(+), 24 deletions(-)
lib/efi_loader/efi_console.c +80 -24
index 139f7ea55b..e2b1b88ecf 100644
@@ -47,6 +47,38 @@ static struct cout_mode efi_cout_modes[] = {
 
 const efi_guid_t efi_guid_console_control = CONSOLE_CONTROL_GUID;
 
+static struct stdio_dev *efiin, *efiout;
+
+static int efi_tstc(void)
+{
+	return efiin->tstc(efiin);
+}
+
+static int efi_getc(void)
+{
+	return efiin->getc(efiin);
+}
+
+static int efi_printf(const char *fmt, ...)
+{
+	va_list args;
+	uint i;
+	char printbuffer[CONFIG_SYS_PBSIZE];
+
+	va_start(args, fmt);
+
+	/*
+	 * For this to work, printbuffer must be larger than
+	 * anything we ever want to print.
+	 */
+	i = vsnprintf(printbuffer, sizeof(printbuffer), fmt, args);
+	va_end(args);
+
+	/* Print the string */
+	efiout->puts(efiout, printbuffer);
+	return i;
+}
+
 #define cESC '\x1b'
 #define ESC "\x1b"
 
@@ -111,16 +143,16 @@ static int term_read_reply(int *n, int maxnum, char end_char)
 	char c;
 	int i = 0;
 
-	c = getc();
+	c = efi_getc();
 	if (c != cESC)
 		return -1;
-	c = getc();
+	c = efi_getc();
 	if (c != '[')
 		return -1;
 
 	n[0] = 0;
 	while (1) {
-		c = getc();
+		c = efi_getc();
 		if (c == ';') {
 			i++;
 			if (i >= maxnum)
@@ -164,7 +196,7 @@ static efi_status_t EFIAPI efi_cout_output_string(
 
 	*utf16_to_utf8((u8 *)buf, string, n16) = '\0';
 
-	fputs(stdout, buf);
+	efiout->puts(efiout, buf);
 
 	for (p = buf; *p; p++) {
 		switch (*p) {
@@ -217,14 +249,14 @@ static int query_console_serial(int *rows, int *cols)
 	u64 timeout;
 
 	/* Empty input buffer */
-	while (tstc())
-		getc();
+	while (efi_tstc())
+		efi_getc();
 
-	printf(ESC"[18t");
+	efi_printf(ESC"[18t");
 
 	/* Check if we have a terminal that understands */
 	timeout = timer_get_us() + 1000000;
-	while (!tstc())
+	while (!efi_tstc())
 		if (timer_get_us() > timeout)
 			return -1;
 
@@ -348,9 +380,9 @@ static efi_status_t EFIAPI efi_cout_set_attribute(
 	EFI_ENTRY("%p, %lx", this, attribute);
 
 	if (attribute)
-		printf(ESC"[%u;%um", color[fg].fg, color[bg].bg);
+		efi_printf(ESC"[%u;%um", color[fg].fg, color[bg].bg);
 	else
-		printf(ESC"[37;40m");
+		efi_printf(ESC"[37;40m");
 
 	/* Just ignore attributes (colors) for now */
 	return EFI_EXIT(EFI_UNSUPPORTED);
@@ -361,7 +393,7 @@ static efi_status_t EFIAPI efi_cout_clear_screen(
 {
 	EFI_ENTRY("%p", this);
 
-	printf(ESC"[2J");
+	efi_printf(ESC"[2J");
 
 	return EFI_EXIT(EFI_SUCCESS);
 }
@@ -372,7 +404,7 @@ static efi_status_t EFIAPI efi_cout_set_cursor_position(
 {
 	EFI_ENTRY("%p, %ld, %ld", this, column, row);
 
-	printf(ESC"[%d;%df", (int)row, (int)column);
+	efi_printf(ESC"[%d;%df", (int)row, (int)column);
 	efi_con_mode.cursor_column = column;
 	efi_con_mode.cursor_row = row;
 
@@ -385,7 +417,7 @@ static efi_status_t EFIAPI efi_cout_enable_cursor(
 {
 	EFI_ENTRY("%p, %d", this, enable);
 
-	printf(ESC"[?25%c", enable ? 'h' : 'l');
+	efi_printf(ESC"[?25%c", enable ? 'h' : 'l');
 
 	return EFI_EXIT(EFI_SUCCESS);
 }
@@ -427,27 +459,27 @@ static efi_status_t read_key_stroke(struct efi_key_data *key_data)
 	/* We don't do interrupts, so check for timers cooperatively */
 	efi_timer_check();
 
-	if (!tstc()) {
+	if (!efi_tstc()) {
 		/* No key pressed */
 		return EFI_NOT_READY;
 	}
 
-	ch = getc();
+	ch = efi_getc();
 	if (ch == cESC) {
 		/* Escape Sequence */
-		ch = getc();
+		ch = efi_getc();
 		switch (ch) {
 		case cESC: /* ESC */
 			pressed_key.scan_code = 23;
 			break;
 		case 'O': /* F1 - F4 */
-			pressed_key.scan_code = getc() - 'P' + 11;
+			pressed_key.scan_code = efi_getc() - 'P' + 11;
 			break;
 		case 'a'...'z':
 			ch = ch - 'a';
 			break;
 		case '[':
-			ch = getc();
+			ch = efi_getc();
 			switch (ch) {
 			case 'A'...'D': /* up, down right, left */
 				pressed_key.scan_code = ch - 'A' + 1;
@@ -459,16 +491,16 @@ static efi_status_t read_key_stroke(struct efi_key_data *key_data)
 				pressed_key.scan_code = 5;
 				break;
 			case '1': /* F5 - F8 */
-				pressed_key.scan_code = getc() - '0' + 11;
-				getc();
+				pressed_key.scan_code = efi_getc() - '0' + 11;
+				efi_getc();
 				break;
 			case '2': /* F9 - F12 */
-				pressed_key.scan_code = getc() - '0' + 19;
-				getc();
+				pressed_key.scan_code = efi_getc() - '0' + 19;
+				efi_getc();
 				break;
 			case '3': /* DEL */
 				pressed_key.scan_code = 8;
-				getc();
+				efi_getc();
 				break;
 			}
 			break;
@@ -521,7 +553,7 @@ static void EFIAPI efi_console_timer_notify(struct efi_event *event,
 					    void *context)
 {
 	EFI_ENTRY("%p, %p", event, context);
-	if (tstc())
+	if (efi_tstc())
 		efi_signal_event(efi_con_in.wait_for_key);
 	EFI_EXIT(EFI_SUCCESS);
 }
@@ -604,6 +636,27 @@ struct efi_object efi_console_input_obj = {
 	.handle = &efi_console_input_obj,
 };
 
+static struct stdio_dev *get_stdio_dev(const char *envname, int default_dev)
+{
+	const char *name;
+	struct stdio_dev *dev = NULL;
+
+	name = env_get(envname);
+	if (name) {
+		dev = stdio_get_by_name(name);
+		if (dev && dev->start) {
+			int ret = dev->start(dev);
+			if (ret < 0)
+				dev = NULL;
+		}
+	}
+
+	if (!dev)
+		dev = stdio_devices[default_dev];
+
+	return dev;
+}
+
 /* This gets called from do_bootefi_exec(). */
 int efi_console_register(void)
 {
@@ -614,6 +667,9 @@ int efi_console_register(void)
 	list_add_tail(&efi_console_output_obj.link, &efi_obj_list);
 	list_add_tail(&efi_console_input_obj.link, &efi_obj_list);
 
+	efiout = get_stdio_dev("efiout", stdout);
+	efiin  = get_stdio_dev("efiin",  stdin);
+
 	r = efi_create_event(EVT_NOTIFY_WAIT, TPL_CALLBACK,
 			     efi_key_notify, NULL, &efi_con_in.wait_for_key);
 	if (r != EFI_SUCCESS) {
Signature · 1 line
2.13.5
author
#1 lore raw

PATCH 1/1 efi_loader: Decouple EFI input/output from stdin/stdout

Quoted 215 lines · Rob Clark

In some cases, it is quite useful to have (for example) EFI on screen but u-boot on serial port.

---
Applies on top of my previous efi_loader patchset.

 lib/efi_loader/efi_console.c | 104 +++++++++++++++++++++++++++++++++----------
 1 file changed, 80 insertions(+), 24 deletions(-)
lib/efi_loader/efi_console.c +63 -24
index 139f7ea55b..e2b1b88ecf 100644
@@ -47,6 +47,38 @@ static struct cout_mode efi_cout_modes[] = {
 
 const efi_guid_t efi_guid_console_control = CONSOLE_CONTROL_GUID;
 
+static struct stdio_dev *efiin, *efiout;
+
+static int efi_tstc(void)
+{
+       return efiin->tstc(efiin);
+}
+
+static int efi_getc(void)
+{
+       return efiin->getc(efiin);
+}
+
+static int efi_printf(const char *fmt, ...)
+{
+       va_list args;
+       uint i;
+       char printbuffer[CONFIG_SYS_PBSIZE];
+
+       va_start(args, fmt);
+
+       /*
+        * For this to work, printbuffer must be larger than
+        * anything we ever want to print.
+        */
+       i = vsnprintf(printbuffer, sizeof(printbuffer), fmt, args);
+       va_end(args);
+
+       /* Print the string */
+       efiout->puts(efiout, printbuffer);
+       return i;
+}
+
 #define cESC '\x1b'
 #define ESC "\x1b"
 
@@ -111,16 +143,16 @@ static int term_read_reply(int *n, int maxnum, char end_char)
        char c;
        int i = 0;
 
-       c = getc();
+       c = efi_getc();
        if (c != cESC)
                return -1;
-       c = getc();
+       c = efi_getc();
        if (c != '[')
                return -1;
 
        n[0] = 0;
        while (1) {
-               c = getc();
+               c = efi_getc();
                if (c == ';') {
                        i++;
                        if (i >= maxnum)
@@ -164,7 +196,7 @@ static efi_status_t EFIAPI efi_cout_output_string(
 
        *utf16_to_utf8((u8 *)buf, string, n16) = '\0';
 
-       fputs(stdout, buf);
+       efiout->puts(efiout, buf);
 
        for (p = buf; *p; p++) {
                switch (*p) {
@@ -217,14 +249,14 @@ static int query_console_serial(int *rows, int *cols)
        u64 timeout;
 
        /* Empty input buffer */
-       while (tstc())
-               getc();
+       while (efi_tstc())
+               efi_getc();
 
-       printf(ESC"[18t");
+       efi_printf(ESC"[18t");
 
        /* Check if we have a terminal that understands */
        timeout = timer_get_us() + 1000000;
-       while (!tstc())
+       while (!efi_tstc())
                if (timer_get_us() > timeout)
                        return -1;
 
@@ -348,9 +380,9 @@ static efi_status_t EFIAPI efi_cout_set_attribute(
        EFI_ENTRY("%p, %lx", this, attribute);
 
        if (attribute)
-               printf(ESC"[%u;%um", color[fg].fg, color[bg].bg);
+               efi_printf(ESC"[%u;%um", color[fg].fg, color[bg].bg);
        else
-               printf(ESC"[37;40m");
+               efi_printf(ESC"[37;40m");
 
        /* Just ignore attributes (colors) for now */
        return EFI_EXIT(EFI_UNSUPPORTED);
@@ -361,7 +393,7 @@ static efi_status_t EFIAPI efi_cout_clear_screen(
 {
        EFI_ENTRY("%p", this);
 
-       printf(ESC"[2J");
+       efi_printf(ESC"[2J");
 
        return EFI_EXIT(EFI_SUCCESS);
 }
@@ -372,7 +404,7 @@ static efi_status_t EFIAPI efi_cout_set_cursor_position(
 {
        EFI_ENTRY("%p, %ld, %ld", this, column, row);
 
-       printf(ESC"[%d;%df", (int)row, (int)column);
+       efi_printf(ESC"[%d;%df", (int)row, (int)column);
        efi_con_mode.cursor_column = column;
        efi_con_mode.cursor_row = row;
 
@@ -385,7 +417,7 @@ static efi_status_t EFIAPI efi_cout_enable_cursor(
 {
        EFI_ENTRY("%p, %d", this, enable);
 
-       printf(ESC"[?25%c", enable ? 'h' : 'l');
+       efi_printf(ESC"[?25%c", enable ? 'h' : 'l');
 
        return EFI_EXIT(EFI_SUCCESS);
 }
@@ -427,27 +459,27 @@ static efi_status_t read_key_stroke(struct efi_key_data *key_data)
        /* We don't do interrupts, so check for timers cooperatively */
        efi_timer_check();
 
-       if (!tstc()) {
+       if (!efi_tstc()) {
                /* No key pressed */
                return EFI_NOT_READY;
        }
 
-       ch = getc();
+       ch = efi_getc();
        if (ch == cESC) {
                /* Escape Sequence */
-               ch = getc();
+               ch = efi_getc();
                switch (ch) {
                case cESC: /* ESC */
                        pressed_key.scan_code = 23;
                        break;
                case 'O': /* F1 - F4 */
-                       pressed_key.scan_code = getc() - 'P' + 11;
+                       pressed_key.scan_code = efi_getc() - 'P' + 11;
                        break;
                case 'a'...'z':
                        ch = ch - 'a';
                        break;
                case '[':
-                       ch = getc();
+                       ch = efi_getc();
                        switch (ch) {
                        case 'A'...'D': /* up, down right, left */
                                pressed_key.scan_code = ch - 'A' + 1;
@@ -459,16 +491,16 @@ static efi_status_t read_key_stroke(struct efi_key_data *key_data)
                                pressed_key.scan_code = 5;
                                break;
                        case '1': /* F5 - F8 */
-                               pressed_key.scan_code = getc() - '0' + 11;
-                               getc();
+                               pressed_key.scan_code = efi_getc() - '0' + 11;
+                               efi_getc();
                                break;
                        case '2': /* F9 - F12 */
-                               pressed_key.scan_code = getc() - '0' + 19;
-                               getc();
+                               pressed_key.scan_code = efi_getc() - '0' + 19;
+                               efi_getc();
                                break;
                        case '3': /* DEL */
                                pressed_key.scan_code = 8;
-                               getc();
+                               efi_getc();
                                break;
                        }
                        break;
@@ -521,7 +553,7 @@ static void EFIAPI efi_console_timer_notify(struct efi_event *event,
                                            void *context)
 {
        EFI_ENTRY("%p, %p", event, context);
-       if (tstc())
+       if (efi_tstc())
                efi_signal_event(efi_con_in.wait_for_key);
        EFI_EXIT(EFI_SUCCESS);
 }
@@ -604,6 +636,27 @@ struct efi_object efi_console_input_obj = {
        .handle = &efi_console_input_obj,
 };
 
+static struct stdio_dev *get_stdio_dev(const char *envname, int default_dev)
+{
+       const char *name;
+       struct stdio_dev *dev = NULL;
+
+       name = env_get(envname);
+       if (name) {

lib/efi_loader/efi_console.c struct efi_object efi_console_input_obj = { · line 655

Quoted 10 lines
lib/efi_loader/efi_console.c +10 -0
+               dev = stdio_get_by_name(name);
+               if (dev && dev->start) {
+                       int ret = dev->start(dev);
+                       if (ret < 0)
+                               dev = NULL;
+               }
+       }
+
+       if (!dev)
+               dev = stdio_devices[default_dev];

btw, the one thing remaining holding up re-sending the efi_loader patches to get Shell.efi working is this one.. it isn't so much a problem with this patch, as much as that on the qemu-x86 target, printf() != fprintf(stdout), which breaks 'bootefi hello'.. I'm not quite sure yet what to do about that.

somehow stdio_devices[stdio] is vidconsole but printf() goes to serial, which the test is expecting. We could perhaps explicitly set 'stdout' env var somewhere. Although I suspect we should probably also fix puts() to be the same thing as fputs(stdout) and fix the various boards where that accidentally working before :-/

suggestions welcome.. I could drop this patch for now, since not strictly required, but I think we should somehow fix the root problem.

BR,
-R

Quoted 20 lines
lib/efi_loader/efi_console.c +7 -1
+
+       return dev;
+}
+
 /* This gets called from do_bootefi_exec(). */
 int efi_console_register(void)
 {
@@ -614,6 +667,9 @@ int efi_console_register(void)
        list_add_tail(&efi_console_output_obj.link, &efi_obj_list);
        list_add_tail(&efi_console_input_obj.link, &efi_obj_list);
 
+       efiout = get_stdio_dev("efiout", stdout);
+       efiin  = get_stdio_dev("efiin",  stdin);
+
        r = efi_create_event(EVT_NOTIFY_WAIT, TPL_CALLBACK,
                             efi_key_notify, NULL, &efi_con_in.wait_for_key);
        if (r != EFI_SUCCESS) {
--

2.13.5

#2 lore raw

PATCH 1/1 efi_loader: Decouple EFI input/output from stdin/stdout

Quoted 224 lines · Rob Clark
Quoted 223 lines · Rob Clark

In some cases, it is quite useful to have (for example) EFI on screen but u-boot on serial port.

---
Applies on top of my previous efi_loader patchset.

 lib/efi_loader/efi_console.c | 104 +++++++++++++++++++++++++++++++++----------
 1 file changed, 80 insertions(+), 24 deletions(-)
lib/efi_loader/efi_console.c +71 -24
index 139f7ea55b..e2b1b88ecf 100644
@@ -47,6 +47,38 @@ static struct cout_mode efi_cout_modes[] = {
 
 const efi_guid_t efi_guid_console_control = CONSOLE_CONTROL_GUID;
 
+static struct stdio_dev *efiin, *efiout;
+
+static int efi_tstc(void)
+{
+       return efiin->tstc(efiin);
+}
+
+static int efi_getc(void)
+{
+       return efiin->getc(efiin);
+}
+
+static int efi_printf(const char *fmt, ...)
+{
+       va_list args;
+       uint i;
+       char printbuffer[CONFIG_SYS_PBSIZE];
+
+       va_start(args, fmt);
+
+       /*
+        * For this to work, printbuffer must be larger than
+        * anything we ever want to print.
+        */
+       i = vsnprintf(printbuffer, sizeof(printbuffer), fmt, args);
+       va_end(args);
+
+       /* Print the string */
+       efiout->puts(efiout, printbuffer);
+       return i;
+}
+
 #define cESC '\x1b'
 #define ESC "\x1b"
 
@@ -111,16 +143,16 @@ static int term_read_reply(int *n, int maxnum, char end_char)
        char c;
        int i = 0;
 
-       c = getc();
+       c = efi_getc();
        if (c != cESC)
                return -1;
-       c = getc();
+       c = efi_getc();
        if (c != '[')
                return -1;
 
        n[0] = 0;
        while (1) {
-               c = getc();
+               c = efi_getc();
                if (c == ';') {
                        i++;
                        if (i >= maxnum)
@@ -164,7 +196,7 @@ static efi_status_t EFIAPI efi_cout_output_string(
 
        *utf16_to_utf8((u8 *)buf, string, n16) = '\0';
 
-       fputs(stdout, buf);
+       efiout->puts(efiout, buf);
 
        for (p = buf; *p; p++) {
                switch (*p) {
@@ -217,14 +249,14 @@ static int query_console_serial(int *rows, int *cols)
        u64 timeout;
 
        /* Empty input buffer */
-       while (tstc())
-               getc();
+       while (efi_tstc())
+               efi_getc();
 
-       printf(ESC"[18t");
+       efi_printf(ESC"[18t");
 
        /* Check if we have a terminal that understands */
        timeout = timer_get_us() + 1000000;
-       while (!tstc())
+       while (!efi_tstc())
                if (timer_get_us() > timeout)
                        return -1;
 
@@ -348,9 +380,9 @@ static efi_status_t EFIAPI efi_cout_set_attribute(
        EFI_ENTRY("%p, %lx", this, attribute);
 
        if (attribute)
-               printf(ESC"[%u;%um", color[fg].fg, color[bg].bg);
+               efi_printf(ESC"[%u;%um", color[fg].fg, color[bg].bg);
        else
-               printf(ESC"[37;40m");
+               efi_printf(ESC"[37;40m");
 
        /* Just ignore attributes (colors) for now */
        return EFI_EXIT(EFI_UNSUPPORTED);
@@ -361,7 +393,7 @@ static efi_status_t EFIAPI efi_cout_clear_screen(
 {
        EFI_ENTRY("%p", this);
 
-       printf(ESC"[2J");
+       efi_printf(ESC"[2J");
 
        return EFI_EXIT(EFI_SUCCESS);
 }
@@ -372,7 +404,7 @@ static efi_status_t EFIAPI efi_cout_set_cursor_position(
 {
        EFI_ENTRY("%p, %ld, %ld", this, column, row);
 
-       printf(ESC"[%d;%df", (int)row, (int)column);
+       efi_printf(ESC"[%d;%df", (int)row, (int)column);
        efi_con_mode.cursor_column = column;
        efi_con_mode.cursor_row = row;
 
@@ -385,7 +417,7 @@ static efi_status_t EFIAPI efi_cout_enable_cursor(
 {
        EFI_ENTRY("%p, %d", this, enable);
 
-       printf(ESC"[?25%c", enable ? 'h' : 'l');
+       efi_printf(ESC"[?25%c", enable ? 'h' : 'l');
 
        return EFI_EXIT(EFI_SUCCESS);
 }
@@ -427,27 +459,27 @@ static efi_status_t read_key_stroke(struct efi_key_data *key_data)
        /* We don't do interrupts, so check for timers cooperatively */
        efi_timer_check();
 
-       if (!tstc()) {
+       if (!efi_tstc()) {
                /* No key pressed */
                return EFI_NOT_READY;
        }
 
-       ch = getc();
+       ch = efi_getc();
        if (ch == cESC) {
                /* Escape Sequence */
-               ch = getc();
+               ch = efi_getc();
                switch (ch) {
                case cESC: /* ESC */
                        pressed_key.scan_code = 23;
                        break;
                case 'O': /* F1 - F4 */
-                       pressed_key.scan_code = getc() - 'P' + 11;
+                       pressed_key.scan_code = efi_getc() - 'P' + 11;
                        break;
                case 'a'...'z':
                        ch = ch - 'a';
                        break;
                case '[':
-                       ch = getc();
+                       ch = efi_getc();
                        switch (ch) {
                        case 'A'...'D': /* up, down right, left */
                                pressed_key.scan_code = ch - 'A' + 1;
@@ -459,16 +491,16 @@ static efi_status_t read_key_stroke(struct efi_key_data *key_data)
                                pressed_key.scan_code = 5;
                                break;
                        case '1': /* F5 - F8 */
-                               pressed_key.scan_code = getc() - '0' + 11;
-                               getc();
+                               pressed_key.scan_code = efi_getc() - '0' + 11;
+                               efi_getc();
                                break;
                        case '2': /* F9 - F12 */
-                               pressed_key.scan_code = getc() - '0' + 19;
-                               getc();
+                               pressed_key.scan_code = efi_getc() - '0' + 19;
+                               efi_getc();
                                break;
                        case '3': /* DEL */
                                pressed_key.scan_code = 8;
-                               getc();
+                               efi_getc();
                                break;
                        }
                        break;
@@ -521,7 +553,7 @@ static void EFIAPI efi_console_timer_notify(struct efi_event *event,
                                            void *context)
 {
        EFI_ENTRY("%p, %p", event, context);
-       if (tstc())
+       if (efi_tstc())
                efi_signal_event(efi_con_in.wait_for_key);
        EFI_EXIT(EFI_SUCCESS);
 }
@@ -604,6 +636,27 @@ struct efi_object efi_console_input_obj = {
        .handle = &efi_console_input_obj,
 };
 
+static struct stdio_dev *get_stdio_dev(const char *envname, int default_dev)
+{
+       const char *name;
+       struct stdio_dev *dev = NULL;
+
+       name = env_get(envname);
+       if (name) {
+               dev = stdio_get_by_name(name);
+               if (dev && dev->start) {
+                       int ret = dev->start(dev);
+                       if (ret < 0)
+                               dev = NULL;
+               }
+       }
+
Quoted 8 lines

lib/efi_loader/efi_console.c struct efi_object efi_console_input_obj = { · line 655

Quoted 2 lines
lib/efi_loader/efi_console.c +2 -0
+       if (!dev)
+               dev = stdio_devices[default_dev];

btw, the one thing remaining holding up re-sending the efi_loader patches to get Shell.efi working is this one.. it isn't so much a problem with this patch, as much as that on the qemu-x86 target, printf() != fprintf(stdout), which breaks 'bootefi hello'.. I'm not quite sure yet what to do about that.

Let's ask Bin and Simon :). There's a lot of magic in the putc() code to account for cases where device initialization didn't happen yet. Maybe the serial driver just wasn't probed properly yet?

Alex

Quoted 33 lines

somehow stdio_devices[stdio] is vidconsole but printf() goes to serial, which the test is expecting. We could perhaps explicitly set 'stdout' env var somewhere. Although I suspect we should probably also fix puts() to be the same thing as fputs(stdout) and fix the various boards where that accidentally working before :-/

suggestions welcome.. I could drop this patch for now, since not strictly required, but I think we should somehow fix the root problem.

BR,
-R

Quoted 20 lines
lib/efi_loader/efi_console.c +7 -1
+
+       return dev;
+}
+
 /* This gets called from do_bootefi_exec(). */
 int efi_console_register(void)
 {
@@ -614,6 +667,9 @@ int efi_console_register(void)
        list_add_tail(&efi_console_output_obj.link, &efi_obj_list);
        list_add_tail(&efi_console_input_obj.link, &efi_obj_list);
 
+       efiout = get_stdio_dev("efiout", stdout);
+       efiin  = get_stdio_dev("efiin",  stdin);
+
        r = efi_create_event(EVT_NOTIFY_WAIT, TPL_CALLBACK,
                             efi_key_notify, NULL, &efi_con_in.wait_for_key);
        if (r != EFI_SUCCESS) {
--

2.13.5

#3 lore raw

PATCH 1/1 efi_loader: Decouple EFI input/output from stdin/stdout

Hi,

Quoted 236 lines · Alexander Graf
Quoted 224 lines · Rob Clark
Quoted 223 lines · Rob Clark

In some cases, it is quite useful to have (for example) EFI on screen but u-boot on serial port.

---
Applies on top of my previous efi_loader patchset.

 lib/efi_loader/efi_console.c | 104 +++++++++++++++++++++++++++++++++----------
 1 file changed, 80 insertions(+), 24 deletions(-)
lib/efi_loader/efi_console.c +71 -24
index 139f7ea55b..e2b1b88ecf 100644
@@ -47,6 +47,38 @@ static struct cout_mode efi_cout_modes[] = {
 
 const efi_guid_t efi_guid_console_control = CONSOLE_CONTROL_GUID;
 
+static struct stdio_dev *efiin, *efiout;
+
+static int efi_tstc(void)
+{
+       return efiin->tstc(efiin);
+}
+
+static int efi_getc(void)
+{
+       return efiin->getc(efiin);
+}
+
+static int efi_printf(const char *fmt, ...)
+{
+       va_list args;
+       uint i;
+       char printbuffer[CONFIG_SYS_PBSIZE];
+
+       va_start(args, fmt);
+
+       /*
+        * For this to work, printbuffer must be larger than
+        * anything we ever want to print.
+        */
+       i = vsnprintf(printbuffer, sizeof(printbuffer), fmt, args);
+       va_end(args);
+
+       /* Print the string */
+       efiout->puts(efiout, printbuffer);
+       return i;
+}
+
 #define cESC '\x1b'
 #define ESC "\x1b"
 
@@ -111,16 +143,16 @@ static int term_read_reply(int *n, int maxnum, char end_char)
        char c;
        int i = 0;
 
-       c = getc();
+       c = efi_getc();
        if (c != cESC)
                return -1;
-       c = getc();
+       c = efi_getc();
        if (c != '[')
                return -1;
 
        n[0] = 0;
        while (1) {
-               c = getc();
+               c = efi_getc();
                if (c == ';') {
                        i++;
                        if (i >= maxnum)
@@ -164,7 +196,7 @@ static efi_status_t EFIAPI efi_cout_output_string(
 
        *utf16_to_utf8((u8 *)buf, string, n16) = '\0';
 
-       fputs(stdout, buf);
+       efiout->puts(efiout, buf);
 
        for (p = buf; *p; p++) {
                switch (*p) {
@@ -217,14 +249,14 @@ static int query_console_serial(int *rows, int *cols)
        u64 timeout;
 
        /* Empty input buffer */
-       while (tstc())
-               getc();
+       while (efi_tstc())
+               efi_getc();
 
-       printf(ESC"[18t");
+       efi_printf(ESC"[18t");
 
        /* Check if we have a terminal that understands */
        timeout = timer_get_us() + 1000000;
-       while (!tstc())
+       while (!efi_tstc())
                if (timer_get_us() > timeout)
                        return -1;
 
@@ -348,9 +380,9 @@ static efi_status_t EFIAPI efi_cout_set_attribute(
        EFI_ENTRY("%p, %lx", this, attribute);
 
        if (attribute)
-               printf(ESC"[%u;%um", color[fg].fg, color[bg].bg);
+               efi_printf(ESC"[%u;%um", color[fg].fg, color[bg].bg);
        else
-               printf(ESC"[37;40m");
+               efi_printf(ESC"[37;40m");
 
        /* Just ignore attributes (colors) for now */
        return EFI_EXIT(EFI_UNSUPPORTED);
@@ -361,7 +393,7 @@ static efi_status_t EFIAPI efi_cout_clear_screen(
 {
        EFI_ENTRY("%p", this);
 
-       printf(ESC"[2J");
+       efi_printf(ESC"[2J");
 
        return EFI_EXIT(EFI_SUCCESS);
 }
@@ -372,7 +404,7 @@ static efi_status_t EFIAPI efi_cout_set_cursor_position(
 {
        EFI_ENTRY("%p, %ld, %ld", this, column, row);
 
-       printf(ESC"[%d;%df", (int)row, (int)column);
+       efi_printf(ESC"[%d;%df", (int)row, (int)column);
        efi_con_mode.cursor_column = column;
        efi_con_mode.cursor_row = row;
 
@@ -385,7 +417,7 @@ static efi_status_t EFIAPI efi_cout_enable_cursor(
 {
        EFI_ENTRY("%p, %d", this, enable);
 
-       printf(ESC"[?25%c", enable ? 'h' : 'l');
+       efi_printf(ESC"[?25%c", enable ? 'h' : 'l');
 
        return EFI_EXIT(EFI_SUCCESS);
 }
@@ -427,27 +459,27 @@ static efi_status_t read_key_stroke(struct efi_key_data *key_data)
        /* We don't do interrupts, so check for timers cooperatively */
        efi_timer_check();
 
-       if (!tstc()) {
+       if (!efi_tstc()) {
                /* No key pressed */
                return EFI_NOT_READY;
        }
 
-       ch = getc();
+       ch = efi_getc();
        if (ch == cESC) {
                /* Escape Sequence */
-               ch = getc();
+               ch = efi_getc();
                switch (ch) {
                case cESC: /* ESC */
                        pressed_key.scan_code = 23;
                        break;
                case 'O': /* F1 - F4 */
-                       pressed_key.scan_code = getc() - 'P' + 11;
+                       pressed_key.scan_code = efi_getc() - 'P' + 11;
                        break;
                case 'a'...'z':
                        ch = ch - 'a';
                        break;
                case '[':
-                       ch = getc();
+                       ch = efi_getc();
                        switch (ch) {
                        case 'A'...'D': /* up, down right, left */
                                pressed_key.scan_code = ch - 'A' + 1;
@@ -459,16 +491,16 @@ static efi_status_t read_key_stroke(struct efi_key_data *key_data)
                                pressed_key.scan_code = 5;
                                break;
                        case '1': /* F5 - F8 */
-                               pressed_key.scan_code = getc() - '0' + 11;
-                               getc();
+                               pressed_key.scan_code = efi_getc() - '0' + 11;
+                               efi_getc();
                                break;
                        case '2': /* F9 - F12 */
-                               pressed_key.scan_code = getc() - '0' + 19;
-                               getc();
+                               pressed_key.scan_code = efi_getc() - '0' + 19;
+                               efi_getc();
                                break;
                        case '3': /* DEL */
                                pressed_key.scan_code = 8;
-                               getc();
+                               efi_getc();
                                break;
                        }
                        break;
@@ -521,7 +553,7 @@ static void EFIAPI efi_console_timer_notify(struct efi_event *event,
                                            void *context)
 {
        EFI_ENTRY("%p, %p", event, context);
-       if (tstc())
+       if (efi_tstc())
                efi_signal_event(efi_con_in.wait_for_key);
        EFI_EXIT(EFI_SUCCESS);
 }
@@ -604,6 +636,27 @@ struct efi_object efi_console_input_obj = {
        .handle = &efi_console_input_obj,
 };
 
+static struct stdio_dev *get_stdio_dev(const char *envname, int default_dev)
+{
+       const char *name;
+       struct stdio_dev *dev = NULL;
+
+       name = env_get(envname);
+       if (name) {
+               dev = stdio_get_by_name(name);
+               if (dev && dev->start) {
+                       int ret = dev->start(dev);
+                       if (ret < 0)
+                               dev = NULL;
+               }
+       }
+
Quoted 8 lines

lib/efi_loader/efi_console.c struct efi_object efi_console_input_obj = { · line 655

Quoted 2 lines
lib/efi_loader/efi_console.c +2 -0
+       if (!dev)
+               dev = stdio_devices[default_dev];

btw, the one thing remaining holding up re-sending the efi_loader patches to get Shell.efi working is this one.. it isn't so much a problem with this patch, as much as that on the qemu-x86 target, printf() != fprintf(stdout), which breaks 'bootefi hello'.. I'm not quite sure yet what to do about that.

Quoted 3 lines

Let's ask Bin and Simon :). There's a lot of magic in the putc() code to account for cases where device initialization didn't happen yet. Maybe the serial driver just wasn't probed properly yet?

That magic should be ignored for EFI - once console_init_r() is called we are in a 'normal' state.

It's funny that (in that state) you see that inconsistency. I cannot think of a reason for it, but more study might perhaps provide an explanation.

Regards,
Simon