vpd_reader.c 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  1. // SPDX-License-Identifier: GPL-2.0+
  2. /*
  3. * Copyright 2016 General Electric Company
  4. */
  5. #include "vpd_reader.h"
  6. #include <linux/bch.h>
  7. #include <stdlib.h>
  8. /* BCH configuration */
  9. const struct {
  10. int header_ecc_capability_bits;
  11. int data_ecc_capability_bits;
  12. unsigned int prim_poly;
  13. struct {
  14. int min;
  15. int max;
  16. } galois_field_order;
  17. } bch_configuration = {
  18. .header_ecc_capability_bits = 4,
  19. .data_ecc_capability_bits = 16,
  20. .prim_poly = 0,
  21. .galois_field_order = {
  22. .min = 5,
  23. .max = 15,
  24. },
  25. };
  26. static int calculate_galois_field_order(size_t source_length)
  27. {
  28. int gfo = bch_configuration.galois_field_order.min;
  29. for (; gfo < bch_configuration.galois_field_order.max &&
  30. ((((1 << gfo) - 1) - ((int)source_length * 8)) < 0);
  31. gfo++) {
  32. }
  33. if (gfo == bch_configuration.galois_field_order.max)
  34. return -1;
  35. return gfo + 1;
  36. }
  37. static int verify_bch(int ecc_bits, unsigned int prim_poly, u8 *data,
  38. size_t data_length, const u8 *ecc, size_t ecc_length)
  39. {
  40. int gfo = calculate_galois_field_order(data_length);
  41. if (gfo < 0)
  42. return -1;
  43. struct bch_control *bch = init_bch(gfo, ecc_bits, prim_poly);
  44. if (!bch)
  45. return -1;
  46. if (bch->ecc_bytes != ecc_length) {
  47. free_bch(bch);
  48. return -1;
  49. }
  50. unsigned int *errloc = (unsigned int *)calloc(data_length,
  51. sizeof(unsigned int));
  52. int errors = decode_bch(bch, data, data_length, ecc, NULL, NULL,
  53. errloc);
  54. free_bch(bch);
  55. if (errors < 0) {
  56. free(errloc);
  57. return -1;
  58. }
  59. if (errors > 0) {
  60. for (int n = 0; n < errors; n++) {
  61. if (errloc[n] >= 8 * data_length) {
  62. /*
  63. * n-th error located in ecc (no need for data
  64. * correction)
  65. */
  66. } else {
  67. /* n-th error located in data */
  68. data[errloc[n] / 8] ^= 1 << (errloc[n] % 8);
  69. }
  70. }
  71. }
  72. free(errloc);
  73. return 0;
  74. }
  75. static const int ID;
  76. static const int LEN = 1;
  77. static const int VER = 2;
  78. static const int TYP = 3;
  79. static const int BLOCK_SIZE = 4;
  80. static const u8 HEADER_BLOCK_ID;
  81. static const u8 HEADER_BLOCK_LEN = 18;
  82. static const u32 HEADER_BLOCK_MAGIC = 0xca53ca53;
  83. static const size_t HEADER_BLOCK_VERIFY_LEN = 14;
  84. static const size_t HEADER_BLOCK_ECC_OFF = 14;
  85. static const size_t HEADER_BLOCK_ECC_LEN = 4;
  86. static const u8 ECC_BLOCK_ID = 0xFF;
  87. int vpd_reader(size_t size, u8 *data, void *userdata,
  88. int (*fn)(void *userdata, u8 id, u8 version, u8 type,
  89. size_t size, u8 const *data))
  90. {
  91. if (size < HEADER_BLOCK_LEN || !data || !fn)
  92. return -EINVAL;
  93. /*
  94. * +--------------------+----------------+--//--+--------------------+
  95. * | header block | data block | ... | ecc block |
  96. * +--------------------+----------------+--//--+--------------------+
  97. * : : :
  98. * +------+-------+-----+ +------+-------------+
  99. * | id | magic | ecc | | ... | ecc |
  100. * | len | off | | +------+-------------+
  101. * | ver | size | | :
  102. * | type | | | :
  103. * +------+-------+-----+ :
  104. * : : : :
  105. * <----- [1] ----> <--------- [2] --------->
  106. *
  107. * Repair (if necessary) the contents of header block [1] by using a
  108. * 4 byte ECC located at the end of the header block. A successful
  109. * return value means that we can trust the header.
  110. */
  111. int ret = verify_bch(bch_configuration.header_ecc_capability_bits,
  112. bch_configuration.prim_poly, data,
  113. HEADER_BLOCK_VERIFY_LEN,
  114. &data[HEADER_BLOCK_ECC_OFF], HEADER_BLOCK_ECC_LEN);
  115. if (ret < 0)
  116. return ret;
  117. /* Validate header block { id, length, version, type }. */
  118. if (data[ID] != HEADER_BLOCK_ID || data[LEN] != HEADER_BLOCK_LEN ||
  119. data[VER] != 0 || data[TYP] != 0 ||
  120. ntohl(*(u32 *)(&data[4])) != HEADER_BLOCK_MAGIC)
  121. return -EINVAL;
  122. u32 offset = ntohl(*(u32 *)(&data[8]));
  123. u16 size_bits = ntohs(*(u16 *)(&data[12]));
  124. /* Check that ECC header fits. */
  125. if (offset + 3 >= size)
  126. return -EINVAL;
  127. /* Validate ECC block. */
  128. u8 *ecc = &data[offset];
  129. if (ecc[ID] != ECC_BLOCK_ID || ecc[LEN] < BLOCK_SIZE ||
  130. ecc[LEN] + offset > size ||
  131. ecc[LEN] - BLOCK_SIZE != size_bits / 8 || ecc[VER] != 1 ||
  132. ecc[TYP] != 1)
  133. return -EINVAL;
  134. /*
  135. * Use the header block to locate the ECC block and verify the data
  136. * blocks [2] against the ecc block ECC.
  137. */
  138. ret = verify_bch(bch_configuration.data_ecc_capability_bits,
  139. bch_configuration.prim_poly, &data[data[LEN]],
  140. offset - data[LEN], &data[offset + BLOCK_SIZE],
  141. ecc[LEN] - BLOCK_SIZE);
  142. if (ret < 0)
  143. return ret;
  144. /* Stop after ECC. Ignore possible zero padding. */
  145. size = offset;
  146. for (;;) {
  147. /* Move to next block. */
  148. size -= data[LEN];
  149. data += data[LEN];
  150. if (size == 0) {
  151. /* Finished iterating through blocks. */
  152. return 0;
  153. }
  154. if (size < BLOCK_SIZE || data[LEN] < BLOCK_SIZE) {
  155. /* Not enough data for a header, or short header. */
  156. return -EINVAL;
  157. }
  158. ret = fn(userdata, data[ID], data[VER], data[TYP],
  159. data[LEN] - BLOCK_SIZE, &data[BLOCK_SIZE]);
  160. if (ret)
  161. return ret;
  162. }
  163. }