[U-Boot] [PATCH] cmd_bmp: fix very long uncompressing time of gzipped bitmaps

If a compressed bitmap is located in sectors at the end of the flash and it's offset + CONFIG_SYS_VIDEO_LOGO_MAX_SIZE > 0xFFFFFFFF, the uncompressing time is very long, since processing the stream is done bytewise (and not blockwise) due to overflow in inflate_fast() while calculation and checking for enough input available.
Fix available bitmap data input size for gunzip() to match the actually available data size to prevent the observed misbehaviour.
Reported-by: Werner Pfister werner.pfister@intercontrol.de Signed-off-by: Anatolij Gustschin agust@denx.de --- common/cmd_bmp.c | 9 +++++++++ drivers/video/cfb_console.c | 10 ++++++++++ 2 files changed, 19 insertions(+), 0 deletions(-)
diff --git a/common/cmd_bmp.c b/common/cmd_bmp.c index 23fc82f..0640a95 100644 --- a/common/cmd_bmp.c +++ b/common/cmd_bmp.c @@ -32,6 +32,8 @@ #include <asm/byteorder.h> #include <malloc.h>
+DECLARE_GLOBAL_DATA_PTR; + static int bmp_info (ulong addr); static int bmp_display (ulong addr, int x, int y);
@@ -47,6 +49,7 @@ static int bmp_display (ulong addr, int x, int y); #ifdef CONFIG_VIDEO_BMP_GZIP bmp_image_t *gunzip_bmp(unsigned long addr, unsigned long *lenp) { + unsigned long flash_end; void *dst; unsigned long len; bmp_image_t *bmp; @@ -55,6 +58,12 @@ bmp_image_t *gunzip_bmp(unsigned long addr, unsigned long *lenp) * Decompress bmp image */ len = CONFIG_SYS_VIDEO_LOGO_MAX_SIZE; + flash_end = gd->bd->bi_flashstart + gd->bd->bi_flashsize - 1; + if (addr >= gd->bd->bi_flashstart && addr <= flash_end) { + if (flash_end - addr < CONFIG_SYS_VIDEO_LOGO_MAX_SIZE) + len = flash_end - addr + 1; + } + dst = malloc(CONFIG_SYS_VIDEO_LOGO_MAX_SIZE); if (dst == NULL) { puts("Error: malloc in gunzip failed!\n"); diff --git a/drivers/video/cfb_console.c b/drivers/video/cfb_console.c index b427c84..42b4b21 100644 --- a/drivers/video/cfb_console.c +++ b/drivers/video/cfb_console.c @@ -334,6 +334,7 @@ void console_cursor (int state); #define PRINTD(x) #endif
+DECLARE_GLOBAL_DATA_PTR;
#ifdef CONFIG_CONSOLE_EXTRA_INFO extern void video_get_info_str ( /* setup a board string: type, speed, etc. */ @@ -1043,7 +1044,16 @@ int video_display_bitmap (ulong bmp_image, int x, int y) /* * Could be a gzipped bmp image, try to decrompress... */ + unsigned long addr = (unsigned long)bmp; + unsigned long flash_end; + len = CONFIG_SYS_VIDEO_LOGO_MAX_SIZE; + flash_end = gd->bd->bi_flashstart + gd->bd->bi_flashsize - 1; + if (addr >= gd->bd->bi_flashstart && addr <= flash_end) { + if (flash_end - addr < CONFIG_SYS_VIDEO_LOGO_MAX_SIZE) + len = flash_end - addr + 1; + } + dst = malloc(CONFIG_SYS_VIDEO_LOGO_MAX_SIZE); if (dst == NULL) { printf("Error: malloc in gunzip failed!\n");

On Tuesday, July 19, 2011 08:12:43 Anatolij Gustschin wrote:
If a compressed bitmap is located in sectors at the end of the flash and it's offset + CONFIG_SYS_VIDEO_LOGO_MAX_SIZE > 0xFFFFFFFF, the uncompressing time is very long, since processing the stream is done bytewise (and not blockwise) due to overflow in inflate_fast() while calculation and checking for enough input available.
Fix available bitmap data input size for gunzip() to match the actually available data size to prevent the observed misbehaviour.
this doesnt sound right. the flash region should have no relevance at all to the bmp funcs (and the current ones dont check it at all). also, i'm not sure your code currently handles multiple flashes as bi_flashstart really is only good for flash_info[0].
if there's an overflow happening, then the overflow should be detected generically and handled without any knowledge at all of flashes. -mike

If compressed data is located in sectors at the end of the flash and it's offset + input stream size > 0xFFFFFFFF, the uncompressing time is very long, since processing of the stream is done bytewise (and not blockwise) due to overflow in inflate_fast() while calculation and checking for enough input available.
Check for this overflow condition and limit the available stream input size to the actually max. possible input size. This fixes the problem.
The issue is easily reproduceable by placing a gziped bitmap in flash, e.g. at FFF80000, and running 'bmp' commands like 'bmp info FFF80000' or 'bmp display FFF80000'. The uncompressing can take up to 3 sec. whereas it should normaly take a fraction of a second. If the 'splashimage' environment variable points to this address, the booting time also increases significantly.
Signed-off-by: Anatolij Gustschin agust@denx.de --- Note: there are 6 errors and 4 warning reported by checkpatch.pl for this patch. I didn't fix them intentionally and used the coding style of the zlib code here. The code would look ugly otherwise.
lib/zlib/inffast.c | 8 ++++++++ 1 files changed, 8 insertions(+), 0 deletions(-)
diff --git a/lib/zlib/inffast.c b/lib/zlib/inffast.c index 8e823df..4834b0c 100644 --- a/lib/zlib/inffast.c +++ b/lib/zlib/inffast.c @@ -100,6 +100,14 @@ unsigned start; /* inflate()'s starting value for strm->avail_out */ state = (struct inflate_state FAR *)strm->state; in = strm->next_in - OFF; last = in + (strm->avail_in - 5); + if (in > last && strm->avail_in > 5) { + /* + * overflow detected, limit strm->avail_in to the + * max. possible size and recalculate last + */ + strm->avail_in = 0xffffffff - (unsigned int)in; + last = in + (strm->avail_in - 5); + } out = strm->next_out - OFF; beg = out - (start - strm->avail_out); end = out + (strm->avail_out - 257);

On Saturday 15 October 2011 12:32:52 Anatolij Gustschin wrote:
If compressed data is located in sectors at the end of the flash and it's offset + input stream size > 0xFFFFFFFF, the uncompressing time is very long, since processing of the stream is done bytewise (and not blockwise) due to overflow in inflate_fast() while calculation and checking for enough input available.
Check for this overflow condition and limit the available stream input size to the actually max. possible input size. This fixes the problem.
The issue is easily reproduceable by placing a gziped bitmap in flash, e.g. at FFF80000, and running 'bmp' commands like 'bmp info FFF80000' or 'bmp display FFF80000'. The uncompressing can take up to 3 sec. whereas it should normaly take a fraction of a second. If the 'splashimage' environment variable points to this address, the booting time also increases significantly.
can we send this to the upstream zlib project if it isn't there already and get feedback from them ? -mike

Dear Anatolij Gustschin,
In message 1318696372-13816-1-git-send-email-agust@denx.de you wrote:
If compressed data is located in sectors at the end of the flash and it's offset + input stream size > 0xFFFFFFFF, the uncompressing time is very long, since processing of the stream is done bytewise (and not blockwise) due to overflow in inflate_fast() while calculation and checking for enough input available.
Check for this overflow condition and limit the available stream input size to the actually max. possible input size. This fixes the problem.
The issue is easily reproduceable by placing a gziped bitmap in flash, e.g. at FFF80000, and running 'bmp' commands like 'bmp info FFF80000' or 'bmp display FFF80000'. The uncompressing can take up to 3 sec. whereas it should normaly take a fraction of a second. If the 'splashimage' environment variable points to this address, the booting time also increases significantly.
Signed-off-by: Anatolij Gustschin agust@denx.de
Note: there are 6 errors and 4 warning reported by checkpatch.pl for this patch. I didn't fix them intentionally and used the coding style of the zlib code here. The code would look ugly otherwise.
lib/zlib/inffast.c | 8 ++++++++ 1 files changed, 8 insertions(+), 0 deletions(-)
Applied, thanks.
Best regards,
Wolfgang Denk
participants (3)
-
Anatolij Gustschin
-
Mike Frysinger
-
Wolfgang Denk