1207753Smm///////////////////////////////////////////////////////////////////////////////
2207753Smm//
3207753Smm/// \file       ia64.c
4207753Smm/// \brief      Filter for IA64 (Itanium) binaries
5207753Smm///
6207753Smm//  Authors:    Igor Pavlov
7207753Smm//              Lasse Collin
8207753Smm//
9207753Smm//  This file has been put into the public domain.
10207753Smm//  You can do whatever you want with this file.
11207753Smm//
12207753Smm///////////////////////////////////////////////////////////////////////////////
13207753Smm
14207753Smm#include "simple_private.h"
15207753Smm
16207753Smm
17207753Smmstatic size_t
18312518Sdelphijia64_code(void *simple lzma_attribute((__unused__)),
19207753Smm		uint32_t now_pos, bool is_encoder,
20207753Smm		uint8_t *buffer, size_t size)
21207753Smm{
22207753Smm	static const uint32_t BRANCH_TABLE[32] = {
23207753Smm		0, 0, 0, 0, 0, 0, 0, 0,
24207753Smm		0, 0, 0, 0, 0, 0, 0, 0,
25207753Smm		4, 4, 6, 6, 0, 0, 7, 7,
26207753Smm		4, 4, 0, 0, 4, 4, 0, 0
27207753Smm	};
28207753Smm
29207753Smm	size_t i;
30207753Smm	for (i = 0; i + 16 <= size; i += 16) {
31207753Smm		const uint32_t instr_template = buffer[i] & 0x1F;
32207753Smm		const uint32_t mask = BRANCH_TABLE[instr_template];
33207753Smm		uint32_t bit_pos = 5;
34207753Smm
35207753Smm		for (size_t slot = 0; slot < 3; ++slot, bit_pos += 41) {
36207753Smm			if (((mask >> slot) & 1) == 0)
37207753Smm				continue;
38207753Smm
39207753Smm			const size_t byte_pos = (bit_pos >> 3);
40207753Smm			const uint32_t bit_res = bit_pos & 0x7;
41207753Smm			uint64_t instruction = 0;
42207753Smm
43207753Smm			for (size_t j = 0; j < 6; ++j)
44207753Smm				instruction += (uint64_t)(
45207753Smm						buffer[i + j + byte_pos])
46207753Smm						<< (8 * j);
47207753Smm
48207753Smm			uint64_t inst_norm = instruction >> bit_res;
49207753Smm
50207753Smm			if (((inst_norm >> 37) & 0xF) == 0x5
51207753Smm					&& ((inst_norm >> 9) & 0x7) == 0
52207753Smm					/* &&  (inst_norm & 0x3F)== 0 */
53207753Smm					) {
54207753Smm				uint32_t src = (uint32_t)(
55207753Smm						(inst_norm >> 13) & 0xFFFFF);
56207753Smm				src |= ((inst_norm >> 36) & 1) << 20;
57207753Smm
58207753Smm				src <<= 4;
59207753Smm
60207753Smm				uint32_t dest;
61207753Smm				if (is_encoder)
62207753Smm					dest = now_pos + (uint32_t)(i) + src;
63207753Smm				else
64207753Smm					dest = src - (now_pos + (uint32_t)(i));
65207753Smm
66207753Smm				dest >>= 4;
67207753Smm
68207753Smm				inst_norm &= ~((uint64_t)(0x8FFFFF) << 13);
69207753Smm				inst_norm |= (uint64_t)(dest & 0xFFFFF) << 13;
70207753Smm				inst_norm |= (uint64_t)(dest & 0x100000)
71207753Smm						<< (36 - 20);
72207753Smm
73207753Smm				instruction &= (1 << bit_res) - 1;
74207753Smm				instruction |= (inst_norm << bit_res);
75207753Smm
76207753Smm				for (size_t j = 0; j < 6; j++)
77207753Smm					buffer[i + j + byte_pos] = (uint8_t)(
78207753Smm							instruction
79207753Smm							>> (8 * j));
80207753Smm			}
81207753Smm		}
82207753Smm	}
83207753Smm
84207753Smm	return i;
85207753Smm}
86207753Smm
87207753Smm
88207753Smmstatic lzma_ret
89292588Sdelphijia64_coder_init(lzma_next_coder *next, const lzma_allocator *allocator,
90207753Smm		const lzma_filter_info *filters, bool is_encoder)
91207753Smm{
92207753Smm	return lzma_simple_coder_init(next, allocator, filters,
93207753Smm			&ia64_code, 0, 16, 16, is_encoder);
94207753Smm}
95207753Smm
96207753Smm
97207753Smmextern lzma_ret
98207753Smmlzma_simple_ia64_encoder_init(lzma_next_coder *next,
99292588Sdelphij		const lzma_allocator *allocator,
100292588Sdelphij		const lzma_filter_info *filters)
101207753Smm{
102207753Smm	return ia64_coder_init(next, allocator, filters, true);
103207753Smm}
104207753Smm
105207753Smm
106207753Smmextern lzma_ret
107207753Smmlzma_simple_ia64_decoder_init(lzma_next_coder *next,
108292588Sdelphij		const lzma_allocator *allocator,
109292588Sdelphij		const lzma_filter_info *filters)
110207753Smm{
111207753Smm	return ia64_coder_init(next, allocator, filters, false);
112207753Smm}
113