1// SPDX-License-Identifier: GPL-2.0+ 2/* 3 * Copyright 2016 General Electric Company 4 */ 5 6#include "vpd_reader.h" 7#include <malloc.h> 8 9#include <i2c.h> 10#include <linux/bch.h> 11#include <stdlib.h> 12#include <dm/uclass.h> 13#include <i2c_eeprom.h> 14#include <hexdump.h> 15 16/* BCH configuration */ 17 18const struct { 19 int header_ecc_capability_bits; 20 int data_ecc_capability_bits; 21 unsigned int prim_poly; 22 struct { 23 int min; 24 int max; 25 } galois_field_order; 26} bch_configuration = { 27 .header_ecc_capability_bits = 4, 28 .data_ecc_capability_bits = 16, 29 .prim_poly = 0, 30 .galois_field_order = { 31 .min = 5, 32 .max = 15, 33 }, 34}; 35 36static int calculate_galois_field_order(size_t source_length) 37{ 38 int gfo = bch_configuration.galois_field_order.min; 39 40 for (; gfo < bch_configuration.galois_field_order.max && 41 ((((1 << gfo) - 1) - ((int)source_length * 8)) < 0); 42 gfo++) { 43 } 44 45 if (gfo == bch_configuration.galois_field_order.max) 46 return -1; 47 48 return gfo + 1; 49} 50 51static int verify_bch(int ecc_bits, unsigned int prim_poly, u8 *data, 52 size_t data_length, const u8 *ecc, size_t ecc_length) 53{ 54 int gfo = calculate_galois_field_order(data_length); 55 56 if (gfo < 0) 57 return -1; 58 59 struct bch_control *bch = init_bch(gfo, ecc_bits, prim_poly); 60 61 if (!bch) 62 return -1; 63 64 if (bch->ecc_bytes != ecc_length) { 65 free_bch(bch); 66 return -1; 67 } 68 69 unsigned int *errloc = (unsigned int *)calloc(data_length, 70 sizeof(unsigned int)); 71 int errors = decode_bch(bch, data, data_length, ecc, NULL, NULL, 72 errloc); 73 74 free_bch(bch); 75 if (errors < 0) { 76 free(errloc); 77 return -1; 78 } 79 80 if (errors > 0) { 81 for (int n = 0; n < errors; n++) { 82 if (errloc[n] >= 8 * data_length) { 83 /* 84 * n-th error located in ecc (no need for data 85 * correction) 86 */ 87 } else { 88 /* n-th error located in data */ 89 data[errloc[n] / 8] ^= 1 << (errloc[n] % 8); 90 } 91 } 92 } 93 94 free(errloc); 95 return 0; 96} 97 98static const int ID; 99static const int LEN = 1; 100static const int VER = 2; 101static const int TYP = 3; 102static const int BLOCK_SIZE = 4; 103 104static const u8 HEADER_BLOCK_ID; 105static const u8 HEADER_BLOCK_LEN = 18; 106static const u32 HEADER_BLOCK_MAGIC = 0xca53ca53; 107static const size_t HEADER_BLOCK_VERIFY_LEN = 14; 108static const size_t HEADER_BLOCK_ECC_OFF = 14; 109static const size_t HEADER_BLOCK_ECC_LEN = 4; 110 111static const u8 ECC_BLOCK_ID = 0xFF; 112 113int vpd_reader(size_t size, u8 *data, struct vpd_cache *userdata, 114 int (*fn)(struct vpd_cache *, u8 id, u8 version, u8 type, 115 size_t size, u8 const *data)) 116{ 117 if (size < HEADER_BLOCK_LEN || !data || !fn) 118 return -EINVAL; 119 120 /* 121 * +--------------------+----------------+--//--+--------------------+ 122 * | header block | data block | ... | ecc block | 123 * +--------------------+----------------+--//--+--------------------+ 124 * : : : 125 * +------+-------+-----+ +------+-------------+ 126 * | id | magic | ecc | | ... | ecc | 127 * | len | off | | +------+-------------+ 128 * | ver | size | | : 129 * | type | | | : 130 * +------+-------+-----+ : 131 * : : : : 132 * <----- [1] ----> <--------- [2] ---------> 133 * 134 * Repair (if necessary) the contents of header block [1] by using a 135 * 4 byte ECC located at the end of the header block. A successful 136 * return value means that we can trust the header. 137 */ 138 int ret = verify_bch(bch_configuration.header_ecc_capability_bits, 139 bch_configuration.prim_poly, data, 140 HEADER_BLOCK_VERIFY_LEN, 141 &data[HEADER_BLOCK_ECC_OFF], HEADER_BLOCK_ECC_LEN); 142 if (ret < 0) 143 return ret; 144 145 /* Validate header block { id, length, version, type }. */ 146 if (data[ID] != HEADER_BLOCK_ID || data[LEN] != HEADER_BLOCK_LEN || 147 data[VER] != 0 || data[TYP] != 0 || 148 ntohl(*(u32 *)(&data[4])) != HEADER_BLOCK_MAGIC) 149 return -EINVAL; 150 151 u32 offset = ntohl(*(u32 *)(&data[8])); 152 u16 size_bits = ntohs(*(u16 *)(&data[12])); 153 154 /* Check that ECC header fits. */ 155 if (offset + 3 >= size) 156 return -EINVAL; 157 158 /* Validate ECC block. */ 159 u8 *ecc = &data[offset]; 160 161 if (ecc[ID] != ECC_BLOCK_ID || ecc[LEN] < BLOCK_SIZE || 162 ecc[LEN] + offset > size || 163 ecc[LEN] - BLOCK_SIZE != size_bits / 8 || ecc[VER] != 1 || 164 ecc[TYP] != 1) 165 return -EINVAL; 166 167 /* 168 * Use the header block to locate the ECC block and verify the data 169 * blocks [2] against the ecc block ECC. 170 */ 171 ret = verify_bch(bch_configuration.data_ecc_capability_bits, 172 bch_configuration.prim_poly, &data[data[LEN]], 173 offset - data[LEN], &data[offset + BLOCK_SIZE], 174 ecc[LEN] - BLOCK_SIZE); 175 if (ret < 0) 176 return ret; 177 178 /* Stop after ECC. Ignore possible zero padding. */ 179 size = offset; 180 181 for (;;) { 182 /* Move to next block. */ 183 size -= data[LEN]; 184 data += data[LEN]; 185 186 if (size == 0) { 187 /* Finished iterating through blocks. */ 188 return 0; 189 } 190 191 if (size < BLOCK_SIZE || data[LEN] < BLOCK_SIZE) { 192 /* Not enough data for a header, or short header. */ 193 return -EINVAL; 194 } 195 196 ret = fn(userdata, data[ID], data[VER], data[TYP], 197 data[LEN] - BLOCK_SIZE, &data[BLOCK_SIZE]); 198 if (ret) 199 return ret; 200 } 201} 202 203int read_i2c_vpd(struct vpd_cache *cache, 204 int (*process_block)(struct vpd_cache *, u8 id, u8 version, 205 u8 type, size_t size, u8 const *data)) 206{ 207 struct udevice *dev; 208 int ret; 209 u8 *data; 210 int size; 211 212 ret = uclass_get_device_by_name(UCLASS_I2C_EEPROM, "vpd@0", &dev); 213 if (ret) 214 return ret; 215 216 size = i2c_eeprom_size(dev); 217 if (size < 0) { 218 printf("Unable to get size of eeprom: %d\n", ret); 219 return ret; 220 } 221 222 data = malloc(size); 223 if (!data) 224 return -ENOMEM; 225 226 ret = i2c_eeprom_read(dev, 0, data, size); 227 if (ret) { 228 free(data); 229 return ret; 230 } 231 232 ret = vpd_reader(size, data, cache, process_block); 233 234 free(data); 235 236 return ret; 237} 238