/* * Ezpwd Reed-Solomon -- Reed-Solomon encoder / decoder library * * Copyright (c) 2017, Hard Consulting Corporation. * * Ezpwd Reed-Solomon is free software: you can redistribute it and/or modify it under the terms of * the GNU General Public License as published by the Free Software Foundation, either version 3 of * the License, or (at your option) any later version. See the LICENSE file at the top of the * source tree. Ezpwd Reed-Solomon is also available under Commercial license. The Djelic BCH code * under djelic/ and the c++/ezpwd/bch_base wrapper is redistributed under the terms of the GPLv2+, * regardless of the overall licensing terms. * * Ezpwd Reed-Solomon is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See * the GNU General Public License for more details. */ #ifndef _EZPWD_BCH_BASE #define _EZPWD_BCH_BASE #include #include #include // // Presently, we simply import the Linux Kernel's "C" BCH API directly into the ezpwd:: namespace In // order to compile, you must (at least) run "make djelic" in the base directory of the // https://github.com/pjkundert/bch.git repo. // namespace ezpwd { /** * struct bch_control - BCH control structure * @m: Galois field order * @n: maximum codeword size in bits (= 2^m-1) * @t: error correction capability in bits * @ecc_bits: ecc exact size in bits, i.e. generator polynomial degree (<=m*t) * @ecc_bytes: ecc max size (m*t bits) in bytes * @a_pow_tab: Galois field GF(2^m) exponentiation lookup table * @a_log_tab: Galois field GF(2^m) log lookup table * @mod8_tab: remainder generator polynomial lookup tables * @ecc_buf: ecc parity words buffer * @ecc_buf2: ecc parity words buffer * @xi_tab: GF(2^m) base for solving degree 2 polynomial roots * @syn: syndrome buffer * @cache: log-based polynomial representation buffer * @elp: error locator polynomial * @poly_2t: temporary polynomials of degree 2t */ /** * init_bch - initialize a BCH encoder/decoder * @m: Galois field order, should be in the range 5-15 * @t: maximum error correction capability, in bits * @prim_poly: user-provided primitive polynomial (or 0 to use default) * * Returns: * a newly allocated BCH control structure if successful, NULL otherwise * * This initialization can take some time, as lookup tables are built for fast * encoding/decoding; make sure not to call this function from a time critical * path. Usually, init_bch() should be called on module/driver init and * free_bch() should be called to release memory on exit. * * You may provide your own primitive polynomial of degree @m in argument * @prim_poly, or let init_bch() use its default polynomial. * * Once init_bch() has successfully returned a pointer to a newly allocated * BCH control structure, ecc length in bytes is given by member @ecc_bytes of * the structure. */ /** * encode_bch - calculate BCH ecc parity of data * @bch: BCH control structure * @data: data to encode * @len: data length in bytes * @ecc: ecc parity data, must be initialized by caller * * The @ecc parity array is used both as input and output parameter, in order to * allow incremental computations. It should be of the size indicated by member * @ecc_bytes of @bch, and should be initialized to 0 before the first call. * * The exact number of computed ecc parity bits is given by member @ecc_bits of * @bch; it may be less than m*t for large values of t. */ /** * decode_bch - decode received codeword and find bit error locations * @bch: BCH control structure * @data: received data, ignored if @calc_ecc is provided * @len: data length in bytes, must always be provided * @recv_ecc: received ecc, if NULL then assume it was XORed in @calc_ecc * @calc_ecc: calculated ecc, if NULL then calc_ecc is computed from @data * @syn: hw computed syndrome data (if NULL, syndrome is calculated) * @errloc: output array of error locations * * Returns: * The number of errors found, or -EBADMSG if decoding failed, or -EINVAL if * invalid parameters were provided * * Depending on the available hw BCH support and the need to compute @calc_ecc * separately (using encode_bch()), this function should be called with one of * the following parameter configurations - * * by providing @data and @recv_ecc only: * decode_bch(@bch, @data, @len, @recv_ecc, NULL, NULL, @errloc) * * by providing @recv_ecc and @calc_ecc: * decode_bch(@bch, NULL, @len, @recv_ecc, @calc_ecc, NULL, @errloc) * * by providing ecc = recv_ecc XOR calc_ecc: * decode_bch(@bch, NULL, @len, NULL, ecc, NULL, @errloc) * * by providing syndrome results @syn: * decode_bch(@bch, NULL, @len, NULL, NULL, @syn, @errloc) * * Once decode_bch() has successfully returned with a positive value, error * locations returned in array @errloc should be interpreted as follows - * * if (errloc[n] >= 8*len), then n-th error is located in ecc (no need for * data correction) * * if (errloc[n] < 8*len), then n-th error is located in data and can be * corrected with statement data[errloc[n]/8] ^= 1 << (errloc[n] % 8); * * Note that this function does not perform any data correction by itself, it * merely indicates error locations. */ /** * init_bch - initialize a BCH encoder/decoder * @m: Galois field order, should be in the range 5-15 * @t: maximum error correction capability, in bits * @prim_poly: user-provided primitive polynomial (or 0 to use default) * * Returns: * a newly allocated BCH control structure if successful, NULL otherwise * * This initialization can take some time, as lookup tables are built for fast * encoding/decoding; make sure not to call this function from a time critical * path. Usually, init_bch() should be called on module/driver init and * free_bch() should be called to release memory on exit. * * You may provide your own primitive polynomial of degree @m in argument * @prim_poly, or let init_bch() use its default polynomial. * * Once init_bch() has successfully returned a pointer to a newly allocated * BCH control structure, ecc length in bytes is given by member @ecc_bytes of * the structure. */ extern "C" { #include "../../djelic_bch.h" } // // correct_bch -- corrects data (but not parity!), as suggested by decode_bch, above // // A convenience interface that defaults all of the not strictly required parameters, and // automatically corrects bit-errors in data *and* the supplied parity. Does not attempt to // correct bit errors found in the parity data. If not supplied, 'errloc' is allocated // internally; otherwise, it is assumed to be of at least size bch->t (the minimum error // correction capacity of the BCH codec). // // However, beware -- at larger values of T, the actual correction capacity of the BCH codec // could be greater than the requested T. Therefore, it is recommended that you always supply a // larger than required errloc array; recommend T*2? // inline int correct_bch( struct bch_control *bch, uint8_t *data, unsigned int len, uint8_t *recv_ecc, const uint8_t *calc_ecc= 0, const unsigned int *syn = 0, unsigned int *errloc = 0 ) // must be sized at least bch->t; often, greater! { unsigned int _errloc[511]; // much larger than the correction capacity of largest supported BCH codec if ( ! errloc ) errloc = _errloc; int err = decode_bch( bch, data, len, recv_ecc, calc_ecc, syn, errloc ); if ( err > 0 ) { // A +'ve number of bit-error correction locations were found for ( int n = 0; n < err; ++n ) { /** * if (errloc[n] < 8*len), then n-th error is located in data and can be corrected * with statement data[errloc[n]/8] ^= 1 << (errloc[n] % 8). If in the parity, it * is assumed to be located at the end of the data, so offset by 'len' bytes. */ if ( errloc[n] < 8*len ) { data[errloc[n] / 8] ^= 1 << ( errloc[n] % 8 ); } else if ( recv_ecc && errloc[n] < 8 * len + 8 * bch->ecc_bytes ) { recv_ecc[errloc[n] / 8 - len] ^= 1 << ( errloc[n] % 8 ); } } } return err; } // // << -- output codec in standard BCH( N, N-ECC, T ) form // inline std::ostream &operator<<( std::ostream &lhs, const ezpwd::bch_control &bch ) { return lhs << "BCH( " << std::setw( 3 ) << bch.n << ", " << std::setw( 3 ) << bch.n - bch.ecc_bits << ", " << std::setw( 3 ) << bch.t << " )"; } } // namespace ezpwd #endif // _EZPWD_BCH_BASE