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

test_rslib.c (11273B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * Tests for Generic Reed Solomon encoder / decoder library
      4 *
      5 * Written by Ferdinand Blomqvist
      6 * Based on previous work by Phil Karn, KA9Q
      7 */
      8#include <linux/rslib.h>
      9#include <linux/kernel.h>
     10#include <linux/module.h>
     11#include <linux/moduleparam.h>
     12#include <linux/random.h>
     13#include <linux/slab.h>
     14
     15enum verbosity {
     16	V_SILENT,
     17	V_PROGRESS,
     18	V_CSUMMARY
     19};
     20
     21enum method {
     22	CORR_BUFFER,
     23	CALLER_SYNDROME,
     24	IN_PLACE
     25};
     26
     27#define __param(type, name, init, msg)		\
     28	static type name = init;		\
     29	module_param(name, type, 0444);		\
     30	MODULE_PARM_DESC(name, msg)
     31
     32__param(int, v, V_PROGRESS, "Verbosity level");
     33__param(int, ewsc, 1, "Erasures without symbol corruption");
     34__param(int, bc, 1, "Test for correct behaviour beyond error correction capacity");
     35
     36struct etab {
     37	int	symsize;
     38	int	genpoly;
     39	int	fcs;
     40	int	prim;
     41	int	nroots;
     42	int	ntrials;
     43};
     44
     45/* List of codes to test */
     46static struct etab Tab[] = {
     47	{2,	0x7,	1,	1,	1,	100000	},
     48	{3,	0xb,	1,	1,	2,	100000	},
     49	{3,	0xb,	1,	1,	3,	100000	},
     50	{3,	0xb,	2,	1,	4,	100000	},
     51	{4,	0x13,	1,	1,	4,	10000	},
     52	{5,	0x25,	1,	1,	6,	1000	},
     53	{6,	0x43,	3,	1,	8,	1000	},
     54	{7,	0x89,	1,	1,	14,	500	},
     55	{8,	0x11d,	1,	1,	30,	100	},
     56	{8,	0x187,	112,	11,	32,	100	},
     57	{9,	0x211,	1,	1,	33,	80	},
     58	{0, 0, 0, 0, 0, 0},
     59};
     60
     61
     62struct estat {
     63	int	dwrong;
     64	int	irv;
     65	int	wepos;
     66	int	nwords;
     67};
     68
     69struct bcstat {
     70	int	rfail;
     71	int	rsuccess;
     72	int	noncw;
     73	int	nwords;
     74};
     75
     76struct wspace {
     77	uint16_t	*c;		/* sent codeword */
     78	uint16_t	*r;		/* received word */
     79	uint16_t	*s;		/* syndrome */
     80	uint16_t	*corr;		/* correction buffer */
     81	int		*errlocs;
     82	int		*derrlocs;
     83};
     84
     85struct pad {
     86	int	mult;
     87	int	shift;
     88};
     89
     90static struct pad pad_coef[] = {
     91	{ 0, 0 },
     92	{ 1, 2 },
     93	{ 1, 1 },
     94	{ 3, 2 },
     95	{ 1, 0 },
     96};
     97
     98static void free_ws(struct wspace *ws)
     99{
    100	if (!ws)
    101		return;
    102
    103	kfree(ws->errlocs);
    104	kfree(ws->c);
    105	kfree(ws);
    106}
    107
    108static struct wspace *alloc_ws(struct rs_codec *rs)
    109{
    110	int nroots = rs->nroots;
    111	struct wspace *ws;
    112	int nn = rs->nn;
    113
    114	ws = kzalloc(sizeof(*ws), GFP_KERNEL);
    115	if (!ws)
    116		return NULL;
    117
    118	ws->c = kmalloc_array(2 * (nn + nroots),
    119				sizeof(uint16_t), GFP_KERNEL);
    120	if (!ws->c)
    121		goto err;
    122
    123	ws->r = ws->c + nn;
    124	ws->s = ws->r + nn;
    125	ws->corr = ws->s + nroots;
    126
    127	ws->errlocs = kmalloc_array(nn + nroots, sizeof(int), GFP_KERNEL);
    128	if (!ws->errlocs)
    129		goto err;
    130
    131	ws->derrlocs = ws->errlocs + nn;
    132	return ws;
    133
    134err:
    135	free_ws(ws);
    136	return NULL;
    137}
    138
    139
    140/*
    141 * Generates a random codeword and stores it in c. Generates random errors and
    142 * erasures, and stores the random word with errors in r. Erasure positions are
    143 * stored in derrlocs, while errlocs has one of three values in every position:
    144 *
    145 * 0 if there is no error in this position;
    146 * 1 if there is a symbol error in this position;
    147 * 2 if there is an erasure without symbol corruption.
    148 *
    149 * Returns the number of corrupted symbols.
    150 */
    151static int get_rcw_we(struct rs_control *rs, struct wspace *ws,
    152			int len, int errs, int eras)
    153{
    154	int nroots = rs->codec->nroots;
    155	int *derrlocs = ws->derrlocs;
    156	int *errlocs = ws->errlocs;
    157	int dlen = len - nroots;
    158	int nn = rs->codec->nn;
    159	uint16_t *c = ws->c;
    160	uint16_t *r = ws->r;
    161	int errval;
    162	int errloc;
    163	int i;
    164
    165	/* Load c with random data and encode */
    166	for (i = 0; i < dlen; i++)
    167		c[i] = prandom_u32() & nn;
    168
    169	memset(c + dlen, 0, nroots * sizeof(*c));
    170	encode_rs16(rs, c, dlen, c + dlen, 0);
    171
    172	/* Make copyand add errors and erasures */
    173	memcpy(r, c, len * sizeof(*r));
    174	memset(errlocs, 0, len * sizeof(*errlocs));
    175	memset(derrlocs, 0, nroots * sizeof(*derrlocs));
    176
    177	/* Generating random errors */
    178	for (i = 0; i < errs; i++) {
    179		do {
    180			/* Error value must be nonzero */
    181			errval = prandom_u32() & nn;
    182		} while (errval == 0);
    183
    184		do {
    185			/* Must not choose the same location twice */
    186			errloc = prandom_u32() % len;
    187		} while (errlocs[errloc] != 0);
    188
    189		errlocs[errloc] = 1;
    190		r[errloc] ^= errval;
    191	}
    192
    193	/* Generating random erasures */
    194	for (i = 0; i < eras; i++) {
    195		do {
    196			/* Must not choose the same location twice */
    197			errloc = prandom_u32() % len;
    198		} while (errlocs[errloc] != 0);
    199
    200		derrlocs[i] = errloc;
    201
    202		if (ewsc && (prandom_u32() & 1)) {
    203			/* Erasure with the symbol intact */
    204			errlocs[errloc] = 2;
    205		} else {
    206			/* Erasure with corrupted symbol */
    207			do {
    208				/* Error value must be nonzero */
    209				errval = prandom_u32() & nn;
    210			} while (errval == 0);
    211
    212			errlocs[errloc] = 1;
    213			r[errloc] ^= errval;
    214			errs++;
    215		}
    216	}
    217
    218	return errs;
    219}
    220
    221static void fix_err(uint16_t *data, int nerrs, uint16_t *corr, int *errlocs)
    222{
    223	int i;
    224
    225	for (i = 0; i < nerrs; i++)
    226		data[errlocs[i]] ^= corr[i];
    227}
    228
    229static void compute_syndrome(struct rs_control *rsc, uint16_t *data,
    230				int len, uint16_t *syn)
    231{
    232	struct rs_codec *rs = rsc->codec;
    233	uint16_t *alpha_to = rs->alpha_to;
    234	uint16_t *index_of = rs->index_of;
    235	int nroots = rs->nroots;
    236	int prim = rs->prim;
    237	int fcr = rs->fcr;
    238	int i, j;
    239
    240	/* Calculating syndrome */
    241	for (i = 0; i < nroots; i++) {
    242		syn[i] = data[0];
    243		for (j = 1; j < len; j++) {
    244			if (syn[i] == 0) {
    245				syn[i] = data[j];
    246			} else {
    247				syn[i] = data[j] ^
    248					alpha_to[rs_modnn(rs, index_of[syn[i]]
    249						+ (fcr + i) * prim)];
    250			}
    251		}
    252	}
    253
    254	/* Convert to index form */
    255	for (i = 0; i < nroots; i++)
    256		syn[i] = rs->index_of[syn[i]];
    257}
    258
    259/* Test up to error correction capacity */
    260static void test_uc(struct rs_control *rs, int len, int errs,
    261		int eras, int trials, struct estat *stat,
    262		struct wspace *ws, int method)
    263{
    264	int dlen = len - rs->codec->nroots;
    265	int *derrlocs = ws->derrlocs;
    266	int *errlocs = ws->errlocs;
    267	uint16_t *corr = ws->corr;
    268	uint16_t *c = ws->c;
    269	uint16_t *r = ws->r;
    270	uint16_t *s = ws->s;
    271	int derrs, nerrs;
    272	int i, j;
    273
    274	for (j = 0; j < trials; j++) {
    275		nerrs = get_rcw_we(rs, ws, len, errs, eras);
    276
    277		switch (method) {
    278		case CORR_BUFFER:
    279			derrs = decode_rs16(rs, r, r + dlen, dlen,
    280					NULL, eras, derrlocs, 0, corr);
    281			fix_err(r, derrs, corr, derrlocs);
    282			break;
    283		case CALLER_SYNDROME:
    284			compute_syndrome(rs, r, len, s);
    285			derrs = decode_rs16(rs, NULL, NULL, dlen,
    286					s, eras, derrlocs, 0, corr);
    287			fix_err(r, derrs, corr, derrlocs);
    288			break;
    289		case IN_PLACE:
    290			derrs = decode_rs16(rs, r, r + dlen, dlen,
    291					NULL, eras, derrlocs, 0, NULL);
    292			break;
    293		default:
    294			continue;
    295		}
    296
    297		if (derrs != nerrs)
    298			stat->irv++;
    299
    300		if (method != IN_PLACE) {
    301			for (i = 0; i < derrs; i++) {
    302				if (errlocs[derrlocs[i]] != 1)
    303					stat->wepos++;
    304			}
    305		}
    306
    307		if (memcmp(r, c, len * sizeof(*r)))
    308			stat->dwrong++;
    309	}
    310	stat->nwords += trials;
    311}
    312
    313static int ex_rs_helper(struct rs_control *rs, struct wspace *ws,
    314			int len, int trials, int method)
    315{
    316	static const char * const desc[] = {
    317		"Testing correction buffer interface...",
    318		"Testing with caller provided syndrome...",
    319		"Testing in-place interface..."
    320	};
    321
    322	struct estat stat = {0, 0, 0, 0};
    323	int nroots = rs->codec->nroots;
    324	int errs, eras, retval;
    325
    326	if (v >= V_PROGRESS)
    327		pr_info("  %s\n", desc[method]);
    328
    329	for (errs = 0; errs <= nroots / 2; errs++)
    330		for (eras = 0; eras <= nroots - 2 * errs; eras++)
    331			test_uc(rs, len, errs, eras, trials, &stat, ws, method);
    332
    333	if (v >= V_CSUMMARY) {
    334		pr_info("    Decodes wrong:        %d / %d\n",
    335				stat.dwrong, stat.nwords);
    336		pr_info("    Wrong return value:   %d / %d\n",
    337				stat.irv, stat.nwords);
    338		if (method != IN_PLACE)
    339			pr_info("    Wrong error position: %d\n", stat.wepos);
    340	}
    341
    342	retval = stat.dwrong + stat.wepos + stat.irv;
    343	if (retval && v >= V_PROGRESS)
    344		pr_warn("    FAIL: %d decoding failures!\n", retval);
    345
    346	return retval;
    347}
    348
    349static int exercise_rs(struct rs_control *rs, struct wspace *ws,
    350		       int len, int trials)
    351{
    352
    353	int retval = 0;
    354	int i;
    355
    356	if (v >= V_PROGRESS)
    357		pr_info("Testing up to error correction capacity...\n");
    358
    359	for (i = 0; i <= IN_PLACE; i++)
    360		retval |= ex_rs_helper(rs, ws, len, trials, i);
    361
    362	return retval;
    363}
    364
    365/* Tests for correct behaviour beyond error correction capacity */
    366static void test_bc(struct rs_control *rs, int len, int errs,
    367		int eras, int trials, struct bcstat *stat,
    368		struct wspace *ws)
    369{
    370	int nroots = rs->codec->nroots;
    371	int dlen = len - nroots;
    372	int *derrlocs = ws->derrlocs;
    373	uint16_t *corr = ws->corr;
    374	uint16_t *r = ws->r;
    375	int derrs, j;
    376
    377	for (j = 0; j < trials; j++) {
    378		get_rcw_we(rs, ws, len, errs, eras);
    379		derrs = decode_rs16(rs, r, r + dlen, dlen,
    380				NULL, eras, derrlocs, 0, corr);
    381		fix_err(r, derrs, corr, derrlocs);
    382
    383		if (derrs >= 0) {
    384			stat->rsuccess++;
    385
    386			/*
    387			 * We check that the returned word is actually a
    388			 * codeword. The obvious way to do this would be to
    389			 * compute the syndrome, but we don't want to replicate
    390			 * that code here. However, all the codes are in
    391			 * systematic form, and therefore we can encode the
    392			 * returned word, and see whether the parity changes or
    393			 * not.
    394			 */
    395			memset(corr, 0, nroots * sizeof(*corr));
    396			encode_rs16(rs, r, dlen, corr, 0);
    397
    398			if (memcmp(r + dlen, corr, nroots * sizeof(*corr)))
    399				stat->noncw++;
    400		} else {
    401			stat->rfail++;
    402		}
    403	}
    404	stat->nwords += trials;
    405}
    406
    407static int exercise_rs_bc(struct rs_control *rs, struct wspace *ws,
    408			  int len, int trials)
    409{
    410	struct bcstat stat = {0, 0, 0, 0};
    411	int nroots = rs->codec->nroots;
    412	int errs, eras, cutoff;
    413
    414	if (v >= V_PROGRESS)
    415		pr_info("Testing beyond error correction capacity...\n");
    416
    417	for (errs = 1; errs <= nroots; errs++) {
    418		eras = nroots - 2 * errs + 1;
    419		if (eras < 0)
    420			eras = 0;
    421
    422		cutoff = nroots <= len - errs ? nroots : len - errs;
    423		for (; eras <= cutoff; eras++)
    424			test_bc(rs, len, errs, eras, trials, &stat, ws);
    425	}
    426
    427	if (v >= V_CSUMMARY) {
    428		pr_info("  decoder gives up:        %d / %d\n",
    429				stat.rfail, stat.nwords);
    430		pr_info("  decoder returns success: %d / %d\n",
    431				stat.rsuccess, stat.nwords);
    432		pr_info("    not a codeword:        %d / %d\n",
    433				stat.noncw, stat.rsuccess);
    434	}
    435
    436	if (stat.noncw && v >= V_PROGRESS)
    437		pr_warn("    FAIL: %d silent failures!\n", stat.noncw);
    438
    439	return stat.noncw;
    440}
    441
    442static int run_exercise(struct etab *e)
    443{
    444	int nn = (1 << e->symsize) - 1;
    445	int kk = nn - e->nroots;
    446	struct rs_control *rsc;
    447	int retval = -ENOMEM;
    448	int max_pad = kk - 1;
    449	int prev_pad = -1;
    450	struct wspace *ws;
    451	int i;
    452
    453	rsc = init_rs(e->symsize, e->genpoly, e->fcs, e->prim, e->nroots);
    454	if (!rsc)
    455		return retval;
    456
    457	ws = alloc_ws(rsc->codec);
    458	if (!ws)
    459		goto err;
    460
    461	retval = 0;
    462	for (i = 0; i < ARRAY_SIZE(pad_coef); i++) {
    463		int pad = (pad_coef[i].mult * max_pad) >> pad_coef[i].shift;
    464		int len = nn - pad;
    465
    466		if (pad == prev_pad)
    467			continue;
    468
    469		prev_pad = pad;
    470		if (v >= V_PROGRESS) {
    471			pr_info("Testing (%d,%d)_%d code...\n",
    472					len, kk - pad, nn + 1);
    473		}
    474
    475		retval |= exercise_rs(rsc, ws, len, e->ntrials);
    476		if (bc)
    477			retval |= exercise_rs_bc(rsc, ws, len, e->ntrials);
    478	}
    479
    480	free_ws(ws);
    481
    482err:
    483	free_rs(rsc);
    484	return retval;
    485}
    486
    487static int __init test_rslib_init(void)
    488{
    489	int i, fail = 0;
    490
    491	for (i = 0; Tab[i].symsize != 0 ; i++) {
    492		int retval;
    493
    494		retval = run_exercise(Tab + i);
    495		if (retval < 0)
    496			return -ENOMEM;
    497
    498		fail |= retval;
    499	}
    500
    501	if (fail)
    502		pr_warn("rslib: test failed\n");
    503	else
    504		pr_info("rslib: test ok\n");
    505
    506	return -EAGAIN; /* Fail will directly unload the module */
    507}
    508
    509static void __exit test_rslib_exit(void)
    510{
    511}
    512
    513module_init(test_rslib_init)
    514module_exit(test_rslib_exit)
    515
    516MODULE_LICENSE("GPL");
    517MODULE_AUTHOR("Ferdinand Blomqvist");
    518MODULE_DESCRIPTION("Reed-Solomon library test");