2 * Copyright 2016 General Electric Company
4 * SPDX-License-Identifier: GPL-2.0+
7 #include "vpd_reader.h"
13 /* BCH configuration */
16 int header_ecc_capability_bits;
17 int data_ecc_capability_bits;
18 unsigned int prim_poly;
23 } bch_configuration = {
24 .header_ecc_capability_bits = 4,
25 .data_ecc_capability_bits = 16,
27 .galois_field_order = {
33 static int calculate_galois_field_order(size_t source_length)
35 int gfo = bch_configuration.galois_field_order.min;
37 for (; gfo < bch_configuration.galois_field_order.max &&
38 ((((1 << gfo) - 1) - ((int)source_length * 8)) < 0);
42 if (gfo == bch_configuration.galois_field_order.max) {
49 static int verify_bch(int ecc_bits, unsigned int prim_poly,
50 uint8_t * data, size_t data_length,
51 const uint8_t * ecc, size_t ecc_length)
53 int gfo = calculate_galois_field_order(data_length);
58 struct bch_control * bch = init_bch(gfo, ecc_bits, prim_poly);
63 if (bch->ecc_bytes != ecc_length) {
68 unsigned * errloc = (unsigned *)calloc(data_length, sizeof(unsigned));
69 int errors = decode_bch(
70 bch, data, data_length, ecc, NULL, NULL, errloc);
78 for (int n = 0; n < errors; n++) {
79 if (errloc[n] >= 8 * data_length) {
80 /* n-th error located in ecc (no need for data correction) */
82 /* n-th error located in data */
83 data[errloc[n] / 8] ^= 1 << (errloc[n] % 8);
93 static const int ID = 0;
94 static const int LEN = 1;
95 static const int VER = 2;
96 static const int TYP = 3;
97 static const int BLOCK_SIZE = 4;
99 static const uint8_t HEADER_BLOCK_ID = 0x00;
100 static const uint8_t HEADER_BLOCK_LEN = 18;
101 static const uint32_t HEADER_BLOCK_MAGIC = 0xca53ca53;
102 static const size_t HEADER_BLOCK_VERIFY_LEN = 14;
103 static const size_t HEADER_BLOCK_ECC_OFF = 14;
104 static const size_t HEADER_BLOCK_ECC_LEN = 4;
106 static const uint8_t ECC_BLOCK_ID = 0xFF;
118 uint8_t const * data))
120 if ( size < HEADER_BLOCK_LEN
127 * +--------------------+--------------------+--//--+--------------------+
128 * | header block | data block | ... | ecc block |
129 * +--------------------+--------------------+--//--+--------------------+
131 * +------+-------+-----+ +------+-------------+
132 * | id | magic | ecc | | ... | ecc |
133 * | len | off | | +------+-------------+
136 * +------+-------+-----+ :
138 * <----- [1] ----> <----------- [2] ----------->
140 * Repair (if necessary) the contents of header block [1] by using a
141 * 4 byte ECC located at the end of the header block. A successful
142 * return value means that we can trust the header.
144 int ret = verify_bch(
145 bch_configuration.header_ecc_capability_bits,
146 bch_configuration.prim_poly,
148 HEADER_BLOCK_VERIFY_LEN,
149 &data[HEADER_BLOCK_ECC_OFF],
150 HEADER_BLOCK_ECC_LEN);
155 /* Validate header block { id, length, version, type }. */
156 if ( data[ID] != HEADER_BLOCK_ID
157 || data[LEN] != HEADER_BLOCK_LEN
160 || ntohl(*(uint32_t *)(&data[4])) != HEADER_BLOCK_MAGIC) {
164 uint32_t offset = ntohl(*(uint32_t *)(&data[8]));
165 uint16_t size_bits = ntohs(*(uint16_t *)(&data[12]));
167 /* Check that ECC header fits. */
168 if (offset + 3 >= size) {
172 /* Validate ECC block. */
173 uint8_t * ecc = &data[offset];
174 if ( ecc[ID] != ECC_BLOCK_ID
175 || ecc[LEN] < BLOCK_SIZE
176 || ecc[LEN] + offset > size
177 || ecc[LEN] - BLOCK_SIZE != size_bits / 8
184 * Use the header block to locate the ECC block and verify the data
185 * blocks [2] against the ecc block ECC.
188 bch_configuration.data_ecc_capability_bits,
189 bch_configuration.prim_poly,
192 &data[offset + BLOCK_SIZE],
193 ecc[LEN] - BLOCK_SIZE);
198 /* Stop after ECC. Ignore possible zero padding. */
202 /* Move to next block. */
207 /* Finished iterating through blocks. */
211 if ( size < BLOCK_SIZE
212 || data[LEN] < BLOCK_SIZE) {
213 /* Not enough data for a header, or short header. */
222 data[LEN] - BLOCK_SIZE,