xref: /openbmc/linux/lib/842/842_decompress.c (revision 884caada)
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * 842 Software Decompression
4  *
5  * Copyright (C) 2015 Dan Streetman, IBM Corp
6  *
7  * See 842.h for details of the 842 compressed format.
8  */
9 
10 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
11 #define MODULE_NAME "842_decompress"
12 
13 #include "842.h"
14 #include "842_debugfs.h"
15 
16 /* rolling fifo sizes */
17 #define I2_FIFO_SIZE	(2 * (1 << I2_BITS))
18 #define I4_FIFO_SIZE	(4 * (1 << I4_BITS))
19 #define I8_FIFO_SIZE	(8 * (1 << I8_BITS))
20 
21 static u8 decomp_ops[OPS_MAX][4] = {
22 	{ D8, N0, N0, N0 },
23 	{ D4, D2, I2, N0 },
24 	{ D4, I2, D2, N0 },
25 	{ D4, I2, I2, N0 },
26 	{ D4, I4, N0, N0 },
27 	{ D2, I2, D4, N0 },
28 	{ D2, I2, D2, I2 },
29 	{ D2, I2, I2, D2 },
30 	{ D2, I2, I2, I2 },
31 	{ D2, I2, I4, N0 },
32 	{ I2, D2, D4, N0 },
33 	{ I2, D4, I2, N0 },
34 	{ I2, D2, I2, D2 },
35 	{ I2, D2, I2, I2 },
36 	{ I2, D2, I4, N0 },
37 	{ I2, I2, D4, N0 },
38 	{ I2, I2, D2, I2 },
39 	{ I2, I2, I2, D2 },
40 	{ I2, I2, I2, I2 },
41 	{ I2, I2, I4, N0 },
42 	{ I4, D4, N0, N0 },
43 	{ I4, D2, I2, N0 },
44 	{ I4, I2, D2, N0 },
45 	{ I4, I2, I2, N0 },
46 	{ I4, I4, N0, N0 },
47 	{ I8, N0, N0, N0 }
48 };
49 
50 struct sw842_param {
51 	u8 *in;
52 	u8 bit;
53 	u64 ilen;
54 	u8 *out;
55 	u8 *ostart;
56 	u64 olen;
57 };
58 
59 #define beN_to_cpu(d, s)					\
60 	((s) == 2 ? be16_to_cpu(get_unaligned((__be16 *)d)) :	\
61 	 (s) == 4 ? be32_to_cpu(get_unaligned((__be32 *)d)) :	\
62 	 (s) == 8 ? be64_to_cpu(get_unaligned((__be64 *)d)) :	\
63 	 0)
64 
65 static int next_bits(struct sw842_param *p, u64 *d, u8 n);
66 
67 static int __split_next_bits(struct sw842_param *p, u64 *d, u8 n, u8 s)
68 {
69 	u64 tmp = 0;
70 	int ret;
71 
72 	if (n <= s) {
73 		pr_debug("split_next_bits invalid n %u s %u\n", n, s);
74 		return -EINVAL;
75 	}
76 
77 	ret = next_bits(p, &tmp, n - s);
78 	if (ret)
79 		return ret;
80 	ret = next_bits(p, d, s);
81 	if (ret)
82 		return ret;
83 	*d |= tmp << s;
84 	return 0;
85 }
86 
87 static int next_bits(struct sw842_param *p, u64 *d, u8 n)
88 {
89 	u8 *in = p->in, b = p->bit, bits = b + n;
90 
91 	if (n > 64) {
92 		pr_debug("next_bits invalid n %u\n", n);
93 		return -EINVAL;
94 	}
95 
96 	/* split this up if reading > 8 bytes, or if we're at the end of
97 	 * the input buffer and would read past the end
98 	 */
99 	if (bits > 64)
100 		return __split_next_bits(p, d, n, 32);
101 	else if (p->ilen < 8 && bits > 32 && bits <= 56)
102 		return __split_next_bits(p, d, n, 16);
103 	else if (p->ilen < 4 && bits > 16 && bits <= 24)
104 		return __split_next_bits(p, d, n, 8);
105 
106 	if (DIV_ROUND_UP(bits, 8) > p->ilen)
107 		return -EOVERFLOW;
108 
109 	if (bits <= 8)
110 		*d = *in >> (8 - bits);
111 	else if (bits <= 16)
112 		*d = be16_to_cpu(get_unaligned((__be16 *)in)) >> (16 - bits);
113 	else if (bits <= 32)
114 		*d = be32_to_cpu(get_unaligned((__be32 *)in)) >> (32 - bits);
115 	else
116 		*d = be64_to_cpu(get_unaligned((__be64 *)in)) >> (64 - bits);
117 
118 	*d &= GENMASK_ULL(n - 1, 0);
119 
120 	p->bit += n;
121 
122 	if (p->bit > 7) {
123 		p->in += p->bit / 8;
124 		p->ilen -= p->bit / 8;
125 		p->bit %= 8;
126 	}
127 
128 	return 0;
129 }
130 
131 static int do_data(struct sw842_param *p, u8 n)
132 {
133 	u64 v;
134 	int ret;
135 
136 	if (n > p->olen)
137 		return -ENOSPC;
138 
139 	ret = next_bits(p, &v, n * 8);
140 	if (ret)
141 		return ret;
142 
143 	switch (n) {
144 	case 2:
145 		put_unaligned(cpu_to_be16((u16)v), (__be16 *)p->out);
146 		break;
147 	case 4:
148 		put_unaligned(cpu_to_be32((u32)v), (__be32 *)p->out);
149 		break;
150 	case 8:
151 		put_unaligned(cpu_to_be64((u64)v), (__be64 *)p->out);
152 		break;
153 	default:
154 		return -EINVAL;
155 	}
156 
157 	p->out += n;
158 	p->olen -= n;
159 
160 	return 0;
161 }
162 
163 static int __do_index(struct sw842_param *p, u8 size, u8 bits, u64 fsize)
164 {
165 	u64 index, offset, total = round_down(p->out - p->ostart, 8);
166 	int ret;
167 
168 	ret = next_bits(p, &index, bits);
169 	if (ret)
170 		return ret;
171 
172 	offset = index * size;
173 
174 	/* a ring buffer of fsize is used; correct the offset */
175 	if (total > fsize) {
176 		/* this is where the current fifo is */
177 		u64 section = round_down(total, fsize);
178 		/* the current pos in the fifo */
179 		u64 pos = total - section;
180 
181 		/* if the offset is past/at the pos, we need to
182 		 * go back to the last fifo section
183 		 */
184 		if (offset >= pos)
185 			section -= fsize;
186 
187 		offset += section;
188 	}
189 
190 	if (offset + size > total) {
191 		pr_debug("index%x %lx points past end %lx\n", size,
192 			 (unsigned long)offset, (unsigned long)total);
193 		return -EINVAL;
194 	}
195 
196 	if (size != 2 && size != 4 && size != 8)
197 		WARN(1, "__do_index invalid size %x\n", size);
198 	else
199 		pr_debug("index%x to %lx off %lx adjoff %lx tot %lx data %lx\n",
200 			 size, (unsigned long)index,
201 			 (unsigned long)(index * size), (unsigned long)offset,
202 			 (unsigned long)total,
203 			 (unsigned long)beN_to_cpu(&p->ostart[offset], size));
204 
205 	memcpy(p->out, &p->ostart[offset], size);
206 	p->out += size;
207 	p->olen -= size;
208 
209 	return 0;
210 }
211 
212 static int do_index(struct sw842_param *p, u8 n)
213 {
214 	switch (n) {
215 	case 2:
216 		return __do_index(p, 2, I2_BITS, I2_FIFO_SIZE);
217 	case 4:
218 		return __do_index(p, 4, I4_BITS, I4_FIFO_SIZE);
219 	case 8:
220 		return __do_index(p, 8, I8_BITS, I8_FIFO_SIZE);
221 	default:
222 		return -EINVAL;
223 	}
224 }
225 
226 static int do_op(struct sw842_param *p, u8 o)
227 {
228 	int i, ret = 0;
229 
230 	if (o >= OPS_MAX)
231 		return -EINVAL;
232 
233 	for (i = 0; i < 4; i++) {
234 		u8 op = decomp_ops[o][i];
235 
236 		pr_debug("op is %x\n", op);
237 
238 		switch (op & OP_ACTION) {
239 		case OP_ACTION_DATA:
240 			ret = do_data(p, op & OP_AMOUNT);
241 			break;
242 		case OP_ACTION_INDEX:
243 			ret = do_index(p, op & OP_AMOUNT);
244 			break;
245 		case OP_ACTION_NOOP:
246 			break;
247 		default:
248 			pr_err("Internal error, invalid op %x\n", op);
249 			return -EINVAL;
250 		}
251 
252 		if (ret)
253 			return ret;
254 	}
255 
256 	if (sw842_template_counts)
257 		atomic_inc(&template_count[o]);
258 
259 	return 0;
260 }
261 
262 /**
263  * sw842_decompress
264  *
265  * Decompress the 842-compressed buffer of length @ilen at @in
266  * to the output buffer @out, using no more than @olen bytes.
267  *
268  * The compressed buffer must be only a single 842-compressed buffer,
269  * with the standard format described in the comments in 842.h
270  * Processing will stop when the 842 "END" template is detected,
271  * not the end of the buffer.
272  *
273  * Returns: 0 on success, error on failure.  The @olen parameter
274  * will contain the number of output bytes written on success, or
275  * 0 on error.
276  */
277 int sw842_decompress(const u8 *in, unsigned int ilen,
278 		     u8 *out, unsigned int *olen)
279 {
280 	struct sw842_param p;
281 	int ret;
282 	u64 op, rep, tmp, bytes, total;
283 	u64 crc;
284 
285 	p.in = (u8 *)in;
286 	p.bit = 0;
287 	p.ilen = ilen;
288 	p.out = out;
289 	p.ostart = out;
290 	p.olen = *olen;
291 
292 	total = p.olen;
293 
294 	*olen = 0;
295 
296 	do {
297 		ret = next_bits(&p, &op, OP_BITS);
298 		if (ret)
299 			return ret;
300 
301 		pr_debug("template is %lx\n", (unsigned long)op);
302 
303 		switch (op) {
304 		case OP_REPEAT:
305 			ret = next_bits(&p, &rep, REPEAT_BITS);
306 			if (ret)
307 				return ret;
308 
309 			if (p.out == out) /* no previous bytes */
310 				return -EINVAL;
311 
312 			/* copy rep + 1 */
313 			rep++;
314 
315 			if (rep * 8 > p.olen)
316 				return -ENOSPC;
317 
318 			while (rep-- > 0) {
319 				memcpy(p.out, p.out - 8, 8);
320 				p.out += 8;
321 				p.olen -= 8;
322 			}
323 
324 			if (sw842_template_counts)
325 				atomic_inc(&template_repeat_count);
326 
327 			break;
328 		case OP_ZEROS:
329 			if (8 > p.olen)
330 				return -ENOSPC;
331 
332 			memset(p.out, 0, 8);
333 			p.out += 8;
334 			p.olen -= 8;
335 
336 			if (sw842_template_counts)
337 				atomic_inc(&template_zeros_count);
338 
339 			break;
340 		case OP_SHORT_DATA:
341 			ret = next_bits(&p, &bytes, SHORT_DATA_BITS);
342 			if (ret)
343 				return ret;
344 
345 			if (!bytes || bytes > SHORT_DATA_BITS_MAX)
346 				return -EINVAL;
347 
348 			while (bytes-- > 0) {
349 				ret = next_bits(&p, &tmp, 8);
350 				if (ret)
351 					return ret;
352 				*p.out = (u8)tmp;
353 				p.out++;
354 				p.olen--;
355 			}
356 
357 			if (sw842_template_counts)
358 				atomic_inc(&template_short_data_count);
359 
360 			break;
361 		case OP_END:
362 			if (sw842_template_counts)
363 				atomic_inc(&template_end_count);
364 
365 			break;
366 		default: /* use template */
367 			ret = do_op(&p, op);
368 			if (ret)
369 				return ret;
370 			break;
371 		}
372 	} while (op != OP_END);
373 
374 	/*
375 	 * crc(0:31) is saved in compressed data starting with the
376 	 * next bit after End of stream template.
377 	 */
378 	ret = next_bits(&p, &crc, CRC_BITS);
379 	if (ret)
380 		return ret;
381 
382 	/*
383 	 * Validate CRC saved in compressed data.
384 	 */
385 	if (crc != (u64)crc32_be(0, out, total - p.olen)) {
386 		pr_debug("CRC mismatch for decompression\n");
387 		return -EINVAL;
388 	}
389 
390 	if (unlikely((total - p.olen) > UINT_MAX))
391 		return -ENOSPC;
392 
393 	*olen = total - p.olen;
394 
395 	return 0;
396 }
397 EXPORT_SYMBOL_GPL(sw842_decompress);
398 
399 static int __init sw842_init(void)
400 {
401 	if (sw842_template_counts)
402 		sw842_debugfs_create();
403 
404 	return 0;
405 }
406 module_init(sw842_init);
407 
408 static void __exit sw842_exit(void)
409 {
410 	if (sw842_template_counts)
411 		sw842_debugfs_remove();
412 }
413 module_exit(sw842_exit);
414 
415 MODULE_LICENSE("GPL");
416 MODULE_DESCRIPTION("Software 842 Decompressor");
417 MODULE_AUTHOR("Dan Streetman <ddstreet@ieee.org>");
418