From a95f4c88599176d9a88dc19c02fa8dd95003eebf Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Tue, 16 Mar 2021 12:56:57 +0100 Subject: [PATCH 1/3] efi_loader: NULL dereference in EFI console Even if CONFIG_DM_VIDEO=y and stdout="vidconsole", a video device may not be available. Check the return values of the relevant functions. If no video output device is available, assume that the serial console is in use. Signed-off-by: Heinrich Schuchardt --- lib/efi_loader/efi_console.c | 51 +++++++++++++++++++++++++++--------- 1 file changed, 38 insertions(+), 13 deletions(-) diff --git a/lib/efi_loader/efi_console.c b/lib/efi_loader/efi_console.c index c4003554c2..6040f3a99a 100644 --- a/lib/efi_loader/efi_console.c +++ b/lib/efi_loader/efi_console.c @@ -254,7 +254,7 @@ static bool cout_mode_matches(struct cout_mode *mode, int rows, int cols) } /** - * query_console_serial() - query console size + * query_console_serial() - query serial console size * * When using a serial console or the net console we can only devise the * terminal size by querying the terminal using ECMA-48 control sequences. @@ -299,6 +299,37 @@ out: return ret; } +/** + * query_vidconsole() - query video console size + * + * + * @rows: pointer to return number of rows + * @cols: pointer to return number of columns + * Returns: 0 on success + */ +static int __maybe_unused query_vidconsole(int *rows, int *cols) +{ + const char *stdout_name = env_get("stdout"); + struct stdio_dev *stdout_dev; + struct udevice *dev; + struct vidconsole_priv *priv; + + if (!stdout_name || strncmp(stdout_name, "vidconsole", 10)) + return -ENODEV; + stdout_dev = stdio_get_by_name("vidconsole"); + if (!stdout_dev) + return -ENODEV; + dev = stdout_dev->priv; + if (!dev) + return -ENODEV; + priv = dev_get_uclass_priv(dev); + if (!priv) + return -ENODEV; + *rows = priv->rows; + *cols = priv->cols; + return 0; +} + /** * query_console_size() - update the mode table. * @@ -308,21 +339,15 @@ out: */ static void query_console_size(void) { - const char *stdout_name = env_get("stdout"); int rows = 25, cols = 80; + int ret = -ENODEV; - if (stdout_name && !strncmp(stdout_name, "vidconsole", 10) && - IS_ENABLED(CONFIG_DM_VIDEO)) { - struct stdio_dev *stdout_dev = - stdio_get_by_name("vidconsole"); - struct udevice *dev = stdout_dev->priv; - struct vidconsole_priv *priv = - dev_get_uclass_priv(dev); - rows = priv->rows; - cols = priv->cols; - } else if (query_console_serial(&rows, &cols)) { + if IS_ENABLED(CONFIG_DM_VIDEO) + ret = query_vidconsole(&rows, &cols); + if (ret) + ret = query_console_serial(&rows, &cols); + if (ret) return; - } /* Test if we can have Mode 1 */ if (cols >= 80 && rows >= 50) { From 62df6e9c9994c66efd34afe710a64de27dd120bc Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Fri, 19 Mar 2021 02:49:54 +0100 Subject: [PATCH 2/3] efi_loader: Uart device path When uploading an EFI binary via the UART we need to assign a device path. * Provide devicepath node to text conversion for Uart() node. * Provide function to create Uart() device path. * Add UART support to efi_dp_from_name(). Signed-off-by: Heinrich Schuchardt --- include/efi_api.h | 10 ++++++ lib/efi_loader/efi_device_path.c | 41 ++++++++++++++++++------ lib/efi_loader/efi_device_path_to_text.c | 13 ++++++++ 3 files changed, 55 insertions(+), 9 deletions(-) diff --git a/include/efi_api.h b/include/efi_api.h index 48e48a6263..4ccde1d24d 100644 --- a/include/efi_api.h +++ b/include/efi_api.h @@ -523,6 +523,7 @@ struct efi_device_path_acpi_path { # define DEVICE_PATH_SUB_TYPE_MSG_SCSI 0x02 # define DEVICE_PATH_SUB_TYPE_MSG_USB 0x05 # define DEVICE_PATH_SUB_TYPE_MSG_MAC_ADDR 0x0b +# define DEVICE_PATH_SUB_TYPE_MSG_UART 0x0e # define DEVICE_PATH_SUB_TYPE_MSG_USB_CLASS 0x0f # define DEVICE_PATH_SUB_TYPE_MSG_SATA 0x12 # define DEVICE_PATH_SUB_TYPE_MSG_NVME 0x17 @@ -542,6 +543,15 @@ struct efi_device_path_scsi { u16 logical_unit_number; } __packed; +struct efi_device_path_uart { + struct efi_device_path dp; + u32 reserved; + u64 baud_rate; + u8 data_bits; + u8 parity; + u8 stop_bits; +} __packed; + struct efi_device_path_usb { struct efi_device_path dp; u8 parent_port_number; diff --git a/lib/efi_loader/efi_device_path.c b/lib/efi_loader/efi_device_path.c index c9315dd458..398dbc699b 100644 --- a/lib/efi_loader/efi_device_path.c +++ b/lib/efi_loader/efi_device_path.c @@ -960,6 +960,28 @@ struct efi_device_path *efi_dp_from_file(struct blk_desc *desc, int part, return start; } +struct efi_device_path *efi_dp_from_uart(void) +{ + void *buf, *pos; + struct efi_device_path_uart *uart; + size_t dpsize = sizeof(ROOT) + sizeof(*uart) + sizeof(END); + + buf = dp_alloc(dpsize); + if (!buf) + return NULL; + pos = buf; + memcpy(pos, &ROOT, sizeof(ROOT)); + pos += sizeof(ROOT); + uart = pos; + uart->dp.type = DEVICE_PATH_TYPE_MESSAGING_DEVICE; + uart->dp.sub_type = DEVICE_PATH_SUB_TYPE_MSG_UART; + uart->dp.length = sizeof(*uart); + pos += sizeof(*uart); + memcpy(pos, &END, sizeof(END)); + + return buf; +} + #ifdef CONFIG_NET struct efi_device_path *efi_dp_from_eth(void) { @@ -1086,7 +1108,6 @@ efi_status_t efi_dp_from_name(const char *dev, const char *devnr, struct efi_device_path **device, struct efi_device_path **file) { - int is_net; struct blk_desc *desc = NULL; struct disk_partition fs_partition; int part = 0; @@ -1096,8 +1117,15 @@ efi_status_t efi_dp_from_name(const char *dev, const char *devnr, if (path && !file) return EFI_INVALID_PARAMETER; - is_net = !strcmp(dev, "Net"); - if (!is_net) { + if (!strcmp(dev, "Net")) { +#ifdef CONFIG_NET + if (device) + *device = efi_dp_from_eth(); +#endif + } else if (!strcmp(dev, "Uart")) { + if (device) + *device = efi_dp_from_uart(); + } else { part = blk_get_device_part_str(dev, devnr, &desc, &fs_partition, 1); if (part < 0 || !desc) @@ -1105,11 +1133,6 @@ efi_status_t efi_dp_from_name(const char *dev, const char *devnr, if (device) *device = efi_dp_from_part(desc, part); - } else { -#ifdef CONFIG_NET - if (device) - *device = efi_dp_from_eth(); -#endif } if (!path) @@ -1120,7 +1143,7 @@ efi_status_t efi_dp_from_name(const char *dev, const char *devnr, s = filename; while ((s = strchr(s, '/'))) *s++ = '\\'; - *file = efi_dp_from_file(is_net ? NULL : desc, part, filename); + *file = efi_dp_from_file(desc, part, filename); if (!*file) return EFI_INVALID_PARAMETER; diff --git a/lib/efi_loader/efi_device_path_to_text.c b/lib/efi_loader/efi_device_path_to_text.c index edc9fdc387..43554cd771 100644 --- a/lib/efi_loader/efi_device_path_to_text.c +++ b/lib/efi_loader/efi_device_path_to_text.c @@ -118,6 +118,19 @@ static char *dp_msging(char *s, struct efi_device_path *dp) ide->logical_unit_number); break; } + case DEVICE_PATH_SUB_TYPE_MSG_UART: { + struct efi_device_path_uart *uart = + (struct efi_device_path_uart *)dp; + s += sprintf(s, "Uart(%lld,%d,%d,", uart->baud_rate, + uart->data_bits, uart->parity); + switch (uart->stop_bits) { + case 2: + s += sprintf(s, "1.5)"); + default: + s += sprintf(s, "%d)", uart->stop_bits); + } + break; + } case DEVICE_PATH_SUB_TYPE_MSG_USB: { struct efi_device_path_usb *udp = (struct efi_device_path_usb *)dp; From 76b0a19022e22a5bbb84cd76d516bdb625a70417 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Fri, 19 Mar 2021 02:50:57 +0000 Subject: [PATCH 3/3] cmd/load: support uploading EFI binary via UART When uploading an EFI binary via the UART we have to call efi_set_bootdev() or we won't be able to execute it. Put the includes into alphabetic order. Fixes: 5f59518a7b1a ("efi_loader: setting boot device") Signed-off-by: Heinrich Schuchardt --- cmd/load.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/cmd/load.c b/cmd/load.c index 5bbc39baea..b7894d7db0 100644 --- a/cmd/load.c +++ b/cmd/load.c @@ -11,12 +11,14 @@ #include #include #include +#include #include +#include #include #include -#include +#include #include -#include +#include #include #include #include @@ -996,6 +998,10 @@ static ulong load_serial_ymodem(ulong offset, int mode) } } + if (IS_ENABLED(CONFIG_CMD_BOOTEFI)) + efi_set_bootdev("Uart", "", "", + map_sysmem(offset, 0), size); + } else { printf("%s\n", xyzModem_error(err)); }