Message ID | 20170911140407.7273-1-robdclark@gmail.com |
---|---|
State | Deferred |
Delegated to: | Tom Rini |
Headers | show |
Series | [U-Boot] efi_loader: Decouple EFI input/output from stdin/stdout | expand |
On Mon, Sep 11, 2017 at 10:04 AM, Rob Clark <robdclark@gmail.com> wrote: > In some cases, it is quite useful to have (for example) EFI on screen > but u-boot on serial port. > > Signed-off-by: Rob Clark <robdclark@gmail.com> > --- > Applies on top of my previous efi_loader patchset. > > lib/efi_loader/efi_console.c | 104 +++++++++++++++++++++++++++++++++---------- > 1 file changed, 80 insertions(+), 24 deletions(-) > > diff --git a/lib/efi_loader/efi_console.c b/lib/efi_loader/efi_console.c > index 139f7ea55b..e2b1b88ecf 100644 > --- a/lib/efi_loader/efi_console.c > +++ b/lib/efi_loader/efi_console.c > @@ -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]; 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 > + > + 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 >
On 10.10.17 02:27, Rob Clark wrote: > On Mon, Sep 11, 2017 at 10:04 AM, Rob Clark <robdclark@gmail.com> wrote: >> In some cases, it is quite useful to have (for example) EFI on screen >> but u-boot on serial port. >> >> Signed-off-by: Rob Clark <robdclark@gmail.com> >> --- >> Applies on top of my previous efi_loader patchset. >> >> lib/efi_loader/efi_console.c | 104 +++++++++++++++++++++++++++++++++---------- >> 1 file changed, 80 insertions(+), 24 deletions(-) >> >> diff --git a/lib/efi_loader/efi_console.c b/lib/efi_loader/efi_console.c >> index 139f7ea55b..e2b1b88ecf 100644 >> --- a/lib/efi_loader/efi_console.c >> +++ b/lib/efi_loader/efi_console.c >> @@ -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]; > > 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 > 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 > > >> + >> + 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 >>
Hi, On 10 October 2017 at 10:12, Alexander Graf <agraf@suse.de> wrote: > > > On 10.10.17 02:27, Rob Clark wrote: >> On Mon, Sep 11, 2017 at 10:04 AM, Rob Clark <robdclark@gmail.com> wrote: >>> In some cases, it is quite useful to have (for example) EFI on screen >>> but u-boot on serial port. >>> >>> Signed-off-by: Rob Clark <robdclark@gmail.com> >>> --- >>> Applies on top of my previous efi_loader patchset. >>> >>> lib/efi_loader/efi_console.c | 104 +++++++++++++++++++++++++++++++++---------- >>> 1 file changed, 80 insertions(+), 24 deletions(-) >>> >>> diff --git a/lib/efi_loader/efi_console.c b/lib/efi_loader/efi_console.c >>> index 139f7ea55b..e2b1b88ecf 100644 >>> --- a/lib/efi_loader/efi_console.c >>> +++ b/lib/efi_loader/efi_console.c >>> @@ -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]; >> >> 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? 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
diff --git a/lib/efi_loader/efi_console.c b/lib/efi_loader/efi_console.c index 139f7ea55b..e2b1b88ecf 100644 --- a/lib/efi_loader/efi_console.c +++ b/lib/efi_loader/efi_console.c @@ -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) {
In some cases, it is quite useful to have (for example) EFI on screen but u-boot on serial port. Signed-off-by: Rob Clark <robdclark@gmail.com> --- Applies on top of my previous efi_loader patchset. lib/efi_loader/efi_console.c | 104 +++++++++++++++++++++++++++++++++---------- 1 file changed, 80 insertions(+), 24 deletions(-)