diff options
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/efi_loader/efi_console.c | 7 | ||||
| -rw-r--r-- | lib/fdtdec.c | 18 | ||||
| -rw-r--r-- | lib/gunzip.c | 76 | ||||
| -rw-r--r-- | lib/string.c | 31 | ||||
| -rw-r--r-- | lib/vsprintf.c | 37 |
5 files changed, 142 insertions, 27 deletions
diff --git a/lib/efi_loader/efi_console.c b/lib/efi_loader/efi_console.c index a798d5604a3..8d076058280 100644 --- a/lib/efi_loader/efi_console.c +++ b/lib/efi_loader/efi_console.c @@ -9,6 +9,7 @@ #include <ansi.h> #include <charset.h> +#include <console.h> #include <efi_device_path.h> #include <malloc.h> #include <time.h> @@ -299,8 +300,7 @@ static int query_console_serial(int *rows, int *cols) int n[2]; /* Empty input buffer */ - while (tstc()) - getchar(); + console_flush_stdin(); /* * Not all terminals understand CSI [18t for querying the console size. @@ -960,8 +960,7 @@ static void efi_cin_check(void) */ static void efi_cin_empty_buffer(void) { - while (tstc()) - getchar(); + console_flush_stdin(); key_available = false; } diff --git a/lib/fdtdec.c b/lib/fdtdec.c index fb3375ea157..90d34ae105f 100644 --- a/lib/fdtdec.c +++ b/lib/fdtdec.c @@ -714,6 +714,24 @@ int fdtdec_get_int_array(const void *blob, int node, const char *prop_name, return err; } +int fdtdec_get_long_array(const void *blob, int node, const char *prop_name, + u64 *array, int count) +{ + const u64 *cell; + int err = 0; + + debug("%s: %s\n", __func__, prop_name); + cell = get_prop_check_min_len(blob, node, prop_name, + sizeof(u64) * count, &err); + if (!err) { + int i; + + for (i = 0; i < count; i++) + array[i] = fdt64_to_cpu(cell[i]); + } + return err; +} + int fdtdec_get_int_array_count(const void *blob, int node, const char *prop_name, u32 *array, int count) { diff --git a/lib/gunzip.c b/lib/gunzip.c index 76f3397fced..20cc14f9688 100644 --- a/lib/gunzip.c +++ b/lib/gunzip.c @@ -8,8 +8,10 @@ #include <command.h> #include <console.h> #include <div64.h> +#include <env.h> #include <gzip.h> #include <image.h> +#include <linux/sizes.h> #include <malloc.h> #include <memalign.h> #include <u-boot/crc.h> @@ -119,7 +121,7 @@ void gzwrite_progress_finish(int returnval, int gzwrite(unsigned char *src, size_t len, struct blk_desc *dev, size_t szwritebuf, off_t startoffs, size_t szexpected) { - int i, flags; + int flags; z_stream s; int r = 0; unsigned char *writebuf; @@ -127,13 +129,23 @@ int gzwrite(unsigned char *src, size_t len, struct blk_desc *dev, ulong totalfilled = 0; lbaint_t blksperbuf, outblock; u32 expected_crc; - size_t payload_size; + size_t i, payload_size; + unsigned long blocks_written; + lbaint_t writeblocks; + int numfilled = 0; int iteration = 0; - - if (len > 0xffffffff) { - log_err("Input size over 4 GiB in size not supported\n"); - return -1; - } + /* + * Allow runtime configuration of decompression chunk on + * sandbox to better cover the chunked decompression + * functionality without having to use > 4 GiB files. + */ + const ulong minchunk = 0x400; + const ulong maxchunk = SZ_4G - minchunk; + const ulong chunk = + CONFIG_IS_ENABLED(SANDBOX, + (clamp(env_get_ulong("gzwrite_chunk", 10, maxchunk), + minchunk, maxchunk)), + (maxchunk)); if (!szwritebuf || (szwritebuf % dev->blksz) || @@ -175,7 +187,7 @@ int gzwrite(unsigned char *src, size_t len, struct blk_desc *dev, return -1; } - payload_size = len - i - 8; + payload_size = len - i; memcpy(&expected_crc, src + len - 8, sizeof(expected_crc)); expected_crc = le32_to_cpu(expected_crc); @@ -205,35 +217,44 @@ int gzwrite(unsigned char *src, size_t len, struct blk_desc *dev, return -1; } - s.next_in = src + i; - s.avail_in = payload_size+8; + src += i; + s.avail_in = 0; writebuf = (unsigned char *)malloc_cache_aligned(szwritebuf); /* decompress until deflate stream ends or end of file */ do { if (s.avail_in == 0) { - printf("%s: weird termination with result %d\n", - __func__, r); - break; + if (payload_size == 0) { + printf("%s: weird termination with result %d\n", + __func__, r); + break; + } + + s.next_in = src; + s.avail_in = (payload_size > chunk) ? chunk : payload_size; + src += s.avail_in; + payload_size -= s.avail_in; } /* run inflate() on input until output buffer not full */ do { - unsigned long blocks_written; - int numfilled; - lbaint_t writeblocks; - - s.avail_out = szwritebuf; - s.next_out = writebuf; + if (numfilled) { + s.avail_out = szwritebuf - numfilled; + s.next_out = writebuf + numfilled; + } else { + s.avail_out = szwritebuf; + s.next_out = writebuf; + } r = inflate(&s, Z_SYNC_FLUSH); if ((r != Z_OK) && (r != Z_STREAM_END)) { printf("Error: inflate() returned %d\n", r); goto out; } + crc = crc32(crc, writebuf + numfilled, + szwritebuf - s.avail_out - numfilled); + totalfilled += szwritebuf - s.avail_out - numfilled; numfilled = szwritebuf - s.avail_out; - crc = crc32(crc, writebuf, numfilled); - totalfilled += numfilled; if (numfilled < szwritebuf) { writeblocks = (numfilled+dev->blksz-1) / dev->blksz; @@ -241,14 +262,17 @@ int gzwrite(unsigned char *src, size_t len, struct blk_desc *dev, dev->blksz-(numfilled%dev->blksz)); } else { writeblocks = blksperbuf; + numfilled = 0; } gzwrite_progress(iteration++, totalfilled, szexpected); - blocks_written = blk_dwrite(dev, outblock, + if (!numfilled) { + blocks_written = blk_dwrite(dev, outblock, writeblocks, writebuf); - outblock += blocks_written; + outblock += blocks_written; + } if (ctrlc()) { puts("abort\n"); goto out; @@ -258,6 +282,12 @@ int gzwrite(unsigned char *src, size_t len, struct blk_desc *dev, /* done when inflate() says it's done */ } while (r != Z_STREAM_END); + if (numfilled) { + blocks_written = blk_dwrite(dev, outblock, + writeblocks, writebuf); + outblock += blocks_written; + } + if ((szexpected != totalfilled) || (crc != expected_crc)) r = -1; diff --git a/lib/string.c b/lib/string.c index d56f88d4a84..302efe048b0 100644 --- a/lib/string.c +++ b/lib/string.c @@ -379,6 +379,37 @@ char * strndup(const char *s, size_t n) return new; } + +/** + * strdup_const - conditionally duplicate an existing const string + * @s: the string to duplicate + * + * Note: Strings allocated by kstrdup_const should be freed by kfree_const and + * must not be passed to krealloc(). + * + * Return: source string if it is in .rodata section otherwise + * fallback to kstrdup. + */ +const char *strdup_const(const char *s) +{ + if (is_kernel_rodata((unsigned long)s)) + return s; + + return strdup(s); +} + +/** + * kfree_const - conditionally free memory + * @x: pointer to the memory + * + * Function calls kfree only if @x is not in .rodata section. + */ +void kfree_const(const void *x) +{ + if (!is_kernel_rodata((unsigned long)x)) + free((void *)x); +} + #endif #ifndef __HAVE_ARCH_STRSPN diff --git a/lib/vsprintf.c b/lib/vsprintf.c index c7340a047b2..49dc9c38c65 100644 --- a/lib/vsprintf.c +++ b/lib/vsprintf.c @@ -26,6 +26,11 @@ #include <linux/types.h> #include <linux/string.h> +/* For %pOF */ +#if CONFIG_IS_ENABLED(OF_CONTROL) +#include <dm/ofnode.h> +#endif + /* we use this so that we can do without the ctype library */ #define is_digit(c) ((c) >= '0' && (c) <= '9') @@ -438,6 +443,30 @@ static char *uuid_string(char *buf, char *end, u8 *addr, int field_width, } #endif +#if CONFIG_IS_ENABLED(OF_CONTROL) && !defined(API_BUILD) +static char *ofnode_string(char *buf, char *end, ofnode *dp, int field_width, + int precision, int flags) +{ +#define NP_PATH_MAX 64 + char str[NP_PATH_MAX] = { 0 }; + const char *err = "..."; + + /* If dp == NULL output the string '<NULL>' */ + if (!dp || !ofnode_valid(*dp)) + return string(buf, end, NULL, field_width, precision, flags); + + /* Get the path and indicate if it got cut off */ + if (ofnode_get_path(*dp, str, NP_PATH_MAX)) { + str[NP_PATH_MAX - 1] = '\0'; + char *p = str + min((NP_PATH_MAX - 2) - strlen(err), strlen(str)); + memcpy(p, err, strlen(err) + 1); + } + + return string(buf, end, str, field_width, precision, flags); +#undef NP_PATH_MAX +} +#endif + /* * Show a '%p' thing. A kernel extension is that the '%p' is followed * by an extra set of alphanumeric characters that are extended format @@ -474,6 +503,14 @@ static char *pointer(const char *fmt, char *buf, char *end, void *ptr, return device_path_string(buf, end, ptr, field_width, precision, flags); #endif +/* Device paths only exist in the EFI context. */ +#if CONFIG_IS_ENABLED(OF_CONTROL) && !defined(API_BUILD) + case 'O': + if (fmt[1] == 'F') + return ofnode_string(buf, end, ptr, field_width, + precision, flags); + break; +#endif case 'a': flags |= SPECIAL | ZEROPAD; |
