xz_dec_bcj.c revision 2
/* xz_dec_bcj.c - Branch/Call/Jump (BCJ) filter decoders */
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2010 Free Software Foundation, Inc.
*
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* GRUB is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
*/
/*
* This file is based on code from XZ embedded project
*/
#include "xz_private.h"
struct xz_dec_bcj {
/* Type of the BCJ filter being used */
enum {
} type;
/*
* Return value of the next filter in the chain. We need to preserve
* this information across calls, because we must not call the next
* filter anymore once it has returned XZ_STREAM_END.
*/
/* True if we are operating in single-call mode. */
bool single_call;
/*
* Absolute position relative to the beginning of the uncompressed
* data (in a single .xz Block). We care only about the lowest 32
* bits so this doesn't need to be uint64_t even with big files.
*/
/* x86 filter state */
/* Temporary space to hold the variables from struct xz_buf */
struct {
/* Amount of already filtered data in the beginning of buf */
/* Total amount of data currently stored in buf */
/*
* Buffer to hold a mix of filtered and unfiltered data. This
* needs to be big enough to hold Alignment + 2 * Look-ahead:
*
* Type Alignment Look-ahead
* x86 1 4
* PowerPC 4 0
* IA-64 16 0
* ARM 4 0
* ARM-Thumb 2 2
* SPARC 4 0
*/
} temp;
};
#ifdef XZ_DEC_X86
/*
* This is macro used to test the most significant byte of a memory address
* in an x86 instruction.
*/
{
static const bool mask_to_allowed_status[8]
= { true, true, true, false, true, false, false, false };
size_t i;
uint32_t j;
uint8_t b;
if (size <= 4)
return 0;
size -= 4;
for (i = 0; i < size; ++i) {
continue;
if (prev_pos > 3) {
prev_mask = 0;
} else {
if (prev_mask != 0) {
|| bcj_x86_test_msbyte(b)) {
prev_pos = i;
continue;
}
}
}
prev_pos = i;
while (true) {
if (prev_mask == 0)
break;
if (!bcj_x86_test_msbyte(b))
break;
}
dest &= 0x01FFFFFF;
i += 4;
} else {
}
}
return i;
}
#endif
#ifdef XZ_DEC_POWERPC
{
size_t i;
instr &= 0x03FFFFFC;
instr &= 0x03FFFFFC;
instr |= 0x48000001;
}
}
return i;
}
#endif
#ifdef XZ_DEC_IA64
{
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
4, 4, 6, 6, 0, 0, 7, 7,
4, 4, 0, 0, 4, 4, 0, 0
};
/*
* The local variables take a little bit stack space, but it's less
* than what LZMA2 decoder takes, so it doesn't make sense to reduce
* stack usage here without doing that for the LZMA2 decoder too.
*/
/* Loop counters */
size_t i;
size_t j;
/* Instruction slot (0, 1, or 2) in the 128-bit instruction word */
/* Bitwise offset of the instruction indicated by slot */
/* bit_pos split into byte and bit parts */
/* Address part of an instruction */
/* Mask used to detect which instructions to convert */
/* 41-bit instruction stored somewhere in the lowest 48 bits */
/* Instruction normalized with bit_res for easier manipulation */
continue;
instr = 0;
for (j = 0; j < 6; ++j)
<< (8 * j);
addr <<= 4;
addr >>= 4;
<< (36 - 20);
for (j = 0; j < 6; j++)
}
}
}
return i;
}
#endif
#ifdef XZ_DEC_ARM
{
size_t i;
addr <<= 2;
addr >>= 2;
}
}
return i;
}
#endif
#ifdef XZ_DEC_ARMTHUMB
{
size_t i;
addr <<= 1;
addr >>= 1;
i += 2;
}
}
return i;
}
#endif
#ifdef XZ_DEC_SPARC
{
size_t i;
instr <<= 2;
instr >>= 2;
}
}
return i;
}
#endif
/*
* Apply the selected BCJ filter. Update *pos and s->pos to match the amount
* of data that got filtered.
*
* NOTE: This is implemented as a switch statement to avoid using function
* pointers, which could be problematic in the kernel boot code, which must
* avoid pointers to static data (at least on x86).
*/
static void bcj_apply(struct xz_dec_bcj *s,
{
switch (s->type) {
#ifdef XZ_DEC_X86
case BCJ_X86:
break;
#endif
#ifdef XZ_DEC_POWERPC
case BCJ_POWERPC:
break;
#endif
#ifdef XZ_DEC_IA64
case BCJ_IA64:
break;
#endif
#ifdef XZ_DEC_ARM
case BCJ_ARM:
break;
#endif
#ifdef XZ_DEC_ARMTHUMB
case BCJ_ARMTHUMB:
break;
#endif
#ifdef XZ_DEC_SPARC
case BCJ_SPARC:
break;
#endif
default:
/* Never reached but silence compiler warnings. */
filtered = 0;
break;
}
}
/*
* Flush pending filtered data from temp to the output buffer.
* Move the remaining mixture of possibly filtered and unfiltered
* data to the beginning of temp.
*/
{
}
/*
* The BCJ filter functions are primitive in sense that they process the
* data in chunks of 1-16 bytes. To hide this issue, this function does
* some buffering.
*/
{
/*
* Flush pending already filtered data to the output buffer. Return
* immediatelly if we couldn't flush everything, or if the next
* filter in the chain had already returned XZ_STREAM_END.
*/
bcj_flush(s, b);
return XZ_OK;
if (s->ret == XZ_STREAM_END)
return XZ_STREAM_END;
}
/*
* If we have more output space than what is currently pending in
* temp, copy the unfiltered data from temp to the output buffer
* and try to fill the output buffer by decoding more data from the
* next filter in the chain. Apply the BCJ filter on the new data
* in the output buffer. If everything cannot be filtered, copy it
* to temp and rewind the output buffer position accordingly.
*/
if (s->ret != XZ_STREAM_END
return s->ret;
/*
* As an exception, if the next filter returned XZ_STREAM_END,
* we can do that too, since the last few bytes that remain
* unfiltered are meant to remain unfiltered.
*/
if (s->ret == XZ_STREAM_END)
return XZ_STREAM_END;
}
/*
* If we have unfiltered data in temp, try to fill by decoding more
* data from the next filter. Apply the BCJ filter on temp. Then we
* hopefully can fill the actual output buffer by copying filtered
* data from temp. A mix of filtered and unfiltered data may be left
* in temp; it will be taken care on the next call to this function.
*/
/* Make b->out{,_pos,_size} temporarily point to s->temp. */
return s->ret;
/*
* If the next filter returned XZ_STREAM_END, we mark that
* everything is filtered, since the last unfiltered bytes
* of the stream are meant to be left as is.
*/
if (s->ret == XZ_STREAM_END)
bcj_flush(s, b);
return XZ_OK;
}
return s->ret;
}
#ifdef GRUB_EMBED_DECOMPRESSOR
struct xz_dec_bcj bcj;
#endif
{
struct xz_dec_bcj *s;
#ifdef GRUB_EMBED_DECOMPRESSOR
s = &bcj;
#else
s = kmalloc(sizeof(*s), GFP_KERNEL);
#endif
if (s != NULL)
s->single_call = single_call;
return s;
}
enum xz_ret xz_dec_bcj_reset(
{
switch (id) {
#ifdef XZ_DEC_X86
case BCJ_X86:
#endif
#ifdef XZ_DEC_POWERPC
case BCJ_POWERPC:
#endif
#ifdef XZ_DEC_IA64
case BCJ_IA64:
#endif
#ifdef XZ_DEC_ARM
case BCJ_ARM:
#endif
#ifdef XZ_DEC_ARMTHUMB
case BCJ_ARMTHUMB:
#endif
#ifdef XZ_DEC_SPARC
case BCJ_SPARC:
#endif
break;
default:
/* Unsupported Filter ID */
return XZ_OPTIONS_ERROR;
}
s->pos = 0;
s->x86_prev_mask = 0;
return XZ_OK;
}