[PATCH v2] lz4: fix decompressor on big-endian powerpc

Tom Rini trini at konsulko.com
Fri Jul 17 22:57:04 CEST 2020


On Sun, Jun 07, 2020 at 02:29:18PM +0200, Rasmus Villemoes wrote:

> Booting an lz4-compressed kernel image fails on our powerpc board with
> -EPROTONOSUPPORT. Adding a bit of debug prints, we get
> 
>   magic: 0x184d2204
>   flags: 0x64
>   reserved0: 1
>   has_content_checksum: 1
>   has_content_size: 0
>   has_block_checksum: 0
>   independent_blocks: 1
>   version: 0
>   block_descriptor: 70
>   reserved1: 7
>   max_block_size: 0
>   reserved2: 0
> 
> So the magic is ok, but the version check fails, also some reserved
> bits are apparently set. But that's because the code interprets the
> "flags" and "block_descriptor" bytes wrongly:
> 
> Using bit-fields to access individual bits of an "on the wire" format
> is not portable, not even when restricted to the C flavour implemented
> by gcc. Quoting the gcc manual:
> 
>    * 'The order of allocation of bit-fields within a unit (C90 6.5.2.1,
>      C99 and C11 6.7.2.1).'
> 
>      Determined by ABI.
> 
> and indeed, the PPC Processor ABI supplement says
> 
>    * Bit-fields are allocated from right to left (least to most
>      significant) on Little-Endian implementations and from left to
>      right (most to least significant) on Big-Endian implementations.
> 
> The upstream code (github.com/lz4/lz4) uses explicit shifts and masks
> for encoding/decoding:
> 
>     /* FLG Byte */
>     *dstPtr++ = (BYTE)(((1 & _2BITS) << 6)    /* Version('01') */
>         + ((cctxPtr->prefs.frameInfo.blockMode & _1BIT ) << 5)
>         + ((cctxPtr->prefs.frameInfo.blockChecksumFlag & _1BIT ) << 4)
>         + ((unsigned)(cctxPtr->prefs.frameInfo.contentSize > 0) << 3)
>         + ((cctxPtr->prefs.frameInfo.contentChecksumFlag & _1BIT ) << 2)
>         +  (cctxPtr->prefs.frameInfo.dictID > 0) );
> 
>     /* Flags */
>     {   U32 const FLG = srcPtr[4];
>         U32 const version = (FLG>>6) & _2BITS;
>         blockChecksumFlag = (FLG>>4) & _1BIT;
>         blockMode = (FLG>>5) & _1BIT;
>         contentSizeFlag = (FLG>>3) & _1BIT;
>         contentChecksumFlag = (FLG>>2) & _1BIT;
>         dictIDFlag = FLG & _1BIT;
>         /* validate */
>         if (((FLG>>1)&_1BIT) != 0) return err0r(LZ4F_ERROR_reservedFlag_set); /* Reserved bit */
>         if (version != 1) return err0r(LZ4F_ERROR_headerVersion_wrong);        /* Version Number, only supported value */
>     }
> 
> Do the same here, and while at it, be more careful to use unaligned
> accessors to what is most likely unaligned. Also update the comment to
> make it clear that it only refers to the lz4.c file, not the following
> code of lz4_wrapper.c.
> 
> This has been tested partly, of course, by seeing that my
> lz4-compressed kernel now boots, partly by running the (de)compression
> test-suite in the (x86_64) sandbox - i.e., it should still work just
> fine on little-endian hosts.
> 
> Reviewed-by: Julius Werner <jwerner at chromium.org>
> Signed-off-by: Rasmus Villemoes <rasmus.villemoes at prevas.dk>

Applied to u-boot/master, thanks!

-- 
Tom
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 659 bytes
Desc: not available
URL: <https://lists.denx.de/pipermail/u-boot/attachments/20200717/b5f021fd/attachment.sig>


More information about the U-Boot mailing list