1*f273a7a1Sandvar /* $NetBSD: hamming.c,v 1.2 2021/12/07 21:37:37 andvar Exp $ */
22b6ee221Sahoka
32b6ee221Sahoka /*
42b6ee221Sahoka * Copyright (c) 2008, Atmel Corporation
52b6ee221Sahoka *
62b6ee221Sahoka * All rights reserved.
72b6ee221Sahoka *
82b6ee221Sahoka * Redistribution and use in source and binary forms, with or without
92b6ee221Sahoka * modification, are permitted provided that the following conditions are met:
102b6ee221Sahoka *
112b6ee221Sahoka * - Redistributions of source code must retain the above copyright notice,
122b6ee221Sahoka * this list of conditions and the disclaimer below.
132b6ee221Sahoka *
142b6ee221Sahoka * Atmel's name may not be used to endorse or promote products derived from
152b6ee221Sahoka * this software without specific prior written permission.
162b6ee221Sahoka *
172b6ee221Sahoka * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
182b6ee221Sahoka * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
192b6ee221Sahoka * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
202b6ee221Sahoka * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
212b6ee221Sahoka * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
222b6ee221Sahoka * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
232b6ee221Sahoka * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
242b6ee221Sahoka * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
252b6ee221Sahoka * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
262b6ee221Sahoka * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
272b6ee221Sahoka */
282b6ee221Sahoka
292b6ee221Sahoka #include <sys/cdefs.h>
30*f273a7a1Sandvar __KERNEL_RCSID(0, "$NetBSD: hamming.c,v 1.2 2021/12/07 21:37:37 andvar Exp $");
312b6ee221Sahoka
322b6ee221Sahoka #include <sys/param.h>
332b6ee221Sahoka #include <lib/libkern/libkern.h>
342b6ee221Sahoka #include "hamming.h"
352b6ee221Sahoka
362b6ee221Sahoka /**
372b6ee221Sahoka * Calculates the 22-bit hamming code for a 256-bytes block of data.
382b6ee221Sahoka * \param data Data buffer to calculate code for.
392b6ee221Sahoka * \param code Pointer to a buffer where the code should be stored.
402b6ee221Sahoka */
412b6ee221Sahoka void
hamming_compute_256(const uint8_t * data,uint8_t * code)422b6ee221Sahoka hamming_compute_256(const uint8_t *data, uint8_t *code)
432b6ee221Sahoka {
442b6ee221Sahoka unsigned int i;
452b6ee221Sahoka uint8_t column_sum = 0;
462b6ee221Sahoka uint8_t even_line_code = 0;
472b6ee221Sahoka uint8_t odd_line_code = 0;
482b6ee221Sahoka uint8_t even_column_code = 0;
492b6ee221Sahoka uint8_t odd_column_code = 0;
502b6ee221Sahoka
512b6ee221Sahoka /*-
522b6ee221Sahoka * Xor all bytes together to get the column sum;
532b6ee221Sahoka * At the same time, calculate the even and odd line codes
542b6ee221Sahoka */
552b6ee221Sahoka for (i = 0; i < 256; i++) {
562b6ee221Sahoka column_sum ^= data[i];
572b6ee221Sahoka
582b6ee221Sahoka /*-
592b6ee221Sahoka * If the xor sum of the byte is 0, then this byte has no
602b6ee221Sahoka * incidence on the computed code; so check if the sum is 1.
612b6ee221Sahoka */
622b6ee221Sahoka if ((popcount(data[i]) & 1) == 1) {
632b6ee221Sahoka /*-
642b6ee221Sahoka * Parity groups are formed by forcing a particular
652b6ee221Sahoka * index bit to 0 (even) or 1 (odd).
662b6ee221Sahoka * Example on one byte:
672b6ee221Sahoka *
682b6ee221Sahoka * bits (dec) 7 6 5 4 3 2 1 0
692b6ee221Sahoka * (bin) 111 110 101 100 011 010 001 000
702b6ee221Sahoka * '---'---'---'----------.
712b6ee221Sahoka * |
722b6ee221Sahoka * groups P4' ooooooooooooooo eeeeeeeeeeeeeee P4 |
732b6ee221Sahoka * P2' ooooooo eeeeeee ooooooo eeeeeee P2 |
742b6ee221Sahoka * P1' ooo eee ooo eee ooo eee ooo eee P1 |
752b6ee221Sahoka * |
762b6ee221Sahoka * We can see that: |
772b6ee221Sahoka * - P4 -> bit 2 of index is 0 --------------------'
782b6ee221Sahoka * - P4' -> bit 2 of index is 1.
792b6ee221Sahoka * - P2 -> bit 1 of index if 0.
802b6ee221Sahoka * - etc...
812b6ee221Sahoka * We deduce that a bit position has an impact on all
822b6ee221Sahoka * even Px if the log2(x)nth bit of its index is 0
832b6ee221Sahoka * ex: log2(4) = 2,
842b6ee221Sahoka * bit2 of the index must be 0 (-> 0 1 2 3)
852b6ee221Sahoka * and on all odd Px' if the log2(x)nth bit
862b6ee221Sahoka * of its index is 1
872b6ee221Sahoka * ex: log2(2) = 1,
882b6ee221Sahoka * bit1 of the index must be 1 (-> 0 1 4 5)
892b6ee221Sahoka *
902b6ee221Sahoka * As such, we calculate all the possible Px and Px'
912b6ee221Sahoka * values at the same time in two variables,
922b6ee221Sahoka * even_line_code and odd_line_code, such as
932b6ee221Sahoka * even_line_code bits: P128 P64 P32
942b6ee221Sahoka * P16 P8 P4 P2 P1
952b6ee221Sahoka * odd_line_code bits: P128' P64' P32' P16'
962b6ee221Sahoka * P8' P4' P2' P1'
972b6ee221Sahoka */
982b6ee221Sahoka even_line_code ^= (255 - i);
992b6ee221Sahoka odd_line_code ^= i;
1002b6ee221Sahoka }
1012b6ee221Sahoka }
1022b6ee221Sahoka
1032b6ee221Sahoka /*-
1042b6ee221Sahoka * At this point, we have the line parities, and the column sum.
105*f273a7a1Sandvar * First, We must calculate the parity group values on the column sum.
1062b6ee221Sahoka */
1072b6ee221Sahoka for (i = 0; i < 8; i++) {
1082b6ee221Sahoka if (column_sum & 1) {
1092b6ee221Sahoka even_column_code ^= (7 - i);
1102b6ee221Sahoka odd_column_code ^= i;
1112b6ee221Sahoka }
1122b6ee221Sahoka column_sum >>= 1;
1132b6ee221Sahoka }
1142b6ee221Sahoka
1152b6ee221Sahoka /*-
1162b6ee221Sahoka * Now, we must interleave the parity values,
1172b6ee221Sahoka * to obtain the following layout:
1182b6ee221Sahoka * Code[0] = Line1
1192b6ee221Sahoka * Code[1] = Line2
1202b6ee221Sahoka * Code[2] = Column
1212b6ee221Sahoka * Line = Px' Px P(x-1)- P(x-1) ...
1222b6ee221Sahoka * Column = P4' P4 P2' P2 P1' P1 PadBit PadBit
1232b6ee221Sahoka */
1242b6ee221Sahoka code[0] = 0;
1252b6ee221Sahoka code[1] = 0;
1262b6ee221Sahoka code[2] = 0;
1272b6ee221Sahoka
1282b6ee221Sahoka for (i = 0; i < 4; i++) {
1292b6ee221Sahoka code[0] <<= 2;
1302b6ee221Sahoka code[1] <<= 2;
1312b6ee221Sahoka code[2] <<= 2;
1322b6ee221Sahoka
1332b6ee221Sahoka /* Line 1 */
1342b6ee221Sahoka if ((odd_line_code & 0x80) != 0) {
1352b6ee221Sahoka
1362b6ee221Sahoka code[0] |= 2;
1372b6ee221Sahoka }
1382b6ee221Sahoka if ((even_line_code & 0x80) != 0) {
1392b6ee221Sahoka
1402b6ee221Sahoka code[0] |= 1;
1412b6ee221Sahoka }
1422b6ee221Sahoka
1432b6ee221Sahoka /* Line 2 */
1442b6ee221Sahoka if ((odd_line_code & 0x08) != 0) {
1452b6ee221Sahoka
1462b6ee221Sahoka code[1] |= 2;
1472b6ee221Sahoka }
1482b6ee221Sahoka if ((even_line_code & 0x08) != 0) {
1492b6ee221Sahoka
1502b6ee221Sahoka code[1] |= 1;
1512b6ee221Sahoka }
1522b6ee221Sahoka
1532b6ee221Sahoka /* Column */
1542b6ee221Sahoka if ((odd_column_code & 0x04) != 0) {
1552b6ee221Sahoka
1562b6ee221Sahoka code[2] |= 2;
1572b6ee221Sahoka }
1582b6ee221Sahoka if ((even_column_code & 0x04) != 0) {
1592b6ee221Sahoka
1602b6ee221Sahoka code[2] |= 1;
1612b6ee221Sahoka }
1622b6ee221Sahoka
1632b6ee221Sahoka odd_line_code <<= 1;
1642b6ee221Sahoka even_line_code <<= 1;
1652b6ee221Sahoka odd_column_code <<= 1;
1662b6ee221Sahoka even_column_code <<= 1;
1672b6ee221Sahoka }
1682b6ee221Sahoka
1692b6ee221Sahoka /* Invert codes (linux compatibility) */
1702b6ee221Sahoka code[0] = ~code[0];
1712b6ee221Sahoka code[1] = ~code[1];
1722b6ee221Sahoka code[2] = ~code[2];
1732b6ee221Sahoka }
1742b6ee221Sahoka
1752b6ee221Sahoka /**
1762b6ee221Sahoka * Verifies and corrects a 256-bytes block of data using the given 22-bits
1772b6ee221Sahoka * hamming code.
1782b6ee221Sahoka * Returns 0 if there is no error, otherwise returns a HAMMING_ERROR code.
1792b6ee221Sahoka * param data Data buffer to check.
1802b6ee221Sahoka * \param original_code Hamming code to use for verifying the data.
1812b6ee221Sahoka */
1822b6ee221Sahoka uint8_t
hamming_correct_256(uint8_t * data,const uint8_t * original_code,const uint8_t * computed_code)1832b6ee221Sahoka hamming_correct_256(uint8_t *data, const uint8_t *original_code,
1842b6ee221Sahoka const uint8_t *computed_code)
1852b6ee221Sahoka {
1862b6ee221Sahoka /* Calculate new code */
1872b6ee221Sahoka /* we allocate 4 bytes so we can use popcount32 in one step */
1882b6ee221Sahoka uint8_t correction_code[4];
1892b6ee221Sahoka
1902b6ee221Sahoka /* this byte should remain zero all the time */
1912b6ee221Sahoka correction_code[3] = 0;
1922b6ee221Sahoka
1932b6ee221Sahoka /* Xor both codes together */
1942b6ee221Sahoka correction_code[0] = computed_code[0] ^ original_code[0];
1952b6ee221Sahoka correction_code[1] = computed_code[1] ^ original_code[1];
1962b6ee221Sahoka correction_code[2] = computed_code[2] ^ original_code[2];
1972b6ee221Sahoka
1982b6ee221Sahoka /* If all bytes are 0, there is no error */
1992b6ee221Sahoka if (*(uint32_t *)correction_code == 0) {
2002b6ee221Sahoka return 0;
2012b6ee221Sahoka }
2022b6ee221Sahoka /* If there is a single bit error, there are 11 bits set to 1 */
2032b6ee221Sahoka if (popcount32(*(uint32_t *)correction_code) == 11) {
2042b6ee221Sahoka /* Get byte and bit indexes */
2052b6ee221Sahoka uint8_t byte = correction_code[0] & 0x80;
2062b6ee221Sahoka byte |= (correction_code[0] << 1) & 0x40;
2072b6ee221Sahoka byte |= (correction_code[0] << 2) & 0x20;
2082b6ee221Sahoka byte |= (correction_code[0] << 3) & 0x10;
2092b6ee221Sahoka
2102b6ee221Sahoka byte |= (correction_code[1] >> 4) & 0x08;
2112b6ee221Sahoka byte |= (correction_code[1] >> 3) & 0x04;
2122b6ee221Sahoka byte |= (correction_code[1] >> 2) & 0x02;
2132b6ee221Sahoka byte |= (correction_code[1] >> 1) & 0x01;
2142b6ee221Sahoka
2152b6ee221Sahoka uint8_t bit = (correction_code[2] >> 5) & 0x04;
2162b6ee221Sahoka bit |= (correction_code[2] >> 4) & 0x02;
2172b6ee221Sahoka bit |= (correction_code[2] >> 3) & 0x01;
2182b6ee221Sahoka
2192b6ee221Sahoka /* Correct bit */
2202b6ee221Sahoka data[byte] ^= (1 << bit);
2212b6ee221Sahoka
2222b6ee221Sahoka return HAMMING_ERROR_SINGLEBIT;
2232b6ee221Sahoka }
2242b6ee221Sahoka /* Check if ECC has been corrupted */
2252b6ee221Sahoka if (popcount32(*(uint32_t *)correction_code) == 1) {
2262b6ee221Sahoka return HAMMING_ERROR_ECC;
2272b6ee221Sahoka } else {
2282b6ee221Sahoka /* Otherwise, this is a multi-bit error */
2292b6ee221Sahoka return HAMMING_ERROR_MULTIPLEBITS;
2302b6ee221Sahoka }
2312b6ee221Sahoka }
2322b6ee221Sahoka
233