brintos

brintos / linux-shallow public Read only

0
0
Text · 16.6 KiB · 8237db1 Raw
738 lines · c
1// SPDX-License-Identifier: 0BSD2 3/*4 * Branch/Call/Jump (BCJ) filter decoders5 *6 * Authors: Lasse Collin <lasse.collin@tukaani.org>7 *          Igor Pavlov <https://7-zip.org/>8 */9 10#include "xz_private.h"11 12/*13 * The rest of the file is inside this ifdef. It makes things a little more14 * convenient when building without support for any BCJ filters.15 */16#ifdef XZ_DEC_BCJ17 18struct xz_dec_bcj {19	/* Type of the BCJ filter being used */20	enum {21		BCJ_X86 = 4,        /* x86 or x86-64 */22		BCJ_POWERPC = 5,    /* Big endian only */23		BCJ_IA64 = 6,       /* Big or little endian */24		BCJ_ARM = 7,        /* Little endian only */25		BCJ_ARMTHUMB = 8,   /* Little endian only */26		BCJ_SPARC = 9,      /* Big or little endian */27		BCJ_ARM64 = 10,     /* AArch64 */28		BCJ_RISCV = 11      /* RV32GQC_Zfh, RV64GQC_Zfh */29	} type;30 31	/*32	 * Return value of the next filter in the chain. We need to preserve33	 * this information across calls, because we must not call the next34	 * filter anymore once it has returned XZ_STREAM_END.35	 */36	enum xz_ret ret;37 38	/* True if we are operating in single-call mode. */39	bool single_call;40 41	/*42	 * Absolute position relative to the beginning of the uncompressed43	 * data (in a single .xz Block). We care only about the lowest 3244	 * bits so this doesn't need to be uint64_t even with big files.45	 */46	uint32_t pos;47 48	/* x86 filter state */49	uint32_t x86_prev_mask;50 51	/* Temporary space to hold the variables from struct xz_buf */52	uint8_t *out;53	size_t out_pos;54	size_t out_size;55 56	struct {57		/* Amount of already filtered data in the beginning of buf */58		size_t filtered;59 60		/* Total amount of data currently stored in buf  */61		size_t size;62 63		/*64		 * Buffer to hold a mix of filtered and unfiltered data. This65		 * needs to be big enough to hold Alignment + 2 * Look-ahead:66		 *67		 * Type         Alignment   Look-ahead68		 * x86              1           469		 * PowerPC          4           070		 * IA-64           16           071		 * ARM              4           072		 * ARM-Thumb        2           273		 * SPARC            4           074		 */75		uint8_t buf[16];76	} temp;77};78 79#ifdef XZ_DEC_X8680/*81 * This is used to test the most significant byte of a memory address82 * in an x86 instruction.83 */84static inline int bcj_x86_test_msbyte(uint8_t b)85{86	return b == 0x00 || b == 0xFF;87}88 89static size_t bcj_x86(struct xz_dec_bcj *s, uint8_t *buf, size_t size)90{91	static const bool mask_to_allowed_status[8]92		= { true, true, true, false, true, false, false, false };93 94	static const uint8_t mask_to_bit_num[8] = { 0, 1, 2, 2, 3, 3, 3, 3 };95 96	size_t i;97	size_t prev_pos = (size_t)-1;98	uint32_t prev_mask = s->x86_prev_mask;99	uint32_t src;100	uint32_t dest;101	uint32_t j;102	uint8_t b;103 104	if (size <= 4)105		return 0;106 107	size -= 4;108	for (i = 0; i < size; ++i) {109		if ((buf[i] & 0xFE) != 0xE8)110			continue;111 112		prev_pos = i - prev_pos;113		if (prev_pos > 3) {114			prev_mask = 0;115		} else {116			prev_mask = (prev_mask << (prev_pos - 1)) & 7;117			if (prev_mask != 0) {118				b = buf[i + 4 - mask_to_bit_num[prev_mask]];119				if (!mask_to_allowed_status[prev_mask]120						|| bcj_x86_test_msbyte(b)) {121					prev_pos = i;122					prev_mask = (prev_mask << 1) | 1;123					continue;124				}125			}126		}127 128		prev_pos = i;129 130		if (bcj_x86_test_msbyte(buf[i + 4])) {131			src = get_unaligned_le32(buf + i + 1);132			while (true) {133				dest = src - (s->pos + (uint32_t)i + 5);134				if (prev_mask == 0)135					break;136 137				j = mask_to_bit_num[prev_mask] * 8;138				b = (uint8_t)(dest >> (24 - j));139				if (!bcj_x86_test_msbyte(b))140					break;141 142				src = dest ^ (((uint32_t)1 << (32 - j)) - 1);143			}144 145			dest &= 0x01FFFFFF;146			dest |= (uint32_t)0 - (dest & 0x01000000);147			put_unaligned_le32(dest, buf + i + 1);148			i += 4;149		} else {150			prev_mask = (prev_mask << 1) | 1;151		}152	}153 154	prev_pos = i - prev_pos;155	s->x86_prev_mask = prev_pos > 3 ? 0 : prev_mask << (prev_pos - 1);156	return i;157}158#endif159 160#ifdef XZ_DEC_POWERPC161static size_t bcj_powerpc(struct xz_dec_bcj *s, uint8_t *buf, size_t size)162{163	size_t i;164	uint32_t instr;165 166	size &= ~(size_t)3;167 168	for (i = 0; i < size; i += 4) {169		instr = get_unaligned_be32(buf + i);170		if ((instr & 0xFC000003) == 0x48000001) {171			instr &= 0x03FFFFFC;172			instr -= s->pos + (uint32_t)i;173			instr &= 0x03FFFFFC;174			instr |= 0x48000001;175			put_unaligned_be32(instr, buf + i);176		}177	}178 179	return i;180}181#endif182 183#ifdef XZ_DEC_IA64184static size_t bcj_ia64(struct xz_dec_bcj *s, uint8_t *buf, size_t size)185{186	static const uint8_t branch_table[32] = {187		0, 0, 0, 0, 0, 0, 0, 0,188		0, 0, 0, 0, 0, 0, 0, 0,189		4, 4, 6, 6, 0, 0, 7, 7,190		4, 4, 0, 0, 4, 4, 0, 0191	};192 193	/*194	 * The local variables take a little bit stack space, but it's less195	 * than what LZMA2 decoder takes, so it doesn't make sense to reduce196	 * stack usage here without doing that for the LZMA2 decoder too.197	 */198 199	/* Loop counters */200	size_t i;201	size_t j;202 203	/* Instruction slot (0, 1, or 2) in the 128-bit instruction word */204	uint32_t slot;205 206	/* Bitwise offset of the instruction indicated by slot */207	uint32_t bit_pos;208 209	/* bit_pos split into byte and bit parts */210	uint32_t byte_pos;211	uint32_t bit_res;212 213	/* Address part of an instruction */214	uint32_t addr;215 216	/* Mask used to detect which instructions to convert */217	uint32_t mask;218 219	/* 41-bit instruction stored somewhere in the lowest 48 bits */220	uint64_t instr;221 222	/* Instruction normalized with bit_res for easier manipulation */223	uint64_t norm;224 225	size &= ~(size_t)15;226 227	for (i = 0; i < size; i += 16) {228		mask = branch_table[buf[i] & 0x1F];229		for (slot = 0, bit_pos = 5; slot < 3; ++slot, bit_pos += 41) {230			if (((mask >> slot) & 1) == 0)231				continue;232 233			byte_pos = bit_pos >> 3;234			bit_res = bit_pos & 7;235			instr = 0;236			for (j = 0; j < 6; ++j)237				instr |= (uint64_t)(buf[i + j + byte_pos])238						<< (8 * j);239 240			norm = instr >> bit_res;241 242			if (((norm >> 37) & 0x0F) == 0x05243					&& ((norm >> 9) & 0x07) == 0) {244				addr = (norm >> 13) & 0x0FFFFF;245				addr |= ((uint32_t)(norm >> 36) & 1) << 20;246				addr <<= 4;247				addr -= s->pos + (uint32_t)i;248				addr >>= 4;249 250				norm &= ~((uint64_t)0x8FFFFF << 13);251				norm |= (uint64_t)(addr & 0x0FFFFF) << 13;252				norm |= (uint64_t)(addr & 0x100000)253						<< (36 - 20);254 255				instr &= (1 << bit_res) - 1;256				instr |= norm << bit_res;257 258				for (j = 0; j < 6; j++)259					buf[i + j + byte_pos]260						= (uint8_t)(instr >> (8 * j));261			}262		}263	}264 265	return i;266}267#endif268 269#ifdef XZ_DEC_ARM270static size_t bcj_arm(struct xz_dec_bcj *s, uint8_t *buf, size_t size)271{272	size_t i;273	uint32_t addr;274 275	size &= ~(size_t)3;276 277	for (i = 0; i < size; i += 4) {278		if (buf[i + 3] == 0xEB) {279			addr = (uint32_t)buf[i] | ((uint32_t)buf[i + 1] << 8)280					| ((uint32_t)buf[i + 2] << 16);281			addr <<= 2;282			addr -= s->pos + (uint32_t)i + 8;283			addr >>= 2;284			buf[i] = (uint8_t)addr;285			buf[i + 1] = (uint8_t)(addr >> 8);286			buf[i + 2] = (uint8_t)(addr >> 16);287		}288	}289 290	return i;291}292#endif293 294#ifdef XZ_DEC_ARMTHUMB295static size_t bcj_armthumb(struct xz_dec_bcj *s, uint8_t *buf, size_t size)296{297	size_t i;298	uint32_t addr;299 300	if (size < 4)301		return 0;302 303	size -= 4;304 305	for (i = 0; i <= size; i += 2) {306		if ((buf[i + 1] & 0xF8) == 0xF0307				&& (buf[i + 3] & 0xF8) == 0xF8) {308			addr = (((uint32_t)buf[i + 1] & 0x07) << 19)309					| ((uint32_t)buf[i] << 11)310					| (((uint32_t)buf[i + 3] & 0x07) << 8)311					| (uint32_t)buf[i + 2];312			addr <<= 1;313			addr -= s->pos + (uint32_t)i + 4;314			addr >>= 1;315			buf[i + 1] = (uint8_t)(0xF0 | ((addr >> 19) & 0x07));316			buf[i] = (uint8_t)(addr >> 11);317			buf[i + 3] = (uint8_t)(0xF8 | ((addr >> 8) & 0x07));318			buf[i + 2] = (uint8_t)addr;319			i += 2;320		}321	}322 323	return i;324}325#endif326 327#ifdef XZ_DEC_SPARC328static size_t bcj_sparc(struct xz_dec_bcj *s, uint8_t *buf, size_t size)329{330	size_t i;331	uint32_t instr;332 333	size &= ~(size_t)3;334 335	for (i = 0; i < size; i += 4) {336		instr = get_unaligned_be32(buf + i);337		if ((instr >> 22) == 0x100 || (instr >> 22) == 0x1FF) {338			instr <<= 2;339			instr -= s->pos + (uint32_t)i;340			instr >>= 2;341			instr = ((uint32_t)0x40000000 - (instr & 0x400000))342					| 0x40000000 | (instr & 0x3FFFFF);343			put_unaligned_be32(instr, buf + i);344		}345	}346 347	return i;348}349#endif350 351#ifdef XZ_DEC_ARM64352static size_t bcj_arm64(struct xz_dec_bcj *s, uint8_t *buf, size_t size)353{354	size_t i;355	uint32_t instr;356	uint32_t addr;357 358	size &= ~(size_t)3;359 360	for (i = 0; i < size; i += 4) {361		instr = get_unaligned_le32(buf + i);362 363		if ((instr >> 26) == 0x25) {364			/* BL instruction */365			addr = instr - ((s->pos + (uint32_t)i) >> 2);366			instr = 0x94000000 | (addr & 0x03FFFFFF);367			put_unaligned_le32(instr, buf + i);368 369		} else if ((instr & 0x9F000000) == 0x90000000) {370			/* ADRP instruction */371			addr = ((instr >> 29) & 3) | ((instr >> 3) & 0x1FFFFC);372 373			/* Only convert values in the range +/-512 MiB. */374			if ((addr + 0x020000) & 0x1C0000)375				continue;376 377			addr -= (s->pos + (uint32_t)i) >> 12;378 379			instr &= 0x9000001F;380			instr |= (addr & 3) << 29;381			instr |= (addr & 0x03FFFC) << 3;382			instr |= (0U - (addr & 0x020000)) & 0xE00000;383 384			put_unaligned_le32(instr, buf + i);385		}386	}387 388	return i;389}390#endif391 392#ifdef XZ_DEC_RISCV393static size_t bcj_riscv(struct xz_dec_bcj *s, uint8_t *buf, size_t size)394{395	size_t i;396	uint32_t b1;397	uint32_t b2;398	uint32_t b3;399	uint32_t instr;400	uint32_t instr2;401	uint32_t instr2_rs1;402	uint32_t addr;403 404	if (size < 8)405		return 0;406 407	size -= 8;408 409	for (i = 0; i <= size; i += 2) {410		instr = buf[i];411 412		if (instr == 0xEF) {413			/* JAL */414			b1 = buf[i + 1];415			if ((b1 & 0x0D) != 0)416				continue;417 418			b2 = buf[i + 2];419			b3 = buf[i + 3];420 421			addr = ((b1 & 0xF0) << 13) | (b2 << 9) | (b3 << 1);422			addr -= s->pos + (uint32_t)i;423 424			buf[i + 1] = (uint8_t)((b1 & 0x0F)425					| ((addr >> 8) & 0xF0));426 427			buf[i + 2] = (uint8_t)(((addr >> 16) & 0x0F)428					| ((addr >> 7) & 0x10)429					| ((addr << 4) & 0xE0));430 431			buf[i + 3] = (uint8_t)(((addr >> 4) & 0x7F)432					| ((addr >> 13) & 0x80));433 434			i += 4 - 2;435 436		} else if ((instr & 0x7F) == 0x17) {437			/* AUIPC */438			instr |= (uint32_t)buf[i + 1] << 8;439			instr |= (uint32_t)buf[i + 2] << 16;440			instr |= (uint32_t)buf[i + 3] << 24;441 442			if (instr & 0xE80) {443				/* AUIPC's rd doesn't equal x0 or x2. */444				instr2 = get_unaligned_le32(buf + i + 4);445 446				if (((instr << 8) ^ (instr2 - 3)) & 0xF8003) {447					i += 6 - 2;448					continue;449				}450 451				addr = (instr & 0xFFFFF000) + (instr2 >> 20);452 453				instr = 0x17 | (2 << 7) | (instr2 << 12);454				instr2 = addr;455			} else {456				/* AUIPC's rd equals x0 or x2. */457				instr2_rs1 = instr >> 27;458 459				if ((uint32_t)((instr - 0x3117) << 18)460						>= (instr2_rs1 & 0x1D)) {461					i += 4 - 2;462					continue;463				}464 465				addr = get_unaligned_be32(buf + i + 4);466				addr -= s->pos + (uint32_t)i;467 468				instr2 = (instr >> 12) | (addr << 20);469 470				instr = 0x17 | (instr2_rs1 << 7)471					| ((addr + 0x800) & 0xFFFFF000);472			}473 474			put_unaligned_le32(instr, buf + i);475			put_unaligned_le32(instr2, buf + i + 4);476 477			i += 8 - 2;478		}479	}480 481	return i;482}483#endif484 485/*486 * Apply the selected BCJ filter. Update *pos and s->pos to match the amount487 * of data that got filtered.488 *489 * NOTE: This is implemented as a switch statement to avoid using function490 * pointers, which could be problematic in the kernel boot code, which must491 * avoid pointers to static data (at least on x86).492 */493static void bcj_apply(struct xz_dec_bcj *s,494		      uint8_t *buf, size_t *pos, size_t size)495{496	size_t filtered;497 498	buf += *pos;499	size -= *pos;500 501	switch (s->type) {502#ifdef XZ_DEC_X86503	case BCJ_X86:504		filtered = bcj_x86(s, buf, size);505		break;506#endif507#ifdef XZ_DEC_POWERPC508	case BCJ_POWERPC:509		filtered = bcj_powerpc(s, buf, size);510		break;511#endif512#ifdef XZ_DEC_IA64513	case BCJ_IA64:514		filtered = bcj_ia64(s, buf, size);515		break;516#endif517#ifdef XZ_DEC_ARM518	case BCJ_ARM:519		filtered = bcj_arm(s, buf, size);520		break;521#endif522#ifdef XZ_DEC_ARMTHUMB523	case BCJ_ARMTHUMB:524		filtered = bcj_armthumb(s, buf, size);525		break;526#endif527#ifdef XZ_DEC_SPARC528	case BCJ_SPARC:529		filtered = bcj_sparc(s, buf, size);530		break;531#endif532#ifdef XZ_DEC_ARM64533	case BCJ_ARM64:534		filtered = bcj_arm64(s, buf, size);535		break;536#endif537#ifdef XZ_DEC_RISCV538	case BCJ_RISCV:539		filtered = bcj_riscv(s, buf, size);540		break;541#endif542	default:543		/* Never reached but silence compiler warnings. */544		filtered = 0;545		break;546	}547 548	*pos += filtered;549	s->pos += filtered;550}551 552/*553 * Flush pending filtered data from temp to the output buffer.554 * Move the remaining mixture of possibly filtered and unfiltered555 * data to the beginning of temp.556 */557static void bcj_flush(struct xz_dec_bcj *s, struct xz_buf *b)558{559	size_t copy_size;560 561	copy_size = min_t(size_t, s->temp.filtered, b->out_size - b->out_pos);562	memcpy(b->out + b->out_pos, s->temp.buf, copy_size);563	b->out_pos += copy_size;564 565	s->temp.filtered -= copy_size;566	s->temp.size -= copy_size;567	memmove(s->temp.buf, s->temp.buf + copy_size, s->temp.size);568}569 570/*571 * The BCJ filter functions are primitive in sense that they process the572 * data in chunks of 1-16 bytes. To hide this issue, this function does573 * some buffering.574 */575enum xz_ret xz_dec_bcj_run(struct xz_dec_bcj *s, struct xz_dec_lzma2 *lzma2,576			   struct xz_buf *b)577{578	size_t out_start;579 580	/*581	 * Flush pending already filtered data to the output buffer. Return582	 * immediately if we couldn't flush everything, or if the next583	 * filter in the chain had already returned XZ_STREAM_END.584	 */585	if (s->temp.filtered > 0) {586		bcj_flush(s, b);587		if (s->temp.filtered > 0)588			return XZ_OK;589 590		if (s->ret == XZ_STREAM_END)591			return XZ_STREAM_END;592	}593 594	/*595	 * If we have more output space than what is currently pending in596	 * temp, copy the unfiltered data from temp to the output buffer597	 * and try to fill the output buffer by decoding more data from the598	 * next filter in the chain. Apply the BCJ filter on the new data599	 * in the output buffer. If everything cannot be filtered, copy it600	 * to temp and rewind the output buffer position accordingly.601	 *602	 * This needs to be always run when temp.size == 0 to handle a special603	 * case where the output buffer is full and the next filter has no604	 * more output coming but hasn't returned XZ_STREAM_END yet.605	 */606	if (s->temp.size < b->out_size - b->out_pos || s->temp.size == 0) {607		out_start = b->out_pos;608		memcpy(b->out + b->out_pos, s->temp.buf, s->temp.size);609		b->out_pos += s->temp.size;610 611		s->ret = xz_dec_lzma2_run(lzma2, b);612		if (s->ret != XZ_STREAM_END613				&& (s->ret != XZ_OK || s->single_call))614			return s->ret;615 616		bcj_apply(s, b->out, &out_start, b->out_pos);617 618		/*619		 * As an exception, if the next filter returned XZ_STREAM_END,620		 * we can do that too, since the last few bytes that remain621		 * unfiltered are meant to remain unfiltered.622		 */623		if (s->ret == XZ_STREAM_END)624			return XZ_STREAM_END;625 626		s->temp.size = b->out_pos - out_start;627		b->out_pos -= s->temp.size;628		memcpy(s->temp.buf, b->out + b->out_pos, s->temp.size);629 630		/*631		 * If there wasn't enough input to the next filter to fill632		 * the output buffer with unfiltered data, there's no point633		 * to try decoding more data to temp.634		 */635		if (b->out_pos + s->temp.size < b->out_size)636			return XZ_OK;637	}638 639	/*640	 * We have unfiltered data in temp. If the output buffer isn't full641	 * yet, try to fill the temp buffer by decoding more data from the642	 * next filter. Apply the BCJ filter on temp. Then we hopefully can643	 * fill the actual output buffer by copying filtered data from temp.644	 * A mix of filtered and unfiltered data may be left in temp; it will645	 * be taken care on the next call to this function.646	 */647	if (b->out_pos < b->out_size) {648		/* Make b->out{,_pos,_size} temporarily point to s->temp. */649		s->out = b->out;650		s->out_pos = b->out_pos;651		s->out_size = b->out_size;652		b->out = s->temp.buf;653		b->out_pos = s->temp.size;654		b->out_size = sizeof(s->temp.buf);655 656		s->ret = xz_dec_lzma2_run(lzma2, b);657 658		s->temp.size = b->out_pos;659		b->out = s->out;660		b->out_pos = s->out_pos;661		b->out_size = s->out_size;662 663		if (s->ret != XZ_OK && s->ret != XZ_STREAM_END)664			return s->ret;665 666		bcj_apply(s, s->temp.buf, &s->temp.filtered, s->temp.size);667 668		/*669		 * If the next filter returned XZ_STREAM_END, we mark that670		 * everything is filtered, since the last unfiltered bytes671		 * of the stream are meant to be left as is.672		 */673		if (s->ret == XZ_STREAM_END)674			s->temp.filtered = s->temp.size;675 676		bcj_flush(s, b);677		if (s->temp.filtered > 0)678			return XZ_OK;679	}680 681	return s->ret;682}683 684struct xz_dec_bcj *xz_dec_bcj_create(bool single_call)685{686	struct xz_dec_bcj *s = kmalloc(sizeof(*s), GFP_KERNEL);687	if (s != NULL)688		s->single_call = single_call;689 690	return s;691}692 693enum xz_ret xz_dec_bcj_reset(struct xz_dec_bcj *s, uint8_t id)694{695	switch (id) {696#ifdef XZ_DEC_X86697	case BCJ_X86:698#endif699#ifdef XZ_DEC_POWERPC700	case BCJ_POWERPC:701#endif702#ifdef XZ_DEC_IA64703	case BCJ_IA64:704#endif705#ifdef XZ_DEC_ARM706	case BCJ_ARM:707#endif708#ifdef XZ_DEC_ARMTHUMB709	case BCJ_ARMTHUMB:710#endif711#ifdef XZ_DEC_SPARC712	case BCJ_SPARC:713#endif714#ifdef XZ_DEC_ARM64715	case BCJ_ARM64:716#endif717#ifdef XZ_DEC_RISCV718	case BCJ_RISCV:719#endif720		break;721 722	default:723		/* Unsupported Filter ID */724		return XZ_OPTIONS_ERROR;725	}726 727	s->type = id;728	s->ret = XZ_OK;729	s->pos = 0;730	s->x86_prev_mask = 0;731	s->temp.filtered = 0;732	s->temp.size = 0;733 734	return XZ_OK;735}736 737#endif738