cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

842_decompress.c (8378B)


      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
     21static 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
     50struct 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
     65static int next_bits(struct sw842_param *p, u64 *d, u8 n);
     66
     67static 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
     87static 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
    131static 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
    163static 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
    212static 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
    226static 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 */
    277int 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}
    397EXPORT_SYMBOL_GPL(sw842_decompress);
    398
    399static int __init sw842_init(void)
    400{
    401	if (sw842_template_counts)
    402		sw842_debugfs_create();
    403
    404	return 0;
    405}
    406module_init(sw842_init);
    407
    408static void __exit sw842_exit(void)
    409{
    410	if (sw842_template_counts)
    411		sw842_debugfs_remove();
    412}
    413module_exit(sw842_exit);
    414
    415MODULE_LICENSE("GPL");
    416MODULE_DESCRIPTION("Software 842 Decompressor");
    417MODULE_AUTHOR("Dan Streetman <ddstreet@ieee.org>");