cbtable.c 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266
  1. /*
  2. * This file is part of the flashrom project.
  3. *
  4. * Copyright (C) 2002 Steven James <pyro@linuxlabs.com>
  5. * Copyright (C) 2002 Linux Networx
  6. * (Written by Eric Biederman <ebiederman@lnxi.com> for Linux Networx)
  7. * Copyright (C) 2006-2009 coresystems GmbH
  8. * (Written by Stefan Reinauer <stepan@coresystems.de> for coresystems GmbH)
  9. * Copyright (C) 2010 Carl-Daniel Hailfinger
  10. *
  11. * This program is free software; you can redistribute it and/or modify
  12. * it under the terms of the GNU General Public License as published by
  13. * the Free Software Foundation; version 2 of the License.
  14. *
  15. * This program is distributed in the hope that it will be useful,
  16. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  18. * GNU General Public License for more details.
  19. *
  20. * You should have received a copy of the GNU General Public License
  21. * along with this program; if not, write to the Free Software
  22. * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
  23. */
  24. #include <unistd.h>
  25. #include <stdio.h>
  26. #include <stdlib.h>
  27. #include <string.h>
  28. #include "flash.h"
  29. #include "programmer.h"
  30. #include "coreboot_tables.h"
  31. char *lb_part = NULL, *lb_vendor = NULL;
  32. int partvendor_from_cbtable = 0;
  33. /* Parse the [<vendor>:]<board> string specified by the user as part of
  34. * -p internal:mainboard=[<vendor>:]<board> and set lb_vendor and lb_part
  35. * to the extracted values.
  36. * Note: strtok modifies the original string, so we work on a copy and allocate
  37. * memory for lb_vendor and lb_part with strdup.
  38. */
  39. void lb_vendor_dev_from_string(const char *boardstring)
  40. {
  41. /* strtok may modify the original string. */
  42. char *tempstr = strdup(boardstring);
  43. char *tempstr2 = NULL;
  44. strtok(tempstr, ":");
  45. tempstr2 = strtok(NULL, ":");
  46. if (tempstr2) {
  47. lb_vendor = strdup(tempstr);
  48. lb_part = strdup(tempstr2);
  49. } else {
  50. lb_vendor = NULL;
  51. lb_part = strdup(tempstr);
  52. }
  53. free(tempstr);
  54. }
  55. static unsigned long compute_checksum(void *addr, unsigned long length)
  56. {
  57. uint8_t *ptr;
  58. volatile union {
  59. uint8_t byte[2];
  60. uint16_t word;
  61. } chksum;
  62. unsigned long sum;
  63. unsigned long i;
  64. /* In the most straight forward way possible,
  65. * compute an ip style checksum.
  66. */
  67. sum = 0;
  68. ptr = addr;
  69. for (i = 0; i < length; i++) {
  70. unsigned long value;
  71. value = ptr[i];
  72. if (i & 1) {
  73. value <<= 8;
  74. }
  75. /* Add the new value */
  76. sum += value;
  77. /* Wrap around the carry */
  78. if (sum > 0xFFFF) {
  79. sum = (sum + (sum >> 16)) & 0xFFFF;
  80. }
  81. }
  82. chksum.byte[0] = sum & 0xff;
  83. chksum.byte[1] = (sum >> 8) & 0xff;
  84. return (~chksum.word) & 0xFFFF;
  85. }
  86. #define for_each_lbrec(head, rec) \
  87. for(rec = (struct lb_record *)(((char *)head) + sizeof(*head)); \
  88. (((char *)rec) < (((char *)head) + sizeof(*head) + head->table_bytes)) && \
  89. (rec->size >= 1) && \
  90. ((((char *)rec) + rec->size) <= (((char *)head) + sizeof(*head) + head->table_bytes)); \
  91. rec = (struct lb_record *)(((char *)rec) + rec->size))
  92. static int count_lb_records(struct lb_header *head)
  93. {
  94. struct lb_record *rec;
  95. int count;
  96. count = 0;
  97. for_each_lbrec(head, rec) {
  98. count++;
  99. }
  100. return count;
  101. }
  102. static struct lb_header *find_lb_table(void *base, unsigned long start,
  103. unsigned long end)
  104. {
  105. unsigned long addr;
  106. /* For now be stupid.... */
  107. for (addr = start; addr < end; addr += 16) {
  108. struct lb_header *head =
  109. (struct lb_header *)(((char *)base) + addr);
  110. struct lb_record *recs =
  111. (struct lb_record *)(((char *)base) + addr + sizeof(*head));
  112. if (memcmp(head->signature, "LBIO", 4) != 0)
  113. continue;
  114. msg_pdbg("Found candidate at: %08lx-%08lx\n",
  115. addr, addr + head->table_bytes);
  116. if (head->header_bytes != sizeof(*head)) {
  117. msg_perr("Header bytes of %d are incorrect.\n",
  118. head->header_bytes);
  119. continue;
  120. }
  121. if (count_lb_records(head) != head->table_entries) {
  122. msg_perr("Bad record count: %d.\n",
  123. head->table_entries);
  124. continue;
  125. }
  126. if (compute_checksum((uint8_t *) head, sizeof(*head)) != 0) {
  127. msg_perr("Bad header checksum.\n");
  128. continue;
  129. }
  130. if (compute_checksum(recs, head->table_bytes)
  131. != head->table_checksum) {
  132. msg_perr("Bad table checksum: %04x.\n",
  133. head->table_checksum);
  134. continue;
  135. }
  136. msg_pdbg("Found coreboot table at 0x%08lx.\n", addr);
  137. return head;
  138. };
  139. return NULL;
  140. }
  141. static void find_mainboard(struct lb_record *ptr, unsigned long addr)
  142. {
  143. struct lb_mainboard *rec;
  144. int max_size;
  145. char vendor[256], part[256];
  146. rec = (struct lb_mainboard *)ptr;
  147. max_size = rec->size - sizeof(*rec);
  148. msg_pdbg("Vendor ID: %.*s, part ID: %.*s\n",
  149. max_size - rec->vendor_idx,
  150. rec->strings + rec->vendor_idx,
  151. max_size - rec->part_number_idx,
  152. rec->strings + rec->part_number_idx);
  153. snprintf(vendor, 255, "%.*s", max_size - rec->vendor_idx,
  154. rec->strings + rec->vendor_idx);
  155. snprintf(part, 255, "%.*s", max_size - rec->part_number_idx,
  156. rec->strings + rec->part_number_idx);
  157. if (lb_part) {
  158. msg_pdbg("Overwritten by command line, vendor ID: %s, part ID: %s.\n", lb_vendor, lb_part);
  159. } else {
  160. partvendor_from_cbtable = 1;
  161. lb_part = strdup(part);
  162. lb_vendor = strdup(vendor);
  163. }
  164. }
  165. static struct lb_record *next_record(struct lb_record *rec)
  166. {
  167. return (struct lb_record *)(((char *)rec) + rec->size);
  168. }
  169. static void search_lb_records(struct lb_record *rec, struct lb_record *last,
  170. unsigned long addr)
  171. {
  172. struct lb_record *next;
  173. int count;
  174. count = 0;
  175. for (next = next_record(rec); (rec < last) && (next <= last);
  176. rec = next, addr += rec->size) {
  177. next = next_record(rec);
  178. count++;
  179. if (rec->tag == LB_TAG_MAINBOARD) {
  180. find_mainboard(rec, addr);
  181. break;
  182. }
  183. }
  184. }
  185. #define BYTES_TO_MAP (1024*1024)
  186. int coreboot_init(void)
  187. {
  188. uint8_t *table_area;
  189. unsigned long addr, start;
  190. struct lb_header *lb_table;
  191. struct lb_record *rec, *last;
  192. #ifdef __DARWIN__
  193. /* This is a hack. DirectHW fails to map physical address 0x00000000.
  194. * Why?
  195. */
  196. start = 0x400;
  197. #else
  198. start = 0x0;
  199. #endif
  200. table_area = physmap_try_ro("low megabyte", start, BYTES_TO_MAP - start);
  201. if (ERROR_PTR == table_area) {
  202. msg_perr("Failed getting access to coreboot low tables.\n");
  203. return -1;
  204. }
  205. lb_table = find_lb_table(table_area, 0x00000, 0x1000);
  206. if (!lb_table)
  207. lb_table = find_lb_table(table_area, 0xf0000 - start, BYTES_TO_MAP - start);
  208. if (lb_table) {
  209. struct lb_forward *forward = (struct lb_forward *)
  210. (((char *)lb_table) + lb_table->header_bytes);
  211. if (forward->tag == LB_TAG_FORWARD) {
  212. start = forward->forward;
  213. start &= ~(getpagesize() - 1);
  214. physunmap(table_area, BYTES_TO_MAP);
  215. table_area = physmap_try_ro("high tables", start, BYTES_TO_MAP);
  216. if (ERROR_PTR == table_area) {
  217. msg_perr("Failed getting access to coreboot "
  218. "high tables.\n");
  219. return -1;
  220. }
  221. lb_table = find_lb_table(table_area, 0x00000, 0x1000);
  222. }
  223. }
  224. if (!lb_table) {
  225. msg_pdbg("No coreboot table found.\n");
  226. return -1;
  227. }
  228. addr = ((char *)lb_table) - ((char *)table_area) + start;
  229. msg_pdbg("coreboot table found at 0x%lx.\n",
  230. (unsigned long)lb_table - (unsigned long)table_area + start);
  231. rec = (struct lb_record *)(((char *)lb_table) + lb_table->header_bytes);
  232. last = (struct lb_record *)(((char *)rec) + lb_table->table_bytes);
  233. msg_pdbg("coreboot header(%d) checksum: %04x table(%d) checksum: %04x entries: %d\n",
  234. lb_table->header_bytes, lb_table->header_checksum,
  235. lb_table->table_bytes, lb_table->table_checksum,
  236. lb_table->table_entries);
  237. search_lb_records(rec, last, addr + lb_table->header_bytes);
  238. return 0;
  239. }