From 4972156c9ed72432489cfd6c5499cab9d41694f7 Mon Sep 17 00:00:00 2001 From: Ladislav Michl Date: Wed, 21 Aug 2019 14:42:35 +0200 Subject: startup: Fix typo in comment Fixes: 35266d7e583f ("startup: Factor out the autoboot counter...") Signed-off-by: Ladislav Michl Signed-off-by: Sascha Hauer --- common/startup.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'common') diff --git a/common/startup.c b/common/startup.c index 88eeee5e3d..b5b86d1141 100644 --- a/common/startup.c +++ b/common/startup.c @@ -202,7 +202,7 @@ void set_autoboot_state(enum autoboot_state autoboot) * do_autoboot_countdown - print autoboot countdown to console * * This prints the autoboot countdown to the console and waits for input. This - * evaluates the global.autoboot_about_key to determine which keys are allowed + * evaluates the global.autoboot_abort_key to determine which keys are allowed * to interrupt booting and also global.autoboot_timeout to determine the timeout * for the counter. This function can be called multiple times, it is executed * only the first time. -- cgit v1.2.3 From b1d88eadaa7772f8f01a402dcdd7f70e8c36c166 Mon Sep 17 00:00:00 2001 From: Ahmad Fatoum Date: Thu, 22 Aug 2019 07:51:05 +0200 Subject: ratp: fix use of %hu for printing int While each of path_size and data_size is 16 bit in size, their sum may exceed this. Also the type of the resulting expression is an int, thus change the format specifier accordingly. Signed-off-by: Ahmad Fatoum Signed-off-by: Sascha Hauer --- common/ratp/mw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'common') diff --git a/common/ratp/mw.c b/common/ratp/mw.c index 55e79bbaf0..772910b39d 100644 --- a/common/ratp/mw.c +++ b/common/ratp/mw.c @@ -125,7 +125,7 @@ static int ratp_cmd_mw(const struct ratp_bb *req, int req_len, /* Validate buffer size */ if (buffer_size < (path_size + data_size)) { - pr_err("ignored: size mismatch (%d < %hu): path or data not be fully given\n", + pr_err("ignored: size mismatch (%d < %u): path or data not be fully given\n", req_len, path_size + data_size); ret = -EINVAL; goto out; -- cgit v1.2.3 From 985194f2f928b9af2bdf1f9addfbf78e8b5675f0 Mon Sep 17 00:00:00 2001 From: Ahmad Fatoum Date: Thu, 22 Aug 2019 07:51:06 +0200 Subject: complete: remove unused variable instr_param serves no purpose in the function. Thus remove it. Signed-off-by: Ahmad Fatoum Signed-off-by: Sascha Hauer --- common/complete.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'common') diff --git a/common/complete.c b/common/complete.c index 2dab7d1dde..919e5abc6a 100644 --- a/common/complete.c +++ b/common/complete.c @@ -277,7 +277,6 @@ static int env_param_complete(struct string_list *sl, char *instr, int eval) struct device_d *dev; struct variable_d *var; struct env_context *c; - char *instr_param; int len; char end = '=', *pos, *dot; char *begin = ""; @@ -317,7 +316,6 @@ static int env_param_complete(struct string_list *sl, char *instr, int eval) devname = xstrndup(instr, dot - instr); - instr_param++; dev = get_device_by_name(devname); free(devname); -- cgit v1.2.3 From d421771bcea063b9bce551e06552067b9074d015 Mon Sep 17 00:00:00 2001 From: Ahmad Fatoum Date: Thu, 22 Aug 2019 08:54:05 +0200 Subject: startup: allow ctrl+c abort during boot sequence At the moment e.g. a wait for an ARP response during net boot can only aborted if the auto boot countdown was aborted. Otherwise ctrl+c is without effect. For better user experience allow code querying for ctrl+c to see it even if barebox had not dropped into a shell. Signed-off-by: Ahmad Fatoum Signed-off-by: Sascha Hauer --- common/startup.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'common') diff --git a/common/startup.c b/common/startup.c index b5b86d1141..c6e119966a 100644 --- a/common/startup.c +++ b/common/startup.c @@ -314,11 +314,11 @@ static int run_init(void) autoboot = do_autoboot_countdown(); + console_ctrlc_allow(); + if (autoboot == AUTOBOOT_BOOT) run_command("boot"); - console_ctrlc_allow(); - if (autoboot == AUTOBOOT_MENU) run_command(MENUFILE); -- cgit v1.2.3 From 75a74b5c107b3bc30f9c3836208f4c17f9309eed Mon Sep 17 00:00:00 2001 From: Ahmad Fatoum Date: Fri, 23 Aug 2019 11:25:31 +0200 Subject: console: fix out-of-bounds read in dputc(/dev/*, ...) Trying to output a single character via echo -a /dev/serial0-1 currently results in garbage output after the newline, because console.c's fops_write discards the buffer length and passes the buffer to (struct cdev)::puts which only handles NUL-terminated strings. Fix this by amending (struct cdev)::puts with a new nbytes parameter, which is correctly propagated. All this functions now return at most the nbytes parameter they were passed in. This fixes __console_puts, which used to count new lines twice in its return value. Fixes: b4f55fcf35 ("console: expose consoles in devfs") Cc: Bastian Krause Signed-off-by: Ahmad Fatoum Signed-off-by: Sascha Hauer --- common/console.c | 19 +++++++++---------- common/ratp/ratp.c | 12 +++++------- drivers/serial/efi-stdio.c | 5 +++-- drivers/serial/serial_efi.c | 5 +++-- fs/pstore/platform.c | 29 +++++++++++++++++++++++++++++ include/console.h | 2 +- 6 files changed, 50 insertions(+), 22 deletions(-) (limited to 'common') diff --git a/common/console.c b/common/console.c index ee17a508ba..3f3a30fc82 100644 --- a/common/console.c +++ b/common/console.c @@ -253,20 +253,19 @@ static void console_set_stdoutpath(struct console_device *cdev) free(str); } -static int __console_puts(struct console_device *cdev, const char *s) +static int __console_puts(struct console_device *cdev, const char *s, + size_t nbytes) { - int n = 0; + size_t i; - while (*s) { - if (*s == '\n') { + for (i = 0; i < nbytes; i++) { + if (*s == '\n') cdev->putc(cdev, '\r'); - n++; - } + cdev->putc(cdev, *s); - n++; s++; } - return n; + return i; } static int fops_open(struct cdev *cdev, unsigned long flags) @@ -298,7 +297,7 @@ static ssize_t fops_write(struct cdev* dev, const void* buf, size_t count, { struct console_device *priv = dev->priv; - priv->puts(priv, buf); + priv->puts(priv, buf, count); return count; } @@ -545,7 +544,7 @@ int console_puts(unsigned int ch, const char *str) if (initialized == CONSOLE_INIT_FULL) { for_each_console(cdev) { if (cdev->f_active & ch) { - n = cdev->puts(cdev, str); + n = cdev->puts(cdev, str, strlen(str)); } } return n; diff --git a/common/ratp/ratp.c b/common/ratp/ratp.c index 9aea1786d6..e84ad22167 100644 --- a/common/ratp/ratp.c +++ b/common/ratp/ratp.c @@ -259,19 +259,17 @@ static int ratp_console_tstc(struct console_device *cdev) return kfifo_len(ctx->console_recv_fifo) ? 1 : 0; } -static int ratp_console_puts(struct console_device *cdev, const char *s) +static int ratp_console_puts(struct console_device *cdev, const char *s, + size_t nbytes) { struct ratp_ctx *ctx = container_of(cdev, struct ratp_ctx, ratp_console); - int len = 0; - - len = strlen(s); if (ratp_busy(&ctx->ratp)) - return len; + return nbytes; - kfifo_put(ctx->console_transmit_fifo, s, len); + kfifo_put(ctx->console_transmit_fifo, s, nbytes); - return len; + return nbytes; } static void ratp_console_putc(struct console_device *cdev, char c) diff --git a/drivers/serial/efi-stdio.c b/drivers/serial/efi-stdio.c index 0703f727e7..2ca89fa4f8 100644 --- a/drivers/serial/efi-stdio.c +++ b/drivers/serial/efi-stdio.c @@ -243,12 +243,13 @@ static int efi_process_key(struct efi_console_priv *priv, const char *inp) return 1; } -static int efi_console_puts(struct console_device *cdev, const char *s) +static int efi_console_puts(struct console_device *cdev, const char *s, + size_t nbytes) { struct efi_console_priv *priv = to_efi(cdev); int n = 0; - while (*s) { + while (nbytes--) { if (*s == 27) { priv->efi_console_buffer[n] = 0; priv->out->output_string(priv->out, diff --git a/drivers/serial/serial_efi.c b/drivers/serial/serial_efi.c index f0a2b22c2b..667d51f622 100644 --- a/drivers/serial/serial_efi.c +++ b/drivers/serial/serial_efi.c @@ -130,13 +130,14 @@ static void efi_serial_putc(struct console_device *cdev, char c) serial->write(serial, &buffersize, &c); } -static int efi_serial_puts(struct console_device *cdev, const char *s) +static int efi_serial_puts(struct console_device *cdev, const char *s, + size_t nbytes) { struct efi_serial_port *uart = to_efi_serial_port(cdev); struct efi_serial_io_protocol *serial = uart->serial; uint32_t control; efi_status_t efiret; - unsigned long buffersize = strlen(s) * sizeof(char); + unsigned long buffersize = nbytes; do { efiret = serial->getcontrol(serial, &control); diff --git a/fs/pstore/platform.c b/fs/pstore/platform.c index 0a6fa38edc..15c0174b1f 100644 --- a/fs/pstore/platform.c +++ b/fs/pstore/platform.c @@ -46,6 +46,35 @@ void pstore_set_kmsg_bytes(int bytes) static int pstore_ready; +static void pstore_console_write(const char *s, unsigned c) +{ + const char *e = s + c; + + while (s < e) { + struct pstore_record record = { + .type = PSTORE_TYPE_CONSOLE, + .psi = psinfo, + }; + + if (c > psinfo->bufsize) + c = psinfo->bufsize; + + record.buf = (char *)s; + record.size = c; + psinfo->write_buf(PSTORE_TYPE_CONSOLE, 0, &record.id, 0, + record.buf, 0, record.size, psinfo); + s += c; + c = e - s; + } +} + +static int pstore_console_puts(struct console_device *cdev, const char *s, + size_t nbytes) +{ + pstore_console_write(s, nbytes); + return nbytes; +} + void pstore_log(const char *str) { uint64_t id; diff --git a/include/console.h b/include/console.h index 4062e5abf6..7afe59e93a 100644 --- a/include/console.h +++ b/include/console.h @@ -42,7 +42,7 @@ struct console_device { int (*tstc)(struct console_device *cdev); void (*putc)(struct console_device *cdev, char c); - int (*puts)(struct console_device *cdev, const char *s); + int (*puts)(struct console_device *cdev, const char *s, size_t nbytes); int (*getc)(struct console_device *cdev); int (*setbrg)(struct console_device *cdev, int baudrate); void (*flush)(struct console_device *cdev); -- cgit v1.2.3 From 0ca284b26d0ef59912380478b71a90976e3e79cc Mon Sep 17 00:00:00 2001 From: Clement Leger Date: Wed, 4 Sep 2019 13:24:49 +0200 Subject: elf: add 64 bits elf loading support This patch add elf64 loading support to the elf loader. Since elf32 and elf64 uses completely different types, to avoid copying all the code and simply replace elf32 with elf64, use a macro which will return the appropriate field for each type of header. This macro generates getter for elf structures according to the class of the loaded elf. All direct elf struct dereference are then replaced by call to generated functions. This allows to keep a common loader code even if types are different. Tested-by: Oleksij Rempel Signed-off-by: Clement Leger Signed-off-by: Sascha Hauer --- common/elf.c | 45 +++++++++++++++++++++++---------------------- include/elf.h | 29 ++++++++++++++++++++++++++++- 2 files changed, 51 insertions(+), 23 deletions(-) (limited to 'common') diff --git a/common/elf.c b/common/elf.c index 8edf388564..4733accb05 100644 --- a/common/elf.c +++ b/common/elf.c @@ -45,29 +45,31 @@ static void elf_release_regions(struct elf_image *elf) static int load_elf_phdr_segment(struct elf_image *elf, void *src, - Elf32_Phdr *phdr) + void *phdr) { - void *dst = (void *)phdr->p_paddr; + void *dst = (void *) elf_phdr_p_paddr(elf, phdr); int ret; + u64 p_filesz = elf_phdr_p_filesz(elf, phdr); + u64 p_memsz = elf_phdr_p_memsz(elf, phdr); /* we care only about PT_LOAD segments */ - if (phdr->p_type != PT_LOAD) + if (elf_phdr_p_type(elf, phdr) != PT_LOAD) return 0; - if (!phdr->p_filesz) + if (!p_filesz) return 0; - pr_debug("Loading phdr to 0x%p (%i bytes)\n", dst, phdr->p_filesz); + pr_debug("Loading phdr to 0x%p (%llu bytes)\n", dst, p_filesz); - ret = elf_request_region(elf, (resource_size_t)dst, phdr->p_filesz); + ret = elf_request_region(elf, (resource_size_t)dst, p_filesz); if (ret) return ret; - memcpy(dst, src, phdr->p_filesz); + memcpy(dst, src, p_filesz); - if (phdr->p_filesz < phdr->p_memsz) - memset(dst + phdr->p_filesz, 0x00, - phdr->p_memsz - phdr->p_filesz); + if (p_filesz < p_memsz) + memset(dst + p_filesz, 0x00, + p_memsz - p_filesz); return 0; } @@ -75,14 +77,13 @@ static int load_elf_phdr_segment(struct elf_image *elf, void *src, static int load_elf_image_phdr(struct elf_image *elf) { void *buf = elf->buf; - Elf32_Ehdr *ehdr = buf; - Elf32_Phdr *phdr = (Elf32_Phdr *)(buf + ehdr->e_phoff); + void *phdr = (void *) (buf + elf_hdr_e_phoff(elf, buf)); int i, ret; - elf->entry = ehdr->e_entry; + elf->entry = elf_hdr_e_entry(elf, buf); - for (i = 0; i < ehdr->e_phnum; ++i) { - void *src = buf + phdr->p_offset; + for (i = 0; i < elf_hdr_e_phnum(elf, buf) ; ++i) { + void *src = buf + elf_phdr_p_offset(elf, phdr); ret = load_elf_phdr_segment(elf, src, phdr); /* in case of error elf_load_image() caller should clean up and @@ -90,22 +91,22 @@ static int load_elf_image_phdr(struct elf_image *elf) if (ret) return ret; - ++phdr; + phdr += elf_size_of_phdr(elf); } return 0; } -static int elf_check_image(void *buf) +static int elf_check_image(struct elf_image *elf) { - Elf32_Ehdr *ehdr = (Elf32_Ehdr *)buf; - - if (strncmp(buf, ELFMAG, SELFMAG)) { + if (strncmp(elf->buf, ELFMAG, SELFMAG)) { pr_err("ELF magic not found.\n"); return -EINVAL; } - if (ehdr->e_type != ET_EXEC) { + elf->class = ((char *) elf->buf)[EI_CLASS]; + + if (elf_hdr_e_type(elf, elf->buf) != ET_EXEC) { pr_err("Non EXEC ELF image.\n"); return -ENOEXEC; } @@ -124,7 +125,7 @@ struct elf_image *elf_load_image(void *buf) elf->buf = buf; - ret = elf_check_image(buf); + ret = elf_check_image(elf); if (ret) return ERR_PTR(ret); diff --git a/include/elf.h b/include/elf.h index 92c8d9c127..633f4992dd 100644 --- a/include/elf.h +++ b/include/elf.h @@ -400,11 +400,38 @@ static inline void arch_write_notes(struct file *file) { } struct elf_image { struct list_head list; - unsigned long entry; + u8 class; + u64 entry; void *buf; }; struct elf_image *elf_load_image(void *buf); void elf_release_image(struct elf_image *elf); +#define ELF_GET_FIELD(__s, __field, __type) \ +static inline __type elf_##__s##_##__field(struct elf_image *elf, void *arg) { \ + if (elf->class == ELFCLASS32) \ + return (__type) ((struct elf32_##__s *) arg)->__field; \ + else \ + return (__type) ((struct elf64_##__s *) arg)->__field; \ +} + +ELF_GET_FIELD(hdr, e_entry, u64) +ELF_GET_FIELD(hdr, e_phnum, u16) +ELF_GET_FIELD(hdr, e_phoff, u64) +ELF_GET_FIELD(hdr, e_type, u16) +ELF_GET_FIELD(phdr, p_paddr, u64) +ELF_GET_FIELD(phdr, p_filesz, u64) +ELF_GET_FIELD(phdr, p_memsz, u64) +ELF_GET_FIELD(phdr, p_type, u32) +ELF_GET_FIELD(phdr, p_offset, u64) + +static inline unsigned long elf_size_of_phdr(struct elf_image *elf) +{ + if (elf->class == ELFCLASS32) + return sizeof(Elf32_Phdr); + else + return sizeof(Elf64_Phdr); +} + #endif /* _LINUX_ELF_H */ -- cgit v1.2.3 From b330984ac85f9057846b20361dbf083c2d43547c Mon Sep 17 00:00:00 2001 From: David Dgien Date: Sun, 8 Sep 2019 18:01:11 -0400 Subject: console: set default console_device devname Some commands (loadb/x/y) rely on console_get_by_name, which searches the list of console devices based on console_device->devname. However, some serial drivers do not set devname, meaning that their respective console_devices can never be found. During console_register, ensure that a default devname is set if one is not already explicitly set. Signed-off-by: David Dgien Signed-off-by: Sascha Hauer --- common/console.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'common') diff --git a/common/console.c b/common/console.c index 3f3a30fc82..d04aae58f9 100644 --- a/common/console.c +++ b/common/console.c @@ -323,6 +323,9 @@ int console_register(struct console_device *newcdev) dev->parent = newcdev->dev; platform_device_register(dev); + if (!newcdev->devname) + newcdev->devname = xstrdup(dev_name(dev)); + newcdev->open_count = 0; /* -- cgit v1.2.3