github.com/linuxboot/fiano@v1.2.0/pkg/compression/x86.go (about) 1 // Copyright 2018 the LinuxBoot Authors. All rights reserved 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package compression 6 7 // LZMAX86 implements Compressor and includes the X86 filter which is popular 8 // in some UEFI implementations. 9 type LZMAX86 struct { 10 // The X86 filter is layered on top of an existing LZMA implementation. 11 lzma Compressor 12 } 13 14 // Name returns the type of compression employed. 15 func (c *LZMAX86) Name() string { 16 return "LZMAX86" 17 } 18 19 // Decode decodes LZMA data with the x86 extension. 20 func (c *LZMAX86) Decode(encodedData []byte) ([]byte, error) { 21 decodedData, err := c.lzma.Decode(encodedData) 22 if err != nil { 23 return nil, err 24 } 25 var x86State uint32 26 x86Convert(decodedData, uint(len(decodedData)), 0, &x86State, false) 27 return decodedData, nil 28 } 29 30 // Encode encodes LZMA data with the x86 extension. 31 func (c *LZMAX86) Encode(decodedData []byte) ([]byte, error) { 32 // x86Convert modifies the input, so a copy is recommened. 33 decodedDataCpy := make([]byte, len(decodedData)) 34 copy(decodedDataCpy, decodedData) 35 36 var x86State uint32 37 x86Convert(decodedDataCpy, uint(len(decodedDataCpy)), 0, &x86State, true) 38 return c.lzma.Encode(decodedDataCpy) 39 } 40 41 // Adapted from: https://github.com/tianocore/edk2/blob/00f5e11913a8706a1733da2b591502d59f848a99/BaseTools/Source/C/LzmaCompress/Sdk/C/Bra86.c 42 func x86Convert(data []byte, size uint, ip uint32, state *uint32, encoding bool) uint { 43 var pos uint 44 mask := *state & 7 45 if size < 5 { 46 return 0 47 } 48 size -= 4 49 ip += 5 50 51 for { 52 p := pos 53 for ; p < size; p++ { 54 if data[p]&0xFE == 0xE8 { 55 break 56 } 57 } 58 59 { 60 d := p - pos 61 pos = p 62 if p >= size { 63 if d > 2 { 64 *state = 0 65 } else { 66 *state = mask >> d 67 } 68 return pos 69 } 70 if d > 2 { 71 mask = 0 72 } else { 73 mask >>= d 74 if mask != 0 && (mask > 4 || mask == 3 || test86MSByte(data[p+uint(mask>>1)+1])) { 75 mask = (mask >> 1) | 4 76 pos++ 77 continue 78 } 79 } 80 } 81 82 if test86MSByte(data[p+4]) { 83 v := (uint32(data[p+4]) << 24) + (uint32(data[p+3]) << 16) + (uint32(data[p+2]) << 8) + uint32(data[p+1]) 84 cur := ip + uint32(pos) 85 pos += 5 86 if encoding { 87 v += cur 88 } else { 89 v -= cur 90 } 91 if mask != 0 { 92 sh := uint((mask & 6) << 2) 93 if test86MSByte(uint8(v >> sh)) { 94 v ^= (uint32(0x100) << sh) - 1 95 if encoding { 96 v += cur 97 } else { 98 v -= cur 99 } 100 } 101 mask = 0 102 } 103 data[p+1] = uint8(v) 104 data[p+2] = uint8(v >> 8) 105 data[p+3] = uint8(v >> 16) 106 data[p+4] = uint8(0 - ((v >> 24) & 1)) 107 } else { 108 mask = (mask >> 1) | 4 109 pos++ 110 } 111 } 112 } 113 114 func test86MSByte(b byte) bool { 115 return (b+1)&0xFE == 0 116 }