/* process first unaligned data bytes */
m = ((unsignedlong)data) & 3; if (m) {
mlen = (len < (4-m)) ? len : 4-m;
bch_encode_unaligned(bch, data, mlen, bch->ecc_buf);
data += mlen;
len -= mlen;
}
/* process 32-bit aligned data words */
pdata = (uint32_t *)data;
mlen = len/4;
data += 4*mlen;
len -= 4*mlen;
memcpy(r, bch->ecc_buf, r_bytes);
/* *spliteach32-bitwordinto4polynomialsofweight8asfollows: * *31...2423...1615...87...0 *xxxxxxxxyyyyyyyyzzzzzzzztttttttt *ttttttttmodg=r0(precomputed) *zzzzzzzz00000000modg=r1(precomputed) *yyyyyyyy0000000000000000modg=r2(precomputed) *xxxxxxxx000000000000000000000000modg=r3(precomputed) *xxxxxxxxyyyyyyyyzzzzzzzzttttttttmodg=r0^r1^r2^r3
*/ while (mlen--) { /* input data is read in big-endian format */
w = cpu_to_be32(*pdata++); if (bch->swap_bits)
w = (u32)swap_bits(bch, w) |
((u32)swap_bits(bch, w >> 8) << 8) |
((u32)swap_bits(bch, w >> 16) << 16) |
((u32)swap_bits(bch, w >> 24) << 24);
w ^= r[0];
p0 = tab0 + (l+1)*((w >> 0) & 0xff);
p1 = tab1 + (l+1)*((w >> 8) & 0xff);
p2 = tab2 + (l+1)*((w >> 16) & 0xff);
p3 = tab3 + (l+1)*((w >> 24) & 0xff);
for (i = 0; i < l; i++)
r[i] = r[i+1]^p0[i]^p1[i]^p2[i]^p3[i];
/* process last unaligned bytes */ if (len)
bch_encode_unaligned(bch, data, len, bch->ecc_buf);
/* store ecc parity bytes into original parity buffer */ if (ecc)
store_ecc8(bch, ecc, bch->ecc_buf);
}
EXPORT_SYMBOL_GPL(bch_encode);
staticinlineint modulo(struct bch_control *bch, unsignedint v)
{ constunsignedint n = GF_N(bch); while (v >= n) {
v -= n;
v = (v & n) + (v >> GF_M(bch));
} return v;
}
/* *shorterandfastermodulofunction,onlyworkswhenv<2N.
*/ staticinlineint mod_s(struct bch_control *bch, unsignedint v)
{ constunsignedint n = GF_N(bch); return (v < n) ? v : v-n;
}
staticinlineint deg(unsignedint poly)
{ /* polynomial degree is the most-significant bit index */ return fls(poly)-1;
}
staticinlineint parity(unsignedint x)
{ /* *publicdomaincodesnippet,liftedfrom *http://www-graphics.stanford.edu/~seander/bithacks.html
*/
x ^= x >> 1;
x ^= x >> 2;
x = (x & 0x11111111U) * 0x11111111U; return (x >> 28) & 1;
}
/* Galois field basic operations: multiply, divide, inverse, etc. */
staticinlineunsignedint gf_mul(struct bch_control *bch, unsignedint a, unsignedint b)
{ return (a && b) ? bch->a_pow_tab[mod_s(bch, bch->a_log_tab[a]+
bch->a_log_tab[b])] : 0;
}
staticinlineunsignedint gf_sqr(struct bch_control *bch, unsignedint a)
{ return a ? bch->a_pow_tab[mod_s(bch, 2*bch->a_log_tab[a])] : 0;
}
staticinlineunsignedint gf_div(struct bch_control *bch, unsignedint a, unsignedint b)
{ return a ? bch->a_pow_tab[mod_s(bch, bch->a_log_tab[a]+
GF_N(bch)-bch->a_log_tab[b])] : 0;
}
staticinlineunsignedint gf_inv(struct bch_control *bch, unsignedint a)
{ return bch->a_pow_tab[GF_N(bch)-bch->a_log_tab[a]];
}
/* *compute2tsyndromesofeccpolynomial,i.e.ecc(a^j)forj=1..2t
*/ staticvoid compute_syndromes(struct bch_control *bch, uint32_t *ecc, unsignedint *syn)
{ int i, j, s; unsignedint m;
uint32_t poly; constint t = GF_T(bch);
s = bch->ecc_bits;
/* make sure extra bits in last ecc word are cleared */
m = ((unsignedint)s) & 31; if (m)
ecc[s/32] &= ~((1u << (32-m))-1);
memset(syn, 0, 2*t*sizeof(*syn));
/* compute v(a^j) for j=1 .. 2t-1 */ do {
poly = *ecc++;
s -= 32; while (poly) {
i = deg(poly); for (j = 0; j < 2*t; j += 2)
syn[j] ^= a_pow(bch, (j+1)*(i+s));
/* use simplified binary Berlekamp-Massey algorithm */ for (i = 0; (i < t) && (elp->deg <= t); i++) { if (d) {
k = 2*i-pp;
gf_poly_copy(elp_copy, elp); /* e[i+1](X) = e[i](X)+di*dp^-1*X^2(i-p)*e[p](X) */
tmp = a_log(bch, d)+n-a_log(bch, pd); for (j = 0; j <= pelp->deg; j++) { if (pelp->c[j]) {
l = a_log(bch, pelp->c[j]);
elp->c[j+k] ^= a_pow(bch, tmp+l);
}
} /* compute l[i+1] = max(l[i]->c[l[p]+2*(i-p]) */
tmp = pelp->deg+k; if (tmp > elp->deg) {
elp->deg = tmp;
gf_poly_copy(pelp, elp_copy);
pd = d;
pp = 2*i;
}
} /* di+1 = S(2i+3)+elp[i+1].1*S(2i+2)+...+elp[i+1].lS(2i+3-l) */ if (i < t-1) {
d = syn[2*i+2]; for (j = 1; j <= elp->deg; j++)
d ^= gf_mul(bch, elp->c[j], syn[2*i+2-j]);
}
}
dbg("elp=%s\n", gf_poly_str(elp)); return (elp->deg > t) ? -1 : (int)elp->deg;
}
/* *solveamxmlinearsysteminGF(2)withanexpectednumberofsolutions, *andreturnthenumberoffoundsolutions
*/ staticint solve_linear_system(struct bch_control *bch, unsignedint *rows, unsignedint *sol, int nsol)
{ constint m = GF_M(bch); unsignedint tmp, mask; int rem, c, r, p, k, param[BCH_MAX_M];
k = 0;
mask = 1 << m;
/* Gaussian elimination */ for (c = 0; c < m; c++) {
rem = 0;
p = c-k; /* find suitable row for elimination */ for (r = p; r < m; r++) { if (rows[r] & mask) { if (r != p)
swap(rows[r], rows[p]);
rem = r+1; break;
}
} if (rem) { /* perform elimination on remaining rows */
tmp = rows[p]; for (r = rem; r < m; r++) { if (rows[r] & mask)
rows[r] ^= tmp;
}
} else { /* elimination not needed, store defective row index */
param[k++] = c;
}
mask >>= 1;
} /* rewrite system, inserting fake parameter rows */ if (k > 0) {
p = k; for (r = m-1; r >= 0; r--) { if ((r > m-1-k) && rows[r]) /* system has no solution */ return0;
/* (X+a2)(X^3+a2X^2+b2X+c2) = X^4+aX^2+bX+c (affine) */
c = gf_mul(bch, a2, c2); /* c = a2c2 */
b = gf_mul(bch, a2, b2)^c2; /* b = a2b2 + c2 */
a = gf_sqr(bch, a2)^b2; /* a = a2^2 + b2 */
/* find the 4 roots of this affine polynomial */ if (find_affine4_roots(bch, a, b, c, tmp) == 4) { /* remove a2 from final list of roots */ for (i = 0; i < 4; i++) { if (tmp[i] != a2)
roots[n++] = a_ilog(bch, tmp[i]);
}
}
} return n;
}
/* *computerootsofadegree4polynomialoverGF(2^m)
*/ staticint find_poly_deg4_roots(struct bch_control *bch, struct gf_poly *poly, unsignedint *roots)
{ int i, l, n = 0; unsignedint a, b, c, d, e = 0, f, a2, b2, c2, e4;
if (poly->c[0] == 0) return0;
/* transform polynomial into monic X^4 + aX^3 + bX^2 + cX + d */
e4 = poly->c[4];
d = gf_div(bch, poly->c[0], e4);
c = gf_div(bch, poly->c[1], e4);
b = gf_div(bch, poly->c[2], e4);
a = gf_div(bch, poly->c[3], e4);
/* use Y=1/X transformation to get an affine polynomial */ if (a) { /* first, eliminate cX by using z=X+e with ae^2+c=0 */ if (c) { /* compute e such that e^2 = c/a */
f = gf_div(bch, c, a);
l = a_log(bch, f);
l += (l & 1) ? GF_N(bch) : 0;
e = a_pow(bch, l/2); /* *usetransformationz=X+e: *z^4+e^4+a(z^3+ez^2+e^2z+e^3)+b(z^2+e^2)+cz+ce+d *z^4+az^3+(ae+b)z^2+(ae^2+c)z+e^4+be^2+ae^3+ce+d *z^4+az^3+(ae+b)z^2+e^4+be^2+d *z^4+az^3+b'z^2+d'
*/
d = a_pow(bch, 2*l)^gf_mul(bch, b, f)^d;
b = gf_mul(bch, a, e)^b;
} /* now, use Y=1/X to get Y^4 + b/dY^2 + a/dY + 1/d */ if (d == 0) /* assume all roots have multiplicity 1 */ return0;
c2 = gf_inv(bch, d);
b2 = gf_div(bch, a, d);
a2 = gf_div(bch, b, d);
} else { /* polynomial is already affine */
c2 = d;
b2 = c;
a2 = b;
} /* find the 4 roots of this affine polynomial */ if (find_affine4_roots(bch, a2, b2, c2, roots) == 4) { for (i = 0; i < 4; i++) { /* post-process roots (reverse transformations) */
f = a ? gf_inv(bch, roots[i]) : roots[i];
roots[i] = a_ilog(bch, f^e);
}
n = 4;
} return n;
}
/* *buildmonic,log-basedrepresentationofapolynomial
*/ staticvoid gf_poly_logrep(struct bch_control *bch, conststruct gf_poly *a, int *rep)
{ int i, d = a->deg, l = GF_N(bch)-a_log(bch, a->c[a->deg]);
/* represent 0 values with -1; warning, rep[d] is not set to 1 */ for (i = 0; i < d; i++)
rep[i] = a->c[i] ? mod_s(bch, a_log(bch, a->c[i])+l) : -1;
}
/* *computepolynomialEuclideandivisionremainderinGF(2^m)[X]
*/ staticvoid gf_poly_mod(struct bch_control *bch, struct gf_poly *a, conststruct gf_poly *b, int *rep)
{ int la, p, m; unsignedint i, j, *c = a->c; constunsignedint d = b->deg;
if (a->deg < d) return;
/* reuse or compute log representation of denominator */ if (!rep) {
rep = bch->cache;
gf_poly_logrep(bch, b, rep);
}
for (j = a->deg; j >= d; j--) { if (c[j]) {
la = a_log(bch, c[j]);
p = j-d; for (i = 0; i < d; i++, p++) {
m = rep[i]; if (m >= 0)
c[p] ^= bch->a_pow_tab[mod_s(bch,
m+la)];
}
}
}
a->deg = d-1; while (!c[a->deg] && a->deg)
a->deg--;
}
/* *computepolynomialEuclideandivisionquotientinGF(2^m)[X]
*/ staticvoid gf_poly_div(struct bch_control *bch, struct gf_poly *a, conststruct gf_poly *b, struct gf_poly *q)
{ if (a->deg >= b->deg) {
q->deg = a->deg-b->deg; /* compute a mod b (modifies a) */
gf_poly_mod(bch, a, b, NULL); /* quotient is stored in upper part of polynomial a */
memcpy(q->c, &a->c[b->deg], (1+q->deg)*sizeof(unsignedint));
} else {
q->deg = 0;
q->c[0] = 0;
}
}
while (b->deg > 0) {
gf_poly_mod(bch, a, b, NULL);
swap(a, b);
}
dbg("%s\n", gf_poly_str(a));
return a;
}
/* *Givenapolynomialfandanintegerk,computeTr(a^kX)modf *ThisisusedinBerlekampTracealgorithmforsplittingpolynomials
*/ staticvoid compute_trace_bk_mod(struct bch_control *bch, int k, conststruct gf_poly *f, struct gf_poly *z, struct gf_poly *out)
{ constint m = GF_M(bch); int i, j;
/* z contains z^2j mod f */
z->deg = 1;
z->c[0] = 0;
z->c[1] = bch->a_pow_tab[k];
out->deg = 0;
memset(out, 0, GF_POLY_SZ(f->deg));
/* compute f log representation only once */
gf_poly_logrep(bch, f, bch->cache);
for (i = 0; i < m; i++) { /* add a^(k*2^i)(z^(2^i) mod f) and compute (z^(2^i) mod f)^2 */ for (j = z->deg; j >= 0; j--) {
out->c[j] ^= z->c[j];
z->c[2*j] = gf_sqr(bch, z->c[j]);
z->c[2*j+1] = 0;
} if (z->deg > out->deg)
out->deg = z->deg;
if (i < m-1) {
z->deg *= 2; /* z^(2(i+1)) mod f = (z^(2^i) mod f)^2 mod f */
gf_poly_mod(bch, z, f, bch->cache);
}
} while (!out->c[out->deg] && out->deg)
out->deg--;
dbg("Tr(a^%d.X) mod f = %s\n", k, gf_poly_str(out));
}
/* sanity check: make sure data length can be handled */ if (8*len > (bch->n-bch->ecc_bits)) return -EINVAL;
/* if caller does not provide syndromes, compute them */ if (!syn) { if (!calc_ecc) { /* compute received data ecc into an internal buffer */ if (!data || !recv_ecc) return -EINVAL;
bch_encode(bch, data, len, NULL);
} else { /* load provided calculated ecc */
load_ecc8(bch, bch->ecc_buf, calc_ecc);
} /* load received ecc or assume it was XORed in calc_ecc */ if (recv_ecc) {
load_ecc8(bch, bch->ecc_buf2, recv_ecc); /* XOR received and calculated ecc */ for (i = 0, sum = 0; i < (int)ecc_words; i++) {
bch->ecc_buf[i] ^= bch->ecc_buf2[i];
sum |= bch->ecc_buf[i];
} if (!sum) /* no error found */ return0;
}
compute_syndromes(bch, bch->ecc_buf, bch->syn);
syn = bch->syn;
}
err = compute_error_locator_polynomial(bch, syn); if (err > 0) {
nroots = find_poly_roots(bch, 1, bch->elp, errloc); if (err != nroots)
err = -1;
} if (err > 0) { /* post-process raw error locations for easier correction */
nbits = (len*8)+bch->ecc_bits; for (i = 0; i < err; i++) { if (errloc[i] >= nbits) {
err = -1; break;
}
errloc[i] = nbits-1-errloc[i]; if (!bch->swap_bits)
errloc[i] = (errloc[i] & ~7) |
(7-(errloc[i] & 7));
}
} return (err >= 0) ? err : -EBADMSG;
}
EXPORT_SYMBOL_GPL(bch_decode);
/* *generateGaloisfieldlookuptables
*/ staticint build_gf_tables(struct bch_control *bch, unsignedint poly)
{ unsignedint i, x = 1; constunsignedint k = 1 << deg(poly);
/* primitive polynomial must be of degree m */ if (k != (1u << GF_M(bch))) return -1;
for (i = 0; i < GF_N(bch); i++) {
bch->a_pow_tab[i] = x;
bch->a_log_tab[x] = i; if (i && (x == 1)) /* polynomial is not primitive (a^i=1 with 0<i<2^m-1) */ return -1;
x <<= 1; if (x & k)
x ^= poly;
}
bch->a_pow_tab[GF_N(bch)] = 1;
bch->a_log_tab[0] = 0;
for (i = 0; i < 256; i++) { /* p(X)=i is a small polynomial of weight <= 8 */ for (b = 0; b < 4; b++) { /* we want to compute (p(X).X^(8*b+deg(g))) mod g(X) */
tab = bch->mod8_tab + (b*256+i)*l;
data = i << (8*b); while (data) {
d = deg(data); /* subtract X^d.g(X) from p(X).X^(8*b+deg(g)) */
data ^= g[0] >> (31-d); for (j = 0; j < ecclen; j++) {
hi = (d < 31) ? g[j] << (d+1) : 0;
lo = (j+1 < plen) ?
g[j+1] >> (31-d) : 0;
tab[j] ^= hi|lo;
}
}
}
}
}
/* *buildabaseforfactoringdegree2polynomials
*/ staticint build_deg2_base(struct bch_control *bch)
{ constint m = GF_M(bch); int i, j, r; unsignedint sum, x, y, remaining, ak = 0, xi[BCH_MAX_M];
/* find k s.t. Tr(a^k) = 1 and 0 <= k < m */ for (i = 0; i < m; i++) { for (j = 0, sum = 0; j < m; j++)
sum ^= a_pow(bch, i*(1 << j));
if (sum) {
ak = bch->a_pow_tab[i]; break;
}
} /* find xi, i=0..m-1 such that xi^2+xi = a^i+Tr(a^i).a^k */
remaining = m;
memset(xi, 0, sizeof(xi));
for (x = 0; (x <= GF_N(bch)) && remaining; x++) {
y = gf_sqr(bch, x)^x; for (i = 0; i < 2; i++) {
r = a_log(bch, y); if (y && (r < m) && !xi[r]) {
bch->xi_tab[r] = x;
xi[r] = 1;
remaining--;
dbg("x%d = %x\n", r, x); break;
}
y ^= ak;
}
} /* should not happen but check anyway */ return remaining ? -1 : 0;
}
staticvoid *bch_alloc(size_t size, int *err)
{ void *ptr;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.